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