rustc_attr_parsing/attributes/
rustc_internal.rs1use rustc_ast::{LitIntType, LitKind, MetaItemLit};
2use rustc_hir::attrs::RustcLayoutType;
3use rustc_session::errors;
4
5use super::prelude::*;
6use super::util::parse_single_integer;
7use crate::session_diagnostics::RustcScalableVectorCountOutOfRange;
8
9pub(crate) struct RustcMainParser;
10
11impl<S: Stage> NoArgsAttributeParser<S> for RustcMainParser {
12 const PATH: &'static [Symbol] = &[sym::rustc_main];
13 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
14 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
15 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcMain;
16}
17
18pub(crate) struct RustcMustImplementOneOfParser;
19
20impl<S: Stage> SingleAttributeParser<S> for RustcMustImplementOneOfParser {
21 const PATH: &[Symbol] = &[sym::rustc_must_implement_one_of];
22 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
23 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
24 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
25 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: Some(&["function1, function2, ..."]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["function1, function2, ..."]);
26 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
27 let Some(list) = args.list() else {
28 cx.expected_list(cx.attr_span, args);
29 return None;
30 };
31
32 let mut fn_names = ThinVec::new();
33
34 let inputs: Vec<_> = list.mixed().collect();
35
36 if inputs.len() < 2 {
37 cx.expected_list_with_num_args_or_more(2, list.span);
38 return None;
39 }
40
41 let mut errored = false;
42 for argument in inputs {
43 let Some(meta) = argument.meta_item() else {
44 cx.expected_identifier(argument.span());
45 return None;
46 };
47
48 let Some(ident) = meta.ident() else {
49 cx.dcx().emit_err(errors::MustBeNameOfAssociatedFunction { span: meta.span() });
50 errored = true;
51 continue;
52 };
53
54 fn_names.push(ident);
55 }
56 if errored {
57 return None;
58 }
59
60 Some(AttributeKind::RustcMustImplementOneOf { attr_span: cx.attr_span, fn_names })
61 }
62}
63
64pub(crate) struct RustcNeverReturnsNullPointerParser;
65
66impl<S: Stage> NoArgsAttributeParser<S> for RustcNeverReturnsNullPointerParser {
67 const PATH: &[Symbol] = &[sym::rustc_never_returns_null_ptr];
68 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
69 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
70 Allow(Target::Fn),
71 Allow(Target::Method(MethodKind::Inherent)),
72 Allow(Target::Method(MethodKind::Trait { body: false })),
73 Allow(Target::Method(MethodKind::Trait { body: true })),
74 Allow(Target::Method(MethodKind::TraitImpl)),
75 ]);
76 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNeverReturnsNullPointer;
77}
78pub(crate) struct RustcNoImplicitAutorefsParser;
79
80impl<S: Stage> NoArgsAttributeParser<S> for RustcNoImplicitAutorefsParser {
81 const PATH: &[Symbol] = &[sym::rustc_no_implicit_autorefs];
82 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
83 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
84 Allow(Target::Fn),
85 Allow(Target::Method(MethodKind::Inherent)),
86 Allow(Target::Method(MethodKind::Trait { body: false })),
87 Allow(Target::Method(MethodKind::Trait { body: true })),
88 Allow(Target::Method(MethodKind::TraitImpl)),
89 ]);
90
91 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoImplicitAutorefs;
92}
93
94pub(crate) struct RustcLayoutScalarValidRangeStartParser;
95
96impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeStartParser {
97 const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_start];
98 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
99 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
100 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
101 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: Some(&["start"]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["start"]);
102
103 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
104 parse_single_integer(cx, args)
105 .map(|n| AttributeKind::RustcLayoutScalarValidRangeStart(Box::new(n), cx.attr_span))
106 }
107}
108
109pub(crate) struct RustcLayoutScalarValidRangeEndParser;
110
111impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeEndParser {
112 const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_end];
113 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
114 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
115 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
116 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: Some(&["end"]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["end"]);
117
118 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
119 parse_single_integer(cx, args)
120 .map(|n| AttributeKind::RustcLayoutScalarValidRangeEnd(Box::new(n), cx.attr_span))
121 }
122}
123
124pub(crate) struct RustcLegacyConstGenericsParser;
125
126impl<S: Stage> SingleAttributeParser<S> for RustcLegacyConstGenericsParser {
127 const PATH: &[Symbol] = &[sym::rustc_legacy_const_generics];
128 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
129 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
130 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
131 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: Some(&["N"]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["N"]);
132
133 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
134 let ArgParser::List(meta_items) = args else {
135 cx.expected_list(cx.attr_span, args);
136 return None;
137 };
138
139 let mut parsed_indexes = ThinVec::new();
140 let mut errored = false;
141
142 for possible_index in meta_items.mixed() {
143 if let MetaItemOrLitParser::Lit(MetaItemLit {
144 kind: LitKind::Int(index, LitIntType::Unsuffixed),
145 ..
146 }) = possible_index
147 {
148 parsed_indexes.push((index.0 as usize, possible_index.span()));
149 } else {
150 cx.expected_integer_literal(possible_index.span());
151 errored = true;
152 }
153 }
154 if errored {
155 return None;
156 } else if parsed_indexes.is_empty() {
157 cx.expected_at_least_one_argument(args.span()?);
158 return None;
159 }
160
161 Some(AttributeKind::RustcLegacyConstGenerics {
162 fn_indexes: parsed_indexes,
163 attr_span: cx.attr_span,
164 })
165 }
166}
167
168pub(crate) struct RustcLintOptDenyFieldAccessParser;
169
170impl<S: Stage> SingleAttributeParser<S> for RustcLintOptDenyFieldAccessParser {
171 const PATH: &[Symbol] = &[sym::rustc_lint_opt_deny_field_access];
172 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
173 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
174 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Field)]);
175 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: true,
list: None,
one_of: &[],
name_value_str: None,
docs: None,
}template!(Word);
176 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
177 let Some(arg) = args.list().and_then(MetaItemListParser::single) else {
178 cx.expected_single_argument(cx.attr_span);
179 return None;
180 };
181
182 let MetaItemOrLitParser::Lit(MetaItemLit { kind: LitKind::Str(lint_message, _), .. }) = arg
183 else {
184 cx.expected_string_literal(arg.span(), arg.lit());
185 return None;
186 };
187
188 Some(AttributeKind::RustcLintOptDenyFieldAccess { lint_message: *lint_message })
189 }
190}
191
192pub(crate) struct RustcLintOptTyParser;
193
194impl<S: Stage> NoArgsAttributeParser<S> for RustcLintOptTyParser {
195 const PATH: &[Symbol] = &[sym::rustc_lint_opt_ty];
196 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
197 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
198 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintOptTy;
199}
200
201pub(crate) struct RustcLintQueryInstabilityParser;
202
203impl<S: Stage> NoArgsAttributeParser<S> for RustcLintQueryInstabilityParser {
204 const PATH: &[Symbol] = &[sym::rustc_lint_query_instability];
205 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
206 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
207 Allow(Target::Fn),
208 Allow(Target::Method(MethodKind::Inherent)),
209 Allow(Target::Method(MethodKind::Trait { body: false })),
210 Allow(Target::Method(MethodKind::Trait { body: true })),
211 Allow(Target::Method(MethodKind::TraitImpl)),
212 ]);
213 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintQueryInstability;
214}
215
216pub(crate) struct RustcLintUntrackedQueryInformationParser;
217
218impl<S: Stage> NoArgsAttributeParser<S> for RustcLintUntrackedQueryInformationParser {
219 const PATH: &[Symbol] = &[sym::rustc_lint_untracked_query_information];
220 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
221 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
222 Allow(Target::Fn),
223 Allow(Target::Method(MethodKind::Inherent)),
224 Allow(Target::Method(MethodKind::Trait { body: false })),
225 Allow(Target::Method(MethodKind::Trait { body: true })),
226 Allow(Target::Method(MethodKind::TraitImpl)),
227 ]);
228
229 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintUntrackedQueryInformation;
230}
231
232pub(crate) struct RustcObjectLifetimeDefaultParser;
233
234impl<S: Stage> SingleAttributeParser<S> for RustcObjectLifetimeDefaultParser {
235 const PATH: &[rustc_span::Symbol] = &[sym::rustc_object_lifetime_default];
236 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
237 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
238 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
239 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: true,
list: None,
one_of: &[],
name_value_str: None,
docs: None,
}template!(Word);
240
241 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
242 if let Err(span) = args.no_args() {
243 cx.expected_no_args(span);
244 return None;
245 }
246
247 Some(AttributeKind::RustcObjectLifetimeDefault)
248 }
249}
250
251pub(crate) struct RustcSimdMonomorphizeLaneLimitParser;
252
253impl<S: Stage> SingleAttributeParser<S> for RustcSimdMonomorphizeLaneLimitParser {
254 const PATH: &[Symbol] = &[sym::rustc_simd_monomorphize_lane_limit];
255 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
256 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
257 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
258 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["N"]),
docs: None,
}template!(NameValueStr: "N");
259
260 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
261 let ArgParser::NameValue(nv) = args else {
262 cx.expected_name_value(cx.attr_span, None);
263 return None;
264 };
265 Some(AttributeKind::RustcSimdMonomorphizeLaneLimit(cx.parse_limit_int(nv)?))
266 }
267}
268
269pub(crate) struct RustcScalableVectorParser;
270
271impl<S: Stage> SingleAttributeParser<S> for RustcScalableVectorParser {
272 const PATH: &[rustc_span::Symbol] = &[sym::rustc_scalable_vector];
273 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
274 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
275 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
276 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: true,
list: Some(&["count"]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(Word, List: &["count"]);
277
278 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
279 if args.no_args().is_ok() {
280 return Some(AttributeKind::RustcScalableVector {
281 element_count: None,
282 span: cx.attr_span,
283 });
284 }
285
286 let n = parse_single_integer(cx, args)?;
287 let Ok(n) = n.try_into() else {
288 cx.emit_err(RustcScalableVectorCountOutOfRange { span: cx.attr_span, n });
289 return None;
290 };
291 Some(AttributeKind::RustcScalableVector { element_count: Some(n), span: cx.attr_span })
292 }
293}
294
295pub(crate) struct RustcHasIncoherentInherentImplsParser;
296
297impl<S: Stage> NoArgsAttributeParser<S> for RustcHasIncoherentInherentImplsParser {
298 const PATH: &[Symbol] = &[sym::rustc_has_incoherent_inherent_impls];
299 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
300 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
301 Allow(Target::Trait),
302 Allow(Target::Struct),
303 Allow(Target::Enum),
304 Allow(Target::Union),
305 Allow(Target::ForeignTy),
306 ]);
307 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcHasIncoherentInherentImpls;
308}
309
310pub(crate) struct RustcNounwindParser;
311
312impl<S: Stage> NoArgsAttributeParser<S> for RustcNounwindParser {
313 const PATH: &[Symbol] = &[sym::rustc_nounwind];
314 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
315 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
316 Allow(Target::Fn),
317 Allow(Target::ForeignFn),
318 Allow(Target::Method(MethodKind::Inherent)),
319 Allow(Target::Method(MethodKind::TraitImpl)),
320 Allow(Target::Method(MethodKind::Trait { body: true })),
321 ]);
322 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNounwind;
323}
324
325pub(crate) struct RustcOffloadKernelParser;
326
327impl<S: Stage> NoArgsAttributeParser<S> for RustcOffloadKernelParser {
328 const PATH: &[Symbol] = &[sym::rustc_offload_kernel];
329 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
330 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
331 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcOffloadKernel;
332}
333
334pub(crate) struct RustcLayoutParser;
335
336impl<S: Stage> CombineAttributeParser<S> for RustcLayoutParser {
337 const PATH: &[rustc_span::Symbol] = &[sym::rustc_layout];
338
339 type Item = RustcLayoutType;
340
341 const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::RustcLayout(items);
342
343 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
344 Allow(Target::Struct),
345 Allow(Target::Enum),
346 Allow(Target::Union),
347 Allow(Target::TyAlias),
348 ]);
349
350 const TEMPLATE: AttributeTemplate =
351 ::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"]);
352
353 fn extend(
354 cx: &mut AcceptContext<'_, '_, S>,
355 args: &ArgParser,
356 ) -> impl IntoIterator<Item = Self::Item> {
357 let ArgParser::List(items) = args else {
358 cx.expected_list(cx.attr_span, args);
359 return ::alloc::vec::Vec::new()vec![];
360 };
361
362 let mut result = Vec::new();
363 for item in items.mixed() {
364 let Some(arg) = item.meta_item() else {
365 cx.unexpected_literal(item.span());
366 continue;
367 };
368 let Some(ident) = arg.ident() else {
369 cx.expected_identifier(arg.span());
370 return ::alloc::vec::Vec::new()vec![];
371 };
372 let ty = match ident.name {
373 sym::abi => RustcLayoutType::Abi,
374 sym::align => RustcLayoutType::Align,
375 sym::size => RustcLayoutType::Size,
376 sym::homogeneous_aggregate => RustcLayoutType::HomogenousAggregate,
377 sym::debug => RustcLayoutType::Debug,
378 _ => {
379 cx.expected_specific_argument(
380 ident.span,
381 &[sym::abi, sym::align, sym::size, sym::homogeneous_aggregate, sym::debug],
382 );
383 continue;
384 }
385 };
386 result.push(ty);
387 }
388 result
389 }
390}
391
392pub(crate) struct RustcNonConstTraitMethodParser;
393
394impl<S: Stage> NoArgsAttributeParser<S> for RustcNonConstTraitMethodParser {
395 const PATH: &'static [Symbol] = &[sym::rustc_non_const_trait_method];
396 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
397 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
398 Allow(Target::Method(MethodKind::Trait { body: true })),
399 Allow(Target::Method(MethodKind::Trait { body: false })),
400 ]);
401 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNonConstTraitMethod;
402}