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