Skip to main content

rustc_attr_parsing/attributes/
rustc_internal.rs

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