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