Skip to main content

rustc_attr_parsing/attributes/
rustc_internal.rs

1use 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}