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