Skip to main content

rustc_attr_parsing/attributes/
rustc_internal.rs

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