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