Skip to main content

rustc_attr_parsing/attributes/
rustc_internal.rs

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