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