From f40aa598e97465feb753abbb18268a368ef0118e Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume.gomez@huawei.com>
Date: Tue, 21 Mar 2023 16:43:51 +0100
Subject: [PATCH 1/7] Rename doc(primitive) into rustc_doc_primitive

---
 compiler/rustc_feature/src/active.rs        |  2 +-
 compiler/rustc_feature/src/builtin_attrs.rs |  4 ++++
 compiler/rustc_passes/messages.ftl          |  3 ---
 compiler/rustc_passes/src/check_attr.rs     | 11 -----------
 compiler/rustc_passes/src/errors.rs         |  4 ----
 compiler/rustc_span/src/symbol.rs           |  1 +
 6 files changed, 6 insertions(+), 19 deletions(-)

diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index b7d280b8751..b62da63644d 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -225,7 +225,7 @@ declare_features! (
     (active, rustc_allow_const_fn_unstable, "1.49.0", Some(69399), None),
     /// Allows using compiler's own crates.
     (active, rustc_private, "1.0.0", Some(27812), None),
-    /// Allows using internal rustdoc features like `doc(primitive)` or `doc(keyword)`.
+    /// Allows using internal rustdoc features like `doc(keyword)`.
     (active, rustdoc_internals, "1.58.0", Some(90418), None),
     /// Allows using the `rustdoc::missing_doc_code_examples` lint
     (active, rustdoc_missing_doc_code_examples, "1.31.0", Some(101730), None),
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 493a9cd89e3..c77292fdd16 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -778,6 +778,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         definition of a trait, it's currently in experimental form and should be changed before \
         being exposed outside of the std"
     ),
+    rustc_attr!(
+        rustc_doc_primitive, Normal, template!(NameValueStr: "primitive name"), ErrorFollowing,
+        r#"`rustc_doc_primitive` is a rustc internal attribute"#,
+    ),
 
     // ==========================================================================
     // Internal attributes, Testing:
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index d063b51c8b8..b354dca7cc4 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -148,9 +148,6 @@ passes_doc_test_unknown =
 passes_doc_test_takes_list =
     `#[doc(test(...)]` takes a list of attributes
 
-passes_doc_primitive =
-    `doc(primitive)` should never have been stable
-
 passes_doc_cfg_hide_takes_list =
     `#[doc(cfg_hide(...)]` takes a list of attributes
 
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 1c459edabb8..80a93da2b45 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -1109,17 +1109,6 @@ impl CheckAttrVisitor<'_> {
                             }
                         }
 
-                        sym::primitive => {
-                            if !self.tcx.features().rustdoc_internals {
-                                self.tcx.emit_spanned_lint(
-                                    INVALID_DOC_ATTRIBUTES,
-                                    hir_id,
-                                    i_meta.span,
-                                    errors::DocPrimitive,
-                                );
-                            }
-                        }
-
                         _ => {
                             let path = rustc_ast_pretty::pprust::path_to_string(&i_meta.path);
                             if i_meta.has_name(sym::spotlight) {
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 1b0cd5d91ab..139ba8c9677 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -288,10 +288,6 @@ pub struct DocTestTakesList;
 #[diag(passes_doc_cfg_hide_takes_list)]
 pub struct DocCfgHideTakesList;
 
-#[derive(LintDiagnostic)]
-#[diag(passes_doc_primitive)]
-pub struct DocPrimitive;
-
 #[derive(LintDiagnostic)]
 #[diag(passes_doc_test_unknown_any)]
 pub struct DocTestUnknownAny {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 0ed99353145..f08f84a2a12 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1245,6 +1245,7 @@ symbols! {
         rustc_diagnostic_macros,
         rustc_dirty,
         rustc_do_not_const_check,
+        rustc_doc_primitive,
         rustc_dummy,
         rustc_dump_env_program_clauses,
         rustc_dump_program_clauses,

From 3ef8d2d6075bcac4975b271684ebc6e67c20c83e Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume.gomez@huawei.com>
Date: Tue, 21 Mar 2023 16:44:06 +0100
Subject: [PATCH 2/7] Update tests for rustc_doc_primitive

---
 .../impls/local_for_local_primitive.rs            |  4 ++--
 tests/rustdoc-json/primitives/local_primitive.rs  |  2 +-
 tests/rustdoc-json/primitives/primitive_impls.rs  |  2 +-
 .../primitives/primitive_overloading.rs           |  4 ++--
 tests/rustdoc-json/primitives/use_primitive.rs    |  4 ++--
 tests/rustdoc-ui/coverage/exotic.rs               |  3 ++-
 tests/rustdoc/auto-impl-primitive.rs              |  4 ++--
 tests/rustdoc/auxiliary/issue-15318.rs            |  3 ++-
 tests/rustdoc/auxiliary/primitive-doc.rs          |  3 ++-
 tests/rustdoc/check-source-code-urls-to-def.rs    |  4 ++--
 tests/rustdoc/intra-doc/auxiliary/my-core.rs      |  2 +-
 tests/rustdoc/intra-doc/no-doc-primitive.rs       |  2 +-
 tests/rustdoc/intra-doc/prim-methods-local.rs     |  2 +-
 tests/rustdoc/intra-doc/prim-self.rs              |  2 +-
 tests/rustdoc/issue-15318-3.rs                    |  4 ++--
 tests/rustdoc/issue-23511.rs                      |  2 +-
 .../doc-notable_trait-mut_t_is_not_an_iterator.rs |  4 ++--
 .../doc-notable_trait-mut_t_is_not_ref_t.rs       |  4 ++--
 tests/rustdoc/primitive-reference.rs              |  4 ++--
 tests/rustdoc/primitive-slice-auto-trait.rs       |  4 ++--
 tests/rustdoc/primitive-tuple-auto-trait.rs       |  4 ++--
 tests/rustdoc/primitive-unit-auto-trait.rs        |  4 ++--
 tests/rustdoc/primitive/primitive-generic-impl.rs |  4 ++--
 tests/rustdoc/primitive/primitive.rs              |  6 +++---
 tests/rustdoc/sidebar-all-page.rs                 |  4 ++--
 tests/rustdoc/tab_title.rs                        |  3 ++-
 tests/rustdoc/titles.rs                           |  4 ++--
 tests/ui/rustdoc/feature-gate-doc_primitive.rs    |  6 ++----
 .../ui/rustdoc/feature-gate-doc_primitive.stderr  | 15 +++++++--------
 29 files changed, 57 insertions(+), 56 deletions(-)

diff --git a/tests/rustdoc-json/impls/local_for_local_primitive.rs b/tests/rustdoc-json/impls/local_for_local_primitive.rs
index 38e7e2658df..8383dcc0482 100644
--- a/tests/rustdoc-json/impls/local_for_local_primitive.rs
+++ b/tests/rustdoc-json/impls/local_for_local_primitive.rs
@@ -1,5 +1,5 @@
 #![feature(no_core)]
-#![feature(rustdoc_internals)]
+#![feature(rustc_attrs)]
 #![no_core]
 
 // @set Local = "$.index[*][?(@.name=='Local')].id"
@@ -16,6 +16,6 @@ impl Local for bool {}
 
 // FIXME(#101695): Test bool's `impls` include "Local for bool"
 // @has "$.index[*][?(@.name=='bool')]"
-#[doc(primitive = "bool")]
+#[rustc_doc_primitive = "bool"]
 /// Boolean docs
 mod prim_bool {}
diff --git a/tests/rustdoc-json/primitives/local_primitive.rs b/tests/rustdoc-json/primitives/local_primitive.rs
index f27e6a2adec..0cf479faf29 100644
--- a/tests/rustdoc-json/primitives/local_primitive.rs
+++ b/tests/rustdoc-json/primitives/local_primitive.rs
@@ -8,7 +8,7 @@
 
 //! Link to [i32][prim@i32] [i64][prim@i64]
 
-#[doc(primitive = "i32")]
+#[rustc_doc_primitive = "i32"]
 mod prim_i32 {}
 
 // @set local_i32 = "$.index[*][?(@.name=='i32')].id"
diff --git a/tests/rustdoc-json/primitives/primitive_impls.rs b/tests/rustdoc-json/primitives/primitive_impls.rs
index 1fc9374065f..85d179ee45f 100644
--- a/tests/rustdoc-json/primitives/primitive_impls.rs
+++ b/tests/rustdoc-json/primitives/primitive_impls.rs
@@ -25,7 +25,7 @@ pub trait Trait {}
 impl Trait for i32 {}
 
 /// i32
-#[doc(primitive = "i32")]
+#[rustc_doc_primitive = "i32"]
 mod prim_i32 {}
 
 // @set i32 = "$.index[*][?(@.docs=='i32')].id"
diff --git a/tests/rustdoc-json/primitives/primitive_overloading.rs b/tests/rustdoc-json/primitives/primitive_overloading.rs
index 56b35cd14c0..81e0acdc6e9 100644
--- a/tests/rustdoc-json/primitives/primitive_overloading.rs
+++ b/tests/rustdoc-json/primitives/primitive_overloading.rs
@@ -2,7 +2,7 @@
 
 // Regression test for <https://github.com/rust-lang/rust/issues/98006>.
 
-#![feature(rustdoc_internals)]
+#![feature(rustc_attrs)]
 #![feature(no_core)]
 
 #![no_core]
@@ -10,7 +10,7 @@
 // @has "$.index[*][?(@.name=='usize')]"
 // @has "$.index[*][?(@.name=='prim')]"
 
-#[doc(primitive = "usize")]
+#[rustc_doc_primitive = "usize"]
 /// This is the built-in type `usize`.
 mod prim {
 }
diff --git a/tests/rustdoc-json/primitives/use_primitive.rs b/tests/rustdoc-json/primitives/use_primitive.rs
index e2292737462..5180a804f07 100644
--- a/tests/rustdoc-json/primitives/use_primitive.rs
+++ b/tests/rustdoc-json/primitives/use_primitive.rs
@@ -1,8 +1,8 @@
 // edition:2018
 
-#![feature(rustdoc_internals)]
+#![feature(rustc_attrs)]
 
-#[doc(primitive = "usize")]
+#[rustc_doc_primitive = "usize"]
 mod usize {}
 
 // @set local_crate_id = "$.index[*][?(@.name=='use_primitive')].crate_id"
diff --git a/tests/rustdoc-ui/coverage/exotic.rs b/tests/rustdoc-ui/coverage/exotic.rs
index 72b70d6980b..f45405fbf5d 100644
--- a/tests/rustdoc-ui/coverage/exotic.rs
+++ b/tests/rustdoc-ui/coverage/exotic.rs
@@ -2,12 +2,13 @@
 // check-pass
 
 #![feature(rustdoc_internals)]
+#![feature(rustc_attrs)]
 
 //! the features only used in std also have entries in the table, so make sure those get pulled out
 //! properly as well
 
 /// woo, check it out, we can write our own primitive docs lol
-#[doc(primitive="unit")]
+#[rustc_doc_primitive = "unit"]
 mod prim_unit {}
 
 /// keywords? sure, pile them on
diff --git a/tests/rustdoc/auto-impl-primitive.rs b/tests/rustdoc/auto-impl-primitive.rs
index 172333d445d..a6db93dbc33 100644
--- a/tests/rustdoc/auto-impl-primitive.rs
+++ b/tests/rustdoc/auto-impl-primitive.rs
@@ -1,10 +1,10 @@
-#![feature(rustdoc_internals)]
+#![feature(rustc_attrs)]
 
 #![crate_name = "foo"]
 
 pub use std::fs::File;
 
 // @has 'foo/primitive.i16.html' '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementation'
-#[doc(primitive = "i16")]
+#[rustc_doc_primitive = "i16"]
 /// I love poneys!
 mod prim {}
diff --git a/tests/rustdoc/auxiliary/issue-15318.rs b/tests/rustdoc/auxiliary/issue-15318.rs
index 695fa58ef1d..a2f426c6352 100644
--- a/tests/rustdoc/auxiliary/issue-15318.rs
+++ b/tests/rustdoc/auxiliary/issue-15318.rs
@@ -2,6 +2,7 @@
 // compile-flags: -Cmetadata=aux
 #![crate_type = "rlib"]
 #![doc(html_root_url = "http://example.com/")]
+#![feature(rustc_attrs)]
 #![feature(lang_items)]
 #![no_std]
 
@@ -12,5 +13,5 @@ fn foo() {}
 fn bar(_: &core::panic::PanicInfo) -> ! { loop {} }
 
 /// dox
-#[doc(primitive = "pointer")]
+#[rustc_doc_primitive = "pointer"]
 pub mod ptr {}
diff --git a/tests/rustdoc/auxiliary/primitive-doc.rs b/tests/rustdoc/auxiliary/primitive-doc.rs
index e8da852a57e..d1785e42391 100644
--- a/tests/rustdoc/auxiliary/primitive-doc.rs
+++ b/tests/rustdoc/auxiliary/primitive-doc.rs
@@ -1,9 +1,10 @@
 // compile-flags: --crate-type lib --edition 2018
 
+#![feature(rustc_attrs)]
 #![feature(no_core)]
 #![no_core]
 
-#[doc(primitive = "usize")]
+#[rustc_doc_primitive = "usize"]
 /// This is the built-in type `usize`.
 mod usize {
 }
diff --git a/tests/rustdoc/check-source-code-urls-to-def.rs b/tests/rustdoc/check-source-code-urls-to-def.rs
index 5959f9c7c59..41b9d41fa44 100644
--- a/tests/rustdoc/check-source-code-urls-to-def.rs
+++ b/tests/rustdoc/check-source-code-urls-to-def.rs
@@ -2,7 +2,7 @@
 // aux-build:source_code.rs
 // build-aux-docs
 
-#![feature(rustdoc_internals)]
+#![feature(rustc_attrs)]
 
 #![crate_name = "foo"]
 
@@ -65,5 +65,5 @@ pub fn foo4() {
 }
 
 // @has - '//pre[@class="rust"]//a[@href="../../foo/primitive.bool.html"]' 'bool'
-#[doc(primitive = "bool")]
+#[rustc_doc_primitive = "bool"]
 mod whatever {}
diff --git a/tests/rustdoc/intra-doc/auxiliary/my-core.rs b/tests/rustdoc/intra-doc/auxiliary/my-core.rs
index e22feb03ae6..c050929db96 100644
--- a/tests/rustdoc/intra-doc/auxiliary/my-core.rs
+++ b/tests/rustdoc/intra-doc/auxiliary/my-core.rs
@@ -3,7 +3,7 @@
 #![rustc_coherence_is_core]
 #![crate_type="rlib"]
 
-#[doc(primitive = "char")]
+#[rustc_doc_primitive = "char"]
 /// Some char docs
 mod char {}
 
diff --git a/tests/rustdoc/intra-doc/no-doc-primitive.rs b/tests/rustdoc/intra-doc/no-doc-primitive.rs
index e5eba1d8d48..711ac09ba9a 100644
--- a/tests/rustdoc/intra-doc/no-doc-primitive.rs
+++ b/tests/rustdoc/intra-doc/no-doc-primitive.rs
@@ -1,4 +1,4 @@
-// Crate tree without a `doc(primitive)` module for primitive type linked to by a doc link.
+// Crate tree without a `rustc_doc_primitive` module for primitive type linked to by a doc link.
 
 #![deny(rustdoc::broken_intra_doc_links)]
 #![feature(no_core, lang_items, rustc_attrs)]
diff --git a/tests/rustdoc/intra-doc/prim-methods-local.rs b/tests/rustdoc/intra-doc/prim-methods-local.rs
index 79d8df04515..6de4ec1802f 100644
--- a/tests/rustdoc/intra-doc/prim-methods-local.rs
+++ b/tests/rustdoc/intra-doc/prim-methods-local.rs
@@ -10,7 +10,7 @@
 
 //! A [prim@`char`] and its [`char::len_utf8`].
 
-#[doc(primitive = "char")]
+#[rustc_doc_primitive = "char"]
 mod char {}
 
 impl char {
diff --git a/tests/rustdoc/intra-doc/prim-self.rs b/tests/rustdoc/intra-doc/prim-self.rs
index c7ce71b15f3..d13858a53cf 100644
--- a/tests/rustdoc/intra-doc/prim-self.rs
+++ b/tests/rustdoc/intra-doc/prim-self.rs
@@ -25,7 +25,7 @@ impl usize {
     pub type ME = usize;
 }
 
-#[doc(primitive = "usize")]
+#[rustc_doc_primitive = "usize"]
 /// This has some docs.
 mod usize {}
 
diff --git a/tests/rustdoc/issue-15318-3.rs b/tests/rustdoc/issue-15318-3.rs
index 2fadc26b006..2dab8f94883 100644
--- a/tests/rustdoc/issue-15318-3.rs
+++ b/tests/rustdoc/issue-15318-3.rs
@@ -1,7 +1,7 @@
-#![feature(rustdoc_internals)]
+#![feature(rustc_attrs)]
 
 // @has issue_15318_3/primitive.pointer.html
 
 /// dox
-#[doc(primitive = "pointer")]
+#[rustc_doc_primitive = "pointer"]
 pub mod ptr {}
diff --git a/tests/rustdoc/issue-23511.rs b/tests/rustdoc/issue-23511.rs
index 7576ebb0305..21d02842431 100644
--- a/tests/rustdoc/issue-23511.rs
+++ b/tests/rustdoc/issue-23511.rs
@@ -3,7 +3,7 @@
 #![no_std]
 
 pub mod str {
-    #![doc(primitive = "str")]
+    #![rustc_doc_primitive = "str"]
 
     impl str {
         // @hasraw search-index.js foo
diff --git a/tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs b/tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs
index bfce46cf444..5af5f7616b5 100644
--- a/tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs
+++ b/tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs
@@ -6,10 +6,10 @@
 //!
 //! [#80737]: https://github.com/rust-lang/rust/issues/80737
 
-#![feature(rustdoc_internals)]
+#![feature(rustc_attrs)]
 #![no_std]
 
-#[doc(primitive = "reference")]
+#[rustc_doc_primitive = "reference"]
 /// Some useless docs, wouhou!
 ///
 /// We need to put this in here, because notable traits
diff --git a/tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs b/tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs
index b359dcea0ff..6c980aaa2b1 100644
--- a/tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs
+++ b/tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs
@@ -5,9 +5,9 @@
 //!
 //! [#78160]: https://github.com/rust-lang/rust/issues/78160
 
-#![feature(rustdoc_internals)]
+#![feature(rustc_attrs)]
 
-#[doc(primitive = "reference")]
+#[rustc_doc_primitive = "reference"]
 /// Some useless docs, wouhou!
 ///
 /// We need to put this in here, because notable traits
diff --git a/tests/rustdoc/primitive-reference.rs b/tests/rustdoc/primitive-reference.rs
index 10efbefd2b1..6f034224df5 100644
--- a/tests/rustdoc/primitive-reference.rs
+++ b/tests/rustdoc/primitive-reference.rs
@@ -1,6 +1,6 @@
 #![crate_name = "foo"]
 
-#![feature(rustdoc_internals)]
+#![feature(rustc_attrs)]
 
 // @has foo/index.html
 // @has - '//h2[@id="primitives"]' 'Primitive Types'
@@ -16,7 +16,7 @@
 // @count - '//*[@class="impl"]' 1
 // @has - '//*[@id="impl-Foo%3C%26A%3E-for-%26B"]/*[@class="code-header"]' \
 //        'impl<A, B> Foo<&A> for &B'
-#[doc(primitive = "reference")]
+#[rustc_doc_primitive = "reference"]
 /// this is a test!
 mod reference {}
 
diff --git a/tests/rustdoc/primitive-slice-auto-trait.rs b/tests/rustdoc/primitive-slice-auto-trait.rs
index 77922414676..ba15a73ca1d 100644
--- a/tests/rustdoc/primitive-slice-auto-trait.rs
+++ b/tests/rustdoc/primitive-slice-auto-trait.rs
@@ -1,7 +1,7 @@
 // compile-flags: --crate-type lib --edition 2018
 
 #![crate_name = "foo"]
-#![feature(rustdoc_internals)]
+#![feature(rustc_attrs)]
 
 // @has foo/primitive.slice.html '//a[@class="primitive"]' 'slice'
 // @has - '//h1' 'Primitive Type slice'
@@ -9,6 +9,6 @@
 // @has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
 // @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Send for [T]where T: Send'
 // @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Sync for [T]where T: Sync'
-#[doc(primitive = "slice")]
+#[rustc_doc_primitive = "slice"]
 /// this is a test!
 mod slice_prim {}
diff --git a/tests/rustdoc/primitive-tuple-auto-trait.rs b/tests/rustdoc/primitive-tuple-auto-trait.rs
index 4344d24f986..2b407b586a3 100644
--- a/tests/rustdoc/primitive-tuple-auto-trait.rs
+++ b/tests/rustdoc/primitive-tuple-auto-trait.rs
@@ -1,7 +1,7 @@
 // compile-flags: --crate-type lib --edition 2018
 
 #![crate_name = "foo"]
-#![feature(rustdoc_internals)]
+#![feature(rustc_attrs)]
 
 // @has foo/primitive.tuple.html '//a[@class="primitive"]' 'tuple'
 // @has - '//h1' 'Primitive Type tuple'
@@ -9,7 +9,7 @@
 // @has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
 // @has - '//div[@id="synthetic-implementations-list"]//h3' 'Send'
 // @has - '//div[@id="synthetic-implementations-list"]//h3' 'Sync'
-#[doc(primitive = "tuple")]
+#[rustc_doc_primitive = "tuple"]
 /// this is a test!
 ///
 // Hardcoded anchor to header written in library/core/src/primitive_docs.rs
diff --git a/tests/rustdoc/primitive-unit-auto-trait.rs b/tests/rustdoc/primitive-unit-auto-trait.rs
index 61850e2462d..5a56f1fd83b 100644
--- a/tests/rustdoc/primitive-unit-auto-trait.rs
+++ b/tests/rustdoc/primitive-unit-auto-trait.rs
@@ -1,7 +1,7 @@
 // compile-flags: --crate-type lib --edition 2018
 
 #![crate_name = "foo"]
-#![feature(rustdoc_internals)]
+#![feature(rustc_attrs)]
 
 // @has foo/primitive.unit.html '//a[@class="primitive"]' 'unit'
 // @has - '//h1' 'Primitive Type unit'
@@ -9,6 +9,6 @@
 // @has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
 // @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl Send for ()'
 // @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl Sync for ()'
-#[doc(primitive = "unit")]
+#[rustc_doc_primitive = "unit"]
 /// this is a test!
 mod unit_prim {}
diff --git a/tests/rustdoc/primitive/primitive-generic-impl.rs b/tests/rustdoc/primitive/primitive-generic-impl.rs
index 7b336b39810..2da8ae6ff38 100644
--- a/tests/rustdoc/primitive/primitive-generic-impl.rs
+++ b/tests/rustdoc/primitive/primitive-generic-impl.rs
@@ -1,8 +1,8 @@
-#![feature(rustdoc_internals)]
+#![feature(rustc_attrs)]
 #![crate_name = "foo"]
 
 // @has foo/primitive.i32.html '//*[@id="impl-ToString-for-i32"]//h3[@class="code-header"]' 'impl<T> ToString for T'
 
-#[doc(primitive = "i32")]
+#[rustc_doc_primitive = "i32"]
 /// Some useless docs, wouhou!
 mod i32 {}
diff --git a/tests/rustdoc/primitive/primitive.rs b/tests/rustdoc/primitive/primitive.rs
index 516c7c0c6fe..32af2636c18 100644
--- a/tests/rustdoc/primitive/primitive.rs
+++ b/tests/rustdoc/primitive/primitive.rs
@@ -1,6 +1,6 @@
 #![crate_name = "foo"]
 
-#![feature(rustdoc_internals)]
+#![feature(rustc_attrs)]
 
 // @has foo/index.html '//h2[@id="primitives"]' 'Primitive Types'
 // @has foo/index.html '//a[@href="primitive.i32.html"]' 'i32'
@@ -11,11 +11,11 @@
 // @has foo/primitive.i32.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
 // @has foo/index.html '//a/@href' '../foo/index.html'
 // @!has foo/index.html '//span' '🔒'
-#[doc(primitive = "i32")]
+#[rustc_doc_primitive = "i32"]
 /// this is a test!
 mod i32{}
 
 // @has foo/primitive.bool.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'hello'
-#[doc(primitive = "bool")]
+#[rustc_doc_primitive = "bool"]
 /// hello
 mod bool {}
diff --git a/tests/rustdoc/sidebar-all-page.rs b/tests/rustdoc/sidebar-all-page.rs
index e74b981de64..45a6ba8ed2e 100644
--- a/tests/rustdoc/sidebar-all-page.rs
+++ b/tests/rustdoc/sidebar-all-page.rs
@@ -1,6 +1,6 @@
 #![crate_name = "foo"]
 
-#![feature(rustdoc_internals)]
+#![feature(rustc_attrs)]
 
 // @has 'foo/all.html'
 // @has - '//*[@class="sidebar-elems"]//li' 'Structs'
@@ -31,5 +31,5 @@ macro_rules! foo {
 pub type Type = u8;
 pub const FOO: u8 = 0;
 pub static BAR: u8 = 0;
-#[doc(primitive = "u8")]
+#[rustc_doc_primitive = "u8"]
 mod u8 {}
diff --git a/tests/rustdoc/tab_title.rs b/tests/rustdoc/tab_title.rs
index 0cc4f147e1c..8d781b40e46 100644
--- a/tests/rustdoc/tab_title.rs
+++ b/tests/rustdoc/tab_title.rs
@@ -1,4 +1,5 @@
 #![crate_name = "foo"]
+#![feature(rustc_attrs)]
 #![feature(rustdoc_internals)]
 
 // tests for the html <title> element
@@ -39,6 +40,6 @@ mod continue_keyword {}
 
 // @has foo/primitive.u8.html '//head/title' 'u8 - Rust'
 // @!has - '//head/title' 'foo'
-#[doc(primitive = "u8")]
+#[rustc_doc_primitive = "u8"]
 /// `u8` docs
 mod u8 {}
diff --git a/tests/rustdoc/titles.rs b/tests/rustdoc/titles.rs
index 69e8b856b0a..e1feb1cd64f 100644
--- a/tests/rustdoc/titles.rs
+++ b/tests/rustdoc/titles.rs
@@ -1,5 +1,5 @@
 #![crate_name = "foo"]
-#![feature(rustdoc_internals)]
+#![feature(rustc_attrs)]
 
 // @matches 'foo/index.html' '//h1' 'Crate foo'
 // @matches 'foo/index.html' '//h2[@class="location"]' 'Crate foo'
@@ -41,7 +41,7 @@ macro_rules! foo_macro {
 }
 
 // @matches 'foo/primitive.bool.html' '//h1' 'Primitive Type bool'
-#[doc(primitive = "bool")]
+#[rustc_doc_primitive = "bool"]
 mod bool {}
 
 // @matches 'foo/static.FOO_STATIC.html' '//h1' 'Static foo::FOO_STATIC'
diff --git a/tests/ui/rustdoc/feature-gate-doc_primitive.rs b/tests/ui/rustdoc/feature-gate-doc_primitive.rs
index 18e99e72f8b..78fcd90752e 100644
--- a/tests/ui/rustdoc/feature-gate-doc_primitive.rs
+++ b/tests/ui/rustdoc/feature-gate-doc_primitive.rs
@@ -1,7 +1,5 @@
-// check-pass
-#[doc(primitive = "usize")]
-//~^ WARNING `doc(primitive)` should never have been stable
-//~| WARNING hard error in a future release
+#[rustc_doc_primitive = "usize"]
+//~^ ERROR `rustc_doc_primitive` is a rustc internal attribute
 /// Some docs
 mod usize {}
 
diff --git a/tests/ui/rustdoc/feature-gate-doc_primitive.stderr b/tests/ui/rustdoc/feature-gate-doc_primitive.stderr
index 194b2d87db2..5920880675d 100644
--- a/tests/ui/rustdoc/feature-gate-doc_primitive.stderr
+++ b/tests/ui/rustdoc/feature-gate-doc_primitive.stderr
@@ -1,12 +1,11 @@
-warning: `doc(primitive)` should never have been stable
-  --> $DIR/feature-gate-doc_primitive.rs:2:7
+error[E0658]: `rustc_doc_primitive` is a rustc internal attribute
+  --> $DIR/feature-gate-doc_primitive.rs:1:1
    |
-LL | #[doc(primitive = "usize")]
-   |       ^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_doc_primitive = "usize"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
-   = note: `#[warn(invalid_doc_attributes)]` on by default
+   = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
 
-warning: 1 warning emitted
+error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0658`.

From 364e961417c4308f8a1d3b7ec69ead9d98af2a01 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume.gomez@huawei.com>
Date: Tue, 21 Mar 2023 16:52:59 +0100
Subject: [PATCH 3/7] Replace doc(primitive) with rustc_doc_primitive

---
 library/core/src/primitive_docs.rs            | 75 ++++++++++++-------
 library/std/src/primitive_docs.rs             | 75 ++++++++++++-------
 src/librustdoc/clean/types.rs                 | 37 +++++----
 src/librustdoc/json/conversions.rs            |  4 +-
 src/librustdoc/json/mod.rs                    |  2 +-
 .../passes/collect_intra_doc_links.rs         |  6 +-
 6 files changed, 123 insertions(+), 76 deletions(-)

diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs
index e12a3e378a6..bf8339335dd 100644
--- a/library/core/src/primitive_docs.rs
+++ b/library/core/src/primitive_docs.rs
@@ -1,7 +1,8 @@
 // `library/{std,core}/src/primitive_docs.rs` should have the same contents.
 // These are different files so that relative links work properly without
 // having to have `CARGO_PKG_NAME` set, but conceptually they should always be the same.
-#[doc(primitive = "bool")]
+#[cfg_attr(bootstrap, doc(primitive = "bool"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "bool")]
 #[doc(alias = "true")]
 #[doc(alias = "false")]
 /// The boolean type.
@@ -63,7 +64,8 @@
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_bool {}
 
-#[doc(primitive = "never")]
+#[cfg_attr(bootstrap, doc(primitive = "never"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "never")]
 #[doc(alias = "!")]
 //
 /// The `!` type, also called "never".
@@ -274,7 +276,8 @@ mod prim_bool {}
 #[unstable(feature = "never_type", issue = "35121")]
 mod prim_never {}
 
-#[doc(primitive = "char")]
+#[cfg_attr(bootstrap, doc(primitive = "char"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "char")]
 #[allow(rustdoc::invalid_rust_codeblocks)]
 /// A character type.
 ///
@@ -398,7 +401,8 @@ mod prim_never {}
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_char {}
 
-#[doc(primitive = "unit")]
+#[cfg_attr(bootstrap, doc(primitive = "unit"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "unit")]
 #[doc(alias = "(")]
 #[doc(alias = ")")]
 #[doc(alias = "()")]
@@ -460,7 +464,8 @@ impl Copy for () {
     // empty
 }
 
-#[doc(primitive = "pointer")]
+#[cfg_attr(bootstrap, doc(primitive = "pointer"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "pointer")]
 #[doc(alias = "ptr")]
 #[doc(alias = "*")]
 #[doc(alias = "*const")]
@@ -577,7 +582,8 @@ impl Copy for () {
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_pointer {}
 
-#[doc(primitive = "array")]
+#[cfg_attr(bootstrap, doc(primitive = "array"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "array")]
 #[doc(alias = "[]")]
 #[doc(alias = "[T;N]")] // unfortunately, rustdoc doesn't have fuzzy search for aliases
 #[doc(alias = "[T; N]")]
@@ -778,7 +784,8 @@ mod prim_pointer {}
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_array {}
 
-#[doc(primitive = "slice")]
+#[cfg_attr(bootstrap, doc(primitive = "slice"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "slice")]
 #[doc(alias = "[")]
 #[doc(alias = "]")]
 #[doc(alias = "[]")]
@@ -870,7 +877,8 @@ mod prim_array {}
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_slice {}
 
-#[doc(primitive = "str")]
+#[cfg_attr(bootstrap, doc(primitive = "str"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "str")]
 /// String slices.
 ///
 /// *[See also the `std::str` module](crate::str).*
@@ -937,7 +945,8 @@ mod prim_slice {}
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_str {}
 
-#[doc(primitive = "tuple")]
+#[cfg_attr(bootstrap, doc(primitive = "tuple"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "tuple")]
 #[doc(alias = "(")]
 #[doc(alias = ")")]
 #[doc(alias = "()")]
@@ -1081,7 +1090,8 @@ impl<T: Copy> Copy for (T,) {
     // empty
 }
 
-#[doc(primitive = "f32")]
+#[cfg_attr(bootstrap, doc(primitive = "f32"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "f32")]
 /// A 32-bit floating point type (specifically, the "binary32" type defined in IEEE 754-2008).
 ///
 /// This type can represent a wide range of decimal numbers, like `3.5`, `27`,
@@ -1147,7 +1157,8 @@ impl<T: Copy> Copy for (T,) {
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_f32 {}
 
-#[doc(primitive = "f64")]
+#[cfg_attr(bootstrap, doc(primitive = "f64"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "f64")]
 /// A 64-bit floating point type (specifically, the "binary64" type defined in IEEE 754-2008).
 ///
 /// This type is very similar to [`f32`], but has increased
@@ -1162,67 +1173,78 @@ mod prim_f32 {}
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_f64 {}
 
-#[doc(primitive = "i8")]
+#[cfg_attr(bootstrap, doc(primitive = "i8"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "i8")]
 //
 /// The 8-bit signed integer type.
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_i8 {}
 
-#[doc(primitive = "i16")]
+#[cfg_attr(bootstrap, doc(primitive = "i16"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "i16")]
 //
 /// The 16-bit signed integer type.
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_i16 {}
 
-#[doc(primitive = "i32")]
+#[cfg_attr(bootstrap, doc(primitive = "i32"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "i32")]
 //
 /// The 32-bit signed integer type.
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_i32 {}
 
-#[doc(primitive = "i64")]
+#[cfg_attr(bootstrap, doc(primitive = "i64"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "i64")]
 //
 /// The 64-bit signed integer type.
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_i64 {}
 
-#[doc(primitive = "i128")]
+#[cfg_attr(bootstrap, doc(primitive = "i128"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "i128")]
 //
 /// The 128-bit signed integer type.
 #[stable(feature = "i128", since = "1.26.0")]
 mod prim_i128 {}
 
-#[doc(primitive = "u8")]
+#[cfg_attr(bootstrap, doc(primitive = "u8"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "u8")]
 //
 /// The 8-bit unsigned integer type.
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_u8 {}
 
-#[doc(primitive = "u16")]
+#[cfg_attr(bootstrap, doc(primitive = "u16"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "u16")]
 //
 /// The 16-bit unsigned integer type.
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_u16 {}
 
-#[doc(primitive = "u32")]
+#[cfg_attr(bootstrap, doc(primitive = "u32"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "u32")]
 //
 /// The 32-bit unsigned integer type.
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_u32 {}
 
-#[doc(primitive = "u64")]
+#[cfg_attr(bootstrap, doc(primitive = "u64"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "u64")]
 //
 /// The 64-bit unsigned integer type.
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_u64 {}
 
-#[doc(primitive = "u128")]
+#[cfg_attr(bootstrap, doc(primitive = "u128"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "u128")]
 //
 /// The 128-bit unsigned integer type.
 #[stable(feature = "i128", since = "1.26.0")]
 mod prim_u128 {}
 
-#[doc(primitive = "isize")]
+#[cfg_attr(bootstrap, doc(primitive = "isize"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "isize")]
 //
 /// The pointer-sized signed integer type.
 ///
@@ -1232,7 +1254,8 @@ mod prim_u128 {}
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_isize {}
 
-#[doc(primitive = "usize")]
+#[cfg_attr(bootstrap, doc(primitive = "usize"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "usize")]
 //
 /// The pointer-sized unsigned integer type.
 ///
@@ -1242,7 +1265,8 @@ mod prim_isize {}
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_usize {}
 
-#[doc(primitive = "reference")]
+#[cfg_attr(bootstrap, doc(primitive = "reference"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "reference")]
 #[doc(alias = "&")]
 #[doc(alias = "&mut")]
 //
@@ -1373,7 +1397,8 @@ mod prim_usize {}
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_ref {}
 
-#[doc(primitive = "fn")]
+#[cfg_attr(bootstrap, doc(primitive = "fn"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "fn")]
 //
 /// Function pointers, like `fn(usize) -> bool`.
 ///
diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs
index e12a3e378a6..bf8339335dd 100644
--- a/library/std/src/primitive_docs.rs
+++ b/library/std/src/primitive_docs.rs
@@ -1,7 +1,8 @@
 // `library/{std,core}/src/primitive_docs.rs` should have the same contents.
 // These are different files so that relative links work properly without
 // having to have `CARGO_PKG_NAME` set, but conceptually they should always be the same.
-#[doc(primitive = "bool")]
+#[cfg_attr(bootstrap, doc(primitive = "bool"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "bool")]
 #[doc(alias = "true")]
 #[doc(alias = "false")]
 /// The boolean type.
@@ -63,7 +64,8 @@
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_bool {}
 
-#[doc(primitive = "never")]
+#[cfg_attr(bootstrap, doc(primitive = "never"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "never")]
 #[doc(alias = "!")]
 //
 /// The `!` type, also called "never".
@@ -274,7 +276,8 @@ mod prim_bool {}
 #[unstable(feature = "never_type", issue = "35121")]
 mod prim_never {}
 
-#[doc(primitive = "char")]
+#[cfg_attr(bootstrap, doc(primitive = "char"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "char")]
 #[allow(rustdoc::invalid_rust_codeblocks)]
 /// A character type.
 ///
@@ -398,7 +401,8 @@ mod prim_never {}
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_char {}
 
-#[doc(primitive = "unit")]
+#[cfg_attr(bootstrap, doc(primitive = "unit"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "unit")]
 #[doc(alias = "(")]
 #[doc(alias = ")")]
 #[doc(alias = "()")]
@@ -460,7 +464,8 @@ impl Copy for () {
     // empty
 }
 
-#[doc(primitive = "pointer")]
+#[cfg_attr(bootstrap, doc(primitive = "pointer"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "pointer")]
 #[doc(alias = "ptr")]
 #[doc(alias = "*")]
 #[doc(alias = "*const")]
@@ -577,7 +582,8 @@ impl Copy for () {
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_pointer {}
 
-#[doc(primitive = "array")]
+#[cfg_attr(bootstrap, doc(primitive = "array"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "array")]
 #[doc(alias = "[]")]
 #[doc(alias = "[T;N]")] // unfortunately, rustdoc doesn't have fuzzy search for aliases
 #[doc(alias = "[T; N]")]
@@ -778,7 +784,8 @@ mod prim_pointer {}
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_array {}
 
-#[doc(primitive = "slice")]
+#[cfg_attr(bootstrap, doc(primitive = "slice"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "slice")]
 #[doc(alias = "[")]
 #[doc(alias = "]")]
 #[doc(alias = "[]")]
@@ -870,7 +877,8 @@ mod prim_array {}
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_slice {}
 
-#[doc(primitive = "str")]
+#[cfg_attr(bootstrap, doc(primitive = "str"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "str")]
 /// String slices.
 ///
 /// *[See also the `std::str` module](crate::str).*
@@ -937,7 +945,8 @@ mod prim_slice {}
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_str {}
 
-#[doc(primitive = "tuple")]
+#[cfg_attr(bootstrap, doc(primitive = "tuple"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "tuple")]
 #[doc(alias = "(")]
 #[doc(alias = ")")]
 #[doc(alias = "()")]
@@ -1081,7 +1090,8 @@ impl<T: Copy> Copy for (T,) {
     // empty
 }
 
-#[doc(primitive = "f32")]
+#[cfg_attr(bootstrap, doc(primitive = "f32"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "f32")]
 /// A 32-bit floating point type (specifically, the "binary32" type defined in IEEE 754-2008).
 ///
 /// This type can represent a wide range of decimal numbers, like `3.5`, `27`,
@@ -1147,7 +1157,8 @@ impl<T: Copy> Copy for (T,) {
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_f32 {}
 
-#[doc(primitive = "f64")]
+#[cfg_attr(bootstrap, doc(primitive = "f64"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "f64")]
 /// A 64-bit floating point type (specifically, the "binary64" type defined in IEEE 754-2008).
 ///
 /// This type is very similar to [`f32`], but has increased
@@ -1162,67 +1173,78 @@ mod prim_f32 {}
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_f64 {}
 
-#[doc(primitive = "i8")]
+#[cfg_attr(bootstrap, doc(primitive = "i8"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "i8")]
 //
 /// The 8-bit signed integer type.
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_i8 {}
 
-#[doc(primitive = "i16")]
+#[cfg_attr(bootstrap, doc(primitive = "i16"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "i16")]
 //
 /// The 16-bit signed integer type.
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_i16 {}
 
-#[doc(primitive = "i32")]
+#[cfg_attr(bootstrap, doc(primitive = "i32"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "i32")]
 //
 /// The 32-bit signed integer type.
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_i32 {}
 
-#[doc(primitive = "i64")]
+#[cfg_attr(bootstrap, doc(primitive = "i64"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "i64")]
 //
 /// The 64-bit signed integer type.
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_i64 {}
 
-#[doc(primitive = "i128")]
+#[cfg_attr(bootstrap, doc(primitive = "i128"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "i128")]
 //
 /// The 128-bit signed integer type.
 #[stable(feature = "i128", since = "1.26.0")]
 mod prim_i128 {}
 
-#[doc(primitive = "u8")]
+#[cfg_attr(bootstrap, doc(primitive = "u8"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "u8")]
 //
 /// The 8-bit unsigned integer type.
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_u8 {}
 
-#[doc(primitive = "u16")]
+#[cfg_attr(bootstrap, doc(primitive = "u16"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "u16")]
 //
 /// The 16-bit unsigned integer type.
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_u16 {}
 
-#[doc(primitive = "u32")]
+#[cfg_attr(bootstrap, doc(primitive = "u32"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "u32")]
 //
 /// The 32-bit unsigned integer type.
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_u32 {}
 
-#[doc(primitive = "u64")]
+#[cfg_attr(bootstrap, doc(primitive = "u64"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "u64")]
 //
 /// The 64-bit unsigned integer type.
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_u64 {}
 
-#[doc(primitive = "u128")]
+#[cfg_attr(bootstrap, doc(primitive = "u128"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "u128")]
 //
 /// The 128-bit unsigned integer type.
 #[stable(feature = "i128", since = "1.26.0")]
 mod prim_u128 {}
 
-#[doc(primitive = "isize")]
+#[cfg_attr(bootstrap, doc(primitive = "isize"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "isize")]
 //
 /// The pointer-sized signed integer type.
 ///
@@ -1232,7 +1254,8 @@ mod prim_u128 {}
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_isize {}
 
-#[doc(primitive = "usize")]
+#[cfg_attr(bootstrap, doc(primitive = "usize"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "usize")]
 //
 /// The pointer-sized unsigned integer type.
 ///
@@ -1242,7 +1265,8 @@ mod prim_isize {}
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_usize {}
 
-#[doc(primitive = "reference")]
+#[cfg_attr(bootstrap, doc(primitive = "reference"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "reference")]
 #[doc(alias = "&")]
 #[doc(alias = "&mut")]
 //
@@ -1373,7 +1397,8 @@ mod prim_usize {}
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_ref {}
 
-#[doc(primitive = "fn")]
+#[cfg_attr(bootstrap, doc(primitive = "fn"))]
+#[cfg_attr(not(bootstrap), rustc_doc_primitive = "fn")]
 //
 /// Function pointers, like `fn(usize) -> bool`.
 ///
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 909e0a07e4c..fe4186babfd 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -249,13 +249,13 @@ impl ExternalCrate {
         //
         // Note that this loop only searches the top-level items of the crate,
         // and this is intentional. If we were to search the entire crate for an
-        // item tagged with `#[doc(primitive)]` then we would also have to
+        // item tagged with `#[rustc_doc_primitive]` then we would also have to
         // search the entirety of external modules for items tagged
-        // `#[doc(primitive)]`, which is a pretty inefficient process (decoding
+        // `#[rustc_doc_primitive]`, which is a pretty inefficient process (decoding
         // all that metadata unconditionally).
         //
         // In order to keep the metadata load under control, the
-        // `#[doc(primitive)]` feature is explicitly designed to only allow the
+        // `#[rustc_doc_primitive]` feature is explicitly designed to only allow the
         // primitive tags to show up as the top level items in a crate.
         //
         // Also note that this does not attempt to deal with modules tagged
@@ -264,18 +264,13 @@ impl ExternalCrate {
         let as_primitive = |res: Res<!>| {
             if let Res::Def(DefKind::Mod, def_id) = res {
                 let mut prim = None;
-                let meta_items = tcx
-                    .get_attrs(def_id, sym::doc)
-                    .flat_map(|attr| attr.meta_item_list().unwrap_or_default());
-                for meta in meta_items {
-                    if let Some(v) = meta.value_str() {
-                        if meta.has_name(sym::primitive) {
-                            prim = PrimitiveType::from_symbol(v);
-                            if prim.is_some() {
-                                break;
-                            }
-                            // FIXME: should warn on unknown primitives?
+                for attr in tcx.get_attrs(def_id, sym::rustc_doc_primitive) {
+                    if let Some(v) = attr.value_str() {
+                        prim = PrimitiveType::from_symbol(v);
+                        if prim.is_some() {
+                            break;
                         }
+                        // FIXME: should warn on unknown primitives?
                     }
                 }
                 return prim.map(|p| (def_id, p));
@@ -1829,13 +1824,17 @@ impl PrimitiveType {
         }
     }
 
-    /// Returns the DefId of the module with `doc(primitive)` for this primitive type.
+    /// Returns the DefId of the module with `rustc_doc_primitive` for this primitive type.
     /// Panics if there is no such module.
     ///
-    /// This gives precedence to primitives defined in the current crate, and deprioritizes primitives defined in `core`,
-    /// but otherwise, if multiple crates define the same primitive, there is no guarantee of which will be picked.
-    /// In particular, if a crate depends on both `std` and another crate that also defines `doc(primitive)`, then
-    /// it's entirely random whether `std` or the other crate is picked. (no_std crates are usually fine unless multiple dependencies define a primitive.)
+    /// This gives precedence to primitives defined in the current crate, and deprioritizes
+    /// primitives defined in `core`,
+    /// but otherwise, if multiple crates define the same primitive, there is no guarantee of which
+    /// will be picked.
+    ///
+    /// In particular, if a crate depends on both `std` and another crate that also defines
+    /// `rustc_doc_primitive`, then it's entirely random whether `std` or the other crate is picked.
+    /// (no_std crates are usually fine unless multiple dependencies define a primitive.)
     pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxHashMap<PrimitiveType, DefId> {
         static PRIMITIVE_LOCATIONS: OnceCell<FxHashMap<PrimitiveType, DefId>> = OnceCell::new();
         PRIMITIVE_LOCATIONS.get_or_init(|| {
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 59d67f27b30..c39caf73a93 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -249,9 +249,7 @@ pub(crate) fn id_from_item_inner(
                     // instead, we directly get the primitive symbol and convert it to u32 to
                     // generate the ID.
                     if matches!(tcx.def_kind(def_id), DefKind::Mod) &&
-                        let Some(prim) = tcx.get_attrs(*def_id, sym::doc)
-                            .flat_map(|attr| attr.meta_item_list().unwrap_or_default())
-                            .filter(|attr| attr.has_name(sym::primitive))
+                        let Some(prim) = tcx.get_attrs(*def_id, sym::rustc_doc_primitive)
                             .find_map(|attr| attr.value_str()) {
                         format!(":{}", prim.as_u32())
                     } else {
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index 08bceb59cfd..d6da6e09938 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -78,7 +78,7 @@ impl<'tcx> JsonRenderer<'tcx> {
                         // HACK(hkmatsumoto): For impls of primitive types, we index them
                         // regardless of whether they're local. This is because users can
                         // document primitive items in an arbitrary crate by using
-                        // `doc(primitive)`.
+                        // `rustc_doc_primitive`.
                         let mut is_primitive_impl = false;
                         if let clean::types::ItemKind::ImplItem(ref impl_) = *item.kind &&
                             impl_.trait_.is_none() &&
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index d98cf251e97..48f69029dbb 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -433,8 +433,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
             })?;
 
         // FIXME(#83862): this arbitrarily gives precedence to primitives over modules to support
-        // links to primitives when `#[doc(primitive)]` is present. It should give an ambiguity
-        // error instead and special case *only* modules with `#[doc(primitive)]`, not all
+        // links to primitives when `#[rustc_doc_primitive]` is present. It should give an ambiguity
+        // error instead and special case *only* modules with `#[rustc_doc_primitive]`, not all
         // primitives.
         resolve_primitive(&path_root, TypeNS)
             .or_else(|| self.resolve_path(&path_root, TypeNS, item_id, module_id))
@@ -1102,7 +1102,7 @@ impl LinkCollector<'_, '_> {
                 }
             }
 
-        // item can be non-local e.g. when using #[doc(primitive = "pointer")]
+        // item can be non-local e.g. when using `#[rustc_doc_primitive = "pointer"]`
         if let Some((src_id, dst_id)) = id.as_local().and_then(|dst_id| {
             item.item_id.expect_def_id().as_local().map(|src_id| (src_id, dst_id))
         }) {

From 48f7148fcab44e030882d3c0a7a93e66a92f2ba4 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume.gomez@huawei.com>
Date: Tue, 21 Mar 2023 16:53:12 +0100
Subject: [PATCH 4/7] Update documentation for rustc_doc_primitive

---
 src/doc/rustdoc/src/unstable-features.md | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md
index b8b5014ab42..960c1de1782 100644
--- a/src/doc/rustdoc/src/unstable-features.md
+++ b/src/doc/rustdoc/src/unstable-features.md
@@ -177,9 +177,9 @@ Book][unstable-masked] and [its tracking issue][issue-masked].
 This is for Rust compiler internal use only.
 
 Since primitive types are defined in the compiler, there's no place to attach documentation
-attributes. The `#[doc(primitive)]` attribute is used by the standard library to provide a way
-to generate documentation for primitive types, and requires `#![feature(rustdoc_internals)]` to
-enable.
+attributes. The `#[rustc_doc_primitive = "..."]` attribute is used by the standard library to
+provide a way to generate documentation for primitive types, and requires `#![feature(rustc_attrs)]`
+to enable.
 
 ### Document keywords
 

From fa2824aef4541230c1cd0c39e307a789bd0820a8 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume.gomez@huawei.com>
Date: Tue, 21 Mar 2023 16:59:16 +0100
Subject: [PATCH 5/7] Add test to ensure doc(primitive) is not recognized
 anymore

---
 tests/ui/rustdoc/doc-primitive.rs     |  8 ++++++++
 tests/ui/rustdoc/doc-primitive.stderr | 16 ++++++++++++++++
 2 files changed, 24 insertions(+)
 create mode 100644 tests/ui/rustdoc/doc-primitive.rs
 create mode 100644 tests/ui/rustdoc/doc-primitive.stderr

diff --git a/tests/ui/rustdoc/doc-primitive.rs b/tests/ui/rustdoc/doc-primitive.rs
new file mode 100644
index 00000000000..4336961e3b5
--- /dev/null
+++ b/tests/ui/rustdoc/doc-primitive.rs
@@ -0,0 +1,8 @@
+#![deny(invalid_doc_attributes)]
+
+#[doc(primitive = "foo")]
+//~^ ERROR unknown `doc` attribute `primitive`
+//~| WARN
+mod bar {}
+
+fn main() {}
diff --git a/tests/ui/rustdoc/doc-primitive.stderr b/tests/ui/rustdoc/doc-primitive.stderr
new file mode 100644
index 00000000000..d61eb381647
--- /dev/null
+++ b/tests/ui/rustdoc/doc-primitive.stderr
@@ -0,0 +1,16 @@
+error: unknown `doc` attribute `primitive`
+  --> $DIR/doc-primitive.rs:3:7
+   |
+LL | #[doc(primitive = "foo")]
+   |       ^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
+note: the lint level is defined here
+  --> $DIR/doc-primitive.rs:1:9
+   |
+LL | #![deny(invalid_doc_attributes)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+

From bcf8a8b58ccdced38a3b7e9d1f3f219df782cf07 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume.gomez@huawei.com>
Date: Thu, 30 Mar 2023 17:59:35 +0200
Subject: [PATCH 6/7] Improve code

---
 src/librustdoc/clean/types.rs | 19 +++++--------------
 1 file changed, 5 insertions(+), 14 deletions(-)

diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index fe4186babfd..ffa13ebb77c 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -262,20 +262,11 @@ impl ExternalCrate {
         // duplicately for the same primitive. This is handled later on when
         // rendering by delegating everything to a hash map.
         let as_primitive = |res: Res<!>| {
-            if let Res::Def(DefKind::Mod, def_id) = res {
-                let mut prim = None;
-                for attr in tcx.get_attrs(def_id, sym::rustc_doc_primitive) {
-                    if let Some(v) = attr.value_str() {
-                        prim = PrimitiveType::from_symbol(v);
-                        if prim.is_some() {
-                            break;
-                        }
-                        // FIXME: should warn on unknown primitives?
-                    }
-                }
-                return prim.map(|p| (def_id, p));
-            }
-            None
+            let Res::Def(DefKind::Mod, def_id) = res else { return None };
+            tcx.get_attrs(def_id, sym::rustc_doc_primitive).find_map(|attr| {
+                // FIXME: should warn on unknown primitives?
+                Some((def_id, PrimitiveType::from_symbol(attr.value_str()?)?))
+            })
         };
 
         if root.is_local() {

From f6035fb0fa68de45befc032e35bb68592ce1d029 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume.gomez@huawei.com>
Date: Fri, 31 Mar 2023 00:04:24 +0200
Subject: [PATCH 7/7] Update doc(primitive) in rustc_resolve

---
 compiler/rustc_resolve/src/rustdoc.rs | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs
index 44a27bbc175..9eae99be2e9 100644
--- a/compiler/rustc_resolve/src/rustdoc.rs
+++ b/compiler/rustc_resolve/src/rustdoc.rs
@@ -339,12 +339,14 @@ pub fn inner_docs(attrs: &[ast::Attribute]) -> bool {
     attrs.iter().find(|a| a.doc_str().is_some()).map_or(true, |a| a.style == ast::AttrStyle::Inner)
 }
 
-/// Has `#[doc(primitive)]` or `#[doc(keyword)]`.
+/// Has `#[rustc_doc_primitive]` or `#[doc(keyword)]`.
 pub fn has_primitive_or_keyword_docs(attrs: &[ast::Attribute]) -> bool {
     for attr in attrs {
-        if attr.has_name(sym::doc) && let Some(items) = attr.meta_item_list() {
+        if attr.has_name(sym::rustc_doc_primitive) {
+            return true;
+        } else if attr.has_name(sym::doc) && let Some(items) = attr.meta_item_list() {
             for item in items {
-                if item.has_name(sym::primitive) || item.has_name(sym::keyword) {
+                if item.has_name(sym::keyword) {
                     return true;
                 }
             }