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};
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}