rustc_attr_parsing/attributes/
macro_attrs.rs1use rustc_ast::ItemKind;
2use rustc_attr_ir::{MacroUseArgs, find_attr};
3use rustc_feature::AttributeStability;
4use rustc_lint_defs::builtin::{INVALID_MACRO_EXPORT_ARGUMENTS, UNUSED_ATTRIBUTES};
5use rustc_structures::CollapseMacroDebuginfo;
6
7use super::prelude::*;
8use crate::diagnostics::{MacroExport, MacroOnlyAttribute};
9
10pub(crate) struct MacroEscapeParser;
11impl NoArgsAttributeParser for MacroEscapeParser {
12 const PATH: &[Symbol] = &[sym::macro_escape];
13 const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
14 const ALLOWED_TARGETS: AllowedTargets<'_> = MACRO_USE_ALLOWED_TARGETS;
15 const STABILITY: AttributeStability = AttributeStability::Stable;
16 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::MacroEscape;
17}
18
19#[derive(#[automatically_derived]
impl ::core::default::Default for MacroUseParser {
#[inline]
fn default() -> Self {
Self {
state: ::core::default::Default::default(),
uses_attr_spans: ::core::default::Default::default(),
first_span: ::core::default::Default::default(),
}
}
}Default)]
24pub(crate) struct MacroUseParser {
25 state: MacroUseArgs,
26
27 uses_attr_spans: ThinVec<Span>,
29 first_span: Option<Span>,
32}
33
34const MACRO_USE_TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
word: true,
list: Some(&["name1, name2, ..."]),
one_of: &[],
name_value_str: None,
docs: Some("https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute"),
}template!(
35 Word, List: &["name1, name2, ..."],
36 "https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute"
37);
38const MACRO_USE_ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[
39 Allow(Target::Mod),
40 Allow(Target::ExternCrate),
41 Error(Target::WherePredicate),
42]);
43
44impl AttributeParser for MacroUseParser {
45 const ATTRIBUTES: AcceptMapping<Self> = &[(
46 &[sym::macro_use],
47 MACRO_USE_TEMPLATE,
48 AttributeStability::Stable,
49 |group: &mut Self, cx: &mut AcceptContext<'_, '_>, args| {
50 let span = cx.attr_span;
51 group.first_span.get_or_insert(span);
52 match args {
53 ArgParser::NoArgs => {
54 match group.state {
55 MacroUseArgs::UseAll => {
56 let first_span = group.first_span.expect(
57 "State is UseAll is some so this is not the first attribute",
58 );
59 cx.warn_unused_duplicate(first_span, span);
61 }
62 MacroUseArgs::UseSpecific(_) => {
63 group.state = MacroUseArgs::UseAll;
64 group.first_span = Some(span);
65 for specific_use in group.uses_attr_spans.drain(..) {
67 cx.warn_unused_duplicate(span, specific_use);
68 }
69 }
70 }
71 }
72 ArgParser::List(list) => {
73 if list.is_empty() {
74 cx.adcx().warn_empty_attribute(list.span);
75 return;
76 }
77
78 match &mut group.state {
79 MacroUseArgs::UseAll => {
80 let first_span = group.first_span.expect(
81 "State is UseAll is some so this is not the first attribute",
82 );
83 cx.warn_unused_duplicate(first_span, span);
84 }
85 MacroUseArgs::UseSpecific(arguments) => {
86 group.uses_attr_spans.push(cx.attr_span);
88
89 for item in list.mixed() {
90 let Some(item) = item.meta_item() else {
91 cx.adcx().expected_identifier(item.span());
92 continue;
93 };
94 let Some(()) = cx.expect_no_args(item.args()) else {
95 continue;
96 };
97 let Some(item) = item.path().word() else {
98 cx.adcx().expected_identifier(item.span());
99 continue;
100 };
101 arguments.push(item);
102 }
103 }
104 }
105 }
106 ArgParser::NameValue(nv) => {
107 cx.adcx().expected_list_or_no_args(nv.args_span());
108 }
109 }
110 },
111 )];
112 const ALLOWED_TARGETS: AllowedTargets<'_> = MACRO_USE_ALLOWED_TARGETS;
113
114 fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {
115 Some(AttributeKind::MacroUse { span: self.first_span?, arguments: self.state })
116 }
117}
118
119pub(crate) fn check_macro_only(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) {
123 if cx.target == Target::Fn
124 && !{
{
'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(ProcMacro |
ProcMacroAttribute | ProcMacroDerive { .. }) => {
break 'done Some(());
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}.is_some()
}find_attr!(cx.parsed_attrs, ProcMacro | ProcMacroAttribute | ProcMacroDerive { .. })
125 {
126 cx.emit_err(MacroOnlyAttribute { attr_span, span: cx.target_span });
127 }
128}
129
130pub(crate) struct AllowInternalUnsafeParser;
131
132impl NoArgsAttributeParser for AllowInternalUnsafeParser {
133 const PATH: &[Symbol] = &[sym::allow_internal_unsafe];
134 const ON_DUPLICATE: OnDuplicate = OnDuplicate::Ignore;
135 const ALLOWED_TARGETS: AllowedTargets<'_> =
136 AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::MacroDef)]);
137 const STABILITY: AttributeStability = {
_ = rustc_feature::Features::allow_internal_unsafe;
AttributeStability::Unstable {
gate_name: rustc_span::sym::allow_internal_unsafe,
notes: &[],
}
}unstable!(allow_internal_unsafe);
138 const CREATE: fn(Span) -> AttributeKind = |span| AttributeKind::AllowInternalUnsafe(span);
139
140 fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {
141 check_macro_only(cx, attr_span);
142 }
143}
144
145pub(crate) struct MacroExportParser;
146
147impl SingleAttributeParser for MacroExportParser {
148 const PATH: &[Symbol] = &[sym::macro_export];
149 const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
150 const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
word: true,
list: Some(&["local_inner_macros"]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(Word, List: &["local_inner_macros"]);
151 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[
152 Allow(Target::MacroDef),
153 Error(Target::WherePredicate),
154 Error(Target::Crate),
155 ]);
156 const STABILITY: AttributeStability = AttributeStability::Stable;
157
158 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
159 let local_inner_macros = match args {
160 ArgParser::NoArgs => false,
161 ArgParser::List(list) => {
162 let Some(l) = list.as_single() else {
163 cx.adcx().warn_ill_formed_attribute_input(INVALID_MACRO_EXPORT_ARGUMENTS);
164 return None;
165 };
166 if l.meta_item_no_args().is_some_and(|m| m.path().word_is(sym::local_inner_macros))
167 {
168 true
169 } else {
170 cx.adcx().warn_ill_formed_attribute_input(INVALID_MACRO_EXPORT_ARGUMENTS);
171 return None;
172 }
173 }
174 ArgParser::NameValue(nv) => {
175 cx.adcx().expected_list_or_no_args(nv.args_span());
176 return None;
177 }
178 };
179
180 Some(AttributeKind::MacroExport { span: cx.attr_span, local_inner_macros })
181 }
182
183 fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {
184 if cx.target != Target::MacroDef {
185 return;
186 }
187
188 let item = cx.target_item.unwrap();
189 if let ItemKind::MacroDef(_, macro_def) = &item.kind
190 && !macro_def.macro_rules
191 {
192 cx.emit_lint(UNUSED_ATTRIBUTES, MacroExport::OnDeclMacro, attr_span);
193 }
194 }
195}
196
197pub(crate) struct CollapseDebugInfoParser;
198
199impl SingleAttributeParser for CollapseDebugInfoParser {
200 const PATH: &[Symbol] = &[sym::collapse_debuginfo];
201 const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
word: false,
list: Some(&["no", "external", "yes"]),
one_of: &[],
name_value_str: None,
docs: Some("https://doc.rust-lang.org/reference/attributes/debugger.html#the-collapse_debuginfo-attribute"),
}template!(
202 List: &["no", "external", "yes"],
203 "https://doc.rust-lang.org/reference/attributes/debugger.html#the-collapse_debuginfo-attribute"
204 );
205 const ALLOWED_TARGETS: AllowedTargets<'_> =
206 AllowedTargets::AllowList(&[Allow(Target::MacroDef)]);
207 const STABILITY: AttributeStability = AttributeStability::Stable;
208
209 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
210 let single = cx.expect_single_element_list(args, cx.attr_span)?;
211 let Some(mi) = single.meta_item() else {
212 cx.adcx().expected_not_literal(single.span());
213 return None;
214 };
215 let _ = cx.expect_no_args(mi.args());
216 let path = mi.path().word_sym();
217 let info = match path {
218 Some(sym::yes) => CollapseMacroDebuginfo::Yes,
219 Some(sym::no) => CollapseMacroDebuginfo::No,
220 Some(sym::external) => CollapseMacroDebuginfo::External,
221 _ => {
222 cx.adcx()
223 .expected_specific_argument(mi.span(), &[sym::yes, sym::no, sym::external]);
224 return None;
225 }
226 };
227
228 Some(AttributeKind::CollapseDebugInfo(info))
229 }
230}
231
232pub(crate) struct RustcProcMacroDeclsParser;
233
234impl NoArgsAttributeParser for RustcProcMacroDeclsParser {
235 const PATH: &[Symbol] = &[sym::rustc_proc_macro_decls];
236 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Static)]);
237 const STABILITY: AttributeStability = {
_ = rustc_feature::Features::rustc_attrs;
AttributeStability::Unstable {
gate_name: rustc_span::sym::rustc_attrs,
notes: &[],
}
}unstable!(rustc_attrs);
238 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcProcMacroDecls;
239}