rustc_attr_parsing/attributes/
rustc_internal.rs

1use rustc_ast::{LitIntType, LitKind, MetaItemLit};
2use rustc_session::errors;
3
4use super::prelude::*;
5use super::util::parse_single_integer;
6use crate::session_diagnostics::RustcScalableVectorCountOutOfRange;
7
8pub(crate) struct RustcMainParser;
9
10impl<S: Stage> NoArgsAttributeParser<S> for RustcMainParser {
11    const PATH: &'static [Symbol] = &[sym::rustc_main];
12    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
13    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
14    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcMain;
15}
16
17pub(crate) struct RustcMustImplementOneOfParser;
18
19impl<S: Stage> SingleAttributeParser<S> for RustcMustImplementOneOfParser {
20    const PATH: &[Symbol] = &[sym::rustc_must_implement_one_of];
21    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
22    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
23    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
24    const TEMPLATE: AttributeTemplate = template!(List: &["function1, function2, ..."]);
25    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
26        let Some(list) = args.list() else {
27            cx.expected_list(cx.attr_span, args);
28            return None;
29        };
30
31        let mut fn_names = ThinVec::new();
32
33        let inputs: Vec<_> = list.mixed().collect();
34
35        if inputs.len() < 2 {
36            cx.expected_list_with_num_args_or_more(2, list.span);
37            return None;
38        }
39
40        let mut errored = false;
41        for argument in inputs {
42            let Some(meta) = argument.meta_item() else {
43                cx.expected_identifier(argument.span());
44                return None;
45            };
46
47            let Some(ident) = meta.ident() else {
48                cx.dcx().emit_err(errors::MustBeNameOfAssociatedFunction { span: meta.span() });
49                errored = true;
50                continue;
51            };
52
53            fn_names.push(ident);
54        }
55        if errored {
56            return None;
57        }
58
59        Some(AttributeKind::RustcMustImplementOneOf { attr_span: cx.attr_span, fn_names })
60    }
61}
62
63pub(crate) struct RustcNeverReturnsNullPointerParser;
64
65impl<S: Stage> NoArgsAttributeParser<S> for RustcNeverReturnsNullPointerParser {
66    const PATH: &[Symbol] = &[sym::rustc_never_returns_null_ptr];
67    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
68    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
69        Allow(Target::Fn),
70        Allow(Target::Method(MethodKind::Inherent)),
71        Allow(Target::Method(MethodKind::Trait { body: false })),
72        Allow(Target::Method(MethodKind::Trait { body: true })),
73        Allow(Target::Method(MethodKind::TraitImpl)),
74    ]);
75    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNeverReturnsNullPointer;
76}
77pub(crate) struct RustcNoImplicitAutorefsParser;
78
79impl<S: Stage> NoArgsAttributeParser<S> for RustcNoImplicitAutorefsParser {
80    const PATH: &[Symbol] = &[sym::rustc_no_implicit_autorefs];
81    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
82    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
83        Allow(Target::Fn),
84        Allow(Target::Method(MethodKind::Inherent)),
85        Allow(Target::Method(MethodKind::Trait { body: false })),
86        Allow(Target::Method(MethodKind::Trait { body: true })),
87        Allow(Target::Method(MethodKind::TraitImpl)),
88    ]);
89
90    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoImplicitAutorefs;
91}
92
93pub(crate) struct RustcLayoutScalarValidRangeStartParser;
94
95impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeStartParser {
96    const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_start];
97    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
98    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
99    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
100    const TEMPLATE: AttributeTemplate = template!(List: &["start"]);
101
102    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
103        parse_single_integer(cx, args)
104            .map(|n| AttributeKind::RustcLayoutScalarValidRangeStart(Box::new(n), cx.attr_span))
105    }
106}
107
108pub(crate) struct RustcLayoutScalarValidRangeEndParser;
109
110impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeEndParser {
111    const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_end];
112    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
113    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
114    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
115    const TEMPLATE: AttributeTemplate = template!(List: &["end"]);
116
117    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
118        parse_single_integer(cx, args)
119            .map(|n| AttributeKind::RustcLayoutScalarValidRangeEnd(Box::new(n), cx.attr_span))
120    }
121}
122
123pub(crate) struct RustcLegacyConstGenericsParser;
124
125impl<S: Stage> SingleAttributeParser<S> for RustcLegacyConstGenericsParser {
126    const PATH: &[Symbol] = &[sym::rustc_legacy_const_generics];
127    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
128    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
129    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
130    const TEMPLATE: AttributeTemplate = template!(List: &["N"]);
131
132    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
133        let ArgParser::List(meta_items) = args else {
134            cx.expected_list(cx.attr_span, args);
135            return None;
136        };
137
138        let mut parsed_indexes = ThinVec::new();
139        let mut errored = false;
140
141        for possible_index in meta_items.mixed() {
142            if let MetaItemOrLitParser::Lit(MetaItemLit {
143                kind: LitKind::Int(index, LitIntType::Unsuffixed),
144                ..
145            }) = possible_index
146            {
147                parsed_indexes.push((index.0 as usize, possible_index.span()));
148            } else {
149                cx.expected_integer_literal(possible_index.span());
150                errored = true;
151            }
152        }
153        if errored {
154            return None;
155        } else if parsed_indexes.is_empty() {
156            cx.expected_at_least_one_argument(args.span()?);
157            return None;
158        }
159
160        Some(AttributeKind::RustcLegacyConstGenerics {
161            fn_indexes: parsed_indexes,
162            attr_span: cx.attr_span,
163        })
164    }
165}
166
167pub(crate) struct RustcLintDiagnosticsParser;
168
169impl<S: Stage> NoArgsAttributeParser<S> for RustcLintDiagnosticsParser {
170    const PATH: &[Symbol] = &[sym::rustc_lint_diagnostics];
171    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
172    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
173        Allow(Target::Fn),
174        Allow(Target::Method(MethodKind::Inherent)),
175        Allow(Target::Method(MethodKind::Trait { body: false })),
176        Allow(Target::Method(MethodKind::Trait { body: true })),
177        Allow(Target::Method(MethodKind::TraitImpl)),
178    ]);
179    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintDiagnostics;
180}
181
182pub(crate) struct RustcLintOptDenyFieldAccessParser;
183
184impl<S: Stage> SingleAttributeParser<S> for RustcLintOptDenyFieldAccessParser {
185    const PATH: &[Symbol] = &[sym::rustc_lint_opt_deny_field_access];
186    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
187    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
188    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Field)]);
189    const TEMPLATE: AttributeTemplate = template!(Word);
190    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
191        let Some(arg) = args.list().and_then(MetaItemListParser::single) else {
192            cx.expected_single_argument(cx.attr_span);
193            return None;
194        };
195
196        let MetaItemOrLitParser::Lit(MetaItemLit { kind: LitKind::Str(lint_message, _), .. }) = arg
197        else {
198            cx.expected_string_literal(arg.span(), arg.lit());
199            return None;
200        };
201
202        Some(AttributeKind::RustcLintOptDenyFieldAccess { lint_message: *lint_message })
203    }
204}
205
206pub(crate) struct RustcLintOptTyParser;
207
208impl<S: Stage> NoArgsAttributeParser<S> for RustcLintOptTyParser {
209    const PATH: &[Symbol] = &[sym::rustc_lint_opt_ty];
210    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
211    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
212    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintOptTy;
213}
214
215pub(crate) struct RustcLintQueryInstabilityParser;
216
217impl<S: Stage> NoArgsAttributeParser<S> for RustcLintQueryInstabilityParser {
218    const PATH: &[Symbol] = &[sym::rustc_lint_query_instability];
219    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
220    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
221        Allow(Target::Fn),
222        Allow(Target::Method(MethodKind::Inherent)),
223        Allow(Target::Method(MethodKind::Trait { body: false })),
224        Allow(Target::Method(MethodKind::Trait { body: true })),
225        Allow(Target::Method(MethodKind::TraitImpl)),
226    ]);
227    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintQueryInstability;
228}
229
230pub(crate) struct RustcLintUntrackedQueryInformationParser;
231
232impl<S: Stage> NoArgsAttributeParser<S> for RustcLintUntrackedQueryInformationParser {
233    const PATH: &[Symbol] = &[sym::rustc_lint_untracked_query_information];
234    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
235    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
236        Allow(Target::Fn),
237        Allow(Target::Method(MethodKind::Inherent)),
238        Allow(Target::Method(MethodKind::Trait { body: false })),
239        Allow(Target::Method(MethodKind::Trait { body: true })),
240        Allow(Target::Method(MethodKind::TraitImpl)),
241    ]);
242
243    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintUntrackedQueryInformation;
244}
245
246pub(crate) struct RustcObjectLifetimeDefaultParser;
247
248impl<S: Stage> SingleAttributeParser<S> for RustcObjectLifetimeDefaultParser {
249    const PATH: &[rustc_span::Symbol] = &[sym::rustc_object_lifetime_default];
250    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
251    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
252    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
253    const TEMPLATE: AttributeTemplate = template!(Word);
254
255    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
256        if let Err(span) = args.no_args() {
257            cx.expected_no_args(span);
258            return None;
259        }
260
261        Some(AttributeKind::RustcObjectLifetimeDefault)
262    }
263}
264
265pub(crate) struct RustcSimdMonomorphizeLaneLimitParser;
266
267impl<S: Stage> SingleAttributeParser<S> for RustcSimdMonomorphizeLaneLimitParser {
268    const PATH: &[Symbol] = &[sym::rustc_simd_monomorphize_lane_limit];
269    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
270    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
271    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
272    const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
273
274    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
275        let ArgParser::NameValue(nv) = args else {
276            cx.expected_name_value(cx.attr_span, None);
277            return None;
278        };
279        Some(AttributeKind::RustcSimdMonomorphizeLaneLimit(cx.parse_limit_int(nv)?))
280    }
281}
282
283pub(crate) struct RustcScalableVectorParser;
284
285impl<S: Stage> SingleAttributeParser<S> for RustcScalableVectorParser {
286    const PATH: &[rustc_span::Symbol] = &[sym::rustc_scalable_vector];
287    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
288    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
289    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
290    const TEMPLATE: AttributeTemplate = template!(Word, List: &["count"]);
291
292    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
293        if args.no_args().is_ok() {
294            return Some(AttributeKind::RustcScalableVector {
295                element_count: None,
296                span: cx.attr_span,
297            });
298        }
299
300        let n = parse_single_integer(cx, args)?;
301        let Ok(n) = n.try_into() else {
302            cx.emit_err(RustcScalableVectorCountOutOfRange { span: cx.attr_span, n });
303            return None;
304        };
305        Some(AttributeKind::RustcScalableVector { element_count: Some(n), span: cx.attr_span })
306    }
307}