Skip to main content

rustc_attr_parsing/attributes/
inline.rs

1use rustc_attr_ir::{Attribute, AttributeKind, InlineAttr, find_attr};
2use rustc_feature::AttributeStability;
3use rustc_lint_defs::builtin::{ILL_FORMED_ATTRIBUTE_INPUT, UNUSED_ATTRIBUTES};
4
5use super::prelude::*;
6use crate::diagnostics::{InlineForceInlineConflict, InlineIgnoredForExported, UnusedMultiple};
7
8#[derive(#[automatically_derived]impl ::core::default::Default for InlineParser {
    #[inline]
    fn default() -> Self { InlineParser(::core::default::Default::default()) }
}Default)]
9pub(crate) struct InlineParser(Option<(InlineAttr, Span)>);
10
11impl AttributeParser for InlineParser {
12    const ATTRIBUTES: AcceptMapping<Self> = &[
13        (
14            &[sym::inline],
15            crate::AttributeTemplate {
    word: true,
    list: Some(&["always", "never"]),
    one_of: &[],
    name_value_str: None,
    docs: Some("https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute"),
}template!(
16                Word,
17                List: &["always", "never"],
18                "https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute"
19            ),
20            AttributeStability::Stable,
21            |this, cx, args| {
22                cx.check_target(
23                    "",
24                    &AllowedTargets::AllowList(&[
25                        Allow(Target::Fn),
26                        Allow(Target::Method(MethodKind::Inherent)),
27                        Allow(Target::Method(MethodKind::Trait { body: true })),
28                        Allow(Target::Method(MethodKind::TraitImpl)),
29                        Allow(Target::Closure),
30                        Allow(Target::Delegation { mac: false }),
31                        Warn(Target::Method(MethodKind::Trait { body: false })),
32                        Warn(Target::ForeignFn),
33                        Warn(Target::Field),
34                        Warn(Target::MacroDef),
35                        Warn(Target::Arm),
36                        Warn(Target::AssocConst(AssocCtxt::Impl { of_trait: false })),
37                        Warn(Target::AssocConst(AssocCtxt::Trait)),
38                        Warn(Target::AssocConst(AssocCtxt::Impl { of_trait: true })),
39                        Warn(Target::MacroCall),
40                    ]),
41                );
42
43                let inline_span = cx.attr_span;
44                let attr = match args {
45                    ArgParser::NoArgs => InlineAttr::Hint,
46                    ArgParser::List(list) => {
47                        let Some(l) = cx.expect_single(list) else { return };
48
49                        match l.meta_item_no_args().and_then(|i| i.path().word_sym()) {
50                            Some(sym::always) => InlineAttr::Always,
51                            Some(sym::never) => InlineAttr::Never,
52                            _ => {
53                                cx.adcx().expected_specific_argument(
54                                    l.span(),
55                                    &[sym::always, sym::never],
56                                );
57                                return;
58                            }
59                        }
60                    }
61                    ArgParser::NameValue(_) => {
62                        cx.adcx().warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT);
63                        return;
64                    }
65                };
66
67                match this.0 {
68                    None => this.0 = Some((attr, inline_span)),
69                    Some((InlineAttr::Force { .. }, force_inline_span)) => {
70                        cx.emit_err(InlineForceInlineConflict { inline_span, force_inline_span });
71                    }
72                    Some((_, first_inline_span)) => {
73                        cx.warn_unused_duplicate_future_error(first_inline_span, inline_span);
74                    }
75                }
76            },
77        ),
78        (
79            &[sym::rustc_force_inline],
80            crate::AttributeTemplate {
    word: true,
    list: Some(&["reason"]),
    one_of: &[],
    name_value_str: Some(&["reason"]),
    docs: None,
}template!(Word, List: &["reason"], NameValueStr: "reason"),
81            {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &["the `rustc_force_inline` attribute forces a free function to be inlined"],
    }
}unstable!(
82                rustc_attrs,
83                "the `rustc_force_inline` attribute forces a free function to be inlined"
84            ),
85            |this, cx, args| {
86                cx.check_target(
87                    "",
88                    &AllowedTargets::AllowList(&[
89                        Allow(Target::Fn),
90                        Allow(Target::Method(MethodKind::Inherent)),
91                    ]),
92                );
93                let force_inline_span = cx.attr_span;
94                let reason = match args {
95                    ArgParser::NoArgs => None,
96                    ArgParser::List(list) => {
97                        let Some(l) = cx.expect_single(list) else { return };
98
99                        let Some(reason) = cx.expect_string_literal(l) else { return };
100
101                        Some(reason)
102                    }
103                    ArgParser::NameValue(v) => cx.expect_string_literal(v),
104                };
105
106                let attr = InlineAttr::Force { attr_span: cx.attr_span, reason };
107
108                match this.0 {
109                    None => this.0 = Some((attr, force_inline_span)),
110                    Some((InlineAttr::Force { .. }, first_force_inline_span)) => {
111                        cx.emit_err(UnusedMultiple {
112                            this: force_inline_span,
113                            other: first_force_inline_span,
114                            name: sym::rustc_force_inline,
115                        });
116                    }
117                    Some((_, inline_span)) => {
118                        cx.emit_err(InlineForceInlineConflict { inline_span, force_inline_span });
119                    }
120                }
121            },
122        ),
123    ];
124
125    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::ManuallyChecked;
126
127    fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {
128        self.0.map(|(a, s)| AttributeKind::Inline(a, s))
129    }
130
131    fn deferred_finalize_check(
132        &self,
133    ) -> Option<(fn(&mut FinalizeCheckContext<'_, '_>, Span), Span)> {
134        Some((
135            |cx: &mut FinalizeCheckContext<'_, '_>, span| {
136                let exported = cx.parsed_attrs.iter().any(|attr| {
137                    let Attribute::Parsed(kind) = attr else { return false };
138                    kind.is_extern_indicator()
139                });
140                if #[allow(non_exhaustive_omitted_patterns)] match cx.target {
    Target::Fn | Target::Closure |
        Target::Method(MethodKind::Trait { body: true } |
        MethodKind::TraitImpl | MethodKind::Inherent) => true,
    _ => false,
}matches!(
141                    cx.target,
142                    Target::Fn
143                        | Target::Closure
144                        | Target::Method(
145                            MethodKind::Trait { body: true }
146                                | MethodKind::TraitImpl
147                                | MethodKind::Inherent,
148                        )
149                ) && !{
    {
            'done:
                {
                for i in cx.parsed_attrs {
                    #[allow(unused_imports)]
                    use ::rustc_attr_ir::AttributeKind::*;
                    let i: &::rustc_attr_ir::Attribute = i;
                    match i {
                        ::rustc_attr_ir::Attribute::Parsed(Inline(InlineAttr::Never,
                            _)) => {
                            break 'done Some(());
                        }
                        ::rustc_attr_ir::Attribute::Tool(..) |
                            ::rustc_attr_ir::Attribute::DeriveHelper(..) =>
                            {}
                            #[deny(unreachable_patterns)]
                            _ => {}
                    }
                }
                None
            }
        }.is_some()
}find_attr!(cx.parsed_attrs, Inline(InlineAttr::Never, _))
150                    && exported
151                {
152                    cx.emit_lint(UNUSED_ATTRIBUTES, InlineIgnoredForExported, span);
153                }
154            },
155            self.0?.1,
156        ))
157    }
158}