1use 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
18const GATED_CFGS: &[GatedCfg] = &[
20 (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 (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
65pub 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#[derive(Copy, Clone, PartialEq, Debug)]
75pub enum AttributeType {
76 Normal,
79
80 CrateLevel,
82}
83
84#[derive(Copy, Clone, PartialEq, Debug)]
85pub enum AttributeSafety {
86 Normal,
88
89 Unsafe { unsafe_since: Option<Edition> },
95}
96
97#[derive(Clone, Copy)]
98pub enum AttributeGate {
99 Gated(Stability, Symbol, &'static str, fn(&Features) -> bool),
102
103 Ungated,
105}
106
107impl 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#[derive(Clone, Copy, Default)]
128pub struct AttributeTemplate {
129 pub word: bool,
131 pub list: Option<&'static str>,
133 pub one_of: &'static [Symbol],
136 pub name_value_str: Option<&'static str>,
139}
140
141#[derive(Clone, Copy, Default)]
143pub enum AttributeDuplicates {
144 #[default]
151 DuplicatesOk,
152 WarnFollowing,
158 WarnFollowingWordOnly,
164 ErrorFollowing,
170 ErrorPreceding,
176 FutureWarnFollowing,
183 FutureWarnPreceding,
190}
191
192macro_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 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#[rustfmt::skip]
356pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
357 ungated!(cfg, Normal, template!(List: "predicate"), DuplicatesOk, EncodeCrossCrate::Yes),
363 ungated!(cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ..."), DuplicatesOk, EncodeCrossCrate::Yes),
364
365 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 ungated!(
377 reexport_test_harness_main, CrateLevel, template!(NameValueStr: "name"), ErrorFollowing,
378 EncodeCrossCrate::No,
379 ),
380
381 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), 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 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 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 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 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 ungated!(no_main, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No),
484
485 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 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), 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 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 gated!(
541 export_stable, Normal, template!(Word), WarnFollowing,
542 EncodeCrossCrate::No, experimental!(export_stable)
543 ),
544
545 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 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 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 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 gated!(
592 deprecated_safe, Normal, template!(List: r#"since = "version", note = "...""#), ErrorFollowing,
593 EncodeCrossCrate::Yes, experimental!(deprecated_safe),
594 ),
595
596 gated!(
598 cfi_encoding, Normal, template!(NameValueStr: "encoding"), ErrorPreceding,
599 EncodeCrossCrate::Yes, experimental!(cfi_encoding)
600 ),
601
602 gated!(
604 coroutine, Normal, template!(Word), ErrorFollowing,
605 EncodeCrossCrate::No, coroutines, experimental!(coroutine)
606 ),
607
608 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 gated!(
618 type_const, Normal, template!(Word), ErrorFollowing,
619 EncodeCrossCrate::Yes, min_generic_const_args, experimental!(type_const),
620 ),
621
622 ungated!(
627 feature, CrateLevel,
628 template!(List: "name1, name2, ..."), DuplicatesOk, EncodeCrossCrate::No,
629 ),
630 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 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 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 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 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 ungated!(
796 cfg_trace, Normal, template!(Word ), DuplicatesOk,
797 EncodeCrossCrate::No
798 ),
799 ungated!(
800 cfg_attr_trace, Normal, template!(Word ), DuplicatesOk,
801 EncodeCrossCrate::No
802 ),
803
804 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 rustc_attr!(
825 rustc_conversion_suggestion, Normal, template!(Word),
826 WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
827 ),
828 rustc_attr!(
831 rustc_trivial_field_reads, Normal, template!(Word),
832 WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
833 ),
834 rustc_attr!(
837 rustc_lint_query_instability, Normal, template!(Word),
838 WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
839 ),
840 rustc_attr!(
843 rustc_lint_untracked_query_information, Normal, template!(Word),
844 WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
845 ),
846 rustc_attr!(
849 rustc_lint_diagnostics, Normal, template!(Word),
850 WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
851 ),
852 rustc_attr!(
855 rustc_lint_opt_ty, Normal, template!(Word),
856 WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
857 ),
858 rustc_attr!(
861 rustc_lint_opt_deny_field_access, Normal, template!(List: "message"),
862 WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
863 ),
864
865 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 rustc_attr!(
878 rustc_do_not_const_check, Normal, template!(Word), WarnFollowing,
879 EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
880 ),
881 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 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 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 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 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 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 ),
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
1220pub 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}