Skip to main content

rustc_attr_parsing/attributes/
rustc_internal.rs

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