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