rustc_feature/
builtin_attrs.rs

1//! Built-in attributes and `cfg` flag gating.
2
3use std::sync::LazyLock;
4
5use AttributeDuplicates::*;
6use AttributeGate::*;
7use AttributeType::*;
8use rustc_data_structures::fx::FxHashMap;
9use rustc_span::edition::Edition;
10use rustc_span::{Symbol, sym};
11
12use crate::{Features, Stability};
13
14type GateFn = fn(&Features) -> bool;
15
16pub type GatedCfg = (Symbol, Symbol, GateFn);
17
18/// `cfg(...)`'s that are feature gated.
19const GATED_CFGS: &[GatedCfg] = &[
20    // (name in cfg, feature, function to check if the feature is enabled)
21    (sym::overflow_checks, sym::cfg_overflow_checks, Features::cfg_overflow_checks),
22    (sym::ub_checks, sym::cfg_ub_checks, Features::cfg_ub_checks),
23    (sym::contract_checks, sym::cfg_contract_checks, Features::cfg_contract_checks),
24    (sym::target_thread_local, sym::cfg_target_thread_local, Features::cfg_target_thread_local),
25    (
26        sym::target_has_atomic_equal_alignment,
27        sym::cfg_target_has_atomic_equal_alignment,
28        Features::cfg_target_has_atomic_equal_alignment,
29    ),
30    (
31        sym::target_has_atomic_load_store,
32        sym::cfg_target_has_atomic,
33        Features::cfg_target_has_atomic,
34    ),
35    (sym::sanitize, sym::cfg_sanitize, Features::cfg_sanitize),
36    (sym::version, sym::cfg_version, Features::cfg_version),
37    (sym::relocation_model, sym::cfg_relocation_model, Features::cfg_relocation_model),
38    (sym::sanitizer_cfi_generalize_pointers, sym::cfg_sanitizer_cfi, Features::cfg_sanitizer_cfi),
39    (sym::sanitizer_cfi_normalize_integers, sym::cfg_sanitizer_cfi, Features::cfg_sanitizer_cfi),
40    // this is consistent with naming of the compiler flag it's for
41    (sym::fmt_debug, sym::fmt_debug, Features::fmt_debug),
42    (sym::emscripten_wasm_eh, sym::cfg_emscripten_wasm_eh, Features::cfg_emscripten_wasm_eh),
43    (
44        sym::target_has_reliable_f16,
45        sym::cfg_target_has_reliable_f16_f128,
46        Features::cfg_target_has_reliable_f16_f128,
47    ),
48    (
49        sym::target_has_reliable_f16_math,
50        sym::cfg_target_has_reliable_f16_f128,
51        Features::cfg_target_has_reliable_f16_f128,
52    ),
53    (
54        sym::target_has_reliable_f128,
55        sym::cfg_target_has_reliable_f16_f128,
56        Features::cfg_target_has_reliable_f16_f128,
57    ),
58    (
59        sym::target_has_reliable_f128_math,
60        sym::cfg_target_has_reliable_f16_f128,
61        Features::cfg_target_has_reliable_f16_f128,
62    ),
63];
64
65/// Find a gated cfg determined by the `pred`icate which is given the cfg's name.
66pub fn find_gated_cfg(pred: impl Fn(Symbol) -> bool) -> Option<&'static GatedCfg> {
67    GATED_CFGS.iter().find(|(cfg_sym, ..)| pred(*cfg_sym))
68}
69
70// If you change this, please modify `src/doc/unstable-book` as well. You must
71// move that documentation into the relevant place in the other docs, and
72// remove the chapter on the flag.
73
74#[derive(Copy, Clone, PartialEq, Debug)]
75pub enum AttributeType {
76    /// Normal, builtin attribute that is consumed
77    /// by the compiler before the unused_attribute check
78    Normal,
79
80    /// Builtin attribute that is only allowed at the crate level
81    CrateLevel,
82}
83
84#[derive(Copy, Clone, PartialEq, Debug)]
85pub enum AttributeSafety {
86    /// Normal attribute that does not need `#[unsafe(...)]`
87    Normal,
88
89    /// Unsafe attribute that requires safety obligations to be discharged.
90    ///
91    /// An error is emitted when `#[unsafe(...)]` is omitted, except when the attribute's edition
92    /// is less than the one stored in `unsafe_since`. This handles attributes that were safe in
93    /// earlier editions, but become unsafe in later ones.
94    Unsafe { unsafe_since: Option<Edition> },
95}
96
97#[derive(Clone, Copy)]
98pub enum AttributeGate {
99    /// Is gated by a given feature gate, reason
100    /// and function to check if enabled
101    Gated(Stability, Symbol, &'static str, fn(&Features) -> bool),
102
103    /// Ungated attribute, can be used on all release channels
104    Ungated,
105}
106
107// fn() is not Debug
108impl std::fmt::Debug for AttributeGate {
109    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110        match *self {
111            Self::Gated(ref stab, name, expl, _) => {
112                write!(fmt, "Gated({stab:?}, {name}, {expl})")
113            }
114            Self::Ungated => write!(fmt, "Ungated"),
115        }
116    }
117}
118
119impl AttributeGate {
120    fn is_deprecated(&self) -> bool {
121        matches!(*self, Self::Gated(Stability::Deprecated(_, _), ..))
122    }
123}
124
125/// A template that the attribute input must match.
126/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now.
127#[derive(Clone, Copy, Default)]
128pub struct AttributeTemplate {
129    /// If `true`, the attribute is allowed to be a bare word like `#[test]`.
130    pub word: bool,
131    /// If `Some`, the attribute is allowed to take a list of items like `#[allow(..)]`.
132    pub list: Option<&'static str>,
133    /// If non-empty, the attribute is allowed to take a list containing exactly
134    /// one of the listed words, like `#[coverage(off)]`.
135    pub one_of: &'static [Symbol],
136    /// If `Some`, the attribute is allowed to be a name/value pair where the
137    /// value is a string, like `#[must_use = "reason"]`.
138    pub name_value_str: Option<&'static str>,
139}
140
141/// How to handle multiple duplicate attributes on the same item.
142#[derive(Clone, Copy, Default)]
143pub enum AttributeDuplicates {
144    /// Duplicates of this attribute are allowed.
145    ///
146    /// This should only be used with attributes where duplicates have semantic
147    /// meaning, or some kind of "additive" behavior. For example, `#[warn(..)]`
148    /// can be specified multiple times, and it combines all the entries. Or use
149    /// this if there is validation done elsewhere.
150    #[default]
151    DuplicatesOk,
152    /// Duplicates after the first attribute will be an unused_attribute warning.
153    ///
154    /// This is usually used for "word" attributes, where they are used as a
155    /// boolean marker, like `#[used]`. It is not necessarily wrong that there
156    /// are duplicates, but the others should probably be removed.
157    WarnFollowing,
158    /// Same as `WarnFollowing`, but only issues warnings for word-style attributes.
159    ///
160    /// This is only for special cases, for example multiple `#[macro_use]` can
161    /// be warned, but multiple `#[macro_use(...)]` should not because the list
162    /// form has different meaning from the word form.
163    WarnFollowingWordOnly,
164    /// Duplicates after the first attribute will be an error.
165    ///
166    /// This should be used where duplicates would be ignored, but carry extra
167    /// meaning that could cause confusion. For example, `#[stable(since="1.0")]
168    /// #[stable(since="2.0")]`, which version should be used for `stable`?
169    ErrorFollowing,
170    /// Duplicates preceding the last instance of the attribute will be an error.
171    ///
172    /// This is the same as `ErrorFollowing`, except the last attribute is the
173    /// one that is "used". This is typically used in cases like codegen
174    /// attributes which usually only honor the last attribute.
175    ErrorPreceding,
176    /// Duplicates after the first attribute will be an unused_attribute warning
177    /// with a note that this will be an error in the future.
178    ///
179    /// This should be used for attributes that should be `ErrorFollowing`, but
180    /// because older versions of rustc silently accepted (and ignored) the
181    /// attributes, this is used to transition.
182    FutureWarnFollowing,
183    /// Duplicates preceding the last instance of the attribute will be a
184    /// warning, with a note that this will be an error in the future.
185    ///
186    /// This is the same as `FutureWarnFollowing`, except the last attribute is
187    /// the one that is "used". Ideally these can eventually migrate to
188    /// `ErrorPreceding`.
189    FutureWarnPreceding,
190}
191
192/// A convenience macro for constructing attribute templates.
193/// E.g., `template!(Word, List: "description")` means that the attribute
194/// supports forms `#[attr]` and `#[attr(description)]`.
195macro_rules! template {
196    (Word) => { template!(@ true, None, &[], None) };
197    (List: $descr: expr) => { template!(@ false, Some($descr), &[], None) };
198    (OneOf: $one_of: expr) => { template!(@ false, None, $one_of, None) };
199    (NameValueStr: $descr: expr) => { template!(@ false, None, &[], Some($descr)) };
200    (Word, List: $descr: expr) => { template!(@ true, Some($descr), &[], None) };
201    (Word, NameValueStr: $descr: expr) => { template!(@ true, None, &[], Some($descr)) };
202    (List: $descr1: expr, NameValueStr: $descr2: expr) => {
203        template!(@ false, Some($descr1), &[], Some($descr2))
204    };
205    (Word, List: $descr1: expr, NameValueStr: $descr2: expr) => {
206        template!(@ true, Some($descr1), &[], Some($descr2))
207    };
208    (@ $word: expr, $list: expr, $one_of: expr, $name_value_str: expr) => { AttributeTemplate {
209        word: $word, list: $list, one_of: $one_of, name_value_str: $name_value_str
210    } };
211}
212
213macro_rules! ungated {
214    (unsafe($edition:ident) $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => {
215        BuiltinAttribute {
216            name: sym::$attr,
217            encode_cross_crate: $encode_cross_crate,
218            type_: $typ,
219            safety: AttributeSafety::Unsafe { unsafe_since: Some(Edition::$edition) },
220            template: $tpl,
221            gate: Ungated,
222            duplicates: $duplicates,
223        }
224    };
225    (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => {
226        BuiltinAttribute {
227            name: sym::$attr,
228            encode_cross_crate: $encode_cross_crate,
229            type_: $typ,
230            safety: AttributeSafety::Unsafe { unsafe_since: None },
231            template: $tpl,
232            gate: Ungated,
233            duplicates: $duplicates,
234        }
235    };
236    ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => {
237        BuiltinAttribute {
238            name: sym::$attr,
239            encode_cross_crate: $encode_cross_crate,
240            type_: $typ,
241            safety: AttributeSafety::Normal,
242            template: $tpl,
243            gate: Ungated,
244            duplicates: $duplicates,
245        }
246    };
247}
248
249macro_rules! gated {
250    (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => {
251        BuiltinAttribute {
252            name: sym::$attr,
253            encode_cross_crate: $encode_cross_crate,
254            type_: $typ,
255            safety: AttributeSafety::Unsafe { unsafe_since: None },
256            template: $tpl,
257            duplicates: $duplicates,
258            gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate),
259        }
260    };
261    (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => {
262        BuiltinAttribute {
263            name: sym::$attr,
264            encode_cross_crate: $encode_cross_crate,
265            type_: $typ,
266            safety: AttributeSafety::Unsafe { unsafe_since: None },
267            template: $tpl,
268            duplicates: $duplicates,
269            gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr),
270        }
271    };
272    ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => {
273        BuiltinAttribute {
274            name: sym::$attr,
275            encode_cross_crate: $encode_cross_crate,
276            type_: $typ,
277            safety: AttributeSafety::Normal,
278            template: $tpl,
279            duplicates: $duplicates,
280            gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate),
281        }
282    };
283    ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => {
284        BuiltinAttribute {
285            name: sym::$attr,
286            encode_cross_crate: $encode_cross_crate,
287            type_: $typ,
288            safety: AttributeSafety::Normal,
289            template: $tpl,
290            duplicates: $duplicates,
291            gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr),
292        }
293    };
294}
295
296macro_rules! rustc_attr {
297    (TEST, $attr:ident, $typ:expr, $tpl:expr, $duplicate:expr, $encode_cross_crate:expr $(,)?) => {
298        rustc_attr!(
299            $attr,
300            $typ,
301            $tpl,
302            $duplicate,
303            $encode_cross_crate,
304            concat!(
305                "the `#[",
306                stringify!($attr),
307                "]` attribute is just used for rustc unit tests \
308                and will never be stable",
309            ),
310        )
311    };
312    ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => {
313        BuiltinAttribute {
314            name: sym::$attr,
315            encode_cross_crate: $encode_cross_crate,
316            type_: $typ,
317            safety: AttributeSafety::Normal,
318            template: $tpl,
319            duplicates: $duplicates,
320            gate: Gated(Stability::Unstable, sym::rustc_attrs, $msg, Features::rustc_attrs),
321        }
322    };
323}
324
325macro_rules! experimental {
326    ($attr:ident) => {
327        concat!("the `#[", stringify!($attr), "]` attribute is an experimental feature")
328    };
329}
330
331const IMPL_DETAIL: &str = "internal implementation detail";
332const INTERNAL_UNSTABLE: &str = "this is an internal attribute that will never be stable";
333
334#[derive(PartialEq)]
335pub enum EncodeCrossCrate {
336    Yes,
337    No,
338}
339
340pub struct BuiltinAttribute {
341    pub name: Symbol,
342    /// Whether this attribute is encode cross crate.
343    ///
344    /// If so, it is encoded in the crate metadata.
345    /// Otherwise, it can only be used in the local crate.
346    pub encode_cross_crate: EncodeCrossCrate,
347    pub type_: AttributeType,
348    pub safety: AttributeSafety,
349    pub template: AttributeTemplate,
350    pub duplicates: AttributeDuplicates,
351    pub gate: AttributeGate,
352}
353
354/// Attributes that have a special meaning to rustc or rustdoc.
355#[rustfmt::skip]
356pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
357    // ==========================================================================
358    // Stable attributes:
359    // ==========================================================================
360
361    // Conditional compilation:
362    ungated!(cfg, Normal, template!(List: "predicate"), DuplicatesOk, EncodeCrossCrate::Yes),
363    ungated!(cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ..."), DuplicatesOk, EncodeCrossCrate::Yes),
364
365    // Testing:
366    ungated!(
367        ignore, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing,
368        EncodeCrossCrate::No,
369    ),
370    ungated!(
371        should_panic, Normal,
372        template!(Word, List: r#"expected = "reason""#, NameValueStr: "reason"), FutureWarnFollowing,
373        EncodeCrossCrate::No,
374    ),
375    // FIXME(Centril): This can be used on stable but shouldn't.
376    ungated!(
377        reexport_test_harness_main, CrateLevel, template!(NameValueStr: "name"), ErrorFollowing,
378        EncodeCrossCrate::No,
379    ),
380
381    // Macros:
382    ungated!(automatically_derived, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes),
383    ungated!(
384        macro_use, Normal, template!(Word, List: "name1, name2, ..."), WarnFollowingWordOnly,
385        EncodeCrossCrate::No,
386    ),
387    ungated!(macro_escape, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), // Deprecated synonym for `macro_use`.
388    ungated!(
389        macro_export, Normal, template!(Word, List: "local_inner_macros"),
390        WarnFollowing, EncodeCrossCrate::Yes
391    ),
392    ungated!(proc_macro, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::No),
393    ungated!(
394        proc_macro_derive, Normal, template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)"),
395        ErrorFollowing, EncodeCrossCrate::No,
396    ),
397    ungated!(proc_macro_attribute, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::No),
398
399    // Lints:
400    ungated!(
401        warn, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
402        DuplicatesOk, EncodeCrossCrate::No,
403    ),
404    ungated!(
405        allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
406        DuplicatesOk, EncodeCrossCrate::No,
407    ),
408    ungated!(
409        expect, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
410        DuplicatesOk, EncodeCrossCrate::No,
411    ),
412    ungated!(
413        forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
414        DuplicatesOk, EncodeCrossCrate::No
415    ),
416    ungated!(
417        deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
418        DuplicatesOk, EncodeCrossCrate::No
419    ),
420    ungated!(
421        must_use, Normal, template!(Word, NameValueStr: "reason"),
422        FutureWarnFollowing, EncodeCrossCrate::Yes
423    ),
424    gated!(
425        must_not_suspend, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing,
426        EncodeCrossCrate::Yes, experimental!(must_not_suspend)
427    ),
428    ungated!(
429        deprecated, Normal,
430        template!(
431            Word,
432            List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#,
433            NameValueStr: "reason"
434        ),
435        ErrorFollowing, EncodeCrossCrate::Yes
436    ),
437
438    // Crate properties:
439    ungated!(
440        crate_name, CrateLevel, template!(NameValueStr: "name"), FutureWarnFollowing,
441        EncodeCrossCrate::No,
442    ),
443    ungated!(
444        crate_type, CrateLevel, template!(NameValueStr: "bin|lib|..."), DuplicatesOk,
445        EncodeCrossCrate::No,
446    ),
447
448    // ABI, linking, symbols, and FFI
449    ungated!(
450        link, Normal,
451        template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated""#),
452        DuplicatesOk,
453        EncodeCrossCrate::No,
454    ),
455    ungated!(
456        link_name, Normal, template!(NameValueStr: "name"),
457        FutureWarnPreceding, EncodeCrossCrate::Yes
458    ),
459    ungated!(no_link, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
460    ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, EncodeCrossCrate::No),
461    ungated!(unsafe(Edition2024) export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
462    ungated!(unsafe(Edition2024) link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
463    ungated!(unsafe(Edition2024) no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
464    ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, EncodeCrossCrate::No),
465    ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, EncodeCrossCrate::Yes),
466    ungated!(unsafe naked, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
467
468    // Limits:
469    ungated!(
470        recursion_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing,
471        EncodeCrossCrate::No
472    ),
473    ungated!(
474        type_length_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing,
475        EncodeCrossCrate::No
476    ),
477    gated!(
478        move_size_limit, CrateLevel, template!(NameValueStr: "N"), ErrorFollowing,
479        EncodeCrossCrate::No, large_assignments, experimental!(move_size_limit)
480    ),
481
482    // Entry point:
483    ungated!(no_main, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No),
484
485    // Modules, prelude, and resolution:
486    ungated!(path, Normal, template!(NameValueStr: "file"), FutureWarnFollowing, EncodeCrossCrate::No),
487    ungated!(no_std, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No),
488    ungated!(no_implicit_prelude, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
489    ungated!(non_exhaustive, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes),
490
491    // Runtime
492    ungated!(
493        windows_subsystem, CrateLevel,
494        template!(NameValueStr: "windows|console"), FutureWarnFollowing,
495        EncodeCrossCrate::No
496    ),
497    ungated!(panic_handler, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes), // RFC 2070
498
499    // Code generation:
500    ungated!(inline, Normal, template!(Word, List: "always|never"), FutureWarnFollowing, EncodeCrossCrate::No),
501    ungated!(cold, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
502    ungated!(no_builtins, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::Yes),
503    ungated!(
504        target_feature, Normal, template!(List: r#"enable = "name""#),
505        DuplicatesOk, EncodeCrossCrate::No,
506    ),
507    ungated!(track_caller, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes),
508    ungated!(instruction_set, Normal, template!(List: "set"), ErrorPreceding, EncodeCrossCrate::No),
509    gated!(
510        no_sanitize, Normal,
511        template!(List: "address, kcfi, memory, thread"), DuplicatesOk,
512        EncodeCrossCrate::No, experimental!(no_sanitize)
513    ),
514    gated!(
515        coverage, Normal, template!(OneOf: &[sym::off, sym::on]),
516        ErrorPreceding, EncodeCrossCrate::No,
517        coverage_attribute, experimental!(coverage)
518    ),
519
520    ungated!(
521        doc, Normal, template!(List: "hidden|inline|...", NameValueStr: "string"), DuplicatesOk,
522        EncodeCrossCrate::Yes
523    ),
524
525    // Debugging
526    ungated!(
527        debugger_visualizer, Normal,
528        template!(List: r#"natvis_file = "...", gdb_script_file = "...""#),
529        DuplicatesOk, EncodeCrossCrate::No
530    ),
531    ungated!(collapse_debuginfo, Normal, template!(List: "no|external|yes"), ErrorFollowing,
532        EncodeCrossCrate::Yes
533    ),
534
535    // ==========================================================================
536    // Unstable attributes:
537    // ==========================================================================
538
539    // Linking:
540    gated!(
541        export_stable, Normal, template!(Word), WarnFollowing,
542        EncodeCrossCrate::No, experimental!(export_stable)
543    ),
544
545    // Testing:
546    gated!(
547        test_runner, CrateLevel, template!(List: "path"), ErrorFollowing,
548        EncodeCrossCrate::Yes, custom_test_frameworks,
549        "custom test frameworks are an unstable feature",
550    ),
551    // RFC #1268
552    gated!(
553        marker, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
554        marker_trait_attr, experimental!(marker)
555    ),
556    gated!(
557        thread_local, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
558        "`#[thread_local]` is an experimental feature, and does not currently handle destructors",
559    ),
560    gated!(
561        no_core, CrateLevel, template!(Word), WarnFollowing,
562        EncodeCrossCrate::No, experimental!(no_core)
563    ),
564    // RFC 2412
565    gated!(
566        optimize, Normal, template!(List: "none|size|speed"), ErrorPreceding,
567        EncodeCrossCrate::No, optimize_attribute, experimental!(optimize)
568    ),
569
570    gated!(
571        unsafe ffi_pure, Normal, template!(Word), WarnFollowing,
572        EncodeCrossCrate::No, experimental!(ffi_pure)
573    ),
574    gated!(
575        unsafe ffi_const, Normal, template!(Word), WarnFollowing,
576        EncodeCrossCrate::No, experimental!(ffi_const)
577    ),
578    gated!(
579        register_tool, CrateLevel, template!(List: "tool1, tool2, ..."), DuplicatesOk,
580        EncodeCrossCrate::No, experimental!(register_tool),
581    ),
582
583    // RFC 2632
584    gated!(
585        const_trait, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, const_trait_impl,
586        "`const_trait` is a temporary placeholder for marking a trait that is suitable for `const` \
587        `impls` and all default bodies as `const`, which may be removed or renamed in the \
588        future."
589    ),
590    // lang-team MCP 147
591    gated!(
592        deprecated_safe, Normal, template!(List: r#"since = "version", note = "...""#), ErrorFollowing,
593        EncodeCrossCrate::Yes, experimental!(deprecated_safe),
594    ),
595
596    // `#[cfi_encoding = ""]`
597    gated!(
598        cfi_encoding, Normal, template!(NameValueStr: "encoding"), ErrorPreceding,
599        EncodeCrossCrate::Yes, experimental!(cfi_encoding)
600    ),
601
602    // `#[coroutine]` attribute to be applied to closures to make them coroutines instead
603    gated!(
604        coroutine, Normal, template!(Word), ErrorFollowing,
605        EncodeCrossCrate::No, coroutines, experimental!(coroutine)
606    ),
607
608    // RFC 3543
609    // `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]`
610    gated!(
611        patchable_function_entry, Normal, template!(List: "prefix_nops = m, entry_nops = n"), ErrorPreceding,
612        EncodeCrossCrate::Yes, experimental!(patchable_function_entry)
613    ),
614
615    // Probably temporary component of min_generic_const_args.
616    // `#[type_const] const ASSOC: usize;`
617    gated!(
618        type_const, Normal, template!(Word), ErrorFollowing,
619        EncodeCrossCrate::Yes, min_generic_const_args, experimental!(type_const),
620    ),
621
622    // ==========================================================================
623    // Internal attributes: Stability, deprecation, and unsafe:
624    // ==========================================================================
625
626    ungated!(
627        feature, CrateLevel,
628        template!(List: "name1, name2, ..."), DuplicatesOk, EncodeCrossCrate::No,
629    ),
630    // DuplicatesOk since it has its own validation
631    ungated!(
632        stable, Normal,
633        template!(List: r#"feature = "name", since = "version""#), DuplicatesOk, EncodeCrossCrate::No,
634    ),
635    ungated!(
636        unstable, Normal,
637        template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk,
638        EncodeCrossCrate::Yes
639    ),
640    ungated!(
641        rustc_const_unstable, Normal, template!(List: r#"feature = "name""#),
642        DuplicatesOk, EncodeCrossCrate::Yes
643    ),
644    ungated!(
645        rustc_const_stable, Normal,
646        template!(List: r#"feature = "name""#), DuplicatesOk, EncodeCrossCrate::No,
647    ),
648    ungated!(
649        rustc_default_body_unstable, Normal,
650        template!(List: r#"feature = "name", reason = "...", issue = "N""#),
651        DuplicatesOk, EncodeCrossCrate::No
652    ),
653    gated!(
654        allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."),
655        DuplicatesOk, EncodeCrossCrate::Yes,
656        "allow_internal_unstable side-steps feature gating and stability checks",
657    ),
658    gated!(
659        allow_internal_unsafe, Normal, template!(Word), WarnFollowing,
660        EncodeCrossCrate::No, "allow_internal_unsafe side-steps the unsafe_code lint",
661    ),
662    rustc_attr!(
663        rustc_allowed_through_unstable_modules, Normal, template!(NameValueStr: "deprecation message"),
664        WarnFollowing, EncodeCrossCrate::No,
665        "rustc_allowed_through_unstable_modules special cases accidental stabilizations of stable items \
666        through unstable paths"
667    ),
668    rustc_attr!(
669        rustc_deprecated_safe_2024, Normal, template!(List: r#"audit_that = "...""#),
670        ErrorFollowing, EncodeCrossCrate::Yes,
671        "rustc_deprecated_safe_2024 is supposed to be used in libstd only",
672    ),
673    rustc_attr!(
674        rustc_pub_transparent, Normal, template!(Word),
675        WarnFollowing, EncodeCrossCrate::Yes,
676        "used internally to mark types with a `transparent` representation when it is guaranteed by the documentation",
677    ),
678
679
680    // ==========================================================================
681    // Internal attributes: Type system related:
682    // ==========================================================================
683
684    gated!(fundamental, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes, experimental!(fundamental)),
685    gated!(
686        may_dangle, Normal, template!(Word), WarnFollowing,
687        EncodeCrossCrate::No, dropck_eyepatch,
688        "`may_dangle` has unstable semantics and may be removed in the future",
689    ),
690
691    rustc_attr!(
692        rustc_never_type_options,
693        Normal,
694        template!(List: r#"/*opt*/ fallback = "unit|niko|never|no""#),
695        ErrorFollowing,
696        EncodeCrossCrate::No,
697        "`rustc_never_type_options` is used to experiment with never type fallback and work on \
698         never type stabilization, and will never be stable"
699    ),
700
701    // ==========================================================================
702    // Internal attributes: Runtime related:
703    // ==========================================================================
704
705    rustc_attr!(
706        rustc_allocator, Normal, template!(Word), WarnFollowing,
707        EncodeCrossCrate::No, IMPL_DETAIL
708    ),
709    rustc_attr!(
710        rustc_nounwind, Normal, template!(Word), WarnFollowing,
711        EncodeCrossCrate::No, IMPL_DETAIL
712    ),
713    rustc_attr!(
714        rustc_reallocator, Normal, template!(Word), WarnFollowing,
715        EncodeCrossCrate::No, IMPL_DETAIL
716    ),
717    rustc_attr!(
718        rustc_deallocator, Normal, template!(Word), WarnFollowing,
719        EncodeCrossCrate::No, IMPL_DETAIL
720    ),
721    rustc_attr!(
722        rustc_allocator_zeroed, Normal, template!(Word), WarnFollowing,
723        EncodeCrossCrate::No, IMPL_DETAIL
724    ),
725    gated!(
726        default_lib_allocator, Normal, template!(Word), WarnFollowing,
727        EncodeCrossCrate::No, allocator_internals, experimental!(default_lib_allocator),
728    ),
729    gated!(
730        needs_allocator, Normal, template!(Word), WarnFollowing,
731        EncodeCrossCrate::No, allocator_internals, experimental!(needs_allocator),
732    ),
733    gated!(
734        panic_runtime, CrateLevel, template!(Word), WarnFollowing,
735        EncodeCrossCrate::No, experimental!(panic_runtime)
736    ),
737    gated!(
738        needs_panic_runtime, CrateLevel, template!(Word), WarnFollowing,
739        EncodeCrossCrate::No, experimental!(needs_panic_runtime)
740    ),
741    gated!(
742        compiler_builtins, CrateLevel, template!(Word), WarnFollowing,
743        EncodeCrossCrate::No,
744        "the `#[compiler_builtins]` attribute is used to identify the `compiler_builtins` crate \
745        which contains compiler-rt intrinsics and will never be stable",
746    ),
747    gated!(
748        profiler_runtime, CrateLevel, template!(Word), WarnFollowing,
749        EncodeCrossCrate::No,
750        "the `#[profiler_runtime]` attribute is used to identify the `profiler_builtins` crate \
751        which contains the profiler runtime and will never be stable",
752    ),
753
754    // ==========================================================================
755    // Internal attributes, Linkage:
756    // ==========================================================================
757
758    gated!(
759        linkage, Normal, template!(NameValueStr: "external|internal|..."),
760        ErrorPreceding, EncodeCrossCrate::No,
761        "the `linkage` attribute is experimental and not portable across platforms",
762    ),
763    rustc_attr!(
764        rustc_std_internal_symbol, Normal, template!(Word), WarnFollowing,
765        EncodeCrossCrate::No, INTERNAL_UNSTABLE
766    ),
767
768    // ==========================================================================
769    // Internal attributes, Macro related:
770    // ==========================================================================
771
772    rustc_attr!(
773        rustc_builtin_macro, Normal,
774        template!(Word, List: "name, /*opt*/ attributes(name1, name2, ...)"), ErrorFollowing,
775        EncodeCrossCrate::Yes, IMPL_DETAIL
776    ),
777    rustc_attr!(
778        rustc_proc_macro_decls, Normal, template!(Word), WarnFollowing,
779        EncodeCrossCrate::No, INTERNAL_UNSTABLE
780    ),
781    rustc_attr!(
782        rustc_macro_transparency, Normal,
783        template!(NameValueStr: "transparent|semiopaque|opaque"), ErrorFollowing,
784        EncodeCrossCrate::Yes, "used internally for testing macro hygiene",
785    ),
786    rustc_attr!(
787        rustc_autodiff, Normal,
788        template!(Word, List: r#""...""#), DuplicatesOk,
789        EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
790    ),
791    // Traces that are left when `cfg` and `cfg_attr` attributes are expanded.
792    // The attributes are not gated, to avoid stability errors, but they cannot be used in stable
793    // or unstable code directly because `sym::cfg_(attr_)trace` are not valid identifiers, they
794    // can only be generated by the compiler.
795    ungated!(
796        cfg_trace, Normal, template!(Word /* irrelevant */), DuplicatesOk,
797        EncodeCrossCrate::No
798    ),
799    ungated!(
800        cfg_attr_trace, Normal, template!(Word /* irrelevant */), DuplicatesOk,
801        EncodeCrossCrate::No
802    ),
803
804    // ==========================================================================
805    // Internal attributes, Diagnostics related:
806    // ==========================================================================
807
808    rustc_attr!(
809        rustc_on_unimplemented, Normal,
810        template!(
811            List: r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#,
812            NameValueStr: "message"
813        ),
814        ErrorFollowing, EncodeCrossCrate::Yes,
815        INTERNAL_UNSTABLE
816    ),
817    rustc_attr!(
818        rustc_confusables, Normal,
819        template!(List: r#""name1", "name2", ..."#),
820        ErrorFollowing, EncodeCrossCrate::Yes,
821        INTERNAL_UNSTABLE,
822    ),
823    // Enumerates "identity-like" conversion methods to suggest on type mismatch.
824    rustc_attr!(
825        rustc_conversion_suggestion, Normal, template!(Word),
826        WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
827    ),
828    // Prevents field reads in the marked trait or method to be considered
829    // during dead code analysis.
830    rustc_attr!(
831        rustc_trivial_field_reads, Normal, template!(Word),
832        WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
833    ),
834    // Used by the `rustc::potential_query_instability` lint to warn methods which
835    // might not be stable during incremental compilation.
836    rustc_attr!(
837        rustc_lint_query_instability, Normal, template!(Word),
838        WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
839    ),
840    // Used by the `rustc::untracked_query_information` lint to warn methods which
841    // might not be stable during incremental compilation.
842    rustc_attr!(
843        rustc_lint_untracked_query_information, Normal, template!(Word),
844        WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
845    ),
846    // Used by the `rustc::diagnostic_outside_of_impl` lints to assist in changes to diagnostic
847    // APIs. Any function with this attribute will be checked by that lint.
848    rustc_attr!(
849        rustc_lint_diagnostics, Normal, template!(Word),
850        WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
851    ),
852    // Used by the `rustc::bad_opt_access` lint to identify `DebuggingOptions` and `CodegenOptions`
853    // types (as well as any others in future).
854    rustc_attr!(
855        rustc_lint_opt_ty, Normal, template!(Word),
856        WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
857    ),
858    // Used by the `rustc::bad_opt_access` lint on fields
859    // types (as well as any others in future).
860    rustc_attr!(
861        rustc_lint_opt_deny_field_access, Normal, template!(List: "message"),
862        WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
863    ),
864
865    // ==========================================================================
866    // Internal attributes, Const related:
867    // ==========================================================================
868
869    rustc_attr!(
870        rustc_promotable, Normal, template!(Word), WarnFollowing,
871        EncodeCrossCrate::No, IMPL_DETAIL),
872    rustc_attr!(
873        rustc_legacy_const_generics, Normal, template!(List: "N"), ErrorFollowing,
874        EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
875    ),
876    // Do not const-check this function's body. It will always get replaced during CTFE.
877    rustc_attr!(
878        rustc_do_not_const_check, Normal, template!(Word), WarnFollowing,
879        EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
880    ),
881    // Ensure the argument to this function is &&str during const-check.
882    rustc_attr!(
883        rustc_const_panic_str, Normal, template!(Word), WarnFollowing,
884        EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
885    ),
886    rustc_attr!(
887        rustc_const_stable_indirect, Normal,
888        template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL,
889    ),
890    rustc_attr!(
891        rustc_intrinsic_const_stable_indirect, Normal,
892        template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL,
893    ),
894    gated!(
895        rustc_allow_const_fn_unstable, Normal,
896        template!(Word, List: "feat1, feat2, ..."), DuplicatesOk, EncodeCrossCrate::No,
897        "rustc_allow_const_fn_unstable side-steps feature gating and stability checks"
898    ),
899
900    // ==========================================================================
901    // Internal attributes, Layout related:
902    // ==========================================================================
903
904    rustc_attr!(
905        rustc_layout_scalar_valid_range_start, Normal, template!(List: "value"), ErrorFollowing,
906        EncodeCrossCrate::Yes,
907        "the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \
908        niche optimizations in libcore and libstd and will never be stable",
909    ),
910    rustc_attr!(
911        rustc_layout_scalar_valid_range_end, Normal, template!(List: "value"), ErrorFollowing,
912        EncodeCrossCrate::Yes,
913        "the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \
914        niche optimizations in libcore and libstd and will never be stable",
915    ),
916    rustc_attr!(
917        rustc_nonnull_optimization_guaranteed, Normal, template!(Word), WarnFollowing,
918        EncodeCrossCrate::Yes,
919        "the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document \
920        guaranteed niche optimizations in libcore and libstd and will never be stable\n\
921        (note that the compiler does not even check whether the type indeed is being non-null-optimized; \
922        it is your responsibility to ensure that the attribute is only used on types that are optimized)",
923    ),
924
925    // ==========================================================================
926    // Internal attributes, Misc:
927    // ==========================================================================
928    gated!(
929        lang, Normal, template!(NameValueStr: "name"), DuplicatesOk, EncodeCrossCrate::No, lang_items,
930        "lang items are subject to change",
931    ),
932    rustc_attr!(
933        rustc_as_ptr, Normal, template!(Word), ErrorFollowing,
934        EncodeCrossCrate::Yes,
935        "#[rustc_as_ptr] is used to mark functions returning pointers to their inner allocations."
936    ),
937    rustc_attr!(
938        rustc_pass_by_value, Normal, template!(Word), ErrorFollowing,
939        EncodeCrossCrate::Yes,
940        "#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference."
941    ),
942    rustc_attr!(
943        rustc_never_returns_null_ptr, Normal, template!(Word), ErrorFollowing,
944        EncodeCrossCrate::Yes,
945        "#[rustc_never_returns_null_ptr] is used to mark functions returning non-null pointers."
946    ),
947    rustc_attr!(
948        rustc_no_implicit_autorefs, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes,
949        "`#[rustc_no_implicit_autorefs]` is used to mark functions for which an autoref to the dereference of a raw pointer should not be used as an argument."
950    ),
951    rustc_attr!(
952        rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
953        "#![rustc_coherence_is_core] allows inherent methods on builtin types, only intended to be used in `core`."
954    ),
955    rustc_attr!(
956        rustc_coinductive, AttributeType::Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
957        "#![rustc_coinductive] changes a trait to be coinductive, allowing cycles in the trait solver."
958    ),
959    rustc_attr!(
960        rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
961        "#[rustc_allow_incoherent_impl] has to be added to all impl items of an incoherent inherent impl."
962    ),
963    rustc_attr!(
964        rustc_preserve_ub_checks, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
965        "`#![rustc_preserve_ub_checks]` prevents the designated crate from evaluating whether UB checks are enabled when optimizing MIR",
966    ),
967    rustc_attr!(
968        rustc_deny_explicit_impl,
969        AttributeType::Normal,
970        template!(Word),
971        ErrorFollowing,
972        EncodeCrossCrate::No,
973        "#[rustc_deny_explicit_impl] enforces that a trait can have no user-provided impls"
974    ),
975    rustc_attr!(
976        rustc_do_not_implement_via_object,
977        AttributeType::Normal,
978        template!(Word),
979        ErrorFollowing,
980        EncodeCrossCrate::No,
981        "#[rustc_do_not_implement_via_object] opts out of the automatic trait impl for trait objects \
982        (`impl Trait for dyn Trait`)"
983    ),
984    rustc_attr!(
985        rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word),
986        ErrorFollowing, EncodeCrossCrate::Yes,
987        "#[rustc_has_incoherent_inherent_impls] allows the addition of incoherent inherent impls for \
988         the given type by annotating all impl items with #[rustc_allow_incoherent_impl]."
989    ),
990
991    BuiltinAttribute {
992        name: sym::rustc_diagnostic_item,
993        // FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`.
994        encode_cross_crate: EncodeCrossCrate::Yes,
995        type_: Normal,
996        safety: AttributeSafety::Normal,
997        template: template!(NameValueStr: "name"),
998        duplicates: ErrorFollowing,
999        gate: Gated(
1000            Stability::Unstable,
1001            sym::rustc_attrs,
1002            "diagnostic items compiler internal support for linting",
1003            Features::rustc_attrs,
1004        ),
1005    },
1006    gated!(
1007        // Used in resolve:
1008        prelude_import, Normal, template!(Word), WarnFollowing,
1009        EncodeCrossCrate::No, "`#[prelude_import]` is for use by rustc only",
1010    ),
1011    gated!(
1012        rustc_paren_sugar, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
1013        unboxed_closures, "unboxed_closures are still evolving",
1014    ),
1015    rustc_attr!(
1016        rustc_inherit_overflow_checks, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
1017        "the `#[rustc_inherit_overflow_checks]` attribute is just used to control \
1018        overflow checking behavior of several libcore functions that are inlined \
1019        across crates and will never be stable",
1020    ),
1021    rustc_attr!(
1022        rustc_reservation_impl, Normal,
1023        template!(NameValueStr: "reservation message"), ErrorFollowing, EncodeCrossCrate::Yes,
1024        "the `#[rustc_reservation_impl]` attribute is internally used \
1025         for reserving for `for<T> From<!> for T` impl"
1026    ),
1027    rustc_attr!(
1028        rustc_test_marker, Normal, template!(NameValueStr: "name"), WarnFollowing,
1029        EncodeCrossCrate::No, "the `#[rustc_test_marker]` attribute is used internally to track tests",
1030    ),
1031    rustc_attr!(
1032        rustc_unsafe_specialization_marker, Normal, template!(Word),
1033        WarnFollowing, EncodeCrossCrate::No,
1034        "the `#[rustc_unsafe_specialization_marker]` attribute is used to check specializations"
1035    ),
1036    rustc_attr!(
1037        rustc_specialization_trait, Normal, template!(Word),
1038        WarnFollowing, EncodeCrossCrate::No,
1039        "the `#[rustc_specialization_trait]` attribute is used to check specializations"
1040    ),
1041    rustc_attr!(
1042        rustc_main, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
1043        "the `#[rustc_main]` attribute is used internally to specify test entry point function",
1044    ),
1045    rustc_attr!(
1046        rustc_skip_during_method_dispatch, Normal, template!(List: "array, boxed_slice"), WarnFollowing,
1047        EncodeCrossCrate::No,
1048        "the `#[rustc_skip_during_method_dispatch]` attribute is used to exclude a trait \
1049        from method dispatch when the receiver is of the following type, for compatibility in \
1050        editions < 2021 (array) or editions < 2024 (boxed_slice)."
1051    ),
1052    rustc_attr!(
1053        rustc_must_implement_one_of, Normal, template!(List: "function1, function2, ..."),
1054        ErrorFollowing, EncodeCrossCrate::No,
1055        "the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete \
1056        definition of a trait, it's currently in experimental form and should be changed before \
1057        being exposed outside of the std"
1058    ),
1059    rustc_attr!(
1060        rustc_doc_primitive, Normal, template!(NameValueStr: "primitive name"), ErrorFollowing,
1061        EncodeCrossCrate::Yes, r#"`rustc_doc_primitive` is a rustc internal attribute"#,
1062    ),
1063    gated!(
1064        rustc_intrinsic, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, intrinsics,
1065        "the `#[rustc_intrinsic]` attribute is used to declare intrinsics as function items",
1066    ),
1067    rustc_attr!(
1068        rustc_no_mir_inline, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes,
1069        "#[rustc_no_mir_inline] prevents the MIR inliner from inlining a function while not affecting codegen"
1070    ),
1071    rustc_attr!(
1072        rustc_force_inline, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing, EncodeCrossCrate::Yes,
1073        "#[rustc_force_inline] forces a free function to be inlined"
1074    ),
1075
1076    // ==========================================================================
1077    // Internal attributes, Testing:
1078    // ==========================================================================
1079
1080    rustc_attr!(TEST, rustc_effective_visibility, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes),
1081    rustc_attr!(
1082        TEST, rustc_outlives, Normal, template!(Word),
1083        WarnFollowing, EncodeCrossCrate::No
1084    ),
1085    rustc_attr!(
1086        TEST, rustc_capture_analysis, Normal, template!(Word),
1087        WarnFollowing, EncodeCrossCrate::No
1088    ),
1089    rustc_attr!(
1090        TEST, rustc_insignificant_dtor, Normal, template!(Word),
1091        WarnFollowing, EncodeCrossCrate::Yes
1092    ),
1093    rustc_attr!(
1094        TEST, rustc_strict_coherence, Normal, template!(Word),
1095        WarnFollowing, EncodeCrossCrate::Yes
1096    ),
1097    rustc_attr!(
1098        TEST, rustc_variance, Normal, template!(Word),
1099        WarnFollowing, EncodeCrossCrate::No
1100    ),
1101    rustc_attr!(
1102        TEST, rustc_variance_of_opaques, Normal, template!(Word),
1103        WarnFollowing, EncodeCrossCrate::No
1104    ),
1105    rustc_attr!(
1106        TEST, rustc_hidden_type_of_opaques, Normal, template!(Word),
1107        WarnFollowing, EncodeCrossCrate::No
1108    ),
1109    rustc_attr!(
1110        TEST, rustc_layout, Normal, template!(List: "field1, field2, ..."),
1111        WarnFollowing, EncodeCrossCrate::Yes
1112    ),
1113    rustc_attr!(
1114        TEST, rustc_abi, Normal, template!(List: "field1, field2, ..."),
1115        WarnFollowing, EncodeCrossCrate::No
1116    ),
1117    rustc_attr!(
1118        TEST, rustc_regions, Normal, template!(Word),
1119        WarnFollowing, EncodeCrossCrate::No
1120    ),
1121    rustc_attr!(
1122        TEST, rustc_delayed_bug_from_inside_query, Normal,
1123        template!(Word),
1124        WarnFollowing, EncodeCrossCrate::No
1125    ),
1126    rustc_attr!(
1127        TEST, rustc_dump_user_args, Normal, template!(Word),
1128        WarnFollowing, EncodeCrossCrate::No
1129    ),
1130    rustc_attr!(
1131        TEST, rustc_evaluate_where_clauses, Normal, template!(Word), WarnFollowing,
1132        EncodeCrossCrate::Yes
1133    ),
1134    rustc_attr!(
1135        TEST, rustc_if_this_changed, Normal, template!(Word, List: "DepNode"), DuplicatesOk,
1136        EncodeCrossCrate::No
1137    ),
1138    rustc_attr!(
1139        TEST, rustc_then_this_would_need, Normal, template!(List: "DepNode"), DuplicatesOk,
1140        EncodeCrossCrate::No
1141    ),
1142    rustc_attr!(
1143        TEST, rustc_clean, Normal,
1144        template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#),
1145        DuplicatesOk, EncodeCrossCrate::No
1146    ),
1147    rustc_attr!(
1148        TEST, rustc_partition_reused, Normal,
1149        template!(List: r#"cfg = "...", module = "...""#), DuplicatesOk, EncodeCrossCrate::No
1150    ),
1151    rustc_attr!(
1152        TEST, rustc_partition_codegened, Normal,
1153        template!(List: r#"cfg = "...", module = "...""#), DuplicatesOk, EncodeCrossCrate::No
1154    ),
1155    rustc_attr!(
1156        TEST, rustc_expected_cgu_reuse, Normal,
1157        template!(List: r#"cfg = "...", module = "...", kind = "...""#), DuplicatesOk,
1158        EncodeCrossCrate::No
1159    ),
1160    rustc_attr!(
1161        TEST, rustc_symbol_name, Normal, template!(Word),
1162        WarnFollowing, EncodeCrossCrate::No
1163    ),
1164    rustc_attr!(
1165        TEST, rustc_def_path, Normal, template!(Word),
1166        WarnFollowing, EncodeCrossCrate::No
1167    ),
1168    rustc_attr!(
1169        TEST, rustc_mir, Normal, template!(List: "arg1, arg2, ..."),
1170        DuplicatesOk, EncodeCrossCrate::Yes
1171    ),
1172    gated!(
1173        custom_mir, Normal, template!(List: r#"dialect = "...", phase = "...""#),
1174        ErrorFollowing, EncodeCrossCrate::No,
1175        "the `#[custom_mir]` attribute is just used for the Rust test suite",
1176    ),
1177    rustc_attr!(
1178        TEST, rustc_dump_item_bounds, Normal, template!(Word),
1179        WarnFollowing, EncodeCrossCrate::No
1180    ),
1181    rustc_attr!(
1182        TEST, rustc_dump_predicates, Normal, template!(Word),
1183        WarnFollowing, EncodeCrossCrate::No
1184    ),
1185    rustc_attr!(
1186        TEST, rustc_dump_def_parents, Normal, template!(Word),
1187        WarnFollowing, EncodeCrossCrate::No
1188    ),
1189    rustc_attr!(
1190        TEST, rustc_object_lifetime_default, Normal, template!(Word),
1191        WarnFollowing, EncodeCrossCrate::No
1192    ),
1193    rustc_attr!(
1194        TEST, rustc_dump_vtable, Normal, template!(Word),
1195        WarnFollowing, EncodeCrossCrate::No
1196    ),
1197    rustc_attr!(
1198        TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/),
1199        DuplicatesOk, EncodeCrossCrate::No
1200    ),
1201    gated!(
1202        omit_gdb_pretty_printer_section, Normal, template!(Word),
1203        WarnFollowing, EncodeCrossCrate::No,
1204        "the `#[omit_gdb_pretty_printer_section]` attribute is just used for the Rust test suite",
1205    ),
1206    rustc_attr!(
1207        TEST, pattern_complexity_limit, CrateLevel, template!(NameValueStr: "N"),
1208        ErrorFollowing, EncodeCrossCrate::No,
1209    ),
1210];
1211
1212pub fn deprecated_attributes() -> Vec<&'static BuiltinAttribute> {
1213    BUILTIN_ATTRIBUTES.iter().filter(|attr| attr.gate.is_deprecated()).collect()
1214}
1215
1216pub fn is_builtin_attr_name(name: Symbol) -> bool {
1217    BUILTIN_ATTRIBUTE_MAP.get(&name).is_some()
1218}
1219
1220/// Whether this builtin attribute is encoded cross crate.
1221/// This means it can be used cross crate.
1222pub fn encode_cross_crate(name: Symbol) -> bool {
1223    if let Some(attr) = BUILTIN_ATTRIBUTE_MAP.get(&name) {
1224        attr.encode_cross_crate == EncodeCrossCrate::Yes
1225    } else {
1226        true
1227    }
1228}
1229
1230pub fn is_valid_for_get_attr(name: Symbol) -> bool {
1231    BUILTIN_ATTRIBUTE_MAP.get(&name).is_some_and(|attr| match attr.duplicates {
1232        WarnFollowing | ErrorFollowing | ErrorPreceding | FutureWarnFollowing
1233        | FutureWarnPreceding => true,
1234        DuplicatesOk | WarnFollowingWordOnly => false,
1235    })
1236}
1237
1238pub static BUILTIN_ATTRIBUTE_MAP: LazyLock<FxHashMap<Symbol, &BuiltinAttribute>> =
1239    LazyLock::new(|| {
1240        let mut map = FxHashMap::default();
1241        for attr in BUILTIN_ATTRIBUTES.iter() {
1242            if map.insert(attr.name, attr).is_some() {
1243                panic!("duplicate builtin attribute `{}`", attr.name);
1244            }
1245        }
1246        map
1247    });
1248
1249pub fn is_stable_diagnostic_attribute(sym: Symbol, _features: &Features) -> bool {
1250    match sym {
1251        sym::on_unimplemented | sym::do_not_recommend => true,
1252        _ => false,
1253    }
1254}