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 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 (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); 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); 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 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 ]);
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 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 ]);
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 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 ]);
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}