Skip to main content

rustc_attr_parsing/attributes/
inline.rs

1use rustc_feature::AttributeStability;
2use rustc_hir::attrs::{AttributeKind, InlineAttr};
3use rustc_hir::find_attr;
4use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
5
6use super::prelude::*;
7use crate::session_diagnostics::InlineForceInlineConflict;
8
9pub(crate) struct InlineParser;
10
11impl SingleAttributeParser for InlineParser {
12    const PATH: &[Symbol] = &[sym::inline];
13    const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError;
14    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
15        Allow(Target::Fn),
16        Allow(Target::Method(MethodKind::Inherent)),
17        Allow(Target::Method(MethodKind::Trait { body: true })),
18        Allow(Target::Method(MethodKind::TraitImpl)),
19        Allow(Target::Closure),
20        Allow(Target::Delegation { mac: false }),
21        Warn(Target::Method(MethodKind::Trait { body: false })),
22        Warn(Target::ForeignFn),
23        Warn(Target::Field),
24        Warn(Target::MacroDef),
25        Warn(Target::Arm),
26        Warn(Target::AssocConst),
27        Warn(Target::MacroCall),
28    ]);
29    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!(
30        Word,
31        List: &["always", "never"],
32        "https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute"
33    );
34    const STABILITY: AttributeStability = AttributeStability::Stable;
35
36    fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
37        match args {
38            ArgParser::NoArgs => Some(AttributeKind::Inline(InlineAttr::Hint, cx.attr_span)),
39            ArgParser::List(list) => {
40                let l = cx.expect_single(list)?;
41
42                match l.meta_item_no_args().and_then(|i| i.path().word_sym()) {
43                    Some(sym::always) => {
44                        Some(AttributeKind::Inline(InlineAttr::Always, cx.attr_span))
45                    }
46                    Some(sym::never) => {
47                        Some(AttributeKind::Inline(InlineAttr::Never, cx.attr_span))
48                    }
49                    _ => {
50                        cx.adcx().expected_specific_argument(l.span(), &[sym::always, sym::never]);
51                        None
52                    }
53                }
54            }
55            ArgParser::NameValue(_) => {
56                cx.adcx().warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT);
57                None
58            }
59        }
60    }
61}
62
63pub(crate) struct RustcForceInlineParser;
64
65impl SingleAttributeParser for RustcForceInlineParser {
66    const PATH: &[Symbol] = &[sym::rustc_force_inline];
67    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
68        Allow(Target::Fn),
69        Allow(Target::Method(MethodKind::Inherent)),
70    ]);
71    const STABILITY: AttributeStability = AttributeStability::Unstable {
    gate_name: rustc_span::sym::rustc_attrs,
    gate_check: rustc_feature::Features::rustc_attrs,
    notes: &["the `rustc_force_inline` attribute forces a free function to be inlined"],
}unstable!(
72        rustc_attrs,
73        "the `rustc_force_inline` attribute forces a free function to be inlined"
74    );
75    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");
76
77    fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
78        let reason = match args {
79            ArgParser::NoArgs => None,
80            ArgParser::List(list) => {
81                let l = cx.expect_single(list)?;
82
83                let reason = cx.expect_string_literal(l)?;
84
85                Some(reason)
86            }
87            ArgParser::NameValue(v) => cx.expect_string_literal(v),
88        };
89
90        Some(AttributeKind::Inline(
91            InlineAttr::Force { attr_span: cx.attr_span, reason },
92            cx.attr_span,
93        ))
94    }
95
96    fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) {
97        let Some(inline_span) = {
    'done:
        {
        for i in cx.parsed_attrs {
            #[allow(unused_imports)]
            use ::rustc_hir::attrs::AttributeKind::*;
            let i: &::rustc_hir::Attribute = i;
            match i {
                ::rustc_hir::Attribute::Parsed(Inline(attr, span)) if
                    !#[allow(non_exhaustive_omitted_patterns)] match attr {
                            InlineAttr::Force { .. } => true,
                            _ => false,
                        } => {
                    break 'done Some(span);
                }
                ::rustc_hir::Attribute::Unparsed(..) =>
                    {}
                    #[deny(unreachable_patterns)]
                    _ => {}
            }
        }
        None
    }
}find_attr!(cx.parsed_attrs, Inline(attr, span) if !matches!(attr, InlineAttr::Force { .. }) => span)
98        else {
99            return;
100        };
101
102        cx.emit_err(InlineForceInlineConflict {
103            inline_span: *inline_span,
104            force_inline_span: attr_span,
105        });
106    }
107}