1use std::path::PathBuf;
2
3use rustc_ast::{LitIntType, LitKind, MetaItemLit};
4use rustc_hir::attrs::{
5 BorrowckGraphvizFormatKind, RustcCleanAttribute, RustcCleanQueries, RustcLayoutType,
6 RustcMirKind,
7};
8use rustc_session::errors;
9use rustc_span::Symbol;
10
11use super::prelude::*;
12use super::util::parse_single_integer;
13use crate::session_diagnostics::{AttributeRequiresOpt, RustcScalableVectorCountOutOfRange};
14
15pub(crate) struct RustcMainParser;
16
17impl<S: Stage> NoArgsAttributeParser<S> for RustcMainParser {
18 const PATH: &'static [Symbol] = &[sym::rustc_main];
19 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
20 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
21 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcMain;
22}
23
24pub(crate) struct RustcMustImplementOneOfParser;
25
26impl<S: Stage> SingleAttributeParser<S> for RustcMustImplementOneOfParser {
27 const PATH: &[Symbol] = &[sym::rustc_must_implement_one_of];
28 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
29 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
30 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
31 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: Some(&["function1, function2, ..."]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["function1, function2, ..."]);
32 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
33 let Some(list) = args.list() else {
34 cx.expected_list(cx.attr_span, args);
35 return None;
36 };
37
38 let mut fn_names = ThinVec::new();
39
40 let inputs: Vec<_> = list.mixed().collect();
41
42 if inputs.len() < 2 {
43 cx.expected_list_with_num_args_or_more(2, list.span);
44 return None;
45 }
46
47 let mut errored = false;
48 for argument in inputs {
49 let Some(meta) = argument.meta_item() else {
50 cx.expected_identifier(argument.span());
51 return None;
52 };
53
54 let Some(ident) = meta.ident() else {
55 cx.dcx().emit_err(errors::MustBeNameOfAssociatedFunction { span: meta.span() });
56 errored = true;
57 continue;
58 };
59
60 fn_names.push(ident);
61 }
62 if errored {
63 return None;
64 }
65
66 Some(AttributeKind::RustcMustImplementOneOf { attr_span: cx.attr_span, fn_names })
67 }
68}
69
70pub(crate) struct RustcNeverReturnsNullPointerParser;
71
72impl<S: Stage> NoArgsAttributeParser<S> for RustcNeverReturnsNullPointerParser {
73 const PATH: &[Symbol] = &[sym::rustc_never_returns_null_ptr];
74 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
75 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
76 Allow(Target::Fn),
77 Allow(Target::Method(MethodKind::Inherent)),
78 Allow(Target::Method(MethodKind::Trait { body: false })),
79 Allow(Target::Method(MethodKind::Trait { body: true })),
80 Allow(Target::Method(MethodKind::TraitImpl)),
81 ]);
82 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNeverReturnsNullPointer;
83}
84pub(crate) struct RustcNoImplicitAutorefsParser;
85
86impl<S: Stage> NoArgsAttributeParser<S> for RustcNoImplicitAutorefsParser {
87 const PATH: &[Symbol] = &[sym::rustc_no_implicit_autorefs];
88 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
89 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
90 Allow(Target::Fn),
91 Allow(Target::Method(MethodKind::Inherent)),
92 Allow(Target::Method(MethodKind::Trait { body: false })),
93 Allow(Target::Method(MethodKind::Trait { body: true })),
94 Allow(Target::Method(MethodKind::TraitImpl)),
95 ]);
96
97 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoImplicitAutorefs;
98}
99
100pub(crate) struct RustcLayoutScalarValidRangeStartParser;
101
102impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeStartParser {
103 const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_start];
104 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
105 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
106 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
107 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: Some(&["start"]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["start"]);
108
109 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
110 parse_single_integer(cx, args)
111 .map(|n| AttributeKind::RustcLayoutScalarValidRangeStart(Box::new(n), cx.attr_span))
112 }
113}
114
115pub(crate) struct RustcLayoutScalarValidRangeEndParser;
116
117impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeEndParser {
118 const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_end];
119 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
120 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
121 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
122 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: Some(&["end"]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["end"]);
123
124 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
125 parse_single_integer(cx, args)
126 .map(|n| AttributeKind::RustcLayoutScalarValidRangeEnd(Box::new(n), cx.attr_span))
127 }
128}
129
130pub(crate) struct RustcLegacyConstGenericsParser;
131
132impl<S: Stage> SingleAttributeParser<S> for RustcLegacyConstGenericsParser {
133 const PATH: &[Symbol] = &[sym::rustc_legacy_const_generics];
134 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
135 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
136 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
137 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: Some(&["N"]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["N"]);
138
139 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
140 let ArgParser::List(meta_items) = args else {
141 cx.expected_list(cx.attr_span, args);
142 return None;
143 };
144
145 let mut parsed_indexes = ThinVec::new();
146 let mut errored = false;
147
148 for possible_index in meta_items.mixed() {
149 if let MetaItemOrLitParser::Lit(MetaItemLit {
150 kind: LitKind::Int(index, LitIntType::Unsuffixed),
151 ..
152 }) = possible_index
153 {
154 parsed_indexes.push((index.0 as usize, possible_index.span()));
155 } else {
156 cx.expected_integer_literal(possible_index.span());
157 errored = true;
158 }
159 }
160 if errored {
161 return None;
162 } else if parsed_indexes.is_empty() {
163 cx.expected_at_least_one_argument(args.span()?);
164 return None;
165 }
166
167 Some(AttributeKind::RustcLegacyConstGenerics {
168 fn_indexes: parsed_indexes,
169 attr_span: cx.attr_span,
170 })
171 }
172}
173
174pub(crate) struct RustcLintOptDenyFieldAccessParser;
175
176impl<S: Stage> SingleAttributeParser<S> for RustcLintOptDenyFieldAccessParser {
177 const PATH: &[Symbol] = &[sym::rustc_lint_opt_deny_field_access];
178 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
179 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
180 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Field)]);
181 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: true,
list: None,
one_of: &[],
name_value_str: None,
docs: None,
}template!(Word);
182 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
183 let Some(arg) = args.list().and_then(MetaItemListParser::single) else {
184 cx.expected_single_argument(cx.attr_span);
185 return None;
186 };
187
188 let MetaItemOrLitParser::Lit(MetaItemLit { kind: LitKind::Str(lint_message, _), .. }) = arg
189 else {
190 cx.expected_string_literal(arg.span(), arg.lit());
191 return None;
192 };
193
194 Some(AttributeKind::RustcLintOptDenyFieldAccess { lint_message: *lint_message })
195 }
196}
197
198pub(crate) struct RustcLintOptTyParser;
199
200impl<S: Stage> NoArgsAttributeParser<S> for RustcLintOptTyParser {
201 const PATH: &[Symbol] = &[sym::rustc_lint_opt_ty];
202 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
203 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
204 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintOptTy;
205}
206
207pub(crate) struct RustcLintQueryInstabilityParser;
208
209impl<S: Stage> NoArgsAttributeParser<S> for RustcLintQueryInstabilityParser {
210 const PATH: &[Symbol] = &[sym::rustc_lint_query_instability];
211 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
212 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
213 Allow(Target::Fn),
214 Allow(Target::Method(MethodKind::Inherent)),
215 Allow(Target::Method(MethodKind::Trait { body: false })),
216 Allow(Target::Method(MethodKind::Trait { body: true })),
217 Allow(Target::Method(MethodKind::TraitImpl)),
218 ]);
219 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintQueryInstability;
220}
221
222pub(crate) struct RustcLintUntrackedQueryInformationParser;
223
224impl<S: Stage> NoArgsAttributeParser<S> for RustcLintUntrackedQueryInformationParser {
225 const PATH: &[Symbol] = &[sym::rustc_lint_untracked_query_information];
226 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
227 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
228 Allow(Target::Fn),
229 Allow(Target::Method(MethodKind::Inherent)),
230 Allow(Target::Method(MethodKind::Trait { body: false })),
231 Allow(Target::Method(MethodKind::Trait { body: true })),
232 Allow(Target::Method(MethodKind::TraitImpl)),
233 ]);
234
235 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintUntrackedQueryInformation;
236}
237
238pub(crate) struct RustcObjectLifetimeDefaultParser;
239
240impl<S: Stage> SingleAttributeParser<S> for RustcObjectLifetimeDefaultParser {
241 const PATH: &[Symbol] = &[sym::rustc_object_lifetime_default];
242 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
243 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
244 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
245 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: true,
list: None,
one_of: &[],
name_value_str: None,
docs: None,
}template!(Word);
246
247 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
248 if let Err(span) = args.no_args() {
249 cx.expected_no_args(span);
250 return None;
251 }
252
253 Some(AttributeKind::RustcObjectLifetimeDefault)
254 }
255}
256
257pub(crate) struct RustcSimdMonomorphizeLaneLimitParser;
258
259impl<S: Stage> SingleAttributeParser<S> for RustcSimdMonomorphizeLaneLimitParser {
260 const PATH: &[Symbol] = &[sym::rustc_simd_monomorphize_lane_limit];
261 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
262 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
263 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
264 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["N"]),
docs: None,
}template!(NameValueStr: "N");
265
266 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
267 let ArgParser::NameValue(nv) = args else {
268 cx.expected_name_value(cx.attr_span, None);
269 return None;
270 };
271 Some(AttributeKind::RustcSimdMonomorphizeLaneLimit(cx.parse_limit_int(nv)?))
272 }
273}
274
275pub(crate) struct RustcScalableVectorParser;
276
277impl<S: Stage> SingleAttributeParser<S> for RustcScalableVectorParser {
278 const PATH: &[Symbol] = &[sym::rustc_scalable_vector];
279 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
280 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
281 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
282 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: true,
list: Some(&["count"]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(Word, List: &["count"]);
283
284 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
285 if args.no_args().is_ok() {
286 return Some(AttributeKind::RustcScalableVector {
287 element_count: None,
288 span: cx.attr_span,
289 });
290 }
291
292 let n = parse_single_integer(cx, args)?;
293 let Ok(n) = n.try_into() else {
294 cx.emit_err(RustcScalableVectorCountOutOfRange { span: cx.attr_span, n });
295 return None;
296 };
297 Some(AttributeKind::RustcScalableVector { element_count: Some(n), span: cx.attr_span })
298 }
299}
300
301pub(crate) struct RustcHasIncoherentInherentImplsParser;
302
303impl<S: Stage> NoArgsAttributeParser<S> for RustcHasIncoherentInherentImplsParser {
304 const PATH: &[Symbol] = &[sym::rustc_has_incoherent_inherent_impls];
305 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
306 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
307 Allow(Target::Trait),
308 Allow(Target::Struct),
309 Allow(Target::Enum),
310 Allow(Target::Union),
311 Allow(Target::ForeignTy),
312 ]);
313 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcHasIncoherentInherentImpls;
314}
315
316pub(crate) struct RustcHiddenTypeOfOpaquesParser;
317
318impl<S: Stage> NoArgsAttributeParser<S> for RustcHiddenTypeOfOpaquesParser {
319 const PATH: &[Symbol] = &[sym::rustc_hidden_type_of_opaques];
320 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
321 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
322 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcHiddenTypeOfOpaques;
323}
324pub(crate) struct RustcNounwindParser;
325
326impl<S: Stage> NoArgsAttributeParser<S> for RustcNounwindParser {
327 const PATH: &[Symbol] = &[sym::rustc_nounwind];
328 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
329 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
330 Allow(Target::Fn),
331 Allow(Target::ForeignFn),
332 Allow(Target::Method(MethodKind::Inherent)),
333 Allow(Target::Method(MethodKind::TraitImpl)),
334 Allow(Target::Method(MethodKind::Trait { body: true })),
335 ]);
336 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNounwind;
337}
338
339pub(crate) struct RustcOffloadKernelParser;
340
341impl<S: Stage> NoArgsAttributeParser<S> for RustcOffloadKernelParser {
342 const PATH: &[Symbol] = &[sym::rustc_offload_kernel];
343 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
344 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
345 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcOffloadKernel;
346}
347
348pub(crate) struct RustcLayoutParser;
349
350impl<S: Stage> CombineAttributeParser<S> for RustcLayoutParser {
351 const PATH: &[Symbol] = &[sym::rustc_layout];
352
353 type Item = RustcLayoutType;
354
355 const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::RustcLayout(items);
356
357 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
358 Allow(Target::Struct),
359 Allow(Target::Enum),
360 Allow(Target::Union),
361 Allow(Target::TyAlias),
362 ]);
363
364 const TEMPLATE: AttributeTemplate =
365 ::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"]);
366 fn extend(
367 cx: &mut AcceptContext<'_, '_, S>,
368 args: &ArgParser,
369 ) -> impl IntoIterator<Item = Self::Item> {
370 let ArgParser::List(items) = args else {
371 cx.expected_list(cx.attr_span, args);
372 return ::alloc::vec::Vec::new()vec![];
373 };
374
375 let mut result = Vec::new();
376 for item in items.mixed() {
377 let Some(arg) = item.meta_item() else {
378 cx.unexpected_literal(item.span());
379 continue;
380 };
381 let Some(ident) = arg.ident() else {
382 cx.expected_identifier(arg.span());
383 return ::alloc::vec::Vec::new()vec![];
384 };
385 let ty = match ident.name {
386 sym::abi => RustcLayoutType::Abi,
387 sym::align => RustcLayoutType::Align,
388 sym::size => RustcLayoutType::Size,
389 sym::homogeneous_aggregate => RustcLayoutType::HomogenousAggregate,
390 sym::debug => RustcLayoutType::Debug,
391 _ => {
392 cx.expected_specific_argument(
393 ident.span,
394 &[sym::abi, sym::align, sym::size, sym::homogeneous_aggregate, sym::debug],
395 );
396 continue;
397 }
398 };
399 result.push(ty);
400 }
401 result
402 }
403}
404
405pub(crate) struct RustcMirParser;
406
407impl<S: Stage> CombineAttributeParser<S> for RustcMirParser {
408 const PATH: &[Symbol] = &[sym::rustc_mir];
409
410 type Item = RustcMirKind;
411
412 const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::RustcMir(items);
413
414 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
415 Allow(Target::Fn),
416 Allow(Target::Method(MethodKind::Inherent)),
417 Allow(Target::Method(MethodKind::TraitImpl)),
418 Allow(Target::Method(MethodKind::Trait { body: false })),
419 Allow(Target::Method(MethodKind::Trait { body: true })),
420 ]);
421
422 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: Some(&["arg1, arg2, ..."]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["arg1, arg2, ..."]);
423
424 fn extend(
425 cx: &mut AcceptContext<'_, '_, S>,
426 args: &ArgParser,
427 ) -> impl IntoIterator<Item = Self::Item> {
428 let Some(list) = args.list() else {
429 cx.expected_list(cx.attr_span, args);
430 return ThinVec::new();
431 };
432
433 list.mixed()
434 .filter_map(|arg| arg.meta_item())
435 .filter_map(|mi| {
436 if let Some(ident) = mi.ident() {
437 match ident.name {
438 sym::rustc_peek_maybe_init => Some(RustcMirKind::PeekMaybeInit),
439 sym::rustc_peek_maybe_uninit => Some(RustcMirKind::PeekMaybeUninit),
440 sym::rustc_peek_liveness => Some(RustcMirKind::PeekLiveness),
441 sym::stop_after_dataflow => Some(RustcMirKind::StopAfterDataflow),
442 sym::borrowck_graphviz_postflow => {
443 let Some(nv) = mi.args().name_value() else {
444 cx.expected_name_value(
445 mi.span(),
446 Some(sym::borrowck_graphviz_postflow),
447 );
448 return None;
449 };
450 let Some(path) = nv.value_as_str() else {
451 cx.expected_string_literal(nv.value_span, None);
452 return None;
453 };
454 let path = PathBuf::from(path.to_string());
455 if path.file_name().is_some() {
456 Some(RustcMirKind::BorrowckGraphvizPostflow { path })
457 } else {
458 cx.expected_filename_literal(nv.value_span);
459 None
460 }
461 }
462 sym::borrowck_graphviz_format => {
463 let Some(nv) = mi.args().name_value() else {
464 cx.expected_name_value(
465 mi.span(),
466 Some(sym::borrowck_graphviz_format),
467 );
468 return None;
469 };
470 let Some(format) = nv.value_as_ident() else {
471 cx.expected_identifier(nv.value_span);
472 return None;
473 };
474 match format.name {
475 sym::two_phase => Some(RustcMirKind::BorrowckGraphvizFormat {
476 format: BorrowckGraphvizFormatKind::TwoPhase,
477 }),
478 _ => {
479 cx.expected_specific_argument(format.span, &[sym::two_phase]);
480 None
481 }
482 }
483 }
484 _ => None,
485 }
486 } else {
487 None
488 }
489 })
490 .collect()
491 }
492}
493pub(crate) struct RustcNonConstTraitMethodParser;
494
495impl<S: Stage> NoArgsAttributeParser<S> for RustcNonConstTraitMethodParser {
496 const PATH: &'static [Symbol] = &[sym::rustc_non_const_trait_method];
497 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
498 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
499 Allow(Target::Method(MethodKind::Trait { body: true })),
500 Allow(Target::Method(MethodKind::Trait { body: false })),
501 ]);
502 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNonConstTraitMethod;
503}
504
505pub(crate) struct RustcCleanParser;
506
507impl<S: Stage> CombineAttributeParser<S> for RustcCleanParser {
508 const PATH: &[Symbol] = &[sym::rustc_clean];
509
510 type Item = RustcCleanAttribute;
511
512 const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::RustcClean(items);
513
514 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
515 Allow(Target::AssocConst),
517 Allow(Target::AssocTy),
518 Allow(Target::Const),
519 Allow(Target::Enum),
520 Allow(Target::Expression),
521 Allow(Target::Field),
522 Allow(Target::Fn),
523 Allow(Target::ForeignMod),
524 Allow(Target::Impl { of_trait: false }),
525 Allow(Target::Impl { of_trait: true }),
526 Allow(Target::Method(MethodKind::Inherent)),
527 Allow(Target::Method(MethodKind::Trait { body: false })),
528 Allow(Target::Method(MethodKind::Trait { body: true })),
529 Allow(Target::Method(MethodKind::TraitImpl)),
530 Allow(Target::Mod),
531 Allow(Target::Static),
532 Allow(Target::Struct),
533 Allow(Target::Trait),
534 Allow(Target::TyAlias),
535 Allow(Target::Union),
536 ]);
538
539 const TEMPLATE: AttributeTemplate =
540 ::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 = "...""#]);
541
542 fn extend(
543 cx: &mut AcceptContext<'_, '_, S>,
544 args: &ArgParser,
545 ) -> impl IntoIterator<Item = Self::Item> {
546 if !cx.cx.sess.opts.unstable_opts.query_dep_graph {
547 cx.emit_err(AttributeRequiresOpt { span: cx.attr_span, opt: "-Z query-dep-graph" });
548 }
549 let Some(list) = args.list() else {
550 cx.expected_list(cx.attr_span, args);
551 return None;
552 };
553 let mut except = None;
554 let mut loaded_from_disk = None;
555 let mut cfg = None;
556
557 for item in list.mixed() {
558 let Some((value, name)) =
559 item.meta_item().and_then(|m| Option::zip(m.args().name_value(), m.ident()))
560 else {
561 cx.expected_name_value(item.span(), None);
562 continue;
563 };
564 let value_span = value.value_span;
565 let Some(value) = value.value_as_str() else {
566 cx.expected_string_literal(value_span, None);
567 continue;
568 };
569 match name.name {
570 sym::cfg if cfg.is_some() => {
571 cx.duplicate_key(item.span(), sym::cfg);
572 }
573
574 sym::cfg => {
575 cfg = Some(value);
576 }
577 sym::except if except.is_some() => {
578 cx.duplicate_key(item.span(), sym::except);
579 }
580 sym::except => {
581 let entries =
582 value.as_str().split(',').map(|s| Symbol::intern(s.trim())).collect();
583 except = Some(RustcCleanQueries { entries, span: value_span });
584 }
585 sym::loaded_from_disk if loaded_from_disk.is_some() => {
586 cx.duplicate_key(item.span(), sym::loaded_from_disk);
587 }
588 sym::loaded_from_disk => {
589 let entries =
590 value.as_str().split(',').map(|s| Symbol::intern(s.trim())).collect();
591 loaded_from_disk = Some(RustcCleanQueries { entries, span: value_span });
592 }
593 _ => {
594 cx.expected_specific_argument(
595 name.span,
596 &[sym::cfg, sym::except, sym::loaded_from_disk],
597 );
598 }
599 }
600 }
601 let Some(cfg) = cfg else {
602 cx.expected_specific_argument(list.span, &[sym::cfg]);
603 return None;
604 };
605
606 Some(RustcCleanAttribute { span: cx.attr_span, cfg, except, loaded_from_disk })
607 }
608}
609
610pub(crate) struct RustcIfThisChangedParser;
611
612impl<S: Stage> SingleAttributeParser<S> for RustcIfThisChangedParser {
613 const PATH: &[Symbol] = &[sym::rustc_if_this_changed];
614
615 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
616
617 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
618
619 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
620 Allow(Target::AssocConst),
622 Allow(Target::AssocTy),
623 Allow(Target::Const),
624 Allow(Target::Enum),
625 Allow(Target::Expression),
626 Allow(Target::Field),
627 Allow(Target::Fn),
628 Allow(Target::ForeignMod),
629 Allow(Target::Impl { of_trait: false }),
630 Allow(Target::Impl { of_trait: true }),
631 Allow(Target::Method(MethodKind::Inherent)),
632 Allow(Target::Method(MethodKind::Trait { body: false })),
633 Allow(Target::Method(MethodKind::Trait { body: true })),
634 Allow(Target::Method(MethodKind::TraitImpl)),
635 Allow(Target::Mod),
636 Allow(Target::Static),
637 Allow(Target::Struct),
638 Allow(Target::Trait),
639 Allow(Target::TyAlias),
640 Allow(Target::Union),
641 ]);
643
644 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: true,
list: Some(&["DepNode"]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(Word, List: &["DepNode"]);
645
646 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
647 if !cx.cx.sess.opts.unstable_opts.query_dep_graph {
648 cx.emit_err(AttributeRequiresOpt { span: cx.attr_span, opt: "-Z query-dep-graph" });
649 }
650 match args {
651 ArgParser::NoArgs => Some(AttributeKind::RustcIfThisChanged(cx.attr_span, None)),
652 ArgParser::List(list) => {
653 let Some(item) = list.single() else {
654 cx.expected_single_argument(list.span);
655 return None;
656 };
657 let Some(ident) = item.meta_item().and_then(|item| item.ident()) else {
658 cx.expected_identifier(item.span());
659 return None;
660 };
661 Some(AttributeKind::RustcIfThisChanged(cx.attr_span, Some(ident.name)))
662 }
663 ArgParser::NameValue(_) => {
664 cx.expected_list_or_no_args(cx.inner_span);
665 None
666 }
667 }
668 }
669}
670
671pub(crate) struct RustcThenThisWouldNeedParser;
672
673impl<S: Stage> CombineAttributeParser<S> for RustcThenThisWouldNeedParser {
674 const PATH: &[Symbol] = &[sym::rustc_then_this_would_need];
675 type Item = Ident;
676
677 const CONVERT: ConvertFn<Self::Item> =
678 |items, span| AttributeKind::RustcThenThisWouldNeed(span, items);
679 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
680 Allow(Target::AssocConst),
682 Allow(Target::AssocTy),
683 Allow(Target::Const),
684 Allow(Target::Enum),
685 Allow(Target::Expression),
686 Allow(Target::Field),
687 Allow(Target::Fn),
688 Allow(Target::ForeignMod),
689 Allow(Target::Impl { of_trait: false }),
690 Allow(Target::Impl { of_trait: true }),
691 Allow(Target::Method(MethodKind::Inherent)),
692 Allow(Target::Method(MethodKind::Trait { body: false })),
693 Allow(Target::Method(MethodKind::Trait { body: true })),
694 Allow(Target::Method(MethodKind::TraitImpl)),
695 Allow(Target::Mod),
696 Allow(Target::Static),
697 Allow(Target::Struct),
698 Allow(Target::Trait),
699 Allow(Target::TyAlias),
700 Allow(Target::Union),
701 ]);
703
704 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: Some(&["DepNode"]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["DepNode"]);
705
706 fn extend(
707 cx: &mut AcceptContext<'_, '_, S>,
708 args: &ArgParser,
709 ) -> impl IntoIterator<Item = Self::Item> {
710 if !cx.cx.sess.opts.unstable_opts.query_dep_graph {
711 cx.emit_err(AttributeRequiresOpt { span: cx.attr_span, opt: "-Z query-dep-graph" });
712 }
713 let Some(item) = args.list().and_then(|l| l.single()) else {
714 cx.expected_single_argument(cx.inner_span);
715 return None;
716 };
717 let Some(ident) = item.meta_item().and_then(|item| item.ident()) else {
718 cx.expected_identifier(item.span());
719 return None;
720 };
721 Some(ident)
722 }
723}
724
725pub(crate) struct RustcEffectiveVisibilityParser;
726
727impl<S: Stage> NoArgsAttributeParser<S> for RustcEffectiveVisibilityParser {
728 const PATH: &'static [Symbol] = &[sym::rustc_effective_visibility];
729 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
730 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
731 Allow(Target::Use),
732 Allow(Target::Static),
733 Allow(Target::Const),
734 Allow(Target::Fn),
735 Allow(Target::Closure),
736 Allow(Target::Mod),
737 Allow(Target::ForeignMod),
738 Allow(Target::TyAlias),
739 Allow(Target::Enum),
740 Allow(Target::Variant),
741 Allow(Target::Struct),
742 Allow(Target::Field),
743 Allow(Target::Union),
744 Allow(Target::Trait),
745 Allow(Target::TraitAlias),
746 Allow(Target::Impl { of_trait: false }),
747 Allow(Target::Impl { of_trait: true }),
748 Allow(Target::AssocConst),
749 Allow(Target::Method(MethodKind::Inherent)),
750 Allow(Target::Method(MethodKind::Trait { body: false })),
751 Allow(Target::Method(MethodKind::Trait { body: true })),
752 Allow(Target::Method(MethodKind::TraitImpl)),
753 Allow(Target::AssocTy),
754 Allow(Target::ForeignFn),
755 Allow(Target::ForeignStatic),
756 Allow(Target::ForeignTy),
757 Allow(Target::MacroDef),
758 Allow(Target::PatField),
759 Allow(Target::Crate),
760 ]);
761 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcEffectiveVisibility;
762}