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