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