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