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 TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["N"]),
docs: None,
}template!(NameValueStr: "N");
112 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
113
114 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
115 let ArgParser::NameValue(nv) = args else {
116 let attr_span = cx.attr_span;
117 cx.adcx().expected_name_value(attr_span, None);
118 return None;
119 };
120
121 Some(AttributeKind::MoveSizeLimit {
122 limit: cx.parse_limit_int(nv)?,
123 attr_span: cx.attr_span,
124 limit_span: nv.value_span,
125 })
126 }
127}
128
129pub(crate) struct TypeLengthLimitParser;
130
131impl<S: Stage> SingleAttributeParser<S> for TypeLengthLimitParser {
132 const PATH: &[Symbol] = &[sym::type_length_limit];
133 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
134 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["N"]),
docs: None,
}template!(NameValueStr: "N");
135 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
136
137 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
138 let ArgParser::NameValue(nv) = args else {
139 let attr_span = cx.attr_span;
140 cx.adcx().expected_name_value(attr_span, None);
141 return None;
142 };
143
144 Some(AttributeKind::TypeLengthLimit {
145 limit: cx.parse_limit_int(nv)?,
146 attr_span: cx.attr_span,
147 limit_span: nv.value_span,
148 })
149 }
150}
151
152pub(crate) struct PatternComplexityLimitParser;
153
154impl<S: Stage> SingleAttributeParser<S> for PatternComplexityLimitParser {
155 const PATH: &[Symbol] = &[sym::pattern_complexity_limit];
156 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["N"]),
docs: None,
}template!(NameValueStr: "N");
157 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
158
159 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
160 let ArgParser::NameValue(nv) = args else {
161 let attr_span = cx.attr_span;
162 cx.adcx().expected_name_value(attr_span, None);
163 return None;
164 };
165
166 Some(AttributeKind::PatternComplexityLimit {
167 limit: cx.parse_limit_int(nv)?,
168 attr_span: cx.attr_span,
169 limit_span: nv.value_span,
170 })
171 }
172}
173
174pub(crate) struct NoCoreParser;
175
176impl<S: Stage> NoArgsAttributeParser<S> for NoCoreParser {
177 const PATH: &[Symbol] = &[sym::no_core];
178 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
179 const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoCore;
180}
181
182pub(crate) struct NoStdParser;
183
184impl<S: Stage> NoArgsAttributeParser<S> for NoStdParser {
185 const PATH: &[Symbol] = &[sym::no_std];
186 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
187 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
188 const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoStd;
189}
190
191pub(crate) struct NoMainParser;
192
193impl<S: Stage> NoArgsAttributeParser<S> for NoMainParser {
194 const PATH: &[Symbol] = &[sym::no_main];
195 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
196 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
197 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoMain;
198}
199
200pub(crate) struct RustcCoherenceIsCoreParser;
201
202impl<S: Stage> NoArgsAttributeParser<S> for RustcCoherenceIsCoreParser {
203 const PATH: &[Symbol] = &[sym::rustc_coherence_is_core];
204 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
205 const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcCoherenceIsCore;
206}
207
208pub(crate) struct WindowsSubsystemParser;
209
210impl<S: Stage> SingleAttributeParser<S> for WindowsSubsystemParser {
211 const PATH: &[Symbol] = &[sym::windows_subsystem];
212 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
213 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
214 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");
215
216 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
217 let Some(nv) = args.name_value() else {
218 let inner_span = cx.inner_span;
219 cx.adcx().expected_name_value(
220 args.span().unwrap_or(inner_span),
221 Some(sym::windows_subsystem),
222 );
223 return None;
224 };
225
226 let kind = match nv.value_as_str() {
227 Some(sym::console) => WindowsSubsystemKind::Console,
228 Some(sym::windows) => WindowsSubsystemKind::Windows,
229 Some(_) | None => {
230 cx.adcx().expected_specific_argument_strings(
231 nv.value_span,
232 &[sym::console, sym::windows],
233 );
234 return None;
235 }
236 };
237
238 Some(AttributeKind::WindowsSubsystem(kind, cx.attr_span))
239 }
240}
241
242pub(crate) struct PanicRuntimeParser;
243
244impl<S: Stage> NoArgsAttributeParser<S> for PanicRuntimeParser {
245 const PATH: &[Symbol] = &[sym::panic_runtime];
246 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
247 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::PanicRuntime;
248}
249
250pub(crate) struct NeedsPanicRuntimeParser;
251
252impl<S: Stage> NoArgsAttributeParser<S> for NeedsPanicRuntimeParser {
253 const PATH: &[Symbol] = &[sym::needs_panic_runtime];
254 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
255 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsPanicRuntime;
256}
257
258pub(crate) struct ProfilerRuntimeParser;
259
260impl<S: Stage> NoArgsAttributeParser<S> for ProfilerRuntimeParser {
261 const PATH: &[Symbol] = &[sym::profiler_runtime];
262 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
263 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ProfilerRuntime;
264}
265
266pub(crate) struct NoBuiltinsParser;
267
268impl<S: Stage> NoArgsAttributeParser<S> for NoBuiltinsParser {
269 const PATH: &[Symbol] = &[sym::no_builtins];
270 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
271 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
272 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoBuiltins;
273}
274
275pub(crate) struct RustcPreserveUbChecksParser;
276
277impl<S: Stage> NoArgsAttributeParser<S> for RustcPreserveUbChecksParser {
278 const PATH: &[Symbol] = &[sym::rustc_preserve_ub_checks];
279 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
280 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcPreserveUbChecks;
281}
282
283pub(crate) struct RustcNoImplicitBoundsParser;
284
285impl<S: Stage> NoArgsAttributeParser<S> for RustcNoImplicitBoundsParser {
286 const PATH: &[Symbol] = &[sym::rustc_no_implicit_bounds];
287 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
288 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoImplicitBounds;
289}
290
291pub(crate) struct DefaultLibAllocatorParser;
292
293impl<S: Stage> NoArgsAttributeParser<S> for DefaultLibAllocatorParser {
294 const PATH: &[Symbol] = &[sym::default_lib_allocator];
295 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
296 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::DefaultLibAllocator;
297}
298
299pub(crate) struct FeatureParser;
300
301impl<S: Stage> CombineAttributeParser<S> for FeatureParser {
302 const PATH: &[Symbol] = &[sym::feature];
303 type Item = Ident;
304 const CONVERT: ConvertFn<Self::Item> = AttributeKind::Feature;
305 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
306 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: Some(&["feature1, feature2, ..."]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["feature1, feature2, ..."]);
307
308 fn extend(
309 cx: &mut AcceptContext<'_, '_, S>,
310 args: &ArgParser,
311 ) -> impl IntoIterator<Item = Self::Item> {
312 let ArgParser::List(list) = args else {
313 let attr_span = cx.attr_span;
314 cx.adcx().expected_list(attr_span, args);
315 return Vec::new();
316 };
317
318 if list.is_empty() {
319 let attr_span = cx.attr_span;
320 cx.adcx().warn_empty_attribute(attr_span);
321 }
322
323 let mut res = Vec::new();
324
325 for elem in list.mixed() {
326 let Some(elem) = elem.meta_item() else {
327 cx.adcx().expected_identifier(elem.span());
328 continue;
329 };
330 if let Err(arg_span) = elem.args().no_args() {
331 cx.adcx().expected_no_args(arg_span);
332 continue;
333 }
334
335 let path = elem.path();
336 let Some(ident) = path.word() else {
337 cx.adcx().expected_identifier(path.span());
338 continue;
339 };
340 res.push(ident);
341 }
342
343 res
344 }
345}
346
347pub(crate) struct RegisterToolParser;
348
349impl<S: Stage> CombineAttributeParser<S> for RegisterToolParser {
350 const PATH: &[Symbol] = &[sym::register_tool];
351 type Item = Ident;
352 const CONVERT: ConvertFn<Self::Item> = AttributeKind::RegisterTool;
353 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
354 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: Some(&["tool1, tool2, ..."]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["tool1, tool2, ..."]);
355
356 fn extend(
357 cx: &mut AcceptContext<'_, '_, S>,
358 args: &ArgParser,
359 ) -> impl IntoIterator<Item = Self::Item> {
360 let ArgParser::List(list) = args else {
361 let attr_span = cx.attr_span;
362 cx.adcx().expected_list(attr_span, args);
363 return Vec::new();
364 };
365
366 if list.is_empty() {
367 let attr_span = cx.attr_span;
368 cx.adcx().warn_empty_attribute(attr_span);
369 }
370
371 let mut res = Vec::new();
372
373 for elem in list.mixed() {
374 let Some(elem) = elem.meta_item() else {
375 cx.adcx().expected_identifier(elem.span());
376 continue;
377 };
378 if let Err(arg_span) = elem.args().no_args() {
379 cx.adcx().expected_no_args(arg_span);
380 continue;
381 }
382
383 let path = elem.path();
384 let Some(ident) = path.word() else {
385 cx.adcx().expected_identifier(path.span());
386 continue;
387 };
388
389 res.push(ident);
390 }
391
392 res
393 }
394}