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};
7
8pub(crate) struct InlineParser;
9
10impl SingleAttributeParser for InlineParser {
11    const PATH: &[Symbol] = &[sym::inline];
12    const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError;
13    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
14        Allow(Target::Fn),
15        Allow(Target::Method(MethodKind::Inherent)),
16        Allow(Target::Method(MethodKind::Trait { body: true })),
17        Allow(Target::Method(MethodKind::TraitImpl)),
18        Allow(Target::Closure),
19        Allow(Target::Delegation { mac: false }),
20        Warn(Target::Method(MethodKind::Trait { body: false })),
21        Warn(Target::ForeignFn),
22        Warn(Target::Field),
23        Warn(Target::MacroDef),
24        Warn(Target::Arm),
25        Warn(Target::AssocConst(AssocCtxt::Impl { of_trait: false })),
26        Warn(Target::AssocConst(AssocCtxt::Trait)),
27        Warn(Target::AssocConst(AssocCtxt::Impl { of_trait: true })),
28        Warn(Target::MacroCall),
29    ]);
30    const TEMPLATE: AttributeTemplate = 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!(
31        Word,
32        List: &["always", "never"],
33        "https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute"
34    );
35    const STABILITY: AttributeStability = AttributeStability::Stable;
36
37    fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
38        match args {
39            ArgParser::NoArgs => Some(AttributeKind::Inline(InlineAttr::Hint, cx.attr_span)),
40            ArgParser::List(list) => {
41                let l = cx.expect_single(list)?;
42
43                match l.meta_item_no_args().and_then(|i| i.path().word_sym()) {
44                    Some(sym::always) => {
45                        Some(AttributeKind::Inline(InlineAttr::Always, cx.attr_span))
46                    }
47                    Some(sym::never) => {
48                        Some(AttributeKind::Inline(InlineAttr::Never, cx.attr_span))
49                    }
50                    _ => {
51                        cx.adcx().expected_specific_argument(l.span(), &[sym::always, sym::never]);
52                        None
53                    }
54                }
55            }
56            ArgParser::NameValue(_) => {
57                cx.adcx().warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT);
58                None
59            }
60        }
61    }
62
63    fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {
64        let exported = cx.parsed_attrs.iter().any(|attr| {
65            let Attribute::Parsed(kind) = attr else { return false };
66            kind.is_extern_indicator()
67        });
68        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!(
69            cx.target,
70            Target::Fn
71                | Target::Closure
72                | Target::Method(
73                    MethodKind::Trait { body: true } | MethodKind::TraitImpl | MethodKind::Inherent,
74                )
75        ) && !{
    {
            '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::Unparsed(..) =>
                            {}
                            #[deny(unreachable_patterns)]
                            _ => {}
                    }
                }
                None
            }
        }.is_some()
}find_attr!(cx.parsed_attrs, Inline(InlineAttr::Never, _))
76            && exported
77        {
78            cx.emit_lint(UNUSED_ATTRIBUTES, InlineIgnoredForExported, attr_span);
79        }
80    }
81}
82
83pub(crate) struct RustcForceInlineParser;
84
85impl SingleAttributeParser for RustcForceInlineParser {
86    const PATH: &[Symbol] = &[sym::rustc_force_inline];
87    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
88        Allow(Target::Fn),
89        Allow(Target::Method(MethodKind::Inherent)),
90    ]);
91    const STABILITY: AttributeStability = {
    _ = 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!(
92        rustc_attrs,
93        "the `rustc_force_inline` attribute forces a free function to be inlined"
94    );
95    const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
    word: true,
    list: Some(&["reason"]),
    one_of: &[],
    name_value_str: Some(&["reason"]),
    docs: None,
}template!(Word, List: &["reason"], NameValueStr: "reason");
96
97    fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
98        let reason = match args {
99            ArgParser::NoArgs => None,
100            ArgParser::List(list) => {
101                let l = cx.expect_single(list)?;
102
103                let reason = cx.expect_string_literal(l)?;
104
105                Some(reason)
106            }
107            ArgParser::NameValue(v) => cx.expect_string_literal(v),
108        };
109
110        Some(AttributeKind::Inline(
111            InlineAttr::Force { attr_span: cx.attr_span, reason },
112            cx.attr_span,
113        ))
114    }
115
116    fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {
117        let Some(inline_span) = {
    '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(attr, span)) if
                    !#[allow(non_exhaustive_omitted_patterns)] match attr {
                            InlineAttr::Force { .. } => true,
                            _ => false,
                        } => {
                    break 'done Some(span);
                }
                ::rustc_attr_ir::Attribute::Unparsed(..) =>
                    {}
                    #[deny(unreachable_patterns)]
                    _ => {}
            }
        }
        None
    }
}find_attr!(cx.parsed_attrs, Inline(attr, span) if !matches!(attr, InlineAttr::Force { .. }) => span)
118        else {
119            return;
120        };
121
122        cx.emit_err(InlineForceInlineConflict {
123            inline_span: *inline_span,
124            force_inline_span: attr_span,
125        });
126    }
127}