Skip to main content

rustc_attr_parsing/attributes/
rustc_internal.rs

1use std::path::PathBuf;
2
3use rustc_ast::{GenericParamKind, LitIntType, LitKind, MetaItemLit};
4use rustc_attr_ir::lang_items::LangItem;
5use rustc_attr_ir::target::AstTarget;
6use rustc_attr_ir::{
7    BorrowckGraphvizFormatKind, CguFields, CguKind, RustcAssertVarianceKind, RustcCleanAttribute,
8    RustcCleanQueries, RustcMirKind,
9};
10use rustc_data_structures::fx::FxHashMap;
11use rustc_feature::AttributeStability;
12use rustc_span::Symbol;
13
14use super::prelude::*;
15use super::util::parse_single_integer;
16use crate::diagnostics;
17use crate::diagnostics::{
18    AttributeRequiresOpt, CguFieldsMissing, RustcScalableVectorCountOutOfRange,
19    UnknownExternLangItem, UnknownLangItem,
20};
21
22pub(crate) struct RustcMainParser;
23
24impl NoArgsAttributeParser for RustcMainParser {
25    const PATH: &[Symbol] = &[sym::rustc_main];
26    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
27    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &["the `rustc_main` attribute is used internally to specify test entry point function"],
    }
}unstable!(
28        rustc_attrs,
29        "the `rustc_main` attribute is used internally to specify test entry point function"
30    );
31    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcMain;
32}
33
34pub(crate) struct RustcMustImplementOneOfParser;
35
36impl SingleAttributeParser for RustcMustImplementOneOfParser {
37    const PATH: &[Symbol] = &[sym::rustc_must_implement_one_of];
38    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
39    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &["the `rustc_must_implement_one_of` attribute is used to change minimal complete definition of a trait. Its syntax and semantics are highly experimental and will be subject to change before stabilization"],
    }
}unstable!(
40        rustc_attrs,
41        "the `rustc_must_implement_one_of` attribute is used to change minimal complete definition of a trait. Its syntax and semantics are highly experimental and will be subject to change before stabilization"
42    );
43    const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
    word: false,
    list: Some(&["function1, function2, ..."]),
    one_of: &[],
    name_value_str: None,
    docs: None,
}template!(List: &["function1, function2, ..."]);
44    fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
45        let list = cx.expect_list(args, cx.attr_span)?;
46
47        let mut fn_names = ThinVec::new();
48
49        let inputs: Vec<_> = list.mixed().collect();
50
51        if inputs.len() < 2 {
52            cx.adcx().expected_list_with_num_args_or_more(2, list.span);
53            return None;
54        }
55
56        let mut errored = false;
57        for argument in inputs {
58            let Some(meta) = argument.meta_item_no_args() else {
59                cx.adcx().expected_identifier(argument.span());
60                return None;
61            };
62
63            let Some(ident) = meta.ident() else {
64                cx.dcx()
65                    .emit_err(diagnostics::MustBeNameOfAssociatedFunction { span: meta.span() });
66                errored = true;
67                continue;
68            };
69
70            fn_names.push(ident);
71        }
72        if errored {
73            return None;
74        }
75
76        if cx.target == Target::Trait {
77            // Check for duplicates
78            let mut seen: FxHashMap<Symbol, Span> = FxHashMap::default();
79            for ident in &fn_names {
80                if let Some(dup) = seen.insert(ident.name, ident.span) {
81                    cx.emit_err(diagnostics::FunctionNamesDuplicated {
82                        spans: ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [dup, ident.span]))vec![dup, ident.span],
83                    });
84                }
85            }
86        }
87
88        Some(AttributeKind::RustcMustImplementOneOf { attr_span: cx.attr_span, fn_names })
89    }
90}
91
92pub(crate) struct RustcNeverReturnsNullPtrParser;
93
94impl NoArgsAttributeParser for RustcNeverReturnsNullPtrParser {
95    const PATH: &[Symbol] = &[sym::rustc_never_returns_null_ptr];
96    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
97        Allow(Target::Fn),
98        Allow(Target::Method(MethodKind::Inherent)),
99        Allow(Target::Method(MethodKind::Trait { body: false })),
100        Allow(Target::Method(MethodKind::Trait { body: true })),
101        Allow(Target::Method(MethodKind::TraitImpl)),
102    ]);
103    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
104
105    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNeverReturnsNullPtr;
106}
107
108pub(crate) struct RustcPanicsWhenZeroParser;
109
110impl NoArgsAttributeParser for RustcPanicsWhenZeroParser {
111    const PATH: &[Symbol] = &[sym::rustc_panics_when_zero];
112    const ALLOWED_TARGETS: AllowedTargets<'_> =
113        AllowedTargets::AllowList(&[Allow(Target::ConstParam)]);
114    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
115
116    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcPanicsWhenZero;
117}
118
119pub(crate) struct RustcNoImplicitAutorefsParser;
120
121impl NoArgsAttributeParser for RustcNoImplicitAutorefsParser {
122    const PATH: &[Symbol] = &[sym::rustc_no_implicit_autorefs];
123    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
124        Allow(Target::Fn),
125        Allow(Target::Method(MethodKind::Inherent)),
126        Allow(Target::Method(MethodKind::Trait { body: false })),
127        Allow(Target::Method(MethodKind::Trait { body: true })),
128        Allow(Target::Method(MethodKind::TraitImpl)),
129    ]);
130    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
131
132    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoImplicitAutorefs;
133}
134
135pub(crate) struct RustcLegacyConstGenericsParser;
136
137impl SingleAttributeParser for RustcLegacyConstGenericsParser {
138    const PATH: &[Symbol] = &[sym::rustc_legacy_const_generics];
139    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
140    const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
    word: false,
    list: Some(&["N"]),
    one_of: &[],
    name_value_str: None,
    docs: None,
}template!(List: &["N"]);
141    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
142
143    fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
144        let meta_items = cx.expect_list(args, cx.attr_span)?;
145
146        let mut parsed_indexes = ThinVec::new();
147        let mut errored = false;
148
149        for possible_index in meta_items.mixed() {
150            if let MetaItemOrLitParser::Lit(MetaItemLit {
151                kind: LitKind::Int(index, LitIntType::Unsuffixed),
152                ..
153            }) = possible_index
154            {
155                parsed_indexes.push((index.0 as usize, possible_index.span()));
156            } else {
157                cx.adcx().expected_integer_literal(possible_index.span());
158                errored = true;
159            }
160        }
161        if errored {
162            return None;
163        } else if parsed_indexes.is_empty() {
164            cx.adcx().expected_at_least_one_argument(args.span()?);
165            return None;
166        }
167
168        Some(AttributeKind::RustcLegacyConstGenerics {
169            fn_indexes: parsed_indexes,
170            attr_span: cx.attr_span,
171        })
172    }
173
174    fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {
175        let AstTarget::Fn(function) = cx.ast_target else {
176            return;
177        };
178        let index_list = {
    '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(RustcLegacyConstGenerics {
                    fn_indexes, .. }) => {
                    break 'done Some(fn_indexes);
                }
                ::rustc_attr_ir::Attribute::Unparsed(..) =>
                    {}
                    #[deny(unreachable_patterns)]
                    _ => {}
            }
        }
        None
    }
}rustc_attr_ir::find_attr!(cx.parsed_attrs, RustcLegacyConstGenerics { fn_indexes, .. } => fn_indexes)
179            .expect("missing parsed RustcLegacyConstGenerics attribute in finalize_check");
180        let generics = &function.generics;
181
182        for param in &generics.params {
183            if !#[allow(non_exhaustive_omitted_patterns)] match param.kind {
    GenericParamKind::Const { .. } => true,
    _ => false,
}matches!(param.kind, GenericParamKind::Const { .. }) {
184                cx.emit_err(diagnostics::RustcLegacyConstGenericsOnly {
185                    attr_span,
186                    param_span: param.span(),
187                });
188                return;
189            }
190        }
191
192        if index_list.len() != generics.params.len() {
193            cx.emit_err(diagnostics::RustcLegacyConstGenericsIndex {
194                attr_span,
195                generics_span: generics.span,
196            });
197            return;
198        }
199
200        let arg_count = function.sig.decl.inputs.len() + generics.params.len();
201        for (index, span) in index_list {
202            if *index >= arg_count {
203                cx.emit_err(diagnostics::RustcLegacyConstGenericsIndexExceed {
204                    span: *span,
205                    arg_count,
206                });
207            }
208        }
209    }
210}
211
212pub(crate) struct RustcInheritOverflowChecksParser;
213
214impl NoArgsAttributeParser for RustcInheritOverflowChecksParser {
215    const PATH: &[Symbol] = &[sym::rustc_inherit_overflow_checks];
216    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
217        Allow(Target::Fn),
218        Allow(Target::Method(MethodKind::Inherent)),
219        Allow(Target::Method(MethodKind::TraitImpl)),
220        Allow(Target::Closure),
221    ]);
222    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
223    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcInheritOverflowChecks;
224}
225
226pub(crate) struct RustcLintOptDenyFieldAccessParser;
227
228impl SingleAttributeParser for RustcLintOptDenyFieldAccessParser {
229    const PATH: &[Symbol] = &[sym::rustc_lint_opt_deny_field_access];
230    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Field)]);
231    const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
    word: true,
    list: None,
    one_of: &[],
    name_value_str: None,
    docs: None,
}template!(Word);
232    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
233    fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
234        let arg = cx.expect_single_element_list(args, cx.attr_span)?;
235        let lint_message = cx.expect_string_literal(arg)?;
236
237        Some(AttributeKind::RustcLintOptDenyFieldAccess { lint_message })
238    }
239}
240
241pub(crate) struct RustcLintOptTyParser;
242
243impl NoArgsAttributeParser for RustcLintOptTyParser {
244    const PATH: &[Symbol] = &[sym::rustc_lint_opt_ty];
245    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
246    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
247    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintOptTy;
248}
249
250fn parse_cgu_fields(
251    cx: &mut AcceptContext<'_, '_>,
252    args: &ArgParser,
253    accepts_kind: bool,
254) -> Option<(Symbol, Symbol, Option<CguKind>)> {
255    let args = cx.expect_list(args, cx.attr_span)?;
256
257    let mut cfg = None::<(Symbol, Span)>;
258    let mut module = None::<(Symbol, Span)>;
259    let mut kind = None::<(Symbol, Span)>;
260
261    for arg in args.mixed() {
262        let Some((ident, arg)) = cx.expect_name_value(arg, arg.span(), None) else {
263            continue;
264        };
265
266        let res = match ident.name {
267            sym::cfg => &mut cfg,
268            sym::module => &mut module,
269            sym::kind if accepts_kind => &mut kind,
270            _ => {
271                cx.adcx().expected_specific_argument(
272                    ident.span,
273                    if accepts_kind {
274                        &[sym::cfg, sym::module, sym::kind]
275                    } else {
276                        &[sym::cfg, sym::module]
277                    },
278                );
279                continue;
280            }
281        };
282
283        let str = cx.expect_string_literal(arg)?;
284
285        if res.is_some() {
286            cx.adcx().duplicate_key(ident.span.to(arg.args_span()), ident.name);
287            continue;
288        }
289
290        *res = Some((str, arg.value_span));
291    }
292
293    let Some((cfg, _)) = cfg else {
294        cx.emit_err(CguFieldsMissing { span: args.span, name: &cx.attr_path, field: sym::cfg });
295        return None;
296    };
297    let Some((module, _)) = module else {
298        cx.emit_err(CguFieldsMissing { span: args.span, name: &cx.attr_path, field: sym::module });
299        return None;
300    };
301    let kind = if let Some((kind, span)) = kind {
302        Some(match kind {
303            sym::no => CguKind::No,
304            sym::pre_dash_lto => CguKind::PreDashLto,
305            sym::post_dash_lto => CguKind::PostDashLto,
306            sym::any => CguKind::Any,
307            _ => {
308                cx.adcx().expected_specific_argument_strings(
309                    span,
310                    &[sym::no, sym::pre_dash_lto, sym::post_dash_lto, sym::any],
311                );
312                return None;
313            }
314        })
315    } else {
316        // return None so that an unwrap for the attributes that need it is ok.
317        if accepts_kind {
318            cx.emit_err(CguFieldsMissing {
319                span: args.span,
320                name: &cx.attr_path,
321                field: sym::kind,
322            });
323            return None;
324        };
325
326        None
327    };
328
329    Some((cfg, module, kind))
330}
331
332#[derive(#[automatically_derived]impl ::core::default::Default for
    RustcCguTestAttributeParser {
    #[inline]
    fn default() -> Self {
        RustcCguTestAttributeParser {
            items: ::core::default::Default::default(),
        }
    }
}Default)]
333pub(crate) struct RustcCguTestAttributeParser {
334    items: ThinVec<(Span, CguFields)>,
335}
336
337impl AttributeParser for RustcCguTestAttributeParser {
338    const ATTRIBUTES: AcceptMapping<Self> = &[
339        (
340            &[sym::rustc_partition_reused],
341            crate::AttributeTemplate {
    word: false,
    list: Some(&[r#"cfg = "...", module = "...""#]),
    one_of: &[],
    name_value_str: None,
    docs: None,
}template!(List: &[r#"cfg = "...", module = "...""#]),
342            {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs),
343            |this, cx, args| {
344                this.items.extend(parse_cgu_fields(cx, args, false).map(|(cfg, module, _)| {
345                    (cx.attr_span, CguFields::PartitionReused { cfg, module })
346                }));
347            },
348        ),
349        (
350            &[sym::rustc_partition_codegened],
351            crate::AttributeTemplate {
    word: false,
    list: Some(&[r#"cfg = "...", module = "...""#]),
    one_of: &[],
    name_value_str: None,
    docs: None,
}template!(List: &[r#"cfg = "...", module = "...""#]),
352            {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs),
353            |this, cx, args| {
354                this.items.extend(parse_cgu_fields(cx, args, false).map(|(cfg, module, _)| {
355                    (cx.attr_span, CguFields::PartitionCodegened { cfg, module })
356                }));
357            },
358        ),
359        (
360            &[sym::rustc_expected_cgu_reuse],
361            crate::AttributeTemplate {
    word: false,
    list: Some(&[r#"cfg = "...", module = "...", kind = "...""#]),
    one_of: &[],
    name_value_str: None,
    docs: None,
}template!(List: &[r#"cfg = "...", module = "...", kind = "...""#]),
362            {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs),
363            |this, cx, args| {
364                this.items.extend(parse_cgu_fields(cx, args, true).map(|(cfg, module, kind)| {
365                    // unwrap ok because if not given, we return None in `parse_cgu_fields`.
366                    (cx.attr_span, CguFields::ExpectedCguReuse { cfg, module, kind: kind.unwrap() })
367                }));
368            },
369        ),
370    ];
371
372    const ALLOWED_TARGETS: AllowedTargets<'_> =
373        AllowedTargets::AllowList(&[Allow(Target::Mod), Allow(Target::Crate)]);
374
375    fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {
376        Some(AttributeKind::RustcCguTestAttr(self.items))
377    }
378}
379
380pub(crate) struct RustcDeprecatedSafe2024Parser;
381
382impl SingleAttributeParser for RustcDeprecatedSafe2024Parser {
383    const PATH: &[Symbol] = &[sym::rustc_deprecated_safe_2024];
384    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
385        Allow(Target::Fn),
386        Allow(Target::Method(MethodKind::Inherent)),
387        Allow(Target::Method(MethodKind::Trait { body: false })),
388        Allow(Target::Method(MethodKind::Trait { body: true })),
389        Allow(Target::Method(MethodKind::TraitImpl)),
390    ]);
391    const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
    word: false,
    list: Some(&[r#"audit_that = "...""#]),
    one_of: &[],
    name_value_str: None,
    docs: None,
}template!(List: &[r#"audit_that = "...""#]);
392    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
393
394    fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
395        let single = cx.expect_single_element_list(args, cx.attr_span)?;
396
397        let (path, arg) = cx.expect_name_value(single, cx.attr_span, None)?;
398
399        if path.name != sym::audit_that {
400            cx.adcx().expected_specific_argument(path.span, &[sym::audit_that]);
401            return None;
402        };
403
404        let suggestion = cx.expect_string_literal(arg)?;
405
406        Some(AttributeKind::RustcDeprecatedSafe2024 { suggestion })
407    }
408}
409
410pub(crate) struct RustcConversionSuggestionParser;
411
412impl NoArgsAttributeParser for RustcConversionSuggestionParser {
413    const PATH: &[Symbol] = &[sym::rustc_conversion_suggestion];
414    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
415        Allow(Target::Fn),
416        Allow(Target::Method(MethodKind::Inherent)),
417        Allow(Target::Method(MethodKind::Trait { body: false })),
418        Allow(Target::Method(MethodKind::Trait { body: true })),
419        Allow(Target::Method(MethodKind::TraitImpl)),
420    ]);
421    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
422    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcConversionSuggestion;
423}
424
425pub(crate) struct RustcCaptureAnalysisParser;
426
427impl NoArgsAttributeParser for RustcCaptureAnalysisParser {
428    const PATH: &[Symbol] = &[sym::rustc_capture_analysis];
429    const ALLOWED_TARGETS: AllowedTargets<'_> =
430        AllowedTargets::AllowList(&[Allow(Target::Closure)]);
431    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
432    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcCaptureAnalysis;
433}
434
435pub(crate) struct RustcTrivialFieldReadsParser;
436
437impl NoArgsAttributeParser for RustcTrivialFieldReadsParser {
438    const PATH: &[Symbol] = &[sym::rustc_trivial_field_reads];
439    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
440    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
441    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcTrivialFieldReads;
442}
443
444pub(crate) struct RustcNoMirInlineParser;
445
446impl NoArgsAttributeParser for RustcNoMirInlineParser {
447    const PATH: &[Symbol] = &[sym::rustc_no_mir_inline];
448    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
449        Allow(Target::Fn),
450        Allow(Target::Method(MethodKind::Inherent)),
451        Allow(Target::Method(MethodKind::Trait { body: false })),
452        Allow(Target::Method(MethodKind::Trait { body: true })),
453        Allow(Target::Method(MethodKind::TraitImpl)),
454    ]);
455    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
456    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoMirInline;
457}
458
459pub(crate) struct RustcNoWritableParser;
460
461impl NoArgsAttributeParser for RustcNoWritableParser {
462    const PATH: &[Symbol] = &[sym::rustc_no_writable];
463    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
464        Allow(Target::Fn),
465        Allow(Target::Closure),
466        Allow(Target::Method(MethodKind::Inherent)),
467        Allow(Target::Method(MethodKind::TraitImpl)),
468        Allow(Target::Method(MethodKind::Trait { body: true })),
469    ]);
470    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
471    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoWritable;
472}
473
474pub(crate) struct RustcLintQueryInstabilityParser;
475
476impl NoArgsAttributeParser for RustcLintQueryInstabilityParser {
477    const PATH: &[Symbol] = &[sym::rustc_lint_query_instability];
478    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
479        Allow(Target::Fn),
480        Allow(Target::Method(MethodKind::Inherent)),
481        Allow(Target::Method(MethodKind::Trait { body: false })),
482        Allow(Target::Method(MethodKind::Trait { body: true })),
483        Allow(Target::Method(MethodKind::TraitImpl)),
484    ]);
485    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
486    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintQueryInstability;
487}
488
489pub(crate) struct RustcRegionsParser;
490
491impl NoArgsAttributeParser for RustcRegionsParser {
492    const PATH: &[Symbol] = &[sym::rustc_regions];
493    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
494        Allow(Target::Fn),
495        Allow(Target::Method(MethodKind::Inherent)),
496        Allow(Target::Method(MethodKind::Trait { body: false })),
497        Allow(Target::Method(MethodKind::Trait { body: true })),
498        Allow(Target::Method(MethodKind::TraitImpl)),
499    ]);
500    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
501    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcRegions;
502}
503
504pub(crate) struct RustcLintUntrackedQueryInformationParser;
505
506impl NoArgsAttributeParser for RustcLintUntrackedQueryInformationParser {
507    const PATH: &[Symbol] = &[sym::rustc_lint_untracked_query_information];
508    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
509        Allow(Target::Fn),
510        Allow(Target::Method(MethodKind::Inherent)),
511        Allow(Target::Method(MethodKind::Trait { body: false })),
512        Allow(Target::Method(MethodKind::Trait { body: true })),
513        Allow(Target::Method(MethodKind::TraitImpl)),
514    ]);
515    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
516    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintUntrackedQueryInformation;
517}
518
519pub(crate) struct RustcSimdMonomorphizeLaneLimitParser;
520
521impl SingleAttributeParser for RustcSimdMonomorphizeLaneLimitParser {
522    const PATH: &[Symbol] = &[sym::rustc_simd_monomorphize_lane_limit];
523    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
524    const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
    word: false,
    list: None,
    one_of: &[],
    name_value_str: Some(&["N"]),
    docs: None,
}template!(NameValueStr: "N");
525    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
526
527    fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
528        let nv = cx.expect_name_value(args, cx.attr_span, None)?;
529        Some(AttributeKind::RustcSimdMonomorphizeLaneLimit(cx.parse_limit_int(nv)?))
530    }
531}
532
533pub(crate) struct RustcScalableVectorParser;
534
535impl SingleAttributeParser for RustcScalableVectorParser {
536    const PATH: &[Symbol] = &[sym::rustc_scalable_vector];
537    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
538    const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
    word: true,
    list: Some(&["count"]),
    one_of: &[],
    name_value_str: None,
    docs: None,
}template!(Word, List: &["count"]);
539    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
540
541    fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
542        if args.as_no_args().is_ok() {
543            return Some(AttributeKind::RustcScalableVector { element_count: None });
544        }
545
546        let n = parse_single_integer(cx, args)?;
547        let Ok(n) = n.try_into() else {
548            cx.emit_err(RustcScalableVectorCountOutOfRange { span: cx.attr_span, n });
549            return None;
550        };
551        Some(AttributeKind::RustcScalableVector { element_count: Some(n) })
552    }
553}
554
555pub(crate) struct LangParser;
556
557impl SingleAttributeParser for LangParser {
558    const PATH: &[Symbol] = &[sym::lang];
559    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::ManuallyChecked;
560    const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
    word: false,
    list: None,
    one_of: &[],
    name_value_str: Some(&["name"]),
    docs: None,
}template!(NameValueStr: "name");
561    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::lang_items;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::lang_items,
        notes: &[],
    }
}unstable!(lang_items);
562
563    fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
564        let nv = cx.expect_name_value(args, cx.attr_span, None)?;
565        let name = cx.expect_string_literal(nv)?;
566        let Some(lang_item) = LangItem::from_name(name) else {
567            cx.emit_err(UnknownLangItem { span: cx.attr_span, name });
568            return None;
569        };
570
571        // Only weak lang items may be applied to foreign items,
572        // except for `ForeignTy` which can be a normal lang item.
573        if [Target::ForeignFn, Target::ForeignStatic, Target::ForeignMod].contains(&cx.target)
574            && !lang_item.is_weak()
575        {
576            cx.emit_err(UnknownExternLangItem { span: cx.attr_span, lang_item: lang_item.name() });
577            return None;
578        }
579
580        // Check the target
581        let allowed_targets: &[_] = &[Allow(lang_item.target())];
582        cx.check_target(&::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(" = \"{0}\"", name))
    })format!(" = \"{name}\""), &AllowedTargets::AllowList(allowed_targets));
583
584        Some(AttributeKind::Lang(lang_item))
585    }
586}
587
588pub(crate) struct RustcHasIncoherentInherentImplsParser;
589
590impl NoArgsAttributeParser for RustcHasIncoherentInherentImplsParser {
591    const PATH: &[Symbol] = &[sym::rustc_has_incoherent_inherent_impls];
592    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
593        Allow(Target::Trait),
594        Allow(Target::Struct),
595        Allow(Target::Enum),
596        Allow(Target::Union),
597        Allow(Target::ForeignTy),
598    ]);
599    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
600    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcHasIncoherentInherentImpls;
601}
602
603pub(crate) struct PanicHandlerParser;
604
605impl NoArgsAttributeParser for PanicHandlerParser {
606    const PATH: &[Symbol] = &[sym::panic_handler];
607    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
608    const STABILITY: AttributeStability = AttributeStability::Stable;
609    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::Lang(LangItem::PanicImpl);
610}
611
612pub(crate) struct RustcNounwindParser;
613
614impl NoArgsAttributeParser for RustcNounwindParser {
615    const PATH: &[Symbol] = &[sym::rustc_nounwind];
616    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
617        Allow(Target::Fn),
618        Allow(Target::ForeignFn),
619        Allow(Target::Method(MethodKind::Inherent)),
620        Allow(Target::Method(MethodKind::TraitImpl)),
621        Allow(Target::Method(MethodKind::Trait { body: true })),
622    ]);
623    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
624    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNounwind;
625}
626
627pub(crate) struct RustcOffloadKernelParser;
628
629impl NoArgsAttributeParser for RustcOffloadKernelParser {
630    const PATH: &[Symbol] = &[sym::rustc_offload_kernel];
631    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
632    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
633    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcOffloadKernel;
634}
635
636pub(crate) struct RustcMirParser;
637
638impl CombineAttributeParser for RustcMirParser {
639    const PATH: &[Symbol] = &[sym::rustc_mir];
640
641    type Item = RustcMirKind;
642
643    const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::RustcMir(items);
644    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
645        Allow(Target::Fn),
646        Allow(Target::Method(MethodKind::Inherent)),
647        Allow(Target::Method(MethodKind::TraitImpl)),
648        Allow(Target::Method(MethodKind::Trait { body: false })),
649        Allow(Target::Method(MethodKind::Trait { body: true })),
650    ]);
651    const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
    word: false,
    list: Some(&["arg1, arg2, ..."]),
    one_of: &[],
    name_value_str: None,
    docs: None,
}template!(List: &["arg1, arg2, ..."]);
652    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
653
654    fn extend(
655        cx: &mut AcceptContext<'_, '_>,
656        args: &ArgParser,
657    ) -> impl IntoIterator<Item = Self::Item> {
658        let Some(list) = cx.expect_list(args, cx.attr_span) else {
659            return ThinVec::new();
660        };
661
662        list.mixed()
663            .filter_map(|arg| arg.meta_item())
664            .filter_map(|mi| {
665                if let Some(ident) = mi.ident() {
666                    match ident.name {
667                        sym::rustc_pretty_live_locals => {
668                            cx.expect_no_args(mi.args())?;
669                            Some(RustcMirKind::PrettyLiveLocals)
670                        }
671                        sym::rustc_pretty_precise_liveness => {
672                            cx.expect_no_args(mi.args())?;
673                            Some(RustcMirKind::PrettyPreciseLiveness)
674                        }
675                        sym::rustc_pretty_transitive_live_locals => {
676                            cx.expect_no_args(mi.args())?;
677                            Some(RustcMirKind::PrettyTransitiveLiveLocals)
678                        }
679                        sym::rustc_peek_maybe_init => Some(RustcMirKind::PeekMaybeInit),
680                        sym::rustc_peek_maybe_uninit => Some(RustcMirKind::PeekMaybeUninit),
681                        sym::rustc_peek_liveness => Some(RustcMirKind::PeekLiveness),
682                        sym::stop_after_dataflow => Some(RustcMirKind::StopAfterDataflow),
683                        sym::borrowck_graphviz_postflow => {
684                            let nv = cx.expect_name_value(
685                                mi.args(),
686                                mi.span(),
687                                Some(sym::borrowck_graphviz_postflow),
688                            )?;
689                            let path = cx.expect_string_literal(nv)?;
690                            let path = PathBuf::from(path.to_string());
691                            if path.file_name().is_some() {
692                                Some(RustcMirKind::BorrowckGraphvizPostflow { path })
693                            } else {
694                                cx.adcx().expected_filename_literal(nv.value_span);
695                                None
696                            }
697                        }
698                        sym::borrowck_graphviz_format => {
699                            let nv = cx.expect_name_value(
700                                mi.args(),
701                                mi.span(),
702                                Some(sym::borrowck_graphviz_format),
703                            )?;
704                            let Some(format) = nv.value_as_ident() else {
705                                cx.adcx().expected_identifier(nv.value_span);
706                                return None;
707                            };
708                            match format.name {
709                                sym::two_phase => Some(RustcMirKind::BorrowckGraphvizFormat {
710                                    format: BorrowckGraphvizFormatKind::TwoPhase,
711                                }),
712                                _ => {
713                                    cx.adcx()
714                                        .expected_specific_argument(format.span, &[sym::two_phase]);
715                                    None
716                                }
717                            }
718                        }
719                        _ => None,
720                    }
721                } else {
722                    None
723                }
724            })
725            .collect()
726    }
727}
728pub(crate) struct RustcNonConstTraitMethodParser;
729
730impl NoArgsAttributeParser for RustcNonConstTraitMethodParser {
731    const PATH: &[Symbol] = &[sym::rustc_non_const_trait_method];
732    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
733        Allow(Target::Method(MethodKind::Trait { body: true })),
734        Allow(Target::Method(MethodKind::Trait { body: false })),
735    ]);
736    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &["the `rustc_non_const_trait_method` attribute should only be used by the standard library to mark trait methods as non-const to allow large traits an easier transition to const"],
    }
}unstable!(
737        rustc_attrs,
738        "the `rustc_non_const_trait_method` attribute should only be used by the standard library to mark trait methods as non-const to allow large traits an easier transition to const"
739    );
740    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNonConstTraitMethod;
741}
742
743pub(crate) struct RustcCleanParser;
744
745impl CombineAttributeParser for RustcCleanParser {
746    const PATH: &[Symbol] = &[sym::rustc_clean];
747
748    type Item = RustcCleanAttribute;
749
750    const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::RustcClean(items);
751    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
752        // tidy-alphabetical-start
753        Allow(Target::AssocConst(AssocCtxt::Impl { of_trait: false })),
754        Allow(Target::AssocConst(AssocCtxt::Impl { of_trait: true })),
755        Allow(Target::AssocConst(AssocCtxt::Trait)),
756        Allow(Target::AssocTy(AssocCtxt::Impl { of_trait: false })),
757        Allow(Target::AssocTy(AssocCtxt::Impl { of_trait: true })),
758        Allow(Target::AssocTy(AssocCtxt::Trait)),
759        Allow(Target::Const),
760        Allow(Target::Enum),
761        Allow(Target::Expression),
762        Allow(Target::Field),
763        Allow(Target::Fn),
764        Allow(Target::ForeignMod),
765        Allow(Target::Impl { of_trait: false }),
766        Allow(Target::Impl { of_trait: true }),
767        Allow(Target::Method(MethodKind::Inherent)),
768        Allow(Target::Method(MethodKind::Trait { body: false })),
769        Allow(Target::Method(MethodKind::Trait { body: true })),
770        Allow(Target::Method(MethodKind::TraitImpl)),
771        Allow(Target::Mod),
772        Allow(Target::Static),
773        Allow(Target::Struct),
774        Allow(Target::Trait),
775        Allow(Target::TyAlias),
776        Allow(Target::Union),
777        // tidy-alphabetical-end
778    ]);
779    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
780    const TEMPLATE: AttributeTemplate =
781        crate::AttributeTemplate {
    word: false,
    list: Some(&[r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#]),
    one_of: &[],
    name_value_str: None,
    docs: None,
}template!(List: &[r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#]);
782
783    fn extend(
784        cx: &mut AcceptContext<'_, '_>,
785        args: &ArgParser,
786    ) -> impl IntoIterator<Item = Self::Item> {
787        if !cx.cx.sess.opts.unstable_opts.query_dep_graph {
788            cx.emit_err(AttributeRequiresOpt { span: cx.attr_span, opt: "-Z query-dep-graph" });
789        }
790        let list = cx.expect_list(args, cx.attr_span)?;
791
792        let mut except = None;
793        let mut loaded_from_disk = None;
794        let mut cfg = None;
795
796        for item in list.mixed() {
797            let Some((ident, value)) = cx.expect_name_value(item, item.span(), None) else {
798                continue;
799            };
800            let value_span = value.value_span;
801            let Some(value) = cx.expect_string_literal(value) else {
802                continue;
803            };
804            match ident.name {
805                sym::cfg if cfg.is_some() => {
806                    cx.adcx().duplicate_key(item.span(), sym::cfg);
807                }
808                sym::cfg => {
809                    cfg = Some(value);
810                }
811                sym::except if except.is_some() => {
812                    cx.adcx().duplicate_key(item.span(), sym::except);
813                }
814                sym::except => {
815                    let entries =
816                        value.as_str().split(',').map(|s| Symbol::intern(s.trim())).collect();
817                    except = Some(RustcCleanQueries { entries, span: value_span });
818                }
819                sym::loaded_from_disk if loaded_from_disk.is_some() => {
820                    cx.adcx().duplicate_key(item.span(), sym::loaded_from_disk);
821                }
822                sym::loaded_from_disk => {
823                    let entries =
824                        value.as_str().split(',').map(|s| Symbol::intern(s.trim())).collect();
825                    loaded_from_disk = Some(RustcCleanQueries { entries, span: value_span });
826                }
827                _ => {
828                    cx.adcx().expected_specific_argument(
829                        ident.span,
830                        &[sym::cfg, sym::except, sym::loaded_from_disk],
831                    );
832                }
833            }
834        }
835        let Some(cfg) = cfg else {
836            cx.adcx().expected_specific_argument(list.span, &[sym::cfg]);
837            return None;
838        };
839
840        Some(RustcCleanAttribute { span: cx.attr_span, cfg, except, loaded_from_disk })
841    }
842}
843
844pub(crate) struct RustcIfThisChangedParser;
845
846impl SingleAttributeParser for RustcIfThisChangedParser {
847    const PATH: &[Symbol] = &[sym::rustc_if_this_changed];
848    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
849        // tidy-alphabetical-start
850        Allow(Target::AssocConst(AssocCtxt::Impl { of_trait: false })),
851        Allow(Target::AssocConst(AssocCtxt::Impl { of_trait: true })),
852        Allow(Target::AssocConst(AssocCtxt::Trait)),
853        Allow(Target::AssocTy(AssocCtxt::Impl { of_trait: false })),
854        Allow(Target::AssocTy(AssocCtxt::Impl { of_trait: true })),
855        Allow(Target::AssocTy(AssocCtxt::Trait)),
856        Allow(Target::Const),
857        Allow(Target::Enum),
858        Allow(Target::Expression),
859        Allow(Target::Field),
860        Allow(Target::Fn),
861        Allow(Target::ForeignMod),
862        Allow(Target::Impl { of_trait: false }),
863        Allow(Target::Impl { of_trait: true }),
864        Allow(Target::Method(MethodKind::Inherent)),
865        Allow(Target::Method(MethodKind::Trait { body: false })),
866        Allow(Target::Method(MethodKind::Trait { body: true })),
867        Allow(Target::Method(MethodKind::TraitImpl)),
868        Allow(Target::Mod),
869        Allow(Target::Static),
870        Allow(Target::Struct),
871        Allow(Target::Trait),
872        Allow(Target::TyAlias),
873        Allow(Target::Union),
874        // tidy-alphabetical-end
875    ]);
876    const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
    word: true,
    list: Some(&["DepNode"]),
    one_of: &[],
    name_value_str: None,
    docs: None,
}template!(Word, List: &["DepNode"]);
877    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
878
879    fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
880        if !cx.cx.sess.opts.unstable_opts.query_dep_graph {
881            cx.emit_err(AttributeRequiresOpt { span: cx.attr_span, opt: "-Z query-dep-graph" });
882        }
883        match args {
884            ArgParser::NoArgs => Some(AttributeKind::RustcIfThisChanged(cx.attr_span, None)),
885            ArgParser::List(list) => {
886                let item = cx.expect_single(list)?;
887                let Some(ident) = item.meta_item_no_args().and_then(|item| item.ident()) else {
888                    cx.adcx().expected_identifier(item.span());
889                    return None;
890                };
891                Some(AttributeKind::RustcIfThisChanged(cx.attr_span, Some(ident.name)))
892            }
893            ArgParser::NameValue(_) => {
894                let inner_span = cx.inner_span;
895                cx.adcx().expected_list_or_no_args(inner_span);
896                None
897            }
898        }
899    }
900}
901
902pub(crate) struct RustcThenThisWouldNeedParser;
903
904impl CombineAttributeParser for RustcThenThisWouldNeedParser {
905    const PATH: &[Symbol] = &[sym::rustc_then_this_would_need];
906    type Item = Ident;
907
908    const CONVERT: ConvertFn<Self::Item> =
909        |items, _span| AttributeKind::RustcThenThisWouldNeed(items);
910    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
911        // tidy-alphabetical-start
912        Allow(Target::AssocConst(AssocCtxt::Impl { of_trait: false })),
913        Allow(Target::AssocConst(AssocCtxt::Impl { of_trait: true })),
914        Allow(Target::AssocConst(AssocCtxt::Trait)),
915        Allow(Target::AssocTy(AssocCtxt::Impl { of_trait: false })),
916        Allow(Target::AssocTy(AssocCtxt::Impl { of_trait: true })),
917        Allow(Target::AssocTy(AssocCtxt::Trait)),
918        Allow(Target::Const),
919        Allow(Target::Enum),
920        Allow(Target::Expression),
921        Allow(Target::Field),
922        Allow(Target::Fn),
923        Allow(Target::ForeignMod),
924        Allow(Target::Impl { of_trait: false }),
925        Allow(Target::Impl { of_trait: true }),
926        Allow(Target::Method(MethodKind::Inherent)),
927        Allow(Target::Method(MethodKind::Trait { body: false })),
928        Allow(Target::Method(MethodKind::Trait { body: true })),
929        Allow(Target::Method(MethodKind::TraitImpl)),
930        Allow(Target::Mod),
931        Allow(Target::Static),
932        Allow(Target::Struct),
933        Allow(Target::Trait),
934        Allow(Target::TyAlias),
935        Allow(Target::Union),
936        // tidy-alphabetical-end
937    ]);
938    const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
    word: false,
    list: Some(&["DepNode"]),
    one_of: &[],
    name_value_str: None,
    docs: None,
}template!(List: &["DepNode"]);
939    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
940
941    fn extend(
942        cx: &mut AcceptContext<'_, '_>,
943        args: &ArgParser,
944    ) -> impl IntoIterator<Item = Self::Item> {
945        if !cx.cx.sess.opts.unstable_opts.query_dep_graph {
946            cx.emit_err(AttributeRequiresOpt { span: cx.attr_span, opt: "-Z query-dep-graph" });
947        }
948        let item = cx.expect_single_element_list(args, cx.attr_span)?;
949        let Some(ident) = item.meta_item_no_args().and_then(|item| item.ident()) else {
950            cx.adcx().expected_identifier(item.span());
951            return None;
952        };
953        Some(ident)
954    }
955}
956
957pub(crate) struct RustcInsignificantDtorParser;
958
959impl NoArgsAttributeParser for RustcInsignificantDtorParser {
960    const PATH: &[Symbol] = &[sym::rustc_insignificant_dtor];
961    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
962        Allow(Target::Enum),
963        Allow(Target::Struct),
964        Allow(Target::ForeignTy),
965    ]);
966    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
967    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcInsignificantDtor;
968}
969
970pub(crate) struct RustcEffectiveVisibilityParser;
971
972impl NoArgsAttributeParser for RustcEffectiveVisibilityParser {
973    const PATH: &[Symbol] = &[sym::rustc_effective_visibility];
974    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
975        Allow(Target::Use),
976        Allow(Target::Static),
977        Allow(Target::Const),
978        Allow(Target::Fn),
979        Allow(Target::Closure),
980        Allow(Target::Mod),
981        Allow(Target::ForeignMod),
982        Allow(Target::TyAlias),
983        Allow(Target::Enum),
984        Allow(Target::Variant),
985        Allow(Target::Struct),
986        Allow(Target::Field),
987        Allow(Target::Union),
988        Allow(Target::Trait),
989        Allow(Target::TraitAlias),
990        Allow(Target::Impl { of_trait: false }),
991        Allow(Target::Impl { of_trait: true }),
992        Allow(Target::AssocConst(AssocCtxt::Impl { of_trait: false })),
993        Allow(Target::AssocConst(AssocCtxt::Trait)),
994        Allow(Target::AssocConst(AssocCtxt::Impl { of_trait: true })),
995        Allow(Target::Method(MethodKind::Inherent)),
996        Allow(Target::Method(MethodKind::Trait { body: false })),
997        Allow(Target::Method(MethodKind::Trait { body: true })),
998        Allow(Target::Method(MethodKind::TraitImpl)),
999        Allow(Target::AssocTy(AssocCtxt::Impl { of_trait: false })),
1000        Allow(Target::AssocTy(AssocCtxt::Trait)),
1001        Allow(Target::AssocTy(AssocCtxt::Impl { of_trait: true })),
1002        Allow(Target::ForeignFn),
1003        Allow(Target::ForeignStatic),
1004        Allow(Target::ForeignTy),
1005        Allow(Target::MacroDef),
1006        Allow(Target::PatField),
1007        Allow(Target::Crate),
1008    ]);
1009    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
1010    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcEffectiveVisibility;
1011}
1012
1013pub(crate) struct RustcDiagnosticItemParser;
1014
1015impl SingleAttributeParser for RustcDiagnosticItemParser {
1016    const PATH: &[Symbol] = &[sym::rustc_diagnostic_item];
1017    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
1018        Allow(Target::Trait),
1019        Allow(Target::Struct),
1020        Allow(Target::Enum),
1021        Allow(Target::MacroDef),
1022        Allow(Target::TyAlias),
1023        Allow(Target::AssocConst(AssocCtxt::Impl { of_trait: false })),
1024        Allow(Target::AssocConst(AssocCtxt::Trait)),
1025        Allow(Target::AssocConst(AssocCtxt::Impl { of_trait: true })),
1026        Allow(Target::AssocTy(AssocCtxt::Impl { of_trait: false })),
1027        Allow(Target::AssocTy(AssocCtxt::Trait)),
1028        Allow(Target::AssocTy(AssocCtxt::Impl { of_trait: true })),
1029        Allow(Target::Fn),
1030        Allow(Target::Const),
1031        Allow(Target::Mod),
1032        Allow(Target::Impl { of_trait: false }),
1033        Allow(Target::Method(MethodKind::Inherent)),
1034        Allow(Target::Method(MethodKind::Trait { body: false })),
1035        Allow(Target::Method(MethodKind::Trait { body: true })),
1036        Allow(Target::Method(MethodKind::TraitImpl)),
1037        Allow(Target::Crate),
1038    ]);
1039    const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
    word: false,
    list: None,
    one_of: &[],
    name_value_str: Some(&["name"]),
    docs: None,
}template!(NameValueStr: "name");
1040    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &["the `rustc_diagnostic_item` attribute allows the compiler to reference types from the standard library for diagnostic purposes"],
    }
}unstable!(
1041        rustc_attrs,
1042        "the `rustc_diagnostic_item` attribute allows the compiler to reference types from the standard library for diagnostic purposes"
1043    );
1044
1045    fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
1046        let nv = cx.expect_name_value(args, cx.attr_span, None)?;
1047        let value = cx.expect_string_literal(nv)?;
1048        Some(AttributeKind::RustcDiagnosticItem(value))
1049    }
1050}
1051
1052pub(crate) struct RustcDoNotConstCheckParser;
1053
1054impl NoArgsAttributeParser for RustcDoNotConstCheckParser {
1055    const PATH: &[Symbol] = &[sym::rustc_do_not_const_check];
1056    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
1057        Allow(Target::Fn),
1058        Allow(Target::Method(MethodKind::Inherent)),
1059        Allow(Target::Method(MethodKind::TraitImpl)),
1060        Allow(Target::Method(MethodKind::Trait { body: false })),
1061        Allow(Target::Method(MethodKind::Trait { body: true })),
1062    ]);
1063    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &["the `rustc_do_not_const_check` attribute skips const-check for this function's body"],
    }
}unstable!(
1064        rustc_attrs,
1065        "the `rustc_do_not_const_check` attribute skips const-check for this function's body"
1066    );
1067    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDoNotConstCheck;
1068}
1069
1070pub(crate) struct RustcNonnullOptimizationGuaranteedParser;
1071
1072impl NoArgsAttributeParser for RustcNonnullOptimizationGuaranteedParser {
1073    const PATH: &[Symbol] = &[sym::rustc_nonnull_optimization_guaranteed];
1074    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
1075    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &["the `rustc_nonnull_optimization_guaranteed` attribute is just used to document guaranteed niche optimizations in the standard library",
                    "the compiler does not even check whether the type indeed is being non-null-optimized; it is your responsibility to ensure that the attribute is only used on types that are optimized"],
    }
}unstable!(
1076        rustc_attrs,
1077        "the `rustc_nonnull_optimization_guaranteed` attribute is just used to document guaranteed niche optimizations in the standard library",
1078        "the compiler does not even check whether the type indeed is being non-null-optimized; it is your responsibility to ensure that the attribute is only used on types that are optimized"
1079    );
1080    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNonnullOptimizationGuaranteed;
1081}
1082
1083pub(crate) struct RustcStrictCoherenceParser;
1084
1085impl NoArgsAttributeParser for RustcStrictCoherenceParser {
1086    const PATH: &[Symbol] = &[sym::rustc_strict_coherence];
1087    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
1088        Allow(Target::Trait),
1089        Allow(Target::Struct),
1090        Allow(Target::Enum),
1091        Allow(Target::Union),
1092        Allow(Target::ForeignTy),
1093    ]);
1094    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
1095    const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcStrictCoherence;
1096}
1097
1098pub(crate) struct PreludeImportParser;
1099
1100impl NoArgsAttributeParser for PreludeImportParser {
1101    const PATH: &[Symbol] = &[sym::prelude_import];
1102    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Use)]);
1103    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::prelude_import;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::prelude_import,
        notes: &[],
    }
}unstable!(prelude_import);
1104    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::PreludeImport;
1105}
1106
1107pub(crate) struct RustcDocPrimitiveParser;
1108
1109impl SingleAttributeParser for RustcDocPrimitiveParser {
1110    const PATH: &[Symbol] = &[sym::rustc_doc_primitive];
1111    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Const)]);
1112    const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
    word: false,
    list: None,
    one_of: &[],
    name_value_str: Some(&["primitive name"]),
    docs: None,
}template!(NameValueStr: "primitive name");
1113    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &["the `rustc_doc_primitive` attribute is used by the standard library to provide a way to generate documentation for primitive types"],
    }
}unstable!(
1114        rustc_attrs,
1115        "the `rustc_doc_primitive` attribute is used by the standard library to provide a way to generate documentation for primitive types"
1116    );
1117
1118    fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
1119        let nv = cx.expect_name_value(args, cx.attr_span, None)?;
1120        let value_str = cx.expect_string_literal(nv)?;
1121
1122        Some(AttributeKind::RustcDocPrimitive(cx.attr_span, value_str))
1123    }
1124}
1125
1126pub(crate) struct RustcIntrinsicParser;
1127
1128impl NoArgsAttributeParser for RustcIntrinsicParser {
1129    const PATH: &[Symbol] = &[sym::rustc_intrinsic];
1130    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
1131    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::intrinsics;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::intrinsics,
        notes: &[],
    }
}unstable!(intrinsics);
1132    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcIntrinsic;
1133}
1134
1135pub(crate) struct RustcIntrinsicConstStableIndirectParser;
1136
1137impl NoArgsAttributeParser for RustcIntrinsicConstStableIndirectParser {
1138    const PATH: &'static [Symbol] = &[sym::rustc_intrinsic_const_stable_indirect];
1139    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
1140    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
1141    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcIntrinsicConstStableIndirect;
1142}
1143
1144pub(crate) struct RustcExhaustiveParser;
1145
1146impl NoArgsAttributeParser for RustcExhaustiveParser {
1147    const PATH: &'static [Symbol] = &[sym::rustc_must_match_exhaustively];
1148    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Enum)]);
1149    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
1150    const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcMustMatchExhaustively;
1151}
1152
1153pub(crate) struct RustcCanonicalSymbolParser;
1154
1155impl NoArgsAttributeParser for RustcCanonicalSymbolParser {
1156    const PATH: &[Symbol] = &[sym::rustc_canonical_symbol];
1157    const ALLOWED_TARGETS: AllowedTargets<'_> =
1158        AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
1159    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &["the `rustc_canonical_symbol` attribute registers a function's symbol to be linted against \
        by the `invalid_runtime_symbol_definitions` and `suspicious_runtime_symbol_definitions` \
        lints"],
    }
}unstable!(
1160        rustc_attrs,
1161        "the `rustc_canonical_symbol` attribute registers a function's symbol to be linted against \
1162        by the `invalid_runtime_symbol_definitions` and `suspicious_runtime_symbol_definitions` \
1163        lints"
1164    );
1165    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcCanonicalSymbol;
1166}
1167
1168pub(crate) struct RustcAssertVarianceParser;
1169
1170impl SingleAttributeParser for RustcAssertVarianceParser {
1171    const PATH: &[Symbol] = &[sym::rustc_assert_variance];
1172
1173    const STABILITY: AttributeStability = {
    _ = rustc_feature::Features::rustc_attrs;
    AttributeStability::Unstable {
        gate_name: rustc_span::sym::rustc_attrs,
        notes: &[],
    }
}unstable!(rustc_attrs);
1174
1175    const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
1176        Allow(Target::TypeParam),
1177        Allow(Target::LifetimeParam),
1178        Allow(Target::ConstParam),
1179    ]);
1180
1181    const TEMPLATE: AttributeTemplate =
1182        crate::AttributeTemplate {
    word: false,
    list: None,
    one_of: &[sym::covariant, sym::invariant, sym::contravariant,
                sym::bivariant],
    name_value_str: None,
    docs: None,
}template!(OneOf: &[sym::covariant, sym::invariant, sym::contravariant, sym::bivariant]);
1183
1184    fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
1185        let arg = cx.expect_single_element_list(args, cx.attr_span)?;
1186
1187        let mut fail_arg = |span| {
1188            cx.adcx().expected_specific_argument(
1189                span,
1190                &[sym::covariant, sym::invariant, sym::contravariant, sym::bivariant],
1191            )
1192        };
1193
1194        let Some(arg) = arg.meta_item_no_args() else {
1195            fail_arg(arg.span());
1196            return None;
1197        };
1198
1199        let Some(arg) = arg.ident() else {
1200            fail_arg(arg.span());
1201            return None;
1202        };
1203
1204        let kind = match arg.name {
1205            sym::covariant => RustcAssertVarianceKind::Covariant,
1206            sym::invariant => RustcAssertVarianceKind::Invariant,
1207            sym::contravariant => RustcAssertVarianceKind::Contravariant,
1208            sym::bivariant => RustcAssertVarianceKind::Bivariant,
1209            _ => {
1210                fail_arg(arg.span);
1211                return None;
1212            }
1213        };
1214
1215        Some(AttributeKind::RustcAssertVariance { span: cx.attr_span, kind })
1216    }
1217}