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