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