rustc_attr_parsing/attributes/
macro_attrs.rs1use rustc_ast::AttrStyle;
2use rustc_errors::DiagArgValue;
3use rustc_hir::attrs::MacroUseArgs;
4
5use super::prelude::*;
6use crate::session_diagnostics::IllFormedAttributeInputLint;
7
8pub(crate) struct MacroEscapeParser;
9impl<S: Stage> NoArgsAttributeParser<S> for MacroEscapeParser {
10 const PATH: &[Symbol] = &[sym::macro_escape];
11 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
12 const ALLOWED_TARGETS: AllowedTargets = MACRO_USE_ALLOWED_TARGETS;
13 const CREATE: fn(Span) -> AttributeKind = AttributeKind::MacroEscape;
14}
15
16#[derive(Default)]
21pub(crate) struct MacroUseParser {
22 state: MacroUseArgs,
23
24 uses_attr_spans: ThinVec<Span>,
26 first_span: Option<Span>,
29}
30
31const MACRO_USE_TEMPLATE: AttributeTemplate = template!(
32 Word, List: &["name1, name2, ..."],
33 "https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute"
34);
35const MACRO_USE_ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
36 Allow(Target::Mod),
37 Allow(Target::ExternCrate),
38 Allow(Target::Crate),
39 Error(Target::WherePredicate),
40]);
41
42impl<S: Stage> AttributeParser<S> for MacroUseParser {
43 const ATTRIBUTES: AcceptMapping<Self, S> = &[(
44 &[sym::macro_use],
45 MACRO_USE_TEMPLATE,
46 |group: &mut Self, cx: &mut AcceptContext<'_, '_, S>, args| {
47 let span = cx.attr_span;
48 group.first_span.get_or_insert(span);
49 match args {
50 ArgParser::NoArgs => {
51 match group.state {
52 MacroUseArgs::UseAll => {
53 let first_span = group.first_span.expect(
54 "State is UseAll is some so this is not the first attribute",
55 );
56 cx.warn_unused_duplicate(first_span, span);
58 }
59 MacroUseArgs::UseSpecific(_) => {
60 group.state = MacroUseArgs::UseAll;
61 group.first_span = Some(span);
62 for specific_use in group.uses_attr_spans.drain(..) {
64 cx.warn_unused_duplicate(span, specific_use);
65 }
66 }
67 }
68 }
69 ArgParser::List(list) => {
70 if list.is_empty() {
71 cx.warn_empty_attribute(list.span);
72 return;
73 }
74
75 match &mut group.state {
76 MacroUseArgs::UseAll => {
77 let first_span = group.first_span.expect(
78 "State is UseAll is some so this is not the first attribute",
79 );
80 cx.warn_unused_duplicate(first_span, span);
81 }
82 MacroUseArgs::UseSpecific(arguments) => {
83 group.uses_attr_spans.push(cx.attr_span);
85
86 for item in list.mixed() {
87 let Some(item) = item.meta_item() else {
88 cx.expected_identifier(item.span());
89 continue;
90 };
91 if let Err(err_span) = item.args().no_args() {
92 cx.expected_no_args(err_span);
93 continue;
94 }
95 let Some(item) = item.path().word() else {
96 cx.expected_identifier(item.span());
97 continue;
98 };
99 arguments.push(item);
100 }
101 }
102 }
103 }
104 ArgParser::NameValue(_) => {
105 let suggestions = MACRO_USE_TEMPLATE.suggestions(cx.attr_style, sym::macro_use);
106 cx.emit_err(IllFormedAttributeInputLint {
107 num_suggestions: suggestions.len(),
108 suggestions: DiagArgValue::StrListSepByAnd(
109 suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
110 ),
111 span,
112 });
113 }
114 }
115 },
116 )];
117 const ALLOWED_TARGETS: AllowedTargets = MACRO_USE_ALLOWED_TARGETS;
118
119 fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
120 Some(AttributeKind::MacroUse { span: self.first_span?, arguments: self.state })
121 }
122}
123
124pub(crate) struct AllowInternalUnsafeParser;
125
126impl<S: Stage> NoArgsAttributeParser<S> for AllowInternalUnsafeParser {
127 const PATH: &[Symbol] = &[sym::allow_internal_unsafe];
128 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore;
129 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
130 Allow(Target::Fn),
131 Allow(Target::MacroDef),
132 Warn(Target::Field),
133 Warn(Target::Arm),
134 ]);
135 const CREATE: fn(Span) -> AttributeKind = |span| AttributeKind::AllowInternalUnsafe(span);
136}
137
138pub(crate) struct MacroExportParser;
139
140impl<S: Stage> SingleAttributeParser<S> for MacroExportParser {
141 const PATH: &[Symbol] = &[sym::macro_export];
142 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
143 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
144 const TEMPLATE: AttributeTemplate = template!(Word, List: &["local_inner_macros"]);
145 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
146 Allow(Target::MacroDef),
147 Error(Target::WherePredicate),
148 Error(Target::Crate),
149 ]);
150
151 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
152 let suggestions = || {
153 <Self as SingleAttributeParser<S>>::TEMPLATE
154 .suggestions(AttrStyle::Inner, "macro_export")
155 };
156 let local_inner_macros = match args {
157 ArgParser::NoArgs => false,
158 ArgParser::List(list) => {
159 let Some(l) = list.single() else {
160 let span = cx.attr_span;
161 cx.emit_lint(
162 AttributeLintKind::InvalidMacroExportArguments {
163 suggestions: suggestions(),
164 },
165 span,
166 );
167 return None;
168 };
169 match l.meta_item().and_then(|i| i.path().word_sym()) {
170 Some(sym::local_inner_macros) => true,
171 _ => {
172 let span = cx.attr_span;
173 cx.emit_lint(
174 AttributeLintKind::InvalidMacroExportArguments {
175 suggestions: suggestions(),
176 },
177 span,
178 );
179 return None;
180 }
181 }
182 }
183 ArgParser::NameValue(_) => {
184 let span = cx.attr_span;
185 let suggestions = suggestions();
186 cx.emit_err(IllFormedAttributeInputLint {
187 num_suggestions: suggestions.len(),
188 suggestions: DiagArgValue::StrListSepByAnd(
189 suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
190 ),
191 span,
192 });
193 return None;
194 }
195 };
196 Some(AttributeKind::MacroExport { span: cx.attr_span, local_inner_macros })
197 }
198}