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