]>
Commit | Line | Data |
---|---|---|
f20569fa XL |
1 | //! Built-in attributes and `cfg` flag gating. |
2 | ||
3 | use AttributeGate::*; | |
4 | use AttributeType::*; | |
5 | ||
6 | use crate::{Features, Stability}; | |
7 | ||
8 | use rustc_data_structures::fx::FxHashMap; | |
9 | use rustc_span::symbol::{sym, Symbol}; | |
10 | ||
11 | use std::lazy::SyncLazy; | |
12 | ||
13 | type GateFn = fn(&Features) -> bool; | |
14 | ||
15 | macro_rules! cfg_fn { | |
16 | ($field: ident) => { | |
17 | (|features| features.$field) as GateFn | |
18 | }; | |
19 | } | |
20 | ||
21 | pub type GatedCfg = (Symbol, Symbol, GateFn); | |
22 | ||
23 | /// `cfg(...)`'s that are feature gated. | |
24 | const GATED_CFGS: &[GatedCfg] = &[ | |
25 | // (name in cfg, feature, function to check if the feature is enabled) | |
26 | (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)), | |
27 | (sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), | |
28 | (sym::target_has_atomic_load_store, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), | |
29 | ( | |
30 | sym::target_has_atomic_equal_alignment, | |
31 | sym::cfg_target_has_atomic, | |
32 | cfg_fn!(cfg_target_has_atomic), | |
33 | ), | |
34 | (sym::sanitize, sym::cfg_sanitize, cfg_fn!(cfg_sanitize)), | |
35 | (sym::version, sym::cfg_version, cfg_fn!(cfg_version)), | |
36 | (sym::panic, sym::cfg_panic, cfg_fn!(cfg_panic)), | |
37 | ]; | |
38 | ||
39 | /// Find a gated cfg determined by the `pred`icate which is given the cfg's name. | |
40 | pub fn find_gated_cfg(pred: impl Fn(Symbol) -> bool) -> Option<&'static GatedCfg> { | |
41 | GATED_CFGS.iter().find(|(cfg_sym, ..)| pred(*cfg_sym)) | |
42 | } | |
43 | ||
44 | // If you change this, please modify `src/doc/unstable-book` as well. You must | |
45 | // move that documentation into the relevant place in the other docs, and | |
46 | // remove the chapter on the flag. | |
47 | ||
48 | #[derive(Copy, Clone, PartialEq, Debug)] | |
49 | pub enum AttributeType { | |
50 | /// Normal, builtin attribute that is consumed | |
51 | /// by the compiler before the unused_attribute check | |
52 | Normal, | |
53 | ||
54 | /// Builtin attribute that may not be consumed by the compiler | |
55 | /// before the unused_attribute check. These attributes | |
56 | /// will be ignored by the unused_attribute lint | |
57 | AssumedUsed, | |
58 | ||
59 | /// Builtin attribute that is only allowed at the crate level | |
60 | CrateLevel, | |
61 | } | |
62 | ||
63 | #[derive(Clone, Copy)] | |
64 | pub enum AttributeGate { | |
65 | /// Is gated by a given feature gate, reason | |
66 | /// and function to check if enabled | |
67 | Gated(Stability, Symbol, &'static str, fn(&Features) -> bool), | |
68 | ||
69 | /// Ungated attribute, can be used on all release channels | |
70 | Ungated, | |
71 | } | |
72 | ||
73 | // fn() is not Debug | |
74 | impl std::fmt::Debug for AttributeGate { | |
75 | fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | |
76 | match *self { | |
77 | Self::Gated(ref stab, name, expl, _) => { | |
78 | write!(fmt, "Gated({:?}, {}, {})", stab, name, expl) | |
79 | } | |
80 | Self::Ungated => write!(fmt, "Ungated"), | |
81 | } | |
82 | } | |
83 | } | |
84 | ||
85 | impl AttributeGate { | |
86 | fn is_deprecated(&self) -> bool { | |
87 | matches!(*self, Self::Gated(Stability::Deprecated(_, _), ..)) | |
88 | } | |
89 | } | |
90 | ||
91 | /// A template that the attribute input must match. | |
92 | /// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now. | |
93 | #[derive(Clone, Copy, Default)] | |
94 | pub struct AttributeTemplate { | |
95 | pub word: bool, | |
96 | pub list: Option<&'static str>, | |
97 | pub name_value_str: Option<&'static str>, | |
98 | } | |
99 | ||
100 | /// A convenience macro for constructing attribute templates. | |
101 | /// E.g., `template!(Word, List: "description")` means that the attribute | |
102 | /// supports forms `#[attr]` and `#[attr(description)]`. | |
103 | macro_rules! template { | |
104 | (Word) => { template!(@ true, None, None) }; | |
105 | (List: $descr: expr) => { template!(@ false, Some($descr), None) }; | |
106 | (NameValueStr: $descr: expr) => { template!(@ false, None, Some($descr)) }; | |
107 | (Word, List: $descr: expr) => { template!(@ true, Some($descr), None) }; | |
108 | (Word, NameValueStr: $descr: expr) => { template!(@ true, None, Some($descr)) }; | |
109 | (List: $descr1: expr, NameValueStr: $descr2: expr) => { | |
110 | template!(@ false, Some($descr1), Some($descr2)) | |
111 | }; | |
112 | (Word, List: $descr1: expr, NameValueStr: $descr2: expr) => { | |
113 | template!(@ true, Some($descr1), Some($descr2)) | |
114 | }; | |
115 | (@ $word: expr, $list: expr, $name_value_str: expr) => { AttributeTemplate { | |
116 | word: $word, list: $list, name_value_str: $name_value_str | |
117 | } }; | |
118 | } | |
119 | ||
120 | macro_rules! ungated { | |
121 | ($attr:ident, $typ:expr, $tpl:expr $(,)?) => { | |
122 | (sym::$attr, $typ, $tpl, Ungated) | |
123 | }; | |
124 | } | |
125 | ||
126 | macro_rules! gated { | |
127 | ($attr:ident, $typ:expr, $tpl:expr, $gate:ident, $msg:expr $(,)?) => { | |
128 | (sym::$attr, $typ, $tpl, Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate))) | |
129 | }; | |
130 | ($attr:ident, $typ:expr, $tpl:expr, $msg:expr $(,)?) => { | |
131 | (sym::$attr, $typ, $tpl, Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr))) | |
132 | }; | |
133 | } | |
134 | ||
135 | macro_rules! rustc_attr { | |
136 | (TEST, $attr:ident, $typ:expr, $tpl:expr $(,)?) => { | |
137 | rustc_attr!( | |
138 | $attr, | |
139 | $typ, | |
140 | $tpl, | |
141 | concat!( | |
142 | "the `#[", | |
143 | stringify!($attr), | |
144 | "]` attribute is just used for rustc unit tests \ | |
145 | and will never be stable", | |
146 | ), | |
147 | ) | |
148 | }; | |
149 | ($attr:ident, $typ:expr, $tpl:expr, $msg:expr $(,)?) => { | |
150 | ( | |
151 | sym::$attr, | |
152 | $typ, | |
153 | $tpl, | |
154 | Gated(Stability::Unstable, sym::rustc_attrs, $msg, cfg_fn!(rustc_attrs)), | |
155 | ) | |
156 | }; | |
157 | } | |
158 | ||
159 | macro_rules! experimental { | |
160 | ($attr:ident) => { | |
161 | concat!("the `#[", stringify!($attr), "]` attribute is an experimental feature") | |
162 | }; | |
163 | } | |
164 | ||
165 | const IMPL_DETAIL: &str = "internal implementation detail"; | |
166 | const INTERNAL_UNSTABLE: &str = "this is an internal attribute that will never be stable"; | |
167 | ||
168 | pub type BuiltinAttribute = (Symbol, AttributeType, AttributeTemplate, AttributeGate); | |
169 | ||
170 | /// Attributes that have a special meaning to rustc or rustdoc. | |
171 | #[rustfmt::skip] | |
172 | pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ | |
173 | // ========================================================================== | |
174 | // Stable attributes: | |
175 | // ========================================================================== | |
176 | ||
177 | // Conditional compilation: | |
178 | ungated!(cfg, Normal, template!(List: "predicate")), | |
179 | ungated!(cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ...")), | |
180 | ||
181 | // Testing: | |
182 | ungated!(ignore, Normal, template!(Word, NameValueStr: "reason")), | |
183 | ungated!( | |
184 | should_panic, Normal, | |
185 | template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"), | |
186 | ), | |
187 | // FIXME(Centril): This can be used on stable but shouldn't. | |
188 | ungated!(reexport_test_harness_main, Normal, template!(NameValueStr: "name")), | |
189 | ||
190 | // Macros: | |
191 | ungated!(derive, Normal, template!(List: "Trait1, Trait2, ...")), | |
192 | ungated!(automatically_derived, Normal, template!(Word)), | |
193 | // FIXME(#14407) | |
194 | ungated!(macro_use, Normal, template!(Word, List: "name1, name2, ...")), | |
195 | ungated!(macro_escape, Normal, template!(Word)), // Deprecated synonym for `macro_use`. | |
196 | ungated!(macro_export, Normal, template!(Word, List: "local_inner_macros")), | |
197 | ungated!(proc_macro, Normal, template!(Word)), | |
198 | ungated!( | |
199 | proc_macro_derive, Normal, | |
200 | template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)"), | |
201 | ), | |
202 | ungated!(proc_macro_attribute, Normal, template!(Word)), | |
203 | ||
204 | // Lints: | |
205 | ungated!(warn, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), | |
206 | ungated!(allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), | |
207 | ungated!(forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), | |
208 | ungated!(deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), | |
209 | ungated!(must_use, AssumedUsed, template!(Word, NameValueStr: "reason")), | |
210 | // FIXME(#14407) | |
211 | ungated!( | |
212 | deprecated, Normal, | |
213 | template!( | |
214 | Word, | |
215 | List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#, | |
216 | NameValueStr: "reason" | |
217 | ), | |
218 | ), | |
219 | ||
220 | // Crate properties: | |
221 | ungated!(crate_name, CrateLevel, template!(NameValueStr: "name")), | |
222 | ungated!(crate_type, CrateLevel, template!(NameValueStr: "bin|lib|...")), | |
223 | ungated!(crate_id, CrateLevel, template!(NameValueStr: "ignored")), | |
224 | ||
225 | // ABI, linking, symbols, and FFI | |
226 | ungated!( | |
227 | link, AssumedUsed, | |
228 | template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...""#), | |
229 | ), | |
230 | ungated!(link_name, AssumedUsed, template!(NameValueStr: "name")), | |
231 | ungated!(no_link, Normal, template!(Word)), | |
232 | ungated!(repr, Normal, template!(List: "C")), | |
233 | ungated!(export_name, AssumedUsed, template!(NameValueStr: "name")), | |
234 | ungated!(link_section, AssumedUsed, template!(NameValueStr: "name")), | |
235 | ungated!(no_mangle, AssumedUsed, template!(Word)), | |
236 | ungated!(used, AssumedUsed, template!(Word)), | |
237 | ||
238 | // Limits: | |
239 | ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N")), | |
240 | ungated!(type_length_limit, CrateLevel, template!(NameValueStr: "N")), | |
241 | gated!( | |
242 | const_eval_limit, CrateLevel, template!(NameValueStr: "N"), const_eval_limit, | |
243 | experimental!(const_eval_limit) | |
244 | ), | |
245 | ||
246 | // Entry point: | |
247 | ungated!(main, Normal, template!(Word)), | |
248 | ungated!(start, Normal, template!(Word)), | |
249 | ungated!(no_start, CrateLevel, template!(Word)), | |
250 | ungated!(no_main, CrateLevel, template!(Word)), | |
251 | ||
252 | // Modules, prelude, and resolution: | |
253 | ungated!(path, Normal, template!(NameValueStr: "file")), | |
254 | ungated!(no_std, CrateLevel, template!(Word)), | |
255 | ungated!(no_implicit_prelude, Normal, template!(Word)), | |
256 | ungated!(non_exhaustive, AssumedUsed, template!(Word)), | |
257 | ||
258 | // Runtime | |
259 | ungated!(windows_subsystem, AssumedUsed, template!(NameValueStr: "windows|console")), | |
260 | ungated!(panic_handler, Normal, template!(Word)), // RFC 2070 | |
261 | ||
262 | // Code generation: | |
263 | ungated!(inline, AssumedUsed, template!(Word, List: "always|never")), | |
264 | ungated!(cold, AssumedUsed, template!(Word)), | |
265 | ungated!(no_builtins, AssumedUsed, template!(Word)), | |
266 | ungated!(target_feature, AssumedUsed, template!(List: r#"enable = "name""#)), | |
267 | ungated!(track_caller, AssumedUsed, template!(Word)), | |
268 | gated!( | |
269 | no_sanitize, AssumedUsed, | |
270 | template!(List: "address, memory, thread"), | |
271 | experimental!(no_sanitize) | |
272 | ), | |
273 | ||
274 | // FIXME: #14408 assume docs are used since rustdoc looks at them. | |
275 | ungated!(doc, AssumedUsed, template!(List: "hidden|inline|...", NameValueStr: "string")), | |
276 | ||
277 | // ========================================================================== | |
278 | // Unstable attributes: | |
279 | // ========================================================================== | |
280 | ||
281 | // Linking: | |
282 | gated!(naked, AssumedUsed, template!(Word), naked_functions, experimental!(naked)), | |
283 | gated!( | |
284 | link_args, Normal, template!(NameValueStr: "args"), | |
285 | "the `link_args` attribute is experimental and not portable across platforms, \ | |
286 | it is recommended to use `#[link(name = \"foo\")] instead", | |
287 | ), | |
288 | gated!( | |
289 | link_ordinal, AssumedUsed, template!(List: "ordinal"), raw_dylib, | |
290 | experimental!(link_ordinal) | |
291 | ), | |
292 | ||
293 | // Plugins: | |
294 | ( | |
295 | sym::plugin_registrar, Normal, template!(Word), | |
296 | Gated( | |
297 | Stability::Deprecated( | |
298 | "https://github.com/rust-lang/rust/pull/64675", | |
299 | Some("may be removed in a future compiler version"), | |
300 | ), | |
301 | sym::plugin_registrar, | |
302 | "compiler plugins are deprecated", | |
303 | cfg_fn!(plugin_registrar) | |
304 | ) | |
305 | ), | |
306 | ( | |
307 | sym::plugin, CrateLevel, template!(List: "name"), | |
308 | Gated( | |
309 | Stability::Deprecated( | |
310 | "https://github.com/rust-lang/rust/pull/64675", | |
311 | Some("may be removed in a future compiler version"), | |
312 | ), | |
313 | sym::plugin, | |
314 | "compiler plugins are deprecated", | |
315 | cfg_fn!(plugin) | |
316 | ) | |
317 | ), | |
318 | ||
319 | // Testing: | |
320 | gated!(allow_fail, Normal, template!(Word), experimental!(allow_fail)), | |
321 | gated!( | |
322 | test_runner, CrateLevel, template!(List: "path"), custom_test_frameworks, | |
323 | "custom test frameworks are an unstable feature", | |
324 | ), | |
325 | // RFC #1268 | |
326 | gated!(marker, Normal, template!(Word), marker_trait_attr, experimental!(marker)), | |
327 | gated!( | |
328 | thread_local, AssumedUsed, template!(Word), | |
329 | "`#[thread_local]` is an experimental feature, and does not currently handle destructors", | |
330 | ), | |
331 | gated!(no_core, CrateLevel, template!(Word), experimental!(no_core)), | |
332 | // RFC 2412 | |
333 | gated!( | |
334 | optimize, AssumedUsed, template!(List: "size|speed"), optimize_attribute, | |
335 | experimental!(optimize), | |
336 | ), | |
337 | // RFC 2867 | |
338 | gated!(instruction_set, AssumedUsed, template!(List: "set"), isa_attribute, experimental!(instruction_set)), | |
339 | ||
340 | gated!(ffi_returns_twice, AssumedUsed, template!(Word), experimental!(ffi_returns_twice)), | |
341 | gated!(ffi_pure, AssumedUsed, template!(Word), experimental!(ffi_pure)), | |
342 | gated!(ffi_const, AssumedUsed, template!(Word), experimental!(ffi_const)), | |
343 | gated!( | |
344 | register_attr, CrateLevel, template!(List: "attr1, attr2, ..."), | |
345 | experimental!(register_attr), | |
346 | ), | |
347 | gated!( | |
348 | register_tool, CrateLevel, template!(List: "tool1, tool2, ..."), | |
349 | experimental!(register_tool), | |
350 | ), | |
351 | ||
352 | gated!(cmse_nonsecure_entry, AssumedUsed, template!(Word), experimental!(cmse_nonsecure_entry)), | |
353 | ||
354 | // ========================================================================== | |
355 | // Internal attributes: Stability, deprecation, and unsafe: | |
356 | // ========================================================================== | |
357 | ||
358 | ungated!(feature, CrateLevel, template!(List: "name1, name1, ...")), | |
359 | // FIXME(#14407) -- only looked at on-demand so we can't | |
360 | // guarantee they'll have already been checked. | |
361 | ungated!( | |
362 | rustc_deprecated, AssumedUsed, | |
363 | template!(List: r#"since = "version", reason = "...""#) | |
364 | ), | |
365 | // FIXME(#14407) | |
366 | ungated!(stable, AssumedUsed, template!(List: r#"feature = "name", since = "version""#)), | |
367 | // FIXME(#14407) | |
368 | ungated!( | |
369 | unstable, AssumedUsed, | |
370 | template!(List: r#"feature = "name", reason = "...", issue = "N""#), | |
371 | ), | |
372 | // FIXME(#14407) | |
373 | ungated!(rustc_const_unstable, AssumedUsed, template!(List: r#"feature = "name""#)), | |
374 | // FIXME(#14407) | |
375 | ungated!(rustc_const_stable, AssumedUsed, template!(List: r#"feature = "name""#)), | |
376 | gated!( | |
377 | allow_internal_unstable, AssumedUsed, template!(Word, List: "feat1, feat2, ..."), | |
378 | "allow_internal_unstable side-steps feature gating and stability checks", | |
379 | ), | |
380 | gated!( | |
381 | rustc_allow_const_fn_unstable, AssumedUsed, template!(Word, List: "feat1, feat2, ..."), | |
382 | "rustc_allow_const_fn_unstable side-steps feature gating and stability checks" | |
383 | ), | |
384 | gated!( | |
385 | allow_internal_unsafe, Normal, template!(Word), | |
386 | "allow_internal_unsafe side-steps the unsafe_code lint", | |
387 | ), | |
388 | ||
389 | // ========================================================================== | |
390 | // Internal attributes: Type system related: | |
391 | // ========================================================================== | |
392 | ||
393 | gated!(fundamental, AssumedUsed, template!(Word), experimental!(fundamental)), | |
394 | gated!( | |
395 | may_dangle, Normal, template!(Word), dropck_eyepatch, | |
396 | "`may_dangle` has unstable semantics and may be removed in the future", | |
397 | ), | |
398 | ||
399 | // ========================================================================== | |
400 | // Internal attributes: Runtime related: | |
401 | // ========================================================================== | |
402 | ||
403 | rustc_attr!(rustc_allocator, AssumedUsed, template!(Word), IMPL_DETAIL), | |
404 | rustc_attr!(rustc_allocator_nounwind, AssumedUsed, template!(Word), IMPL_DETAIL), | |
405 | gated!(alloc_error_handler, Normal, template!(Word), experimental!(alloc_error_handler)), | |
406 | gated!( | |
407 | default_lib_allocator, AssumedUsed, template!(Word), allocator_internals, | |
408 | experimental!(default_lib_allocator), | |
409 | ), | |
410 | gated!( | |
411 | needs_allocator, Normal, template!(Word), allocator_internals, | |
412 | experimental!(needs_allocator), | |
413 | ), | |
414 | gated!(panic_runtime, AssumedUsed, template!(Word), experimental!(panic_runtime)), | |
415 | gated!(needs_panic_runtime, AssumedUsed, template!(Word), experimental!(needs_panic_runtime)), | |
416 | gated!( | |
417 | unwind, AssumedUsed, template!(List: "allowed|aborts"), unwind_attributes, | |
418 | experimental!(unwind), | |
419 | ), | |
420 | gated!( | |
421 | compiler_builtins, AssumedUsed, template!(Word), | |
422 | "the `#[compiler_builtins]` attribute is used to identify the `compiler_builtins` crate \ | |
423 | which contains compiler-rt intrinsics and will never be stable", | |
424 | ), | |
425 | gated!( | |
426 | profiler_runtime, AssumedUsed, template!(Word), | |
427 | "the `#[profiler_runtime]` attribute is used to identify the `profiler_builtins` crate \ | |
428 | which contains the profiler runtime and will never be stable", | |
429 | ), | |
430 | ||
431 | // ========================================================================== | |
432 | // Internal attributes, Linkage: | |
433 | // ========================================================================== | |
434 | ||
435 | gated!( | |
436 | linkage, AssumedUsed, template!(NameValueStr: "external|internal|..."), | |
437 | "the `linkage` attribute is experimental and not portable across platforms", | |
438 | ), | |
439 | rustc_attr!(rustc_std_internal_symbol, AssumedUsed, template!(Word), INTERNAL_UNSTABLE), | |
440 | ||
441 | // ========================================================================== | |
442 | // Internal attributes, Macro related: | |
443 | // ========================================================================== | |
444 | ||
445 | rustc_attr!(rustc_builtin_macro, AssumedUsed, template!(Word, NameValueStr: "name"), IMPL_DETAIL), | |
446 | rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), INTERNAL_UNSTABLE), | |
447 | rustc_attr!( | |
448 | rustc_macro_transparency, AssumedUsed, | |
449 | template!(NameValueStr: "transparent|semitransparent|opaque"), | |
450 | "used internally for testing macro hygiene", | |
451 | ), | |
452 | ||
453 | // ========================================================================== | |
454 | // Internal attributes, Diagnostics related: | |
455 | // ========================================================================== | |
456 | ||
457 | rustc_attr!( | |
458 | rustc_on_unimplemented, AssumedUsed, | |
459 | template!( | |
460 | List: r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#, | |
461 | NameValueStr: "message" | |
462 | ), | |
463 | INTERNAL_UNSTABLE | |
464 | ), | |
465 | // Enumerates "identity-like" conversion methods to suggest on type mismatch. | |
466 | rustc_attr!(rustc_conversion_suggestion, AssumedUsed, template!(Word), INTERNAL_UNSTABLE), | |
467 | ||
468 | // ========================================================================== | |
469 | // Internal attributes, Const related: | |
470 | // ========================================================================== | |
471 | ||
472 | rustc_attr!(rustc_promotable, AssumedUsed, template!(Word), IMPL_DETAIL), | |
473 | rustc_attr!(rustc_args_required_const, AssumedUsed, template!(List: "N"), INTERNAL_UNSTABLE), | |
474 | ||
475 | // ========================================================================== | |
476 | // Internal attributes, Layout related: | |
477 | // ========================================================================== | |
478 | ||
479 | rustc_attr!( | |
480 | rustc_layout_scalar_valid_range_start, AssumedUsed, template!(List: "value"), | |
481 | "the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \ | |
482 | niche optimizations in libcore and will never be stable", | |
483 | ), | |
484 | rustc_attr!( | |
485 | rustc_layout_scalar_valid_range_end, AssumedUsed, template!(List: "value"), | |
486 | "the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \ | |
487 | niche optimizations in libcore and will never be stable", | |
488 | ), | |
489 | rustc_attr!( | |
490 | rustc_nonnull_optimization_guaranteed, AssumedUsed, template!(Word), | |
491 | "the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable \ | |
492 | niche optimizations in libcore and will never be stable", | |
493 | ), | |
494 | ||
495 | // ========================================================================== | |
496 | // Internal attributes, Misc: | |
497 | // ========================================================================== | |
498 | gated!( | |
499 | lang, Normal, template!(NameValueStr: "name"), lang_items, | |
500 | "language items are subject to change", | |
501 | ), | |
502 | ( | |
503 | sym::rustc_diagnostic_item, | |
504 | Normal, | |
505 | template!(NameValueStr: "name"), | |
506 | Gated( | |
507 | Stability::Unstable, | |
508 | sym::rustc_attrs, | |
509 | "diagnostic items compiler internal support for linting", | |
510 | cfg_fn!(rustc_attrs), | |
511 | ), | |
512 | ), | |
513 | gated!( | |
514 | // Used in resolve: | |
515 | prelude_import, AssumedUsed, template!(Word), | |
516 | "`#[prelude_import]` is for use by rustc only", | |
517 | ), | |
518 | gated!( | |
519 | rustc_paren_sugar, Normal, template!(Word), unboxed_closures, | |
520 | "unboxed_closures are still evolving", | |
521 | ), | |
522 | rustc_attr!( | |
523 | rustc_inherit_overflow_checks, AssumedUsed, template!(Word), | |
524 | "the `#[rustc_inherit_overflow_checks]` attribute is just used to control \ | |
525 | overflow checking behavior of several libcore functions that are inlined \ | |
526 | across crates and will never be stable", | |
527 | ), | |
528 | rustc_attr!(rustc_reservation_impl, Normal, template!(NameValueStr: "reservation message"), | |
529 | "the `#[rustc_reservation_impl]` attribute is internally used \ | |
530 | for reserving for `for<T> From<!> for T` impl" | |
531 | ), | |
532 | rustc_attr!( | |
533 | rustc_test_marker, Normal, template!(Word), | |
534 | "the `#[rustc_test_marker]` attribute is used internally to track tests", | |
535 | ), | |
536 | rustc_attr!( | |
537 | rustc_unsafe_specialization_marker, Normal, template!(Word), | |
538 | "the `#[rustc_unsafe_specialization_marker]` attribute is used to check specializations" | |
539 | ), | |
540 | rustc_attr!( | |
541 | rustc_specialization_trait, Normal, template!(Word), | |
542 | "the `#[rustc_specialization_trait]` attribute is used to check specializations" | |
543 | ), | |
544 | ||
545 | // ========================================================================== | |
546 | // Internal attributes, Testing: | |
547 | // ========================================================================== | |
548 | ||
549 | rustc_attr!(TEST, rustc_outlives, Normal, template!(Word)), | |
550 | rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word)), | |
551 | rustc_attr!(TEST, rustc_variance, Normal, template!(Word)), | |
552 | rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")), | |
553 | rustc_attr!(TEST, rustc_regions, Normal, template!(Word)), | |
554 | rustc_attr!( | |
555 | TEST, rustc_error, AssumedUsed, | |
556 | template!(Word, List: "delay_span_bug_from_inside_query") | |
557 | ), | |
558 | rustc_attr!(TEST, rustc_dump_user_substs, AssumedUsed, template!(Word)), | |
559 | rustc_attr!(TEST, rustc_if_this_changed, AssumedUsed, template!(Word, List: "DepNode")), | |
560 | rustc_attr!(TEST, rustc_then_this_would_need, AssumedUsed, template!(List: "DepNode")), | |
561 | rustc_attr!( | |
562 | TEST, rustc_dirty, AssumedUsed, | |
563 | template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), | |
564 | ), | |
565 | rustc_attr!( | |
566 | TEST, rustc_clean, AssumedUsed, | |
567 | template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), | |
568 | ), | |
569 | rustc_attr!( | |
570 | TEST, rustc_partition_reused, AssumedUsed, | |
571 | template!(List: r#"cfg = "...", module = "...""#), | |
572 | ), | |
573 | rustc_attr!( | |
574 | TEST, rustc_partition_codegened, AssumedUsed, | |
575 | template!(List: r#"cfg = "...", module = "...""#), | |
576 | ), | |
577 | rustc_attr!( | |
578 | TEST, rustc_expected_cgu_reuse, AssumedUsed, | |
579 | template!(List: r#"cfg = "...", module = "...", kind = "...""#), | |
580 | ), | |
581 | rustc_attr!(TEST, rustc_synthetic, AssumedUsed, template!(Word)), | |
582 | rustc_attr!(TEST, rustc_symbol_name, AssumedUsed, template!(Word)), | |
583 | rustc_attr!(TEST, rustc_polymorphize_error, AssumedUsed, template!(Word)), | |
584 | rustc_attr!(TEST, rustc_def_path, AssumedUsed, template!(Word)), | |
585 | rustc_attr!(TEST, rustc_mir, AssumedUsed, template!(List: "arg1, arg2, ...")), | |
586 | rustc_attr!(TEST, rustc_dump_program_clauses, AssumedUsed, template!(Word)), | |
587 | rustc_attr!(TEST, rustc_dump_env_program_clauses, AssumedUsed, template!(Word)), | |
588 | rustc_attr!(TEST, rustc_object_lifetime_default, AssumedUsed, template!(Word)), | |
589 | rustc_attr!(TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/)), | |
590 | gated!( | |
591 | omit_gdb_pretty_printer_section, AssumedUsed, template!(Word), | |
592 | "the `#[omit_gdb_pretty_printer_section]` attribute is just used for the Rust test suite", | |
593 | ), | |
594 | ]; | |
595 | ||
596 | pub fn deprecated_attributes() -> Vec<&'static BuiltinAttribute> { | |
597 | BUILTIN_ATTRIBUTES.iter().filter(|(.., gate)| gate.is_deprecated()).collect() | |
598 | } | |
599 | ||
600 | pub fn is_builtin_attr_name(name: Symbol) -> bool { | |
601 | BUILTIN_ATTRIBUTE_MAP.get(&name).is_some() | |
602 | } | |
603 | ||
604 | pub static BUILTIN_ATTRIBUTE_MAP: SyncLazy<FxHashMap<Symbol, &BuiltinAttribute>> = | |
605 | SyncLazy::new(|| { | |
606 | let mut map = FxHashMap::default(); | |
607 | for attr in BUILTIN_ATTRIBUTES.iter() { | |
608 | if map.insert(attr.0, attr).is_some() { | |
609 | panic!("duplicate builtin attribute `{}`", attr.0); | |
610 | } | |
611 | } | |
612 | map | |
613 | }); |