rustc_attr_parsing/attributes/
crate_level.rs1use rustc_hir::attrs::{CrateType, WindowsSubsystemKind};
2use rustc_hir::lints::AttributeLintKind;
3use rustc_session::lint::builtin::UNKNOWN_CRATE_TYPES;
4use rustc_span::Symbol;
5use rustc_span::edit_distance::find_best_match_for_name;
6
7use super::prelude::*;
8
9pub(crate) struct CrateNameParser;
10
11impl<S: Stage> SingleAttributeParser<S> for CrateNameParser {
12 const PATH: &[Symbol] = &[sym::crate_name];
13 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
14 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["name"]),
docs: None,
}template!(NameValueStr: "name");
15 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
16
17 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
18 let ArgParser::NameValue(n) = args else {
19 let attr_span = cx.attr_span;
20 cx.adcx().expected_name_value(attr_span, None);
21 return None;
22 };
23
24 let Some(name) = n.value_as_str() else {
25 cx.adcx().expected_string_literal(n.value_span, Some(n.value_as_lit()));
26 return None;
27 };
28
29 Some(AttributeKind::CrateName { name, name_span: n.value_span, attr_span: cx.attr_span })
30 }
31}
32
33pub(crate) struct CrateTypeParser;
34
35impl<S: Stage> CombineAttributeParser<S> for CrateTypeParser {
36 const PATH: &[Symbol] = &[sym::crate_type];
37 type Item = CrateType;
38 const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::CrateType(items);
39
40 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
41
42 const TEMPLATE: AttributeTemplate =
43 ::rustc_feature::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["crate type"]),
docs: Some("https://doc.rust-lang.org/reference/linkage.html"),
}template!(NameValueStr: "crate type", "https://doc.rust-lang.org/reference/linkage.html");
44
45 fn extend(
46 cx: &mut AcceptContext<'_, '_, S>,
47 args: &ArgParser,
48 ) -> impl IntoIterator<Item = Self::Item> {
49 let ArgParser::NameValue(n) = args else {
50 let attr_span = cx.attr_span;
51 cx.adcx().expected_name_value(attr_span, None);
52 return None;
53 };
54
55 let Some(crate_type) = n.value_as_str() else {
56 cx.adcx().expected_string_literal(n.value_span, Some(n.value_as_lit()));
57 return None;
58 };
59
60 let Ok(crate_type) = crate_type.try_into() else {
61 if cx.shared.target == Target::Crate {
63 let candidate = find_best_match_for_name(
64 &CrateType::all_stable().iter().map(|(name, _)| *name).collect::<Vec<_>>(),
65 crate_type,
66 None,
67 );
68 cx.emit_lint(
69 UNKNOWN_CRATE_TYPES,
70 AttributeLintKind::CrateTypeUnknown {
71 span: n.value_span,
72 suggested: candidate,
73 },
74 n.value_span,
75 );
76 }
77 return None;
78 };
79
80 Some(crate_type)
81 }
82}
83
84pub(crate) struct RecursionLimitParser;
85
86impl<S: Stage> SingleAttributeParser<S> for RecursionLimitParser {
87 const PATH: &[Symbol] = &[sym::recursion_limit];
88 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
89 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["N"]),
docs: Some("https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute"),
}template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute");
90 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
91
92 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
93 let ArgParser::NameValue(nv) = args else {
94 let attr_span = cx.attr_span;
95 cx.adcx().expected_name_value(attr_span, None);
96 return None;
97 };
98
99 Some(AttributeKind::RecursionLimit {
100 limit: cx.parse_limit_int(nv)?,
101 attr_span: cx.attr_span,
102 limit_span: nv.value_span,
103 })
104 }
105}
106
107pub(crate) struct MoveSizeLimitParser;
108
109impl<S: Stage> SingleAttributeParser<S> for MoveSizeLimitParser {
110 const PATH: &[Symbol] = &[sym::move_size_limit];
111 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
112 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["N"]),
docs: None,
}template!(NameValueStr: "N");
113 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
114
115 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
116 let ArgParser::NameValue(nv) = args else {
117 let attr_span = cx.attr_span;
118 cx.adcx().expected_name_value(attr_span, None);
119 return None;
120 };
121
122 Some(AttributeKind::MoveSizeLimit {
123 limit: cx.parse_limit_int(nv)?,
124 attr_span: cx.attr_span,
125 limit_span: nv.value_span,
126 })
127 }
128}
129
130pub(crate) struct TypeLengthLimitParser;
131
132impl<S: Stage> SingleAttributeParser<S> for TypeLengthLimitParser {
133 const PATH: &[Symbol] = &[sym::type_length_limit];
134 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
135 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["N"]),
docs: None,
}template!(NameValueStr: "N");
136 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
137
138 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
139 let ArgParser::NameValue(nv) = args else {
140 let attr_span = cx.attr_span;
141 cx.adcx().expected_name_value(attr_span, None);
142 return None;
143 };
144
145 Some(AttributeKind::TypeLengthLimit {
146 limit: cx.parse_limit_int(nv)?,
147 attr_span: cx.attr_span,
148 limit_span: nv.value_span,
149 })
150 }
151}
152
153pub(crate) struct PatternComplexityLimitParser;
154
155impl<S: Stage> SingleAttributeParser<S> for PatternComplexityLimitParser {
156 const PATH: &[Symbol] = &[sym::pattern_complexity_limit];
157 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
158 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["N"]),
docs: None,
}template!(NameValueStr: "N");
159 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
160
161 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
162 let ArgParser::NameValue(nv) = args else {
163 let attr_span = cx.attr_span;
164 cx.adcx().expected_name_value(attr_span, None);
165 return None;
166 };
167
168 Some(AttributeKind::PatternComplexityLimit {
169 limit: cx.parse_limit_int(nv)?,
170 attr_span: cx.attr_span,
171 limit_span: nv.value_span,
172 })
173 }
174}
175
176pub(crate) struct NoCoreParser;
177
178impl<S: Stage> NoArgsAttributeParser<S> for NoCoreParser {
179 const PATH: &[Symbol] = &[sym::no_core];
180 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
181 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
182 const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoCore;
183}
184
185pub(crate) struct NoStdParser;
186
187impl<S: Stage> NoArgsAttributeParser<S> for NoStdParser {
188 const PATH: &[Symbol] = &[sym::no_std];
189 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
190 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
191 const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoStd;
192}
193
194pub(crate) struct NoMainParser;
195
196impl<S: Stage> NoArgsAttributeParser<S> for NoMainParser {
197 const PATH: &[Symbol] = &[sym::no_main];
198 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
199 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
200 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoMain;
201}
202
203pub(crate) struct RustcCoherenceIsCoreParser;
204
205impl<S: Stage> NoArgsAttributeParser<S> for RustcCoherenceIsCoreParser {
206 const PATH: &[Symbol] = &[sym::rustc_coherence_is_core];
207 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
208 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
209 const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcCoherenceIsCore;
210}
211
212pub(crate) struct WindowsSubsystemParser;
213
214impl<S: Stage> SingleAttributeParser<S> for WindowsSubsystemParser {
215 const PATH: &[Symbol] = &[sym::windows_subsystem];
216 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
217 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
218 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["windows", "console"]),
docs: Some("https://doc.rust-lang.org/reference/runtime.html#the-windows_subsystem-attribute"),
}template!(NameValueStr: ["windows", "console"], "https://doc.rust-lang.org/reference/runtime.html#the-windows_subsystem-attribute");
219
220 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
221 let Some(nv) = args.name_value() else {
222 let inner_span = cx.inner_span;
223 cx.adcx().expected_name_value(
224 args.span().unwrap_or(inner_span),
225 Some(sym::windows_subsystem),
226 );
227 return None;
228 };
229
230 let kind = match nv.value_as_str() {
231 Some(sym::console) => WindowsSubsystemKind::Console,
232 Some(sym::windows) => WindowsSubsystemKind::Windows,
233 Some(_) | None => {
234 cx.adcx().expected_specific_argument_strings(
235 nv.value_span,
236 &[sym::console, sym::windows],
237 );
238 return None;
239 }
240 };
241
242 Some(AttributeKind::WindowsSubsystem(kind, cx.attr_span))
243 }
244}
245
246pub(crate) struct PanicRuntimeParser;
247
248impl<S: Stage> NoArgsAttributeParser<S> for PanicRuntimeParser {
249 const PATH: &[Symbol] = &[sym::panic_runtime];
250 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
251 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
252 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::PanicRuntime;
253}
254
255pub(crate) struct NeedsPanicRuntimeParser;
256
257impl<S: Stage> NoArgsAttributeParser<S> for NeedsPanicRuntimeParser {
258 const PATH: &[Symbol] = &[sym::needs_panic_runtime];
259 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
260 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
261 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsPanicRuntime;
262}
263
264pub(crate) struct ProfilerRuntimeParser;
265
266impl<S: Stage> NoArgsAttributeParser<S> for ProfilerRuntimeParser {
267 const PATH: &[Symbol] = &[sym::profiler_runtime];
268 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
269 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
270 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ProfilerRuntime;
271}
272
273pub(crate) struct NoBuiltinsParser;
274
275impl<S: Stage> NoArgsAttributeParser<S> for NoBuiltinsParser {
276 const PATH: &[Symbol] = &[sym::no_builtins];
277 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
278 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
279 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoBuiltins;
280}
281
282pub(crate) struct RustcPreserveUbChecksParser;
283
284impl<S: Stage> NoArgsAttributeParser<S> for RustcPreserveUbChecksParser {
285 const PATH: &[Symbol] = &[sym::rustc_preserve_ub_checks];
286 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
287 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
288 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcPreserveUbChecks;
289}
290
291pub(crate) struct RustcNoImplicitBoundsParser;
292
293impl<S: Stage> NoArgsAttributeParser<S> for RustcNoImplicitBoundsParser {
294 const PATH: &[Symbol] = &[sym::rustc_no_implicit_bounds];
295 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
296 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
297 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoImplicitBounds;
298}
299
300pub(crate) struct DefaultLibAllocatorParser;
301
302impl<S: Stage> NoArgsAttributeParser<S> for DefaultLibAllocatorParser {
303 const PATH: &[Symbol] = &[sym::default_lib_allocator];
304 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
305 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
306 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::DefaultLibAllocator;
307}
308
309pub(crate) struct FeatureParser;
310
311impl<S: Stage> CombineAttributeParser<S> for FeatureParser {
312 const PATH: &[Symbol] = &[sym::feature];
313 type Item = Ident;
314 const CONVERT: ConvertFn<Self::Item> = AttributeKind::Feature;
315 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
316 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: Some(&["feature1, feature2, ..."]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["feature1, feature2, ..."]);
317
318 fn extend(
319 cx: &mut AcceptContext<'_, '_, S>,
320 args: &ArgParser,
321 ) -> impl IntoIterator<Item = Self::Item> {
322 let ArgParser::List(list) = args else {
323 let attr_span = cx.attr_span;
324 cx.adcx().expected_list(attr_span, args);
325 return Vec::new();
326 };
327
328 if list.is_empty() {
329 let attr_span = cx.attr_span;
330 cx.adcx().warn_empty_attribute(attr_span);
331 }
332
333 let mut res = Vec::new();
334
335 for elem in list.mixed() {
336 let Some(elem) = elem.meta_item() else {
337 cx.adcx().expected_identifier(elem.span());
338 continue;
339 };
340 if let Err(arg_span) = elem.args().no_args() {
341 cx.adcx().expected_no_args(arg_span);
342 continue;
343 }
344
345 let path = elem.path();
346 let Some(ident) = path.word() else {
347 cx.adcx().expected_identifier(path.span());
348 continue;
349 };
350 res.push(ident);
351 }
352
353 res
354 }
355}
356
357pub(crate) struct RegisterToolParser;
358
359impl<S: Stage> CombineAttributeParser<S> for RegisterToolParser {
360 const PATH: &[Symbol] = &[sym::register_tool];
361 type Item = Ident;
362 const CONVERT: ConvertFn<Self::Item> = AttributeKind::RegisterTool;
363 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
364 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: Some(&["tool1, tool2, ..."]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["tool1, tool2, ..."]);
365
366 fn extend(
367 cx: &mut AcceptContext<'_, '_, S>,
368 args: &ArgParser,
369 ) -> impl IntoIterator<Item = Self::Item> {
370 let ArgParser::List(list) = args else {
371 let attr_span = cx.attr_span;
372 cx.adcx().expected_list(attr_span, args);
373 return Vec::new();
374 };
375
376 if list.is_empty() {
377 let attr_span = cx.attr_span;
378 cx.adcx().warn_empty_attribute(attr_span);
379 }
380
381 let mut res = Vec::new();
382
383 for elem in list.mixed() {
384 let Some(elem) = elem.meta_item() else {
385 cx.adcx().expected_identifier(elem.span());
386 continue;
387 };
388 if let Err(arg_span) = elem.args().no_args() {
389 cx.adcx().expected_no_args(arg_span);
390 continue;
391 }
392
393 let path = elem.path();
394 let Some(ident) = path.word() else {
395 cx.adcx().expected_identifier(path.span());
396 continue;
397 };
398
399 res.push(ident);
400 }
401
402 res
403 }
404}