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