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