rustc_attr_parsing/attributes/
crate_level.rs1use rustc_attr_ir::WindowsSubsystemKind;
2use rustc_data_structures::fx::FxIndexSet;
3use rustc_feature::AttributeStability;
4use rustc_lint_defs::builtin::{DUPLICATE_TOOLS, UNKNOWN_CRATE_TYPES};
5use rustc_span::Symbol;
6use rustc_span::edit_distance::find_best_match_for_name_with_substrings;
7use rustc_structures::CrateType;
8
9use super::prelude::*;
10use crate::diagnostics::{
11 DuplicateTool, ToolReserved, UnknownCrateTypes, UnknownCrateTypesSuggestion,
12};
13
14pub(crate) struct CrateNameParser;
15
16impl SingleAttributeParser for CrateNameParser {
17 const PATH: &[Symbol] = &[sym::crate_name];
18 const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError;
19 const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["name"]),
docs: None,
}template!(NameValueStr: "name");
20 const ALLOWED_TARGETS: AllowedTargets<'_> =
21 AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]);
22 const STABILITY: AttributeStability = AttributeStability::Stable;
23
24 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
25 let n = cx.expect_name_value(args, cx.attr_span, None)?;
26
27 let name = cx.expect_string_literal(n)?;
28
29 Some(AttributeKind::CrateName { name, name_span: n.value_span, attr_span: cx.attr_span })
30 }
31}
32
33pub(crate) struct CrateTypeParser;
34
35impl CombineAttributeParser for CrateTypeParser {
36 const PATH: &[Symbol] = &[sym::crate_type];
37 type Item = CrateType;
38 const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::CrateType(items);
39 const ALLOWED_TARGETS: AllowedTargets<'_> =
40 AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]);
41 const TEMPLATE: AttributeTemplate =
42 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");
43 const STABILITY: AttributeStability = AttributeStability::Stable;
44
45 fn extend(
46 cx: &mut AcceptContext<'_, '_>,
47 args: &ArgParser,
48 ) -> impl IntoIterator<Item = Self::Item> {
49 let n = cx.expect_name_value(args, cx.attr_span, None)?;
50
51 let crate_type = cx.expect_string_literal(n)?;
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_with_substrings(
57 &CrateType::all_stable().iter().map(|(name, _)| *name).collect::<Vec<_>>(),
58 crate_type,
59 Some(5),
60 );
61 let span = n.value_span;
62 cx.emit_lint(
63 UNKNOWN_CRATE_TYPES,
64 UnknownCrateTypes {
65 sugg: candidate.map(|s| UnknownCrateTypesSuggestion { span, snippet: s }),
66 },
67 span,
68 );
69 }
70 return None;
71 };
72
73 Some(crate_type)
74 }
75}
76
77pub(crate) struct RecursionLimitParser;
78
79impl SingleAttributeParser for RecursionLimitParser {
80 const PATH: &[Symbol] = &[sym::recursion_limit];
81 const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError;
82 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");
83 const ALLOWED_TARGETS: AllowedTargets<'_> =
84 AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]);
85 const STABILITY: AttributeStability = AttributeStability::Stable;
86
87 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
88 let nv = cx.expect_name_value(args, cx.attr_span, None)?;
89
90 Some(AttributeKind::RecursionLimit { limit: cx.parse_limit_int(nv)? })
91 }
92}
93
94pub(crate) struct MoveSizeLimitParser;
95
96impl SingleAttributeParser for MoveSizeLimitParser {
97 const PATH: &[Symbol] = &[sym::move_size_limit];
98 const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["N"]),
docs: None,
}template!(NameValueStr: "N");
99 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
100 const STABILITY: AttributeStability = {
_ = rustc_feature::Features::large_assignments;
AttributeStability::Unstable {
gate_name: rustc_span::sym::large_assignments,
notes: &[],
}
}unstable!(large_assignments);
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 { limit: cx.parse_limit_int(nv)? })
106 }
107}
108
109pub(crate) struct TypeLengthLimitParser;
110
111impl SingleAttributeParser for TypeLengthLimitParser {
112 const PATH: &[Symbol] = &[sym::type_length_limit];
113 const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError;
114 const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["N"]),
docs: None,
}template!(NameValueStr: "N");
115 const ALLOWED_TARGETS: AllowedTargets<'_> =
116 AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]);
117 const STABILITY: AttributeStability = AttributeStability::Stable;
118
119 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
120 let nv = cx.expect_name_value(args, cx.attr_span, None)?;
121
122 Some(AttributeKind::TypeLengthLimit { limit: cx.parse_limit_int(nv)? })
123 }
124}
125
126pub(crate) struct PatternComplexityLimitParser;
127
128impl SingleAttributeParser for PatternComplexityLimitParser {
129 const PATH: &[Symbol] = &[sym::pattern_complexity_limit];
130 const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["N"]),
docs: None,
}template!(NameValueStr: "N");
131 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
132 const STABILITY: AttributeStability = {
_ = rustc_feature::Features::rustc_attrs;
AttributeStability::Unstable {
gate_name: rustc_span::sym::rustc_attrs,
notes: &["the `pattern_complexity_limit` attribute is used for rustc unit tests"],
}
}unstable!(
133 rustc_attrs,
134 "the `pattern_complexity_limit` attribute is used for rustc unit tests"
135 );
136
137 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
138 let nv = cx.expect_name_value(args, cx.attr_span, None)?;
139
140 Some(AttributeKind::PatternComplexityLimit { limit: cx.parse_limit_int(nv)? })
141 }
142}
143
144pub(crate) struct NoCoreParser;
145
146impl NoArgsAttributeParser for NoCoreParser {
147 const PATH: &[Symbol] = &[sym::no_core];
148 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
149 const STABILITY: AttributeStability = {
_ = rustc_feature::Features::no_core;
AttributeStability::Unstable {
gate_name: rustc_span::sym::no_core,
notes: &[],
}
}unstable!(no_core);
150 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoCore;
151}
152
153pub(crate) struct NoStdParser;
154
155impl NoArgsAttributeParser for NoStdParser {
156 const PATH: &[Symbol] = &[sym::no_std];
157 const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
158 const ALLOWED_TARGETS: AllowedTargets<'_> =
159 AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]);
160 const STABILITY: AttributeStability = AttributeStability::Stable;
161 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoStd;
162}
163
164pub(crate) struct NoMainParser;
165
166impl NoArgsAttributeParser for NoMainParser {
167 const PATH: &[Symbol] = &[sym::no_main];
168 const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
169 const ALLOWED_TARGETS: AllowedTargets<'_> =
170 AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]);
171 const STABILITY: AttributeStability = AttributeStability::Stable;
172 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoMain;
173}
174
175pub(crate) struct RustcCoherenceIsCoreParser;
176
177impl NoArgsAttributeParser for RustcCoherenceIsCoreParser {
178 const PATH: &[Symbol] = &[sym::rustc_coherence_is_core];
179 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
180 const STABILITY: AttributeStability = {
_ = rustc_feature::Features::rustc_attrs;
AttributeStability::Unstable {
gate_name: rustc_span::sym::rustc_attrs,
notes: &[],
}
}unstable!(rustc_attrs);
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<'_> =
190 AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]);
191 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");
192 const STABILITY: AttributeStability = AttributeStability::Stable;
193
194 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
195 let nv = cx.expect_name_value(args, cx.inner_span, Some(sym::windows_subsystem))?;
196
197 let kind = match nv.value_as_str() {
198 Some(sym::console) => WindowsSubsystemKind::Console,
199 Some(sym::windows) => WindowsSubsystemKind::Windows,
200 Some(_) | None => {
201 cx.adcx().expected_specific_argument_strings(
202 nv.value_span,
203 &[sym::console, sym::windows],
204 );
205 return None;
206 }
207 };
208
209 Some(AttributeKind::WindowsSubsystem(kind))
210 }
211}
212
213pub(crate) struct PanicRuntimeParser;
214
215impl NoArgsAttributeParser for PanicRuntimeParser {
216 const PATH: &[Symbol] = &[sym::panic_runtime];
217 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
218 const STABILITY: AttributeStability = {
_ = rustc_feature::Features::panic_runtime;
AttributeStability::Unstable {
gate_name: rustc_span::sym::panic_runtime,
notes: &[],
}
}unstable!(panic_runtime);
219 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::PanicRuntime;
220}
221
222pub(crate) struct NeedsPanicRuntimeParser;
223
224impl NoArgsAttributeParser for NeedsPanicRuntimeParser {
225 const PATH: &[Symbol] = &[sym::needs_panic_runtime];
226 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
227 const STABILITY: AttributeStability = {
_ = rustc_feature::Features::needs_panic_runtime;
AttributeStability::Unstable {
gate_name: rustc_span::sym::needs_panic_runtime,
notes: &[],
}
}unstable!(needs_panic_runtime);
228 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsPanicRuntime;
229}
230
231pub(crate) struct ProfilerRuntimeParser;
232
233impl NoArgsAttributeParser for ProfilerRuntimeParser {
234 const PATH: &[Symbol] = &[sym::profiler_runtime];
235 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
236 const STABILITY: AttributeStability = {
_ = rustc_feature::Features::profiler_runtime;
AttributeStability::Unstable {
gate_name: rustc_span::sym::profiler_runtime,
notes: &[],
}
}unstable!(profiler_runtime);
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<'_> =
246 AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]);
247 const STABILITY: AttributeStability = AttributeStability::Stable;
248 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoBuiltins;
249}
250
251pub(crate) struct RustcPreserveUbChecksParser;
252
253impl NoArgsAttributeParser for RustcPreserveUbChecksParser {
254 const PATH: &[Symbol] = &[sym::rustc_preserve_ub_checks];
255 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
256 const STABILITY: AttributeStability = {
_ = rustc_feature::Features::rustc_attrs;
AttributeStability::Unstable {
gate_name: rustc_span::sym::rustc_attrs,
notes: &[],
}
}unstable!(rustc_attrs);
257 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcPreserveUbChecks;
258}
259
260pub(crate) struct RustcNoImplicitBoundsParser;
261
262impl NoArgsAttributeParser for RustcNoImplicitBoundsParser {
263 const PATH: &[Symbol] = &[sym::rustc_no_implicit_bounds];
264 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
265 const STABILITY: AttributeStability = {
_ = rustc_feature::Features::rustc_attrs;
AttributeStability::Unstable {
gate_name: rustc_span::sym::rustc_attrs,
notes: &[],
}
}unstable!(rustc_attrs);
266 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoImplicitBounds;
267}
268
269pub(crate) struct DefaultLibAllocatorParser;
270
271impl NoArgsAttributeParser for DefaultLibAllocatorParser {
272 const PATH: &[Symbol] = &[sym::default_lib_allocator];
273 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
274 const STABILITY: AttributeStability = {
_ = rustc_feature::Features::allocator_internals;
AttributeStability::Unstable {
gate_name: rustc_span::sym::allocator_internals,
notes: &[],
}
}unstable!(allocator_internals);
275 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::DefaultLibAllocator;
276}
277
278pub(crate) struct FeatureParser;
279
280impl CombineAttributeParser for FeatureParser {
281 const PATH: &[Symbol] = &[sym::feature];
282 type Item = Ident;
283 const CONVERT: ConvertFn<Self::Item> = AttributeKind::Feature;
284 const ALLOWED_TARGETS: AllowedTargets<'_> =
285 AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]);
286 const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
word: false,
list: Some(&["feature1, feature2, ..."]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["feature1, feature2, ..."]);
287 const STABILITY: AttributeStability = AttributeStability::Stable;
288
289 fn extend(
290 cx: &mut AcceptContext<'_, '_>,
291 args: &ArgParser,
292 ) -> impl IntoIterator<Item = Self::Item> {
293 let Some(list) = cx.expect_list(args, cx.attr_span) else {
294 return Vec::new();
295 };
296
297 if list.is_empty() {
298 let attr_span = cx.attr_span;
299 cx.adcx().warn_empty_attribute(attr_span);
300 }
301
302 let mut res = Vec::new();
303
304 for elem in list.mixed() {
305 let Some(elem) = elem.meta_item() else {
306 cx.adcx().expected_identifier(elem.span());
307 continue;
308 };
309 let Some(()) = cx.expect_no_args(elem.args()) else {
310 continue;
311 };
312 let path = elem.path();
313 let Some(ident) = path.word() else {
314 cx.adcx().expected_identifier(path.span());
315 continue;
316 };
317 res.push(ident);
318 }
319
320 res
321 }
322}
323
324#[derive(#[automatically_derived]
impl ::core::default::Default for RegisterToolParser {
#[inline]
fn default() -> RegisterToolParser {
RegisterToolParser {
attr_tools: ::core::default::Default::default(),
lint_tools: ::core::default::Default::default(),
}
}
}Default)]
325pub(crate) struct RegisterToolParser {
326 attr_tools: FxIndexSet<Ident>,
327 lint_tools: FxIndexSet<Ident>,
328}
329
330fn parse_register_tool(
331 tools: &mut [&mut FxIndexSet<Ident>],
332 cx: &mut AcceptContext<'_, '_>,
333 args: &ArgParser,
334) {
335 let Some(list) = cx.expect_list(args, cx.attr_span) else {
336 return;
337 };
338
339 if list.is_empty() {
340 let attr_span = cx.attr_span;
341 cx.adcx().warn_empty_attribute(attr_span);
342 }
343
344 for elem in list.mixed() {
345 let Some(elem) = elem.meta_item() else {
346 cx.adcx().expected_identifier(elem.span());
347 continue;
348 };
349 let Some(()) = cx.expect_no_args(elem.args()) else {
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 if !ident.name.can_be_raw() {
359 cx.adcx().expected_identifier(path.span());
360 continue;
361 }
362
363 if ident.name == sym::rustc {
364 cx.should_emit
365 .emit_err(cx.dcx().create_err(ToolReserved { span: ident.span, tool: ident }));
366 continue;
367 }
368
369 let mut lint_emitted = false;
370 for tools in tools.iter_mut() {
371 if let Some(old_ident) = tools.replace(ident)
372 && !lint_emitted
373 {
374 lint_emitted = true;
375 cx.emit_lint(
376 DUPLICATE_TOOLS,
377 DuplicateTool { span: ident.span, tool: ident, old_ident_span: old_ident.span },
378 ident.span,
379 );
380 }
381 }
382 }
383}
384
385impl AttributeParser for RegisterToolParser {
386 const ATTRIBUTES: AcceptMapping<Self> = &[
387 (
388 &[sym::register_tool],
389 crate::AttributeTemplate {
word: false,
list: Some(&["tool1, tool2, ..."]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["tool1, tool2, ..."]),
390 {
_ = rustc_feature::Features::register_tool;
AttributeStability::Unstable {
gate_name: rustc_span::sym::register_tool,
notes: &[],
}
}unstable!(register_tool),
391 |this, cx, args| {
392 parse_register_tool(&mut [&mut this.attr_tools, &mut this.lint_tools], cx, args)
393 },
394 ),
395 (
396 &[sym::register_attribute_tool],
397 crate::AttributeTemplate {
word: false,
list: Some(&["tool1, tool2, ..."]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["tool1, tool2, ..."]),
398 {
_ = rustc_feature::Features::register_tool;
AttributeStability::Unstable {
gate_name: rustc_span::sym::register_tool,
notes: &[],
}
}unstable!(register_tool),
399 |this, cx, args| parse_register_tool(&mut [&mut this.attr_tools], cx, args),
400 ),
401 (
402 &[sym::register_lint_tool],
403 crate::AttributeTemplate {
word: false,
list: Some(&["tool1, tool2, ..."]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["tool1, tool2, ..."]),
404 {
_ = rustc_feature::Features::register_tool;
AttributeStability::Unstable {
gate_name: rustc_span::sym::register_tool,
notes: &[],
}
}unstable!(register_tool),
405 |this, cx, args| parse_register_tool(&mut [&mut this.lint_tools], cx, args),
406 ),
407 ];
408
409 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
410
411 fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {
412 if self.attr_tools.is_empty() && self.lint_tools.is_empty() {
413 None
414 } else {
415 Some(AttributeKind::RegisterTool {
416 attr_tools: self.attr_tools.into_iter().collect(),
417 lint_tools: self.lint_tools.into_iter().collect(),
418 })
419 }
420 }
421}