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