rustc_attr_parsing/attributes/
inline.rs1use 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}