Skip to main content

rustc_attr_parsing/attributes/
rustc_internal.rs

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