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!(Word, List: "name1, name2, ...");
35
36impl<S: Stage> AttributeParser<S> for MacroUseParser {
37 const ATTRIBUTES: AcceptMapping<Self, S> = &[(
38 &[sym::macro_use],
39 MACRO_USE_TEMPLATE,
40 |group: &mut Self, cx: &mut AcceptContext<'_, '_, S>, args| {
41 let span = cx.attr_span;
42 group.first_span.get_or_insert(span);
43 match args {
44 ArgParser::NoArgs => {
45 match group.state {
46 MacroUseArgs::UseAll => {
47 let first_span = group.first_span.expect(
48 "State is UseAll is some so this is not the first attribute",
49 );
50 cx.warn_unused_duplicate(first_span, span);
52 }
53 MacroUseArgs::UseSpecific(_) => {
54 group.state = MacroUseArgs::UseAll;
55 group.first_span = Some(span);
56 for specific_use in group.uses_attr_spans.drain(..) {
58 cx.warn_unused_duplicate(span, specific_use);
59 }
60 }
61 }
62 }
63 ArgParser::List(list) => {
64 if list.is_empty() {
65 cx.warn_empty_attribute(list.span);
66 return;
67 }
68
69 match &mut group.state {
70 MacroUseArgs::UseAll => {
71 let first_span = group.first_span.expect(
72 "State is UseAll is some so this is not the first attribute",
73 );
74 cx.warn_unused_duplicate(first_span, span);
75 }
76 MacroUseArgs::UseSpecific(arguments) => {
77 group.uses_attr_spans.push(cx.attr_span);
79
80 for item in list.mixed() {
81 let Some(item) = item.meta_item() else {
82 cx.expected_identifier(item.span());
83 continue;
84 };
85 if let Err(err_span) = item.args().no_args() {
86 cx.expected_no_args(err_span);
87 continue;
88 }
89 let Some(item) = item.path().word() else {
90 cx.expected_identifier(item.span());
91 continue;
92 };
93 arguments.push(item);
94 }
95 }
96 }
97 }
98 ArgParser::NameValue(_) => {
99 let suggestions = MACRO_USE_TEMPLATE.suggestions(false, sym::macro_use);
100 cx.emit_err(session_diagnostics::IllFormedAttributeInputLint {
101 num_suggestions: suggestions.len(),
102 suggestions: DiagArgValue::StrListSepByAnd(
103 suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
104 ),
105 span,
106 });
107 }
108 }
109 },
110 )];
111
112 fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
113 Some(AttributeKind::MacroUse { span: self.first_span?, arguments: self.state })
114 }
115}