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