rustc_attr_parsing/attributes/
macro_attrs.rs1use rustc_errors::DiagArgValue;
2use rustc_feature::{AttributeTemplate, template};
3use rustc_hir::attrs::{AttributeKind, MacroUseArgs};
4use rustc_span::{Span, Symbol, sym};
5use thin_vec::ThinVec;
6
7use crate::attributes::{AcceptMapping, AttributeParser, NoArgsAttributeParser, OnDuplicate};
8use crate::context::{AcceptContext, FinalizeContext, Stage};
9use crate::parser::ArgParser;
10use crate::session_diagnostics;
11
12pub(crate) struct MacroEscapeParser;
13impl<S: Stage> NoArgsAttributeParser<S> for MacroEscapeParser {
14 const PATH: &[Symbol] = &[sym::macro_escape];
15 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
16 const CREATE: fn(Span) -> AttributeKind = AttributeKind::MacroEscape;
17}
18
19#[derive(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 = template!(
35 Word, List: &["name1, name2, ..."],
36 "https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute"
37);
38
39impl<S: Stage> AttributeParser<S> for MacroUseParser {
40 const ATTRIBUTES: AcceptMapping<Self, S> = &[(
41 &[sym::macro_use],
42 MACRO_USE_TEMPLATE,
43 |group: &mut Self, cx: &mut AcceptContext<'_, '_, S>, args| {
44 let span = cx.attr_span;
45 group.first_span.get_or_insert(span);
46 match args {
47 ArgParser::NoArgs => {
48 match group.state {
49 MacroUseArgs::UseAll => {
50 let first_span = group.first_span.expect(
51 "State is UseAll is some so this is not the first attribute",
52 );
53 cx.warn_unused_duplicate(first_span, span);
55 }
56 MacroUseArgs::UseSpecific(_) => {
57 group.state = MacroUseArgs::UseAll;
58 group.first_span = Some(span);
59 for specific_use in group.uses_attr_spans.drain(..) {
61 cx.warn_unused_duplicate(span, specific_use);
62 }
63 }
64 }
65 }
66 ArgParser::List(list) => {
67 if list.is_empty() {
68 cx.warn_empty_attribute(list.span);
69 return;
70 }
71
72 match &mut group.state {
73 MacroUseArgs::UseAll => {
74 let first_span = group.first_span.expect(
75 "State is UseAll is some so this is not the first attribute",
76 );
77 cx.warn_unused_duplicate(first_span, span);
78 }
79 MacroUseArgs::UseSpecific(arguments) => {
80 group.uses_attr_spans.push(cx.attr_span);
82
83 for item in list.mixed() {
84 let Some(item) = item.meta_item() else {
85 cx.expected_identifier(item.span());
86 continue;
87 };
88 if let Err(err_span) = item.args().no_args() {
89 cx.expected_no_args(err_span);
90 continue;
91 }
92 let Some(item) = item.path().word() else {
93 cx.expected_identifier(item.span());
94 continue;
95 };
96 arguments.push(item);
97 }
98 }
99 }
100 }
101 ArgParser::NameValue(_) => {
102 let suggestions = MACRO_USE_TEMPLATE.suggestions(false, sym::macro_use);
103 cx.emit_err(session_diagnostics::IllFormedAttributeInputLint {
104 num_suggestions: suggestions.len(),
105 suggestions: DiagArgValue::StrListSepByAnd(
106 suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
107 ),
108 span,
109 });
110 }
111 }
112 },
113 )];
114
115 fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
116 Some(AttributeKind::MacroUse { span: self.first_span?, arguments: self.state })
117 }
118}
119
120pub(crate) struct AllowInternalUnsafeParser;
121
122impl<S: Stage> NoArgsAttributeParser<S> for AllowInternalUnsafeParser {
123 const PATH: &[Symbol] = &[sym::allow_internal_unsafe];
124 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore;
125 const CREATE: fn(Span) -> AttributeKind = |span| AttributeKind::AllowInternalUnsafe(span);
126}