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