Skip to main content

rustc_attr_parsing/attributes/
crate_level.rs

1use 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            // We don't error on invalid `#![crate_type]` when not applied to a crate
51            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}