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