rustc_attr_parsing/attributes/
inline.rs

1// FIXME(jdonszelmann): merge these two parsers and error when both attributes are present here.
2//                      note: need to model better how duplicate attr errors work when not using
3//                      SingleAttributeParser which is what we have two of here.
4
5use rustc_hir::attrs::{AttributeKind, InlineAttr};
6use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
7
8use super::prelude::*;
9
10pub(crate) struct InlineParser;
11
12impl<S: Stage> SingleAttributeParser<S> for InlineParser {
13    const PATH: &'static [Symbol] = &[sym::inline];
14    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
15    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
16    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
17        Allow(Target::Fn),
18        Allow(Target::Method(MethodKind::Inherent)),
19        Allow(Target::Method(MethodKind::Trait { body: true })),
20        Allow(Target::Method(MethodKind::TraitImpl)),
21        Allow(Target::Closure),
22        Allow(Target::Delegation { mac: false }),
23        Warn(Target::Method(MethodKind::Trait { body: false })),
24        Warn(Target::ForeignFn),
25        Warn(Target::Field),
26        Warn(Target::MacroDef),
27        Warn(Target::Arm),
28        Warn(Target::AssocConst),
29        Warn(Target::MacroCall),
30    ]);
31    const TEMPLATE: AttributeTemplate = template!(
32        Word,
33        List: &["always", "never"],
34        "https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute"
35    );
36
37    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
38        match args {
39            ArgParser::NoArgs => Some(AttributeKind::Inline(InlineAttr::Hint, cx.attr_span)),
40            ArgParser::List(list) => {
41                let Some(l) = list.single() else {
42                    cx.expected_single_argument(list.span);
43                    return None;
44                };
45
46                match l.meta_item().and_then(|i| i.path().word_sym()) {
47                    Some(sym::always) => {
48                        Some(AttributeKind::Inline(InlineAttr::Always, cx.attr_span))
49                    }
50                    Some(sym::never) => {
51                        Some(AttributeKind::Inline(InlineAttr::Never, cx.attr_span))
52                    }
53                    _ => {
54                        cx.expected_specific_argument(l.span(), &[sym::always, sym::never]);
55                        return None;
56                    }
57                }
58            }
59            ArgParser::NameValue(_) => {
60                cx.warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT);
61                return None;
62            }
63        }
64    }
65}
66
67pub(crate) struct RustcForceInlineParser;
68
69impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
70    const PATH: &'static [Symbol] = &[sym::rustc_force_inline];
71    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
72    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
73    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
74        Allow(Target::Fn),
75        Allow(Target::Method(MethodKind::Inherent)),
76    ]);
77
78    const TEMPLATE: AttributeTemplate = template!(Word, List: &["reason"], NameValueStr: "reason");
79
80    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
81        let reason = match args {
82            ArgParser::NoArgs => None,
83            ArgParser::List(list) => {
84                let Some(l) = list.single() else {
85                    cx.expected_single_argument(list.span);
86                    return None;
87                };
88
89                let Some(reason) = l.lit().and_then(|i| i.kind.str()) else {
90                    cx.expected_string_literal(l.span(), l.lit());
91                    return None;
92                };
93
94                Some(reason)
95            }
96            ArgParser::NameValue(v) => {
97                let Some(reason) = v.value_as_str() else {
98                    cx.expected_string_literal(v.value_span, Some(v.value_as_lit()));
99                    return None;
100                };
101
102                Some(reason)
103            }
104        };
105
106        Some(AttributeKind::Inline(
107            InlineAttr::Force { attr_span: cx.attr_span, reason },
108            cx.attr_span,
109        ))
110    }
111}