Skip to main content

rustc_attr_parsing/attributes/
rustc_internal.rs

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