Skip to main content

rustc_attr_parsing/attributes/
macro_attrs.rs

1use rustc_feature::AttributeStability;
2use rustc_hir::attrs::{CollapseMacroDebuginfo, MacroUseArgs};
3use rustc_session::lint::builtin::INVALID_MACRO_EXPORT_ARGUMENTS;
4
5use super::prelude::*;
6
7pub(crate) struct MacroEscapeParser;
8impl NoArgsAttributeParser for MacroEscapeParser {
9    const PATH: &[Symbol] = &[sym::macro_escape];
10    const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
11    const ALLOWED_TARGETS: AllowedTargets = MACRO_USE_ALLOWED_TARGETS;
12    const STABILITY: AttributeStability = AttributeStability::Stable;
13    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::MacroEscape;
14}
15
16/// `#[macro_use]` attributes can either:
17/// - Use all macros from a crate, if provided without arguments
18/// - Use specific macros from a crate, if provided with arguments `#[macro_use(macro1, macro2)]`
19/// A warning should be provided if an use all is combined with specific uses, or if multiple use-alls are used.
20#[derive(#[automatically_derived]
impl ::core::default::Default for MacroUseParser {
    #[inline]
    fn default() -> MacroUseParser {
        MacroUseParser {
            state: ::core::default::Default::default(),
            uses_attr_spans: ::core::default::Default::default(),
            first_span: ::core::default::Default::default(),
        }
    }
}Default)]
21pub(crate) struct MacroUseParser {
22    state: MacroUseArgs,
23
24    /// Spans of all `#[macro_use]` arguments with arguments, used for linting
25    uses_attr_spans: ThinVec<Span>,
26    /// If `state` is `UseSpecific`, stores the span of the first `#[macro_use]` argument, used as the span for this attribute
27    /// If `state` is `UseAll`, stores the span of the first `#[macro_use]` arguments without arguments
28    first_span: Option<Span>,
29}
30
31const MACRO_USE_TEMPLATE: AttributeTemplate = ::rustc_feature::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!(
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 AttributeParser for MacroUseParser {
43    const ATTRIBUTES: AcceptMapping<Self> = &[(
44        &[sym::macro_use],
45        MACRO_USE_TEMPLATE,
46        AttributeStability::Stable,
47        |group: &mut Self, cx: &mut AcceptContext<'_, '_>, args| {
48            let span = cx.attr_span;
49            group.first_span.get_or_insert(span);
50            match args {
51                ArgParser::NoArgs => {
52                    match group.state {
53                        MacroUseArgs::UseAll => {
54                            let first_span = group.first_span.expect(
55                                "State is UseAll is some so this is not the first attribute",
56                            );
57                            // Since there is a `#[macro_use]` import already, give a warning
58                            cx.warn_unused_duplicate(first_span, span);
59                        }
60                        MacroUseArgs::UseSpecific(_) => {
61                            group.state = MacroUseArgs::UseAll;
62                            group.first_span = Some(span);
63                            // If there is a `#[macro_use]` attribute, warn on all `#[macro_use(...)]` attributes since everything is already imported
64                            for specific_use in group.uses_attr_spans.drain(..) {
65                                cx.warn_unused_duplicate(span, specific_use);
66                            }
67                        }
68                    }
69                }
70                ArgParser::List(list) => {
71                    if list.is_empty() {
72                        cx.adcx().warn_empty_attribute(list.span);
73                        return;
74                    }
75
76                    match &mut group.state {
77                        MacroUseArgs::UseAll => {
78                            let first_span = group.first_span.expect(
79                                "State is UseAll is some so this is not the first attribute",
80                            );
81                            cx.warn_unused_duplicate(first_span, span);
82                        }
83                        MacroUseArgs::UseSpecific(arguments) => {
84                            // Store here so if we encounter a `UseAll` later we can still lint this attribute
85                            group.uses_attr_spans.push(cx.attr_span);
86
87                            for item in list.mixed() {
88                                let Some(item) = item.meta_item() else {
89                                    cx.adcx().expected_identifier(item.span());
90                                    continue;
91                                };
92                                let Some(()) = cx.expect_no_args(item.args()) else {
93                                    continue;
94                                };
95                                let Some(item) = item.path().word() else {
96                                    cx.adcx().expected_identifier(item.span());
97                                    continue;
98                                };
99                                arguments.push(item);
100                            }
101                        }
102                    }
103                }
104                ArgParser::NameValue(nv) => {
105                    cx.adcx().expected_list_or_no_args(nv.args_span());
106                }
107            }
108        },
109    )];
110    const ALLOWED_TARGETS: AllowedTargets = MACRO_USE_ALLOWED_TARGETS;
111
112    fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {
113        Some(AttributeKind::MacroUse { span: self.first_span?, arguments: self.state })
114    }
115}
116
117pub(crate) struct AllowInternalUnsafeParser;
118
119impl NoArgsAttributeParser for AllowInternalUnsafeParser {
120    const PATH: &[Symbol] = &[sym::allow_internal_unsafe];
121    const ON_DUPLICATE: OnDuplicate = OnDuplicate::Ignore;
122    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
123        Allow(Target::Fn),
124        Allow(Target::MacroDef),
125        Warn(Target::Field),
126        Warn(Target::Arm),
127    ]);
128    const STABILITY: AttributeStability = AttributeStability::Unstable {
    gate_name: rustc_span::sym::allow_internal_unsafe,
    gate_check: rustc_feature::Features::allow_internal_unsafe,
    notes: &[],
}unstable!(allow_internal_unsafe);
129    const CREATE: fn(Span) -> AttributeKind = |span| AttributeKind::AllowInternalUnsafe(span);
130}
131
132pub(crate) struct MacroExportParser;
133
134impl SingleAttributeParser for MacroExportParser {
135    const PATH: &[Symbol] = &[sym::macro_export];
136    const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
137    const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
    word: true,
    list: Some(&["local_inner_macros"]),
    one_of: &[],
    name_value_str: None,
    docs: None,
}template!(Word, List: &["local_inner_macros"]);
138    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
139        Allow(Target::MacroDef),
140        Error(Target::WherePredicate),
141        Error(Target::Crate),
142    ]);
143    const STABILITY: AttributeStability = AttributeStability::Stable;
144
145    fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
146        let local_inner_macros = match args {
147            ArgParser::NoArgs => false,
148            ArgParser::List(list) => {
149                let Some(l) = list.as_single() else {
150                    cx.adcx().warn_ill_formed_attribute_input(INVALID_MACRO_EXPORT_ARGUMENTS);
151                    return None;
152                };
153                match l.meta_item_no_args().and_then(|i| i.path().word_sym()) {
154                    Some(sym::local_inner_macros) => true,
155                    _ => {
156                        cx.adcx().warn_ill_formed_attribute_input(INVALID_MACRO_EXPORT_ARGUMENTS);
157                        return None;
158                    }
159                }
160            }
161            ArgParser::NameValue(nv) => {
162                cx.adcx().expected_list_or_no_args(nv.args_span());
163                return None;
164            }
165        };
166        Some(AttributeKind::MacroExport { span: cx.attr_span, local_inner_macros })
167    }
168}
169
170pub(crate) struct CollapseDebugInfoParser;
171
172impl SingleAttributeParser for CollapseDebugInfoParser {
173    const PATH: &[Symbol] = &[sym::collapse_debuginfo];
174    const TEMPLATE: AttributeTemplate = ::rustc_feature::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!(
175        List: &["no", "external", "yes"],
176        "https://doc.rust-lang.org/reference/attributes/debugger.html#the-collapse_debuginfo-attribute"
177    );
178    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]);
179    const STABILITY: AttributeStability = AttributeStability::Stable;
180
181    fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
182        let single = cx.expect_single_element_list(args, cx.attr_span)?;
183        let Some(mi) = single.meta_item() else {
184            cx.adcx().expected_not_literal(single.span());
185            return None;
186        };
187        let _ = cx.expect_no_args(mi.args());
188        let path = mi.path().word_sym();
189        let info = match path {
190            Some(sym::yes) => CollapseMacroDebuginfo::Yes,
191            Some(sym::no) => CollapseMacroDebuginfo::No,
192            Some(sym::external) => CollapseMacroDebuginfo::External,
193            _ => {
194                cx.adcx()
195                    .expected_specific_argument(mi.span(), &[sym::yes, sym::no, sym::external]);
196                return None;
197            }
198        };
199
200        Some(AttributeKind::CollapseDebugInfo(info))
201    }
202}
203
204pub(crate) struct RustcProcMacroDeclsParser;
205
206impl NoArgsAttributeParser for RustcProcMacroDeclsParser {
207    const PATH: &[Symbol] = &[sym::rustc_proc_macro_decls];
208    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Static)]);
209    const STABILITY: AttributeStability = AttributeStability::Unstable {
    gate_name: rustc_span::sym::rustc_attrs,
    gate_check: rustc_feature::Features::rustc_attrs,
    notes: &[],
}unstable!(rustc_attrs);
210    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcProcMacroDecls;
211}