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