Skip to main content

rustc_attr_parsing/attributes/
rustc_internal.rs

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