Skip to main content

rustc_attr_parsing/attributes/
rustc_internal.rs

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