From fee4992fb160ae59f0a35bb5333b801e6c12ac9d Mon Sep 17 00:00:00 2001
From: Kornel <kornel@geekhood.net>
Date: Wed, 31 Jan 2024 23:26:50 +0000
Subject: [PATCH 01/58] Make File::read_to_end less special

Follow-up to #117925
---
 library/std/src/fs.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 80d369eb067d4..25ed51f123361 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -776,14 +776,14 @@ impl Read for &File {
     // Reserves space in the buffer based on the file size when available.
     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
         let size = buffer_capacity_required(self);
-        buf.try_reserve_exact(size.unwrap_or(0)).map_err(|_| io::ErrorKind::OutOfMemory)?;
+        buf.try_reserve(size.unwrap_or(0)).map_err(|_| io::ErrorKind::OutOfMemory)?;
         io::default_read_to_end(self, buf, size)
     }
 
     // Reserves space in the buffer based on the file size when available.
     fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
         let size = buffer_capacity_required(self);
-        buf.try_reserve_exact(size.unwrap_or(0)).map_err(|_| io::ErrorKind::OutOfMemory)?;
+        buf.try_reserve(size.unwrap_or(0)).map_err(|_| io::ErrorKind::OutOfMemory)?;
         io::default_read_to_string(self, buf, size)
     }
 }

From 0a42a540c603846aa22f29f378a61a64c9d4383e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= <bdgdlm@outlook.com>
Date: Wed, 7 Feb 2024 16:21:16 +0100
Subject: [PATCH 02/58] Make `io::BorrowedCursor::advance` safe

This also keeps the old `advance` method under `advance_unchecked` name.

This makes pattern like `std::io::default_read_buf` safe to write.
---
 library/core/src/io/borrowed_buf.rs       | 22 +++++++++++++++++++++-
 library/core/tests/io/borrowed_buf.rs     | 16 ++++------------
 library/std/src/io/mod.rs                 | 12 ++----------
 library/std/src/io/tests.rs               |  2 +-
 library/std/src/io/util.rs                |  2 +-
 library/std/src/sys/pal/hermit/net.rs     |  2 +-
 library/std/src/sys/pal/solid/fs.rs       |  2 +-
 library/std/src/sys/pal/solid/net.rs      |  2 +-
 library/std/src/sys/pal/unix/fd.rs        |  2 +-
 library/std/src/sys/pal/unix/net.rs       |  2 +-
 library/std/src/sys/pal/wasi/fd.rs        |  2 +-
 library/std/src/sys/pal/windows/handle.rs |  2 +-
 library/std/src/sys/pal/windows/net.rs    |  2 +-
 library/std/src/sys/pal/windows/pipe.rs   |  2 +-
 14 files changed, 38 insertions(+), 34 deletions(-)

diff --git a/library/core/src/io/borrowed_buf.rs b/library/core/src/io/borrowed_buf.rs
index fe25cac280fe3..161bb4b6a1fc7 100644
--- a/library/core/src/io/borrowed_buf.rs
+++ b/library/core/src/io/borrowed_buf.rs
@@ -233,6 +233,26 @@ impl<'a> BorrowedCursor<'a> {
         &mut self.buf.buf[self.buf.filled..]
     }
 
+    /// Advance the cursor by asserting that `n` bytes have been filled.
+    ///
+    /// After advancing, the `n` bytes are no longer accessible via the cursor and can only be
+    /// accessed via the underlying buffer. I.e., the buffer's filled portion grows by `n` elements
+    /// and its unfilled portion (and the capacity of this cursor) shrinks by `n` elements.
+    ///
+    /// If less than `n` bytes initialized (by the cursor's point of view), `set_init` should be
+    /// called first.
+    ///
+    /// # Panics
+    ///
+    /// Panics if there are less than `n` bytes initialized.
+    #[inline]
+    pub fn advance(&mut self, n: usize) -> &mut Self {
+        assert!(self.buf.init >= self.buf.filled + n);
+
+        self.buf.filled += n;
+        self
+    }
+
     /// Advance the cursor by asserting that `n` bytes have been filled.
     ///
     /// After advancing, the `n` bytes are no longer accessible via the cursor and can only be
@@ -244,7 +264,7 @@ impl<'a> BorrowedCursor<'a> {
     /// The caller must ensure that the first `n` bytes of the cursor have been properly
     /// initialised.
     #[inline]
-    pub unsafe fn advance(&mut self, n: usize) -> &mut Self {
+    pub unsafe fn advance_unchecked(&mut self, n: usize) -> &mut Self {
         self.buf.filled += n;
         self.buf.init = cmp::max(self.buf.init, self.buf.filled);
         self
diff --git a/library/core/tests/io/borrowed_buf.rs b/library/core/tests/io/borrowed_buf.rs
index 69511e49acdbc..a5dd4e525777a 100644
--- a/library/core/tests/io/borrowed_buf.rs
+++ b/library/core/tests/io/borrowed_buf.rs
@@ -40,9 +40,7 @@ fn advance_filled() {
     let buf: &mut [_] = &mut [0; 16];
     let mut rbuf: BorrowedBuf<'_> = buf.into();
 
-    unsafe {
-        rbuf.unfilled().advance(1);
-    }
+    rbuf.unfilled().advance(1);
 
     assert_eq!(rbuf.filled().len(), 1);
     assert_eq!(rbuf.unfilled().capacity(), 15);
@@ -53,9 +51,7 @@ fn clear() {
     let buf: &mut [_] = &mut [255; 16];
     let mut rbuf: BorrowedBuf<'_> = buf.into();
 
-    unsafe {
-        rbuf.unfilled().advance(16);
-    }
+    rbuf.unfilled().advance(16);
 
     assert_eq!(rbuf.filled().len(), 16);
     assert_eq!(rbuf.unfilled().capacity(), 0);
@@ -79,9 +75,7 @@ fn set_init() {
 
     assert_eq!(rbuf.init_len(), 8);
 
-    unsafe {
-        rbuf.unfilled().advance(4);
-    }
+    rbuf.unfilled().advance(4);
 
     unsafe {
         rbuf.set_init(2);
@@ -153,9 +147,7 @@ fn cursor_set_init() {
     assert_eq!(rbuf.unfilled().uninit_mut().len(), 8);
     assert_eq!(unsafe { rbuf.unfilled().as_mut() }.len(), 16);
 
-    unsafe {
-        rbuf.unfilled().advance(4);
-    }
+    rbuf.unfilled().advance(4);
 
     unsafe {
         rbuf.unfilled().set_init(2);
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index a238e74ed95cf..f842a0b6d554e 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -578,15 +578,7 @@ where
     F: FnOnce(&mut [u8]) -> Result<usize>,
 {
     let n = read(cursor.ensure_init().init_mut())?;
-    assert!(
-        n <= cursor.capacity(),
-        "read should not return more bytes than there is capacity for in the read buffer"
-    );
-    unsafe {
-        // SAFETY: we initialised using `ensure_init` so there is no uninit data to advance to
-        // and we have checked that the read amount is not over capacity (see #120603)
-        cursor.advance(n);
-    }
+    cursor.advance(n);
     Ok(())
 }
 
@@ -2915,7 +2907,7 @@ impl<T: Read> Read for Take<T> {
 
             unsafe {
                 // SAFETY: filled bytes have been filled and therefore initialized
-                buf.advance(filled);
+                buf.advance_unchecked(filled);
                 // SAFETY: new_init bytes of buf's unfilled buffer have been initialized
                 buf.set_init(new_init);
             }
diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs
index 33e9d8efed511..fd7e51688cdeb 100644
--- a/library/std/src/io/tests.rs
+++ b/library/std/src/io/tests.rs
@@ -655,7 +655,7 @@ fn bench_take_read_buf(b: &mut test::Bencher) {
 
 // Issue #120603
 #[test]
-#[should_panic = "read should not return more bytes than there is capacity for in the read buffer"]
+#[should_panic]
 fn read_buf_broken_read() {
     struct MalformedRead;
 
diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs
index a04bc4811460b..16eaed15e720c 100644
--- a/library/std/src/io/util.rs
+++ b/library/std/src/io/util.rs
@@ -198,7 +198,7 @@ impl Read for Repeat {
 
         // SAFETY: the entire unfilled portion of buf has been initialized
         unsafe {
-            buf.advance(remaining);
+            buf.advance_unchecked(remaining);
         }
 
         Ok(())
diff --git a/library/std/src/sys/pal/hermit/net.rs b/library/std/src/sys/pal/hermit/net.rs
index 3cf63fccf2e71..871a2ccdfa49c 100644
--- a/library/std/src/sys/pal/hermit/net.rs
+++ b/library/std/src/sys/pal/hermit/net.rs
@@ -156,7 +156,7 @@ impl Socket {
             )
         })?;
         unsafe {
-            buf.advance(ret as usize);
+            buf.advance_unchecked(ret as usize);
         }
         Ok(())
     }
diff --git a/library/std/src/sys/pal/solid/fs.rs b/library/std/src/sys/pal/solid/fs.rs
index 6c66b93a3e1a3..a6c1336109ad7 100644
--- a/library/std/src/sys/pal/solid/fs.rs
+++ b/library/std/src/sys/pal/solid/fs.rs
@@ -388,7 +388,7 @@ impl File {
 
             // Safety: `num_bytes_read` bytes were written to the unfilled
             // portion of the buffer
-            cursor.advance(num_bytes_read);
+            cursor.advance_unchecked(num_bytes_read);
 
             Ok(())
         }
diff --git a/library/std/src/sys/pal/solid/net.rs b/library/std/src/sys/pal/solid/net.rs
index 1c310648a3db5..6ea874e509e20 100644
--- a/library/std/src/sys/pal/solid/net.rs
+++ b/library/std/src/sys/pal/solid/net.rs
@@ -209,7 +209,7 @@ impl Socket {
             netc::recv(self.as_raw_fd(), buf.as_mut().as_mut_ptr().cast(), buf.capacity(), flags)
         })?;
         unsafe {
-            buf.advance(ret as usize);
+            buf.advance_unchecked(ret as usize);
         }
         Ok(())
     }
diff --git a/library/std/src/sys/pal/unix/fd.rs b/library/std/src/sys/pal/unix/fd.rs
index bf1fb3123c4ce..a1c0321876fa8 100644
--- a/library/std/src/sys/pal/unix/fd.rs
+++ b/library/std/src/sys/pal/unix/fd.rs
@@ -161,7 +161,7 @@ impl FileDesc {
 
         // Safety: `ret` bytes were written to the initialized portion of the buffer
         unsafe {
-            cursor.advance(ret as usize);
+            cursor.advance_unchecked(ret as usize);
         }
         Ok(())
     }
diff --git a/library/std/src/sys/pal/unix/net.rs b/library/std/src/sys/pal/unix/net.rs
index 8f537de7026f5..1b6a6bb2c5c77 100644
--- a/library/std/src/sys/pal/unix/net.rs
+++ b/library/std/src/sys/pal/unix/net.rs
@@ -272,7 +272,7 @@ impl Socket {
             )
         })?;
         unsafe {
-            buf.advance(ret as usize);
+            buf.advance_unchecked(ret as usize);
         }
         Ok(())
     }
diff --git a/library/std/src/sys/pal/wasi/fd.rs b/library/std/src/sys/pal/wasi/fd.rs
index d7295a799daab..8966e4b80ad37 100644
--- a/library/std/src/sys/pal/wasi/fd.rs
+++ b/library/std/src/sys/pal/wasi/fd.rs
@@ -60,7 +60,7 @@ impl WasiFd {
             }];
             match wasi::fd_read(self.as_raw_fd() as wasi::Fd, &bufs) {
                 Ok(n) => {
-                    buf.advance(n);
+                    buf.advance_unchecked(n);
                     Ok(())
                 }
                 Err(e) => Err(err2io(e)),
diff --git a/library/std/src/sys/pal/windows/handle.rs b/library/std/src/sys/pal/windows/handle.rs
index c4495f81a5a3a..3f85bb0a099a9 100644
--- a/library/std/src/sys/pal/windows/handle.rs
+++ b/library/std/src/sys/pal/windows/handle.rs
@@ -121,7 +121,7 @@ impl Handle {
             Ok(read) => {
                 // Safety: `read` bytes were written to the initialized portion of the buffer
                 unsafe {
-                    cursor.advance(read);
+                    cursor.advance_unchecked(read);
                 }
                 Ok(())
             }
diff --git a/library/std/src/sys/pal/windows/net.rs b/library/std/src/sys/pal/windows/net.rs
index c34e01e000aca..e37fbe9ef83e4 100644
--- a/library/std/src/sys/pal/windows/net.rs
+++ b/library/std/src/sys/pal/windows/net.rs
@@ -234,7 +234,7 @@ impl Socket {
                 }
             }
             _ => {
-                unsafe { buf.advance(result as usize) };
+                unsafe { buf.advance_unchecked(result as usize) };
                 Ok(())
             }
         }
diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs
index 7624e746f5c89..fd10df82d8b47 100644
--- a/library/std/src/sys/pal/windows/pipe.rs
+++ b/library/std/src/sys/pal/windows/pipe.rs
@@ -273,7 +273,7 @@ impl AnonPipe {
             Err(e) => Err(e),
             Ok(n) => {
                 unsafe {
-                    buf.advance(n);
+                    buf.advance_unchecked(n);
                 }
                 Ok(())
             }

From 24e2cf01d36039c7e808a1b95688eb25f606cb2a Mon Sep 17 00:00:00 2001
From: Markus Reiter <me@reitermark.us>
Date: Thu, 1 Feb 2024 23:41:19 +0100
Subject: [PATCH 03/58] Make `NonZero::get` generic.

---
 library/core/src/num/nonzero.rs | 41 +++++++++++++++++----------------
 1 file changed, 21 insertions(+), 20 deletions(-)

diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 193f2fa8731af..576178c3ce426 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -164,6 +164,27 @@ where
             }
         }
     }
+
+    /// Returns the contained value as a primitive type.
+    #[stable(feature = "nonzero", since = "1.28.0")]
+    #[rustc_const_stable(feature = "const_nonzero_get", since = "1.34.0")]
+    #[inline]
+    pub const fn get(self) -> T {
+        // FIXME: This can be changed to simply `self.0` once LLVM supports `!range` metadata
+        // for function arguments: https://github.com/llvm/llvm-project/issues/76628
+        //
+        // Rustc can set range metadata only if it loads `self` from
+        // memory somewhere. If the value of `self` was from by-value argument
+        // of some not-inlined function, LLVM don't have range metadata
+        // to understand that the value cannot be zero.
+        match Self::new(self.0) {
+            Some(Self(n)) => n,
+            None => {
+                // SAFETY: `NonZero` is guaranteed to only contain non-zero values, so this is unreachable.
+                unsafe { intrinsics::unreachable() }
+            }
+        }
+    }
 }
 
 macro_rules! impl_nonzero_fmt {
@@ -225,26 +246,6 @@ macro_rules! nonzero_integer {
         pub type $Ty = NonZero<$Int>;
 
         impl $Ty {
-            /// Returns the value as a primitive type.
-            #[$stability]
-            #[inline]
-            #[rustc_const_stable(feature = "const_nonzero_get", since = "1.34.0")]
-            pub const fn get(self) -> $Int {
-                // FIXME: Remove this after LLVM supports `!range` metadata for function
-                // arguments https://github.com/llvm/llvm-project/issues/76628
-                //
-                // Rustc can set range metadata only if it loads `self` from
-                // memory somewhere. If the value of `self` was from by-value argument
-                // of some not-inlined function, LLVM don't have range metadata
-                // to understand that the value cannot be zero.
-
-                // SAFETY: It is an invariant of this type.
-                unsafe {
-                    intrinsics::assume(self.0 != 0);
-                }
-                self.0
-            }
-
             /// The size of this non-zero integer type in bits.
             ///
             #[doc = concat!("This value is equal to [`", stringify!($Int), "::BITS`].")]

From d51e703534c49b5b658a954fe6d387c33ba0c5e3 Mon Sep 17 00:00:00 2001
From: CKingX <CKingX@users.noreply.github.com>
Date: Thu, 8 Feb 2024 17:15:11 -0800
Subject: [PATCH 04/58] As Windows 10 requires certain features like CMPXCHG16B
 and a few others and Rust plans to set Windows 10 as the minimum supported OS
 for target x86_64-pc-windows-msvc, I have added the cmpxchg16b and sse3
 feature (as CPUs that meet the Windows 10 64-bit requirement also support
 SSE3. See https://walbourn.github.io/directxmath-sse3-and-ssse3/ )

---
 compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs
index 357261073a8f7..e3db187e7eb5b 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs
@@ -3,6 +3,7 @@ use crate::spec::{base, SanitizerSet, Target};
 pub fn target() -> Target {
     let mut base = base::windows_msvc::opts();
     base.cpu = "x86-64".into();
+    base.features = "+cmpxchg16b,+sse3".into();
     base.plt_by_default = false;
     base.max_atomic_width = Some(64);
     base.supported_sanitizers = SanitizerSet::ADDRESS;

From d6766e2bc8eb6cfd695f2c9e931c7a712da474ff Mon Sep 17 00:00:00 2001
From: CKingX <CKingX@users.noreply.github.com>
Date: Fri, 9 Feb 2024 07:59:38 -0800
Subject: [PATCH 05/58] Update x86_64_pc_windows_msvc.rs

Fixed a bug where adding CMPXCHG16B would fail due to different names in Rustc and LLVM
---
 .../rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs     | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs
index e3db187e7eb5b..f7dc60df0f475 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs
@@ -3,7 +3,7 @@ use crate::spec::{base, SanitizerSet, Target};
 pub fn target() -> Target {
     let mut base = base::windows_msvc::opts();
     base.cpu = "x86-64".into();
-    base.features = "+cmpxchg16b,+sse3".into();
+    base.features = "+cx16,+sse3".into();
     base.plt_by_default = false;
     base.max_atomic_width = Some(64);
     base.supported_sanitizers = SanitizerSet::ADDRESS;

From 01fa7209d597c770a51c44839a97d2731419392c Mon Sep 17 00:00:00 2001
From: Marcondiro <46560192+Marcondiro@users.noreply.github.com>
Date: Thu, 8 Feb 2024 12:24:27 +0100
Subject: [PATCH 06/58] Bump Unicode to version 15.1.0, regenerate tables

---
 library/core/src/unicode/unicode_data.rs | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/library/core/src/unicode/unicode_data.rs b/library/core/src/unicode/unicode_data.rs
index b25e9df286808..dd2ad9a58f679 100644
--- a/library/core/src/unicode/unicode_data.rs
+++ b/library/core/src/unicode/unicode_data.rs
@@ -99,21 +99,21 @@ fn skip_search<const SOR: usize, const OFFSETS: usize>(
     offset_idx % 2 == 1
 }
 
-pub const UNICODE_VERSION: (u8, u8, u8) = (15, 0, 0);
+pub const UNICODE_VERSION: (u8, u8, u8) = (15, 1, 0);
 
 #[rustfmt::skip]
 pub mod alphabetic {
-    static SHORT_OFFSET_RUNS: [u32; 53] = [
+    static SHORT_OFFSET_RUNS: [u32; 54] = [
         706, 33559113, 872420973, 952114966, 1161831606, 1310731264, 1314926597, 1394619392,
         1444957632, 1447077005, 1451271693, 1459672996, 1648425216, 1658911342, 1661009214,
         1707147904, 1793132343, 1887506048, 2040601600, 2392923872, 2481005466, 2504077200,
         2514564144, 2520859648, 2527151687, 2529257472, 2531355193, 2533453376, 2564917240,
         2596375766, 2600579056, 2606870819, 2621551356, 2642525184, 2644628480, 2665600678,
         2743197440, 2791432848, 2841765072, 2850154464, 2854350336, 2887905584, 3026321408,
-        3038947040, 3041048378, 3045248674, 3053644769, 3057842176, 3059939870, 3062038528,
-        3064140619, 3066241968, 3071550384,
+        3038947040, 3041048378, 3045248674, 3053644769, 3057839710, 3062036480, 3064134174,
+        3066232832, 3068334923, 3070436272, 3075744688,
     ];
-    static OFFSETS: [u8; 1465] = [
+    static OFFSETS: [u8; 1467] = [
         65, 26, 6, 26, 47, 1, 10, 1, 4, 1, 5, 23, 1, 31, 1, 0, 4, 12, 14, 5, 7, 1, 1, 1, 86, 1, 42,
         5, 1, 2, 2, 4, 1, 1, 6, 1, 1, 3, 1, 1, 1, 20, 1, 83, 1, 139, 8, 166, 1, 38, 2, 1, 6, 41, 39,
         14, 1, 1, 1, 2, 1, 2, 1, 1, 8, 27, 4, 4, 29, 11, 5, 56, 1, 7, 14, 102, 1, 8, 4, 8, 4, 3, 10,
@@ -167,7 +167,7 @@ pub mod alphabetic {
         1, 2, 1, 15, 1, 197, 59, 68, 3, 1, 3, 1, 0, 4, 1, 27, 1, 2, 1, 1, 2, 1, 1, 10, 1, 4, 1, 1,
         1, 1, 6, 1, 4, 1, 1, 1, 1, 1, 1, 3, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2,
         4, 1, 7, 1, 4, 1, 4, 1, 1, 1, 10, 1, 17, 5, 3, 1, 5, 1, 17, 0, 26, 6, 26, 6, 26, 0, 0, 32,
-        0, 6, 222, 2, 0, 14, 0, 0, 0, 0, 0, 5, 0, 0,
+        0, 6, 222, 2, 0, 14, 0, 15, 0, 0, 0, 0, 0, 5, 0, 0,
     ];
     pub fn lookup(c: char) -> bool {
         super::skip_search(

From fcb06f7ca2a20d030fdd5f9c53b684557f17c00c Mon Sep 17 00:00:00 2001
From: CKingX <CKingX@users.noreply.github.com>
Date: Fri, 9 Feb 2024 09:19:59 -0800
Subject: [PATCH 07/58] Update x86_64_pc_windows_msvc.rs

As CMPXCHG16B is supported, I updated the max atomic width to 128-bits from 64-bits
---
 .../rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs     | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs
index f7dc60df0f475..e72e97db7756a 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs
@@ -5,7 +5,7 @@ pub fn target() -> Target {
     base.cpu = "x86-64".into();
     base.features = "+cx16,+sse3".into();
     base.plt_by_default = false;
-    base.max_atomic_width = Some(64);
+    base.max_atomic_width = Some(128);
     base.supported_sanitizers = SanitizerSet::ADDRESS;
 
     Target {

From abeac8fbc1cac4bad60094c64179366a802ec949 Mon Sep 17 00:00:00 2001
From: CKingX <CKingX@users.noreply.github.com>
Date: Fri, 9 Feb 2024 12:25:17 -0800
Subject: [PATCH 08/58] Update x86_64_uwp_windows_gnu.rs

Updated x86_64-uwp-windows-gnu to use CMPXCHG16B and SSE3
---
 .../rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs    | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs
index c2981ddbad69b..ee95c67496d66 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs
@@ -3,6 +3,7 @@ use crate::spec::{base, Cc, LinkerFlavor, Lld, Target};
 pub fn target() -> Target {
     let mut base = base::windows_uwp_gnu::opts();
     base.cpu = "x86-64".into();
+    base.features = "+cx16,+sse3".into();
     base.plt_by_default = false;
     // Use high-entropy 64 bit address space for ASLR
     base.add_pre_link_args(
@@ -10,7 +11,7 @@ pub fn target() -> Target {
         &["-m", "i386pep", "--high-entropy-va"],
     );
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64", "-Wl,--high-entropy-va"]);
-    base.max_atomic_width = Some(64);
+    base.max_atomic_width = Some(128);
 
     Target {
         llvm_target: "x86_64-pc-windows-gnu".into(),

From 1c6dda72774d19e79d14b7a51c047414b3126b7b Mon Sep 17 00:00:00 2001
From: Chiragroop <chirag.kahlon@gmail.com>
Date: Fri, 9 Feb 2024 12:54:38 -0800
Subject: [PATCH 09/58] Possibly removed merge policy

---
 .../rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs     | 3 ++-
 .../rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs | 3 ++-
 .../rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs   | 3 ++-
 3 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs
index 9e964d248bf8f..d16e5905eac62 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs
@@ -3,6 +3,7 @@ use crate::spec::{base, Cc, LinkerFlavor, Lld, Target};
 pub fn target() -> Target {
     let mut base = base::windows_gnu::opts();
     base.cpu = "x86-64".into();
+    base.features = "+cx16,+sse3".into();
     base.plt_by_default = false;
     // Use high-entropy 64 bit address space for ASLR
     base.add_pre_link_args(
@@ -10,7 +11,7 @@ pub fn target() -> Target {
         &["-m", "i386pep", "--high-entropy-va"],
     );
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64", "-Wl,--high-entropy-va"]);
-    base.max_atomic_width = Some(64);
+    base.max_atomic_width = Some(128);
     base.linker = Some("x86_64-w64-mingw32-gcc".into());
 
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs
index 1facf9450cd2a..ea7f7df8120f9 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs
@@ -3,9 +3,10 @@ use crate::spec::{base, Cc, LinkerFlavor, Lld, Target};
 pub fn target() -> Target {
     let mut base = base::windows_gnullvm::opts();
     base.cpu = "x86-64".into();
+    base.features = "+cx16,+sse3".into();
     base.plt_by_default = false;
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
-    base.max_atomic_width = Some(64);
+    base.max_atomic_width = Some(128);
     base.linker = Some("x86_64-w64-mingw32-clang".into());
 
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs
index 3f0702c7ad60e..acdf969375ec5 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs
@@ -3,8 +3,9 @@ use crate::spec::{base, Target};
 pub fn target() -> Target {
     let mut base = base::windows_uwp_msvc::opts();
     base.cpu = "x86-64".into();
+    base.features = "+cx16,+sse3".into();
     base.plt_by_default = false;
-    base.max_atomic_width = Some(64);
+    base.max_atomic_width = Some(128);
 
     Target {
         llvm_target: "x86_64-pc-windows-msvc".into(),

From 0eee945680754e30f0f40fb051f98ffc7b1d8c62 Mon Sep 17 00:00:00 2001
From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Date: Tue, 30 Jan 2024 14:20:22 +0000
Subject: [PATCH 10/58] Make `is_intrinsic` query return the intrinsic name

---
 compiler/rustc_borrowck/src/type_check/mod.rs       | 13 +++----------
 .../rustc_const_eval/src/const_eval/fn_queries.rs   |  2 +-
 .../rustc_const_eval/src/interpret/terminator.rs    |  2 +-
 .../src/transform/check_consts/check.rs             |  2 +-
 compiler/rustc_hir_typeck/src/callee.rs             |  3 +--
 compiler/rustc_hir_typeck/src/coercion.rs           |  2 +-
 .../src/infer/error_reporting/suggest.rs            |  6 +++---
 compiler/rustc_lint/src/builtin.rs                  |  2 +-
 compiler/rustc_metadata/src/rmeta/decoder.rs        |  4 ++--
 .../rustc_metadata/src/rmeta/decoder/cstore_impl.rs |  2 +-
 compiler/rustc_metadata/src/rmeta/encoder.rs        |  2 +-
 compiler/rustc_metadata/src/rmeta/mod.rs            |  2 +-
 compiler/rustc_middle/src/query/erase.rs            |  1 +
 compiler/rustc_middle/src/query/mod.rs              |  4 ++--
 compiler/rustc_middle/src/ty/util.rs                | 13 +++++++++----
 compiler/rustc_mir_dataflow/src/rustc_peek.rs       |  3 +--
 compiler/rustc_mir_transform/src/cost_checker.rs    |  2 +-
 compiler/rustc_mir_transform/src/instsimplify.rs    |  5 ++---
 compiler/rustc_mir_transform/src/lib.rs             |  3 +--
 .../rustc_mir_transform/src/lower_intrinsics.rs     |  3 +--
 compiler/rustc_ty_utils/src/instance.rs             |  3 ++-
 .../clippy/clippy_utils/src/qualify_min_const_fn.rs |  2 +-
 22 files changed, 38 insertions(+), 43 deletions(-)

diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index cfb46f3ac8a96..08b6aead7288b 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -1650,16 +1650,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
 
         let func_ty = func.ty(body, self.infcx.tcx);
         if let ty::FnDef(def_id, _) = *func_ty.kind() {
-            if self.tcx().is_intrinsic(def_id) {
-                match self.tcx().item_name(def_id) {
-                    sym::simd_shuffle => {
-                        if !matches!(args[2], Spanned { node: Operand::Constant(_), .. }) {
-                            self.tcx()
-                                .dcx()
-                                .emit_err(SimdShuffleLastConst { span: term.source_info.span });
-                        }
-                    }
-                    _ => {}
+            if let Some(sym::simd_shuffle) = self.tcx().intrinsic(def_id) {
+                if !matches!(args[2], Spanned { node: Operand::Constant(_), .. }) {
+                    self.tcx().dcx().emit_err(SimdShuffleLastConst { span: term.source_info.span });
                 }
             }
         }
diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
index dbc29e607eff9..ddad6683afbd9 100644
--- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
@@ -49,7 +49,7 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness {
         hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => {
             // Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other
             // foreign items cannot be evaluated at compile-time.
-            let is_const = if tcx.is_intrinsic(def_id) {
+            let is_const = if tcx.intrinsic(def_id).is_some() {
                 tcx.lookup_const_stability(def_id).is_some()
             } else {
                 false
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index ff20fc5092c60..0a130d4bc49e0 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -526,7 +526,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
         match instance.def {
             ty::InstanceDef::Intrinsic(def_id) => {
-                assert!(self.tcx.is_intrinsic(def_id));
+                assert!(self.tcx.intrinsic(def_id).is_some());
                 // FIXME: Should `InPlace` arguments be reset to uninit?
                 M::call_intrinsic(
                     self,
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index 28dc69859fd77..1ee7c905d9161 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -859,7 +859,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                     // We do not use `const` modifiers for intrinsic "functions", as intrinsics are
                     // `extern` functions, and these have no way to get marked `const`. So instead we
                     // use `rustc_const_(un)stable` attributes to mean that the intrinsic is `const`
-                    if self.ccx.is_const_stable_const_fn() || tcx.is_intrinsic(callee) {
+                    if self.ccx.is_const_stable_const_fn() || tcx.intrinsic(callee).is_some() {
                         self.check_op(ops::FnCallUnstable(callee, None));
                         return;
                     }
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index c4271c66e1c9d..27614634c6b3e 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -540,8 +540,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         if let Some(def_id) = def_id
             && self.tcx.def_kind(def_id) == hir::def::DefKind::Fn
-            && self.tcx.is_intrinsic(def_id)
-            && self.tcx.item_name(def_id) == sym::const_eval_select
+            && matches!(self.tcx.intrinsic(def_id), Some(sym::const_eval_select))
         {
             let fn_sig = self.resolve_vars_if_possible(fn_sig);
             for idx in 0..=1 {
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 549ad44d7e349..355fc61e79519 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -864,7 +864,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                 let a_sig = a.fn_sig(self.tcx);
                 if let ty::FnDef(def_id, _) = *a.kind() {
                     // Intrinsics are not coercible to function pointers
-                    if self.tcx.is_intrinsic(def_id) {
+                    if self.tcx.intrinsic(def_id).is_some() {
                         return Err(TypeError::IntrinsicCast);
                     }
 
diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
index 248e1c0fcc878..81c531fad5580 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
@@ -313,7 +313,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
 
                 if !self.same_type_modulo_infer(*found_sig, *expected_sig)
                     || !sig.is_suggestable(self.tcx, true)
-                    || self.tcx.is_intrinsic(*did)
+                    || self.tcx.intrinsic(*did).is_some()
                 {
                     return;
                 }
@@ -345,8 +345,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 if !self.same_type_modulo_infer(*found_sig, *expected_sig)
                     || !found_sig.is_suggestable(self.tcx, true)
                     || !expected_sig.is_suggestable(self.tcx, true)
-                    || self.tcx.is_intrinsic(*did1)
-                    || self.tcx.is_intrinsic(*did2)
+                    || self.tcx.intrinsic(*did1).is_some()
+                    || self.tcx.intrinsic(*did2).is_some()
                 {
                     return;
                 }
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 6ee1d1ca92472..faa35f51cd496 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1227,7 +1227,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
         }
 
         fn def_id_is_transmute(cx: &LateContext<'_>, def_id: DefId) -> bool {
-            cx.tcx.is_intrinsic(def_id) && cx.tcx.item_name(def_id) == sym::transmute
+            matches!(cx.tcx.intrinsic(def_id), Some(sym::transmute))
         }
     }
 }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 11cb1bb6d9e6e..a738fc86a068c 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1746,8 +1746,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         self.root.tables.attr_flags.get(self, index)
     }
 
-    fn get_is_intrinsic(self, index: DefIndex) -> bool {
-        self.root.tables.is_intrinsic.get(self, index)
+    fn get_intrinsic(self, index: DefIndex) -> bool {
+        self.root.tables.intrinsic.get(self, index)
     }
 
     fn get_doc_link_resolutions(self, index: DefIndex) -> DocLinkResMap {
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 988388edfd5ff..1faddee2e9812 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -348,7 +348,7 @@ provide! { tcx, def_id, other, cdata,
         cdata.get_stability_implications(tcx).iter().copied().collect()
     }
     stripped_cfg_items => { cdata.get_stripped_cfg_items(cdata.cnum, tcx) }
-    is_intrinsic => { cdata.get_is_intrinsic(def_id.index) }
+    intrinsic => { cdata.get_intrinsic(def_id.index).then(|| tcx.item_name(def_id)) }
     defined_lang_items => { cdata.get_lang_items(tcx) }
     diagnostic_items => { cdata.get_diagnostic_items() }
     missing_lang_items => { cdata.get_missing_lang_items(tcx) }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 6ca1973396f81..f32131854490a 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1411,7 +1411,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             if let DefKind::Fn | DefKind::AssocFn = def_kind {
                 self.tables.asyncness.set_some(def_id.index, tcx.asyncness(def_id));
                 record_array!(self.tables.fn_arg_names[def_id] <- tcx.fn_arg_names(def_id));
-                self.tables.is_intrinsic.set(def_id.index, tcx.is_intrinsic(def_id));
+                self.tables.intrinsic.set(def_id.index, tcx.intrinsic(def_id).is_some());
             }
             if let DefKind::TyParam = def_kind {
                 let default = self.tcx.object_lifetime_default(def_id);
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 8205e995c1962..49c97b8c2e6a7 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -375,7 +375,7 @@ macro_rules! define_tables {
 
 define_tables! {
 - defaulted:
-    is_intrinsic: Table<DefIndex, bool>,
+    intrinsic: Table<DefIndex, bool>,
     is_macro_rules: Table<DefIndex, bool>,
     is_type_alias_impl_trait: Table<DefIndex, bool>,
     type_alias_is_lazy: Table<DefIndex, bool>,
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index a272a51f32747..92ce3854b92a8 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -240,6 +240,7 @@ trivial! {
     Option<rustc_span::Span>,
     Option<rustc_target::spec::PanicStrategy>,
     Option<usize>,
+    Option<rustc_span::Symbol>,
     Result<(), rustc_errors::ErrorGuaranteed>,
     Result<(), rustc_middle::traits::query::NoSolution>,
     Result<rustc_middle::traits::EvaluationResult, rustc_middle::traits::OverflowError>,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 938fba0ed0981..16d3a0bd0cf33 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1753,8 +1753,8 @@ rustc_queries! {
         separate_provide_extern
     }
     /// Whether the function is an intrinsic
-    query is_intrinsic(def_id: DefId) -> bool {
-        desc { |tcx| "checking whether `{}` is an intrinsic", tcx.def_path_str(def_id) }
+    query intrinsic(def_id: DefId) -> Option<Symbol> {
+        desc { |tcx| "fetch intrinsic name if `{}` is an intrinsic", tcx.def_path_str(def_id) }
         separate_provide_extern
     }
     /// Returns the lang items defined in another crate by loading it from metadata.
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 4feaeb0dd0523..626ea0342e568 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -18,7 +18,7 @@ use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_macros::HashStable;
 use rustc_session::Limit;
-use rustc_span::sym;
+use rustc_span::{sym, Symbol};
 use rustc_target::abi::{Integer, IntegerType, Primitive, Size};
 use rustc_target::spec::abi::Abi;
 use smallvec::SmallVec;
@@ -1550,8 +1550,13 @@ pub fn is_doc_notable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
 }
 
 /// Determines whether an item is an intrinsic by Abi.
-pub fn is_intrinsic(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
-    matches!(tcx.fn_sig(def_id).skip_binder().abi(), Abi::RustIntrinsic | Abi::PlatformIntrinsic)
+pub fn intrinsic(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<Symbol> {
+    if matches!(tcx.fn_sig(def_id).skip_binder().abi(), Abi::RustIntrinsic | Abi::PlatformIntrinsic)
+    {
+        Some(tcx.item_name(def_id.into()))
+    } else {
+        None
+    }
 }
 
 pub fn provide(providers: &mut Providers) {
@@ -1559,7 +1564,7 @@ pub fn provide(providers: &mut Providers) {
         reveal_opaque_types_in_bounds,
         is_doc_hidden,
         is_doc_notable_trait,
-        is_intrinsic,
+        intrinsic,
         ..*providers
     }
 }
diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
index cbbf3548c07ef..1575f31e75e0e 100644
--- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs
+++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
@@ -202,8 +202,7 @@ impl PeekCall {
             &terminator.kind
         {
             if let ty::FnDef(def_id, fn_args) = *func.const_.ty().kind() {
-                let name = tcx.item_name(def_id);
-                if !tcx.is_intrinsic(def_id) || name != sym::rustc_peek {
+                if tcx.intrinsic(def_id)? != sym::rustc_peek {
                     return None;
                 }
 
diff --git a/compiler/rustc_mir_transform/src/cost_checker.rs b/compiler/rustc_mir_transform/src/cost_checker.rs
index 79bed960b950f..2c692c9500303 100644
--- a/compiler/rustc_mir_transform/src/cost_checker.rs
+++ b/compiler/rustc_mir_transform/src/cost_checker.rs
@@ -70,7 +70,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
             TerminatorKind::Call { func: Operand::Constant(ref f), unwind, .. } => {
                 let fn_ty = self.instantiate_ty(f.const_.ty());
                 self.cost += if let ty::FnDef(def_id, _) = *fn_ty.kind()
-                    && tcx.is_intrinsic(def_id)
+                    && tcx.intrinsic(def_id).is_some()
                 {
                     // Don't give intrinsics the extra penalty for calls
                     INSTR_COST
diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs
index f65eb5cbea938..81cf31e6bf43a 100644
--- a/compiler/rustc_mir_transform/src/instsimplify.rs
+++ b/compiler/rustc_mir_transform/src/instsimplify.rs
@@ -329,9 +329,8 @@ fn resolve_rust_intrinsic<'tcx>(
     func_ty: Ty<'tcx>,
 ) -> Option<(Symbol, GenericArgsRef<'tcx>)> {
     if let ty::FnDef(def_id, args) = *func_ty.kind() {
-        if tcx.is_intrinsic(def_id) {
-            return Some((tcx.item_name(def_id), args));
-        }
+        let name = tcx.intrinsic(def_id)?;
+        return Some((name, args));
     }
     None
 }
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 72d9ffe8ca573..524d62546ddc7 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -161,8 +161,7 @@ fn remap_mir_for_const_eval_select<'tcx>(
                 fn_span,
                 ..
             } if let ty::FnDef(def_id, _) = *const_.ty().kind()
-                && tcx.item_name(def_id) == sym::const_eval_select
-                && tcx.is_intrinsic(def_id) =>
+                && matches!(tcx.intrinsic(def_id), Some(sym::const_eval_select)) =>
             {
                 let [tupled_args, called_in_const, called_at_rt]: [_; 3] =
                     std::mem::take(args).try_into().unwrap();
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index f43b85173d428..a0af902c4e109 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -14,9 +14,8 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
             if let TerminatorKind::Call { func, args, destination, target, .. } =
                 &mut terminator.kind
                 && let ty::FnDef(def_id, generic_args) = *func.ty(local_decls, tcx).kind()
-                && tcx.is_intrinsic(def_id)
+                && let Some(intrinsic_name) = tcx.intrinsic(def_id)
             {
-                let intrinsic_name = tcx.item_name(def_id);
                 match intrinsic_name {
                     sym::unreachable => {
                         terminator.kind = TerminatorKind::Unreachable;
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 7fa416197b35f..5fc93d666ab16 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -28,7 +28,8 @@ fn resolve_instance<'tcx>(
             tcx.normalize_erasing_regions(param_env, args),
         )
     } else {
-        let def = if matches!(tcx.def_kind(def_id), DefKind::Fn) && tcx.is_intrinsic(def_id) {
+        let def = if matches!(tcx.def_kind(def_id), DefKind::Fn) && tcx.intrinsic(def_id).is_some()
+        {
             debug!(" => intrinsic");
             ty::InstanceDef::Intrinsic(def_id)
         } else if Some(def_id) == tcx.lang_items().drop_in_place_fn() {
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 8d5bcd665ad25..47195fcc17b48 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -335,7 +335,7 @@ fn check_terminator<'tcx>(
                 // within const fns. `transmute` is allowed in all other const contexts.
                 // This won't really scale to more intrinsics or functions. Let's allow const
                 // transmutes in const fn before we add more hacks to this.
-                if tcx.is_intrinsic(fn_def_id) && tcx.item_name(fn_def_id) == sym::transmute {
+                if matches!(tcx.intrinsic(fn_def_id), Some(sym::transmute)) {
                     return Err((
                         span,
                         "can only call `transmute` from const items, not `const fn`".into(),

From 92281c7e815f3898f4403d45a079c7d266b78076 Mon Sep 17 00:00:00 2001
From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Date: Tue, 30 Jan 2024 16:03:58 +0000
Subject: [PATCH 11/58] Implement intrinsics with fallback bodies

---
 compiler/rustc_codegen_ssa/src/mir/block.rs   |   2 +-
 compiler/rustc_feature/src/builtin_attrs.rs   |   4 +
 compiler/rustc_metadata/src/rmeta/decoder.rs  |   4 +-
 .../src/rmeta/decoder/cstore_impl.rs          |   2 +-
 compiler/rustc_metadata/src/rmeta/encoder.rs  |   4 +-
 compiler/rustc_metadata/src/rmeta/mod.rs      |   2 +-
 compiler/rustc_middle/src/ty/util.rs          |   3 +-
 compiler/rustc_span/src/symbol.rs             |   1 +
 library/core/src/intrinsics.rs                | 138 +++++++++---------
 .../src/language-features/intrinsics.md       |  52 ++++++-
 src/librustdoc/clean/types.rs                 |   2 +-
 tests/ui/consts/is_val_statically_known.rs    |   3 +-
 12 files changed, 136 insertions(+), 81 deletions(-)

diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index e35b4029b4506..a4d97200cdbd0 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -787,7 +787,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
         // Handle intrinsics old codegen wants Expr's for, ourselves.
         let intrinsic = match def {
-            Some(ty::InstanceDef::Intrinsic(def_id)) => Some(bx.tcx().item_name(def_id)),
+            Some(ty::InstanceDef::Intrinsic(def_id)) => Some(bx.tcx().intrinsic(def_id).unwrap()),
             _ => None,
         };
 
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 019cc1c847e91..155eb834ecd2a 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -788,6 +788,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         rustc_safe_intrinsic, Normal, template!(Word), WarnFollowing,
         "the `#[rustc_safe_intrinsic]` attribute is used internally to mark intrinsics as safe"
     ),
+    rustc_attr!(
+        rustc_intrinsic, Normal, template!(Word), ErrorFollowing,
+        "the `#[rustc_intrinsic]` attribute is used to declare intrinsics with function bodies",
+    ),
 
     // ==========================================================================
     // Internal attributes, Testing:
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index a738fc86a068c..a24961df67b75 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1746,8 +1746,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         self.root.tables.attr_flags.get(self, index)
     }
 
-    fn get_intrinsic(self, index: DefIndex) -> bool {
-        self.root.tables.intrinsic.get(self, index)
+    fn get_intrinsic(self, index: DefIndex) -> Option<Symbol> {
+        self.root.tables.intrinsic.get(self, index).map(|d| d.decode(self))
     }
 
     fn get_doc_link_resolutions(self, index: DefIndex) -> DocLinkResMap {
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 1faddee2e9812..1cbf854f733de 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -348,7 +348,7 @@ provide! { tcx, def_id, other, cdata,
         cdata.get_stability_implications(tcx).iter().copied().collect()
     }
     stripped_cfg_items => { cdata.get_stripped_cfg_items(cdata.cnum, tcx) }
-    intrinsic => { cdata.get_intrinsic(def_id.index).then(|| tcx.item_name(def_id)) }
+    intrinsic => { cdata.get_intrinsic(def_id.index) }
     defined_lang_items => { cdata.get_lang_items(tcx) }
     diagnostic_items => { cdata.get_diagnostic_items() }
     missing_lang_items => { cdata.get_missing_lang_items(tcx) }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index f32131854490a..54061a2c6fc6b 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1411,7 +1411,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             if let DefKind::Fn | DefKind::AssocFn = def_kind {
                 self.tables.asyncness.set_some(def_id.index, tcx.asyncness(def_id));
                 record_array!(self.tables.fn_arg_names[def_id] <- tcx.fn_arg_names(def_id));
-                self.tables.intrinsic.set(def_id.index, tcx.intrinsic(def_id).is_some());
+                if let Some(name) = tcx.intrinsic(def_id) {
+                    record!(self.tables.intrinsic[def_id] <- name);
+                }
             }
             if let DefKind::TyParam = def_kind {
                 let default = self.tcx.object_lifetime_default(def_id);
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 49c97b8c2e6a7..6b4b12e9d6a04 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -375,7 +375,7 @@ macro_rules! define_tables {
 
 define_tables! {
 - defaulted:
-    intrinsic: Table<DefIndex, bool>,
+    intrinsic: Table<DefIndex, Option<LazyValue<Symbol>>>,
     is_macro_rules: Table<DefIndex, bool>,
     is_type_alias_impl_trait: Table<DefIndex, bool>,
     type_alias_is_lazy: Table<DefIndex, bool>,
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 626ea0342e568..1f64c76a57ce0 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -1549,9 +1549,10 @@ pub fn is_doc_notable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
         .any(|items| items.iter().any(|item| item.has_name(sym::notable_trait)))
 }
 
-/// Determines whether an item is an intrinsic by Abi.
+/// Determines whether an item is an intrinsic by Abi. or by whether it has a `rustc_intrinsic` attribute
 pub fn intrinsic(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<Symbol> {
     if matches!(tcx.fn_sig(def_id).skip_binder().abi(), Abi::RustIntrinsic | Abi::PlatformIntrinsic)
+        || tcx.has_attr(def_id, sym::rustc_intrinsic)
     {
         Some(tcx.item_name(def_id.into()))
     } else {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index aa912c93c08c6..0b5ee2bc51b13 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1418,6 +1418,7 @@ symbols! {
         rustc_if_this_changed,
         rustc_inherit_overflow_checks,
         rustc_insignificant_dtor,
+        rustc_intrinsic,
         rustc_layout,
         rustc_layout_scalar_valid_range_end,
         rustc_layout_scalar_valid_range_start,
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index c8259c0024c75..375fa1350b547 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -2517,79 +2517,79 @@ extern "rust-intrinsic" {
     where
         G: FnOnce<ARG, Output = RET>,
         F: FnOnce<ARG, Output = RET>;
+}
 
-    /// Returns whether the argument's value is statically known at
-    /// compile-time.
-    ///
-    /// This is useful when there is a way of writing the code that will
-    /// be *faster* when some variables have known values, but *slower*
-    /// in the general case: an `if is_val_statically_known(var)` can be used
-    /// to select between these two variants. The `if` will be optimized away
-    /// and only the desired branch remains.
-    ///
-    /// Formally speaking, this function non-deterministically returns `true`
-    /// or `false`, and the caller has to ensure sound behavior for both cases.
-    /// In other words, the following code has *Undefined Behavior*:
-    ///
-    /// ```no_run
-    /// #![feature(is_val_statically_known)]
-    /// #![feature(core_intrinsics)]
-    /// # #![allow(internal_features)]
-    /// use std::hint::unreachable_unchecked;
-    /// use std::intrinsics::is_val_statically_known;
-    ///
-    /// unsafe {
-    ///    if !is_val_statically_known(0) { unreachable_unchecked(); }
-    /// }
-    /// ```
-    ///
-    /// This also means that the following code's behavior is unspecified; it
-    /// may panic, or it may not:
-    ///
-    /// ```no_run
-    /// #![feature(is_val_statically_known)]
-    /// #![feature(core_intrinsics)]
-    /// # #![allow(internal_features)]
-    /// use std::intrinsics::is_val_statically_known;
-    ///
-    /// unsafe {
-    ///     assert_eq!(is_val_statically_known(0), is_val_statically_known(0));
-    /// }
-    /// ```
-    ///
-    /// Unsafe code may not rely on `is_val_statically_known` returning any
-    /// particular value, ever. However, the compiler will generally make it
-    /// return `true` only if the value of the argument is actually known.
-    ///
-    /// When calling this in a `const fn`, both paths must be semantically
-    /// equivalent, that is, the result of the `true` branch and the `false`
-    /// branch must return the same value and have the same side-effects *no
-    /// matter what*.
-    #[rustc_const_unstable(feature = "is_val_statically_known", issue = "none")]
-    #[rustc_nounwind]
-    pub fn is_val_statically_known<T: Copy>(arg: T) -> bool;
-
-    /// Returns the value of `cfg!(debug_assertions)`, but after monomorphization instead of in
-    /// macro expansion.
-    ///
-    /// This always returns `false` in const eval and Miri. The interpreter provides better
-    /// diagnostics than the checks that this is used to implement. However, this means
-    /// you should only be using this intrinsic to guard requirements that, if violated,
-    /// immediately lead to UB. Otherwise, const-eval and Miri will miss out on those
-    /// checks entirely.
-    ///
-    /// Since this is evaluated after monomorphization, branching on this value can be used to
-    /// implement debug assertions that are included in the precompiled standard library, but can
-    /// be optimized out by builds that monomorphize the standard library code with debug
-    /// assertions disabled. This intrinsic is primarily used by [`assert_unsafe_precondition`].
-    #[rustc_const_unstable(feature = "delayed_debug_assertions", issue = "none")]
-    #[rustc_safe_intrinsic]
-    #[cfg(not(bootstrap))]
-    pub(crate) fn debug_assertions() -> bool;
+/// Returns whether the argument's value is statically known at
+/// compile-time.
+///
+/// This is useful when there is a way of writing the code that will
+/// be *faster* when some variables have known values, but *slower*
+/// in the general case: an `if is_val_statically_known(var)` can be used
+/// to select between these two variants. The `if` will be optimized away
+/// and only the desired branch remains.
+///
+/// Formally speaking, this function non-deterministically returns `true`
+/// or `false`, and the caller has to ensure sound behavior for both cases.
+/// In other words, the following code has *Undefined Behavior*:
+///
+/// ```no_run
+/// #![feature(is_val_statically_known)]
+/// #![feature(core_intrinsics)]
+/// # #![allow(internal_features)]
+/// use std::hint::unreachable_unchecked;
+/// use std::intrinsics::is_val_statically_known;
+///
+/// unsafe {
+///    if !is_val_statically_known(0) { unreachable_unchecked(); }
+/// }
+/// ```
+///
+/// This also means that the following code's behavior is unspecified; it
+/// may panic, or it may not:
+///
+/// ```no_run
+/// #![feature(is_val_statically_known)]
+/// #![feature(core_intrinsics)]
+/// # #![allow(internal_features)]
+/// use std::intrinsics::is_val_statically_known;
+///
+/// unsafe {
+///     assert_eq!(is_val_statically_known(0), is_val_statically_known(0));
+/// }
+/// ```
+///
+/// Unsafe code may not rely on `is_val_statically_known` returning any
+/// particular value, ever. However, the compiler will generally make it
+/// return `true` only if the value of the argument is actually known.
+///
+/// When calling this in a `const fn`, both paths must be semantically
+/// equivalent, that is, the result of the `true` branch and the `false`
+/// branch must return the same value and have the same side-effects *no
+/// matter what*.
+#[rustc_const_unstable(feature = "is_val_statically_known", issue = "none")]
+#[rustc_nounwind]
+#[unstable(feature = "core_intrinsics", issue = "none")]
+#[cfg_attr(not(bootstrap), rustc_intrinsic)]
+pub const unsafe fn is_val_statically_known<T: Copy>(_arg: T) -> bool {
+    false
 }
 
-#[cfg(bootstrap)]
+/// Returns the value of `cfg!(debug_assertions)`, but after monomorphization instead of in
+/// macro expansion.
+///
+/// This always returns `false` in const eval and Miri. The interpreter provides better
+/// diagnostics than the checks that this is used to implement. However, this means
+/// you should only be using this intrinsic to guard requirements that, if violated,
+/// immediately lead to UB. Otherwise, const-eval and Miri will miss out on those
+/// checks entirely.
+///
+/// Since this is evaluated after monomorphization, branching on this value can be used to
+/// implement debug assertions that are included in the precompiled standard library, but can
+/// be optimized out by builds that monomorphize the standard library code with debug
+/// assertions disabled. This intrinsic is primarily used by [`assert_unsafe_precondition`].
 #[rustc_const_unstable(feature = "delayed_debug_assertions", issue = "none")]
+#[unstable(feature = "core_intrinsics", issue = "none")]
+#[cfg_attr(not(bootstrap), rustc_intrinsic)]
 pub(crate) const fn debug_assertions() -> bool {
     cfg!(debug_assertions)
 }
diff --git a/src/doc/unstable-book/src/language-features/intrinsics.md b/src/doc/unstable-book/src/language-features/intrinsics.md
index 8fa8f567d7eed..9d07ae6fc67e1 100644
--- a/src/doc/unstable-book/src/language-features/intrinsics.md
+++ b/src/doc/unstable-book/src/language-features/intrinsics.md
@@ -2,13 +2,60 @@
 
 The tracking issue for this feature is: None.
 
-Intrinsics are never intended to be stable directly, but intrinsics are often
+Intrinsics are rarely intended to be stable directly, but are usually
 exported in some sort of stable manner. Prefer using the stable interfaces to
 the intrinsic directly when you can.
 
 ------------------------
 
 
+## Intrinsics with fallback logic
+
+Many intrinsics can be written in pure rust, albeit inefficiently or without supporting
+some features that only exist on some backends. Backends can simply not implement those
+intrinsics without causing any code miscompilations or failures to compile.
+
+```rust
+#![feature(rustc_attrs, effects)]
+#![allow(internal_features)]
+
+#[rustc_intrinsic]
+const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
+```
+
+Since these are just regular functions, it is perfectly ok to create the intrinsic twice:
+
+```rust
+#![feature(rustc_attrs, effects)]
+#![allow(internal_features)]
+
+#[rustc_intrinsic]
+const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
+
+mod foo {
+    #[rustc_intrinsic]
+    const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {
+        panic!("noisy const dealloc")
+    }
+}
+
+```
+
+The behaviour on backends that override the intrinsic is exactly the same. On other
+backends, the intrinsic behaviour depends on which implementation is called, just like
+with any regular function.
+
+## Intrinsics lowered to MIR instructions
+
+Various intrinsics have native MIR operations that they correspond to. Instead of requiring
+backends to implement both the intrinsic and the MIR operation, the `lower_intrinsics` pass
+will convert the calls to the MIR operation. Backends do not need to know about these intrinsics
+at all.
+
+## Intrinsics without fallback logic
+
+These must be implemented by all backends.
+
 These are imported as if they were FFI functions, with the special
 `rust-intrinsic` ABI. For example, if one was in a freestanding
 context, but wished to be able to `transmute` between types, and
@@ -27,4 +74,5 @@ extern "rust-intrinsic" {
 }
 ```
 
-As with any other FFI functions, these are always `unsafe` to call.
+As with any other FFI functions, these are by default always `unsafe` to call.
+You can add `#[rustc_safe_intrinsic]` to the intrinsic to make it safe to call.
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 6710193f9611a..f39276f17780f 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -643,7 +643,7 @@ impl Item {
                 let abi = tcx.fn_sig(def_id).skip_binder().abi();
                 hir::FnHeader {
                     unsafety: if abi == Abi::RustIntrinsic {
-                        intrinsic_operation_unsafety(tcx, self.def_id().unwrap())
+                        intrinsic_operation_unsafety(tcx, def_id.expect_local())
                     } else {
                         hir::Unsafety::Unsafe
                     },
diff --git a/tests/ui/consts/is_val_statically_known.rs b/tests/ui/consts/is_val_statically_known.rs
index b0565842eb4e2..b4056375543ef 100644
--- a/tests/ui/consts/is_val_statically_known.rs
+++ b/tests/ui/consts/is_val_statically_known.rs
@@ -1,7 +1,6 @@
 // run-pass
 
-#![feature(core_intrinsics)]
-#![feature(is_val_statically_known)]
+#![feature(core_intrinsics, is_val_statically_known)]
 
 use std::intrinsics::is_val_statically_known;
 

From 79daf6107c6242dd211d43068b71959f50887146 Mon Sep 17 00:00:00 2001
From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Date: Wed, 31 Jan 2024 14:05:14 +0000
Subject: [PATCH 12/58] Make the signature of equate_intrinsic_type support
 items other than `ForeignItem`

---
 .../rustc_hir_analysis/src/check/intrinsic.rs | 38 ++++++++++---------
 compiler/rustc_hir_analysis/src/collect.rs    |  2 +-
 2 files changed, 22 insertions(+), 18 deletions(-)

diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index dc391ab5648c6..fbafbdcdecc48 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -7,30 +7,35 @@ use crate::errors::{
     WrongNumberOfGenericArgumentsToIntrinsic,
 };
 
-use hir::def_id::DefId;
 use rustc_errors::{codes::*, struct_span_code_err, DiagnosticMessage};
 use rustc_hir as hir;
 use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::{kw, sym};
+use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
 
 fn equate_intrinsic_type<'tcx>(
     tcx: TyCtxt<'tcx>,
-    it: &hir::ForeignItem<'_>,
+    span: Span,
+    def_id: LocalDefId,
     n_tps: usize,
     n_lts: usize,
     n_cts: usize,
     sig: ty::PolyFnSig<'tcx>,
 ) {
-    let (own_counts, span) = match &it.kind {
-        hir::ForeignItemKind::Fn(.., generics) => {
-            let own_counts = tcx.generics_of(it.owner_id.to_def_id()).own_counts();
+    let (own_counts, span) = match tcx.hir_node_by_def_id(def_id) {
+        hir::Node::ForeignItem(hir::ForeignItem {
+            kind: hir::ForeignItemKind::Fn(.., generics),
+            ..
+        }) => {
+            let own_counts = tcx.generics_of(def_id).own_counts();
             (own_counts, generics.span)
         }
         _ => {
-            struct_span_code_err!(tcx.dcx(), it.span, E0622, "intrinsic must be a function")
-                .with_span_label(it.span, "expected a function")
+            struct_span_code_err!(tcx.dcx(), span, E0622, "intrinsic must be a function")
+                .with_span_label(span, "expected a function")
                 .emit();
             return;
         }
@@ -54,23 +59,22 @@ fn equate_intrinsic_type<'tcx>(
         && gen_count_ok(own_counts.types, n_tps, "type")
         && gen_count_ok(own_counts.consts, n_cts, "const")
     {
-        let it_def_id = it.owner_id.def_id;
         let _ = check_function_signature(
             tcx,
-            ObligationCause::new(it.span, it_def_id, ObligationCauseCode::IntrinsicType),
-            it_def_id.into(),
+            ObligationCause::new(span, def_id, ObligationCauseCode::IntrinsicType),
+            def_id.into(),
             sig,
         );
     }
 }
 
 /// Returns the unsafety of the given intrinsic.
-pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: DefId) -> hir::Unsafety {
+pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hir::Unsafety {
     let has_safe_attr = match tcx.has_attr(intrinsic_id, sym::rustc_safe_intrinsic) {
         true => hir::Unsafety::Normal,
         false => hir::Unsafety::Unsafe,
     };
-    let is_in_list = match tcx.item_name(intrinsic_id) {
+    let is_in_list = match tcx.item_name(intrinsic_id.into()) {
         // When adding a new intrinsic to this list,
         // it's usually worth updating that intrinsic's documentation
         // to note that it's safe to call, since
@@ -122,7 +126,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: DefId) -> hir
             tcx.def_span(intrinsic_id),
             DiagnosticMessage::from(format!(
                 "intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `{}`",
-                tcx.item_name(intrinsic_id)
+                tcx.item_name(intrinsic_id.into())
             )
         )).emit();
     }
@@ -144,8 +148,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             Ty::new_error_with_message(tcx, tcx.def_span(it.owner_id), "expected param")
         }
     };
-    let intrinsic_id = it.owner_id.to_def_id();
-    let intrinsic_name = tcx.item_name(intrinsic_id);
+    let intrinsic_id = it.owner_id.def_id;
+    let intrinsic_name = tcx.item_name(intrinsic_id.into());
     let name_str = intrinsic_name.as_str();
 
     let bound_vars = tcx.mk_bound_variable_kinds(&[
@@ -483,7 +487,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
     };
     let sig = tcx.mk_fn_sig(inputs, output, false, unsafety, Abi::RustIntrinsic);
     let sig = ty::Binder::bind_with_vars(sig, bound_vars);
-    equate_intrinsic_type(tcx, it, n_tps, n_lts, 0, sig)
+    equate_intrinsic_type(tcx, it.span, intrinsic_id, n_tps, n_lts, 0, sig)
 }
 
 /// Type-check `extern "platform-intrinsic" { ... }` functions.
@@ -581,5 +585,5 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
 
     let sig = tcx.mk_fn_sig(inputs, output, false, hir::Unsafety::Unsafe, Abi::PlatformIntrinsic);
     let sig = ty::Binder::dummy(sig);
-    equate_intrinsic_type(tcx, it, n_tps, 0, n_cts, sig)
+    equate_intrinsic_type(tcx, it.span, it.owner_id.def_id, n_tps, 0, n_cts, sig)
 }
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index f458ff01c104c..3eb64f8b56e52 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -1480,7 +1480,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
     abi: abi::Abi,
 ) -> ty::PolyFnSig<'tcx> {
     let unsafety = if abi == abi::Abi::RustIntrinsic {
-        intrinsic_operation_unsafety(tcx, def_id.to_def_id())
+        intrinsic_operation_unsafety(tcx, def_id)
     } else {
         hir::Unsafety::Unsafe
     };

From fffcb4c8771ad1a688bf9083d948769664d5fcb0 Mon Sep 17 00:00:00 2001
From: PizzasBear <43722034+PizzasBear@users.noreply.github.com>
Date: Mon, 12 Feb 2024 16:00:15 +0200
Subject: [PATCH 13/58] Fix comment in core/src/str/validations.rs

---
 library/core/src/str/validations.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library/core/src/str/validations.rs b/library/core/src/str/validations.rs
index 2acef432f2063..a11d7fee8af0c 100644
--- a/library/core/src/str/validations.rs
+++ b/library/core/src/str/validations.rs
@@ -161,7 +161,7 @@ pub(super) const fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> {
             //        first  E0 A0 80     last EF BF BF
             //   excluding surrogates codepoints  \u{d800} to  \u{dfff}
             //               ED A0 80 to       ED BF BF
-            // 4-byte encoding is for codepoints \u{1000}0 to \u{10ff}ff
+            // 4-byte encoding is for codepoints \u{10000} to \u{10ffff}
             //        first  F0 90 80 80  last F4 8F BF BF
             //
             // Use the UTF-8 syntax from the RFC

From 09fd5569624f2581337d46c88940ac8db517d88e Mon Sep 17 00:00:00 2001
From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Date: Wed, 31 Jan 2024 14:09:42 +0000
Subject: [PATCH 14/58] Make check_intrinsic_type not require ForeignItems
 anymore

---
 .../rustc_hir_analysis/src/check/check.rs     | 11 ++++---
 .../rustc_hir_analysis/src/check/intrinsic.rs | 32 ++++++++++---------
 2 files changed, 24 insertions(+), 19 deletions(-)

diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 7250dc81faf8b..6bc3617660284 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -533,15 +533,18 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
             match abi {
                 Abi::RustIntrinsic => {
                     for item in items {
-                        let item = tcx.hir().foreign_item(item.id);
-                        intrinsic::check_intrinsic_type(tcx, item);
+                        intrinsic::check_intrinsic_type(tcx, item.id.owner_id.def_id, item.span);
                     }
                 }
 
                 Abi::PlatformIntrinsic => {
                     for item in items {
-                        let item = tcx.hir().foreign_item(item.id);
-                        intrinsic::check_platform_intrinsic_type(tcx, item);
+                        intrinsic::check_platform_intrinsic_type(
+                            tcx,
+                            item.id.owner_id.def_id,
+                            item.span,
+                            item.ident.name,
+                        );
                     }
                 }
 
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index fbafbdcdecc48..50da6bcbf7306 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -13,7 +13,7 @@ use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::{kw, sym};
-use rustc_span::Span;
+use rustc_span::{Span, Symbol};
 use rustc_target::spec::abi::Abi;
 
 fn equate_intrinsic_type<'tcx>(
@@ -136,8 +136,8 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
 
 /// Remember to add all intrinsics here, in `compiler/rustc_codegen_llvm/src/intrinsic.rs`,
 /// and in `library/core/src/intrinsics.rs`.
-pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
-    let generics = tcx.generics_of(it.owner_id);
+pub fn check_intrinsic_type(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId, span: Span) {
+    let generics = tcx.generics_of(intrinsic_id);
     let param = |n| {
         if let Some(&ty::GenericParamDef {
             name, kind: ty::GenericParamDefKind::Type { .. }, ..
@@ -145,10 +145,9 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
         {
             Ty::new_param(tcx, n, name)
         } else {
-            Ty::new_error_with_message(tcx, tcx.def_span(it.owner_id), "expected param")
+            Ty::new_error_with_message(tcx, span, "expected param")
         }
     };
-    let intrinsic_id = it.owner_id.def_id;
     let intrinsic_name = tcx.item_name(intrinsic_id.into());
     let name_str = intrinsic_name.as_str();
 
@@ -191,7 +190,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             | "umin" => (1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], param(0)),
             "fence" | "singlethreadfence" => (0, Vec::new(), Ty::new_unit(tcx)),
             op => {
-                tcx.dcx().emit_err(UnrecognizedAtomicOperation { span: it.span, op });
+                tcx.dcx().emit_err(UnrecognizedAtomicOperation { span, op });
                 return;
             }
         };
@@ -479,7 +478,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             sym::debug_assertions => (0, Vec::new(), tcx.types.bool),
 
             other => {
-                tcx.dcx().emit_err(UnrecognizedIntrinsicFunction { span: it.span, name: other });
+                tcx.dcx().emit_err(UnrecognizedIntrinsicFunction { span, name: other });
                 return;
             }
         };
@@ -487,12 +486,17 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
     };
     let sig = tcx.mk_fn_sig(inputs, output, false, unsafety, Abi::RustIntrinsic);
     let sig = ty::Binder::bind_with_vars(sig, bound_vars);
-    equate_intrinsic_type(tcx, it.span, intrinsic_id, n_tps, n_lts, 0, sig)
+    equate_intrinsic_type(tcx, span, intrinsic_id, n_tps, n_lts, 0, sig)
 }
 
 /// Type-check `extern "platform-intrinsic" { ... }` functions.
-pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
-    let generics = tcx.generics_of(it.owner_id);
+pub fn check_platform_intrinsic_type(
+    tcx: TyCtxt<'_>,
+    intrinsic_id: LocalDefId,
+    span: Span,
+    name: Symbol,
+) {
+    let generics = tcx.generics_of(intrinsic_id);
     let param = |n| {
         if let Some(&ty::GenericParamDef {
             name, kind: ty::GenericParamDefKind::Type { .. }, ..
@@ -500,12 +504,10 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
         {
             Ty::new_param(tcx, n, name)
         } else {
-            Ty::new_error_with_message(tcx, tcx.def_span(it.owner_id), "expected param")
+            Ty::new_error_with_message(tcx, span, "expected param")
         }
     };
 
-    let name = it.ident.name;
-
     let (n_tps, n_cts, inputs, output) = match name {
         sym::simd_eq | sym::simd_ne | sym::simd_lt | sym::simd_le | sym::simd_gt | sym::simd_ge => {
             (2, 0, vec![param(0), param(0)], param(1))
@@ -578,12 +580,12 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
         sym::simd_shuffle_generic => (2, 1, vec![param(0), param(0)], param(1)),
         _ => {
             let msg = format!("unrecognized platform-specific intrinsic function: `{name}`");
-            tcx.dcx().span_err(it.span, msg);
+            tcx.dcx().span_err(span, msg);
             return;
         }
     };
 
     let sig = tcx.mk_fn_sig(inputs, output, false, hir::Unsafety::Unsafe, Abi::PlatformIntrinsic);
     let sig = ty::Binder::dummy(sig);
-    equate_intrinsic_type(tcx, it.span, it.owner_id.def_id, n_tps, 0, n_cts, sig)
+    equate_intrinsic_type(tcx, span, intrinsic_id, n_tps, 0, n_cts, sig)
 }

From 0dac617a75bdc76f7984af9ade104b50182b4388 Mon Sep 17 00:00:00 2001
From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Date: Wed, 31 Jan 2024 14:22:10 +0000
Subject: [PATCH 15/58] support adding const generic params to intrinsics

but right now all of them have zero const generic params
---
 .../rustc_hir_analysis/src/check/intrinsic.rs | 196 ++++++++++--------
 1 file changed, 104 insertions(+), 92 deletions(-)

diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 50da6bcbf7306..fe1a5a289649d 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -172,7 +172,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId, span: Spa
         })
     };
 
-    let (n_tps, n_lts, inputs, output, unsafety) = if name_str.starts_with("atomic_") {
+    let (n_tps, n_lts, n_cts, inputs, output, unsafety) = if name_str.starts_with("atomic_") {
         let split: Vec<&str> = name_str.split('_').collect();
         assert!(split.len() >= 2, "Atomic intrinsic in an incorrect format");
 
@@ -194,45 +194,47 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId, span: Spa
                 return;
             }
         };
-        (n_tps, 0, inputs, output, hir::Unsafety::Unsafe)
+        (n_tps, 0, 0, inputs, output, hir::Unsafety::Unsafe)
     } else {
         let unsafety = intrinsic_operation_unsafety(tcx, intrinsic_id);
-        let (n_tps, inputs, output) = match intrinsic_name {
-            sym::abort => (0, Vec::new(), tcx.types.never),
-            sym::unreachable => (0, Vec::new(), tcx.types.never),
-            sym::breakpoint => (0, Vec::new(), Ty::new_unit(tcx)),
+        let (n_tps, n_cts, inputs, output) = match intrinsic_name {
+            sym::abort => (0, 0, vec![], tcx.types.never),
+            sym::unreachable => (0, 0, vec![], tcx.types.never),
+            sym::breakpoint => (0, 0, vec![], Ty::new_unit(tcx)),
             sym::size_of | sym::pref_align_of | sym::min_align_of | sym::variant_count => {
-                (1, Vec::new(), tcx.types.usize)
+                (1, 0, vec![], tcx.types.usize)
             }
             sym::size_of_val | sym::min_align_of_val => {
-                (1, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.usize)
+                (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.usize)
             }
-            sym::rustc_peek => (1, vec![param(0)], param(0)),
-            sym::caller_location => (0, vec![], tcx.caller_location_ty()),
+            sym::rustc_peek => (1, 0, vec![param(0)], param(0)),
+            sym::caller_location => (0, 0, vec![], tcx.caller_location_ty()),
             sym::assert_inhabited
             | sym::assert_zero_valid
-            | sym::assert_mem_uninitialized_valid => (1, Vec::new(), Ty::new_unit(tcx)),
-            sym::forget => (1, vec![param(0)], Ty::new_unit(tcx)),
-            sym::transmute | sym::transmute_unchecked => (2, vec![param(0)], param(1)),
+            | sym::assert_mem_uninitialized_valid => (1, 0, vec![], Ty::new_unit(tcx)),
+            sym::forget => (1, 0, vec![param(0)], Ty::new_unit(tcx)),
+            sym::transmute | sym::transmute_unchecked => (2, 0, vec![param(0)], param(1)),
             sym::prefetch_read_data
             | sym::prefetch_write_data
             | sym::prefetch_read_instruction
             | sym::prefetch_write_instruction => (
                 1,
+                0,
                 vec![
                     Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
                     tcx.types.i32,
                 ],
                 Ty::new_unit(tcx),
             ),
-            sym::drop_in_place => (1, vec![Ty::new_mut_ptr(tcx, param(0))], Ty::new_unit(tcx)),
-            sym::needs_drop => (1, Vec::new(), tcx.types.bool),
+            sym::drop_in_place => (1, 0, vec![Ty::new_mut_ptr(tcx, param(0))], Ty::new_unit(tcx)),
+            sym::needs_drop => (1, 0, vec![], tcx.types.bool),
 
-            sym::type_name => (1, Vec::new(), Ty::new_static_str(tcx)),
-            sym::type_id => (1, Vec::new(), tcx.types.u128),
-            sym::offset => (2, vec![param(0), param(1)], param(0)),
+            sym::type_name => (1, 0, vec![], Ty::new_static_str(tcx)),
+            sym::type_id => (1, 0, vec![], tcx.types.u128),
+            sym::offset => (2, 0, vec![param(0), param(1)], param(0)),
             sym::arith_offset => (
                 1,
+                0,
                 vec![
                     Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
                     tcx.types.isize,
@@ -241,6 +243,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId, span: Spa
             ),
             sym::ptr_mask => (
                 1,
+                0,
                 vec![
                     Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
                     tcx.types.usize,
@@ -250,6 +253,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId, span: Spa
 
             sym::copy | sym::copy_nonoverlapping => (
                 1,
+                0,
                 vec![
                     Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
                     Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }),
@@ -259,6 +263,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId, span: Spa
             ),
             sym::volatile_copy_memory | sym::volatile_copy_nonoverlapping_memory => (
                 1,
+                0,
                 vec![
                     Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }),
                     Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
@@ -268,10 +273,11 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId, span: Spa
             ),
             sym::compare_bytes => {
                 let byte_ptr = Ty::new_imm_ptr(tcx, tcx.types.u8);
-                (0, vec![byte_ptr, byte_ptr, tcx.types.usize], tcx.types.i32)
+                (0, 0, vec![byte_ptr, byte_ptr, tcx.types.usize], tcx.types.i32)
             }
             sym::write_bytes | sym::volatile_set_memory => (
                 1,
+                0,
                 vec![
                     Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }),
                     tcx.types.u8,
@@ -279,56 +285,56 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId, span: Spa
                 ],
                 Ty::new_unit(tcx),
             ),
-            sym::sqrtf32 => (0, vec![tcx.types.f32], tcx.types.f32),
-            sym::sqrtf64 => (0, vec![tcx.types.f64], tcx.types.f64),
-            sym::powif32 => (0, vec![tcx.types.f32, tcx.types.i32], tcx.types.f32),
-            sym::powif64 => (0, vec![tcx.types.f64, tcx.types.i32], tcx.types.f64),
-            sym::sinf32 => (0, vec![tcx.types.f32], tcx.types.f32),
-            sym::sinf64 => (0, vec![tcx.types.f64], tcx.types.f64),
-            sym::cosf32 => (0, vec![tcx.types.f32], tcx.types.f32),
-            sym::cosf64 => (0, vec![tcx.types.f64], tcx.types.f64),
-            sym::powf32 => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
-            sym::powf64 => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
-            sym::expf32 => (0, vec![tcx.types.f32], tcx.types.f32),
-            sym::expf64 => (0, vec![tcx.types.f64], tcx.types.f64),
-            sym::exp2f32 => (0, vec![tcx.types.f32], tcx.types.f32),
-            sym::exp2f64 => (0, vec![tcx.types.f64], tcx.types.f64),
-            sym::logf32 => (0, vec![tcx.types.f32], tcx.types.f32),
-            sym::logf64 => (0, vec![tcx.types.f64], tcx.types.f64),
-            sym::log10f32 => (0, vec![tcx.types.f32], tcx.types.f32),
-            sym::log10f64 => (0, vec![tcx.types.f64], tcx.types.f64),
-            sym::log2f32 => (0, vec![tcx.types.f32], tcx.types.f32),
-            sym::log2f64 => (0, vec![tcx.types.f64], tcx.types.f64),
-            sym::fmaf32 => (0, vec![tcx.types.f32, tcx.types.f32, tcx.types.f32], tcx.types.f32),
-            sym::fmaf64 => (0, vec![tcx.types.f64, tcx.types.f64, tcx.types.f64], tcx.types.f64),
-            sym::fabsf32 => (0, vec![tcx.types.f32], tcx.types.f32),
-            sym::fabsf64 => (0, vec![tcx.types.f64], tcx.types.f64),
-            sym::minnumf32 => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
-            sym::minnumf64 => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
-            sym::maxnumf32 => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
-            sym::maxnumf64 => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
-            sym::copysignf32 => (0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
-            sym::copysignf64 => (0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
-            sym::floorf32 => (0, vec![tcx.types.f32], tcx.types.f32),
-            sym::floorf64 => (0, vec![tcx.types.f64], tcx.types.f64),
-            sym::ceilf32 => (0, vec![tcx.types.f32], tcx.types.f32),
-            sym::ceilf64 => (0, vec![tcx.types.f64], tcx.types.f64),
-            sym::truncf32 => (0, vec![tcx.types.f32], tcx.types.f32),
-            sym::truncf64 => (0, vec![tcx.types.f64], tcx.types.f64),
-            sym::rintf32 => (0, vec![tcx.types.f32], tcx.types.f32),
-            sym::rintf64 => (0, vec![tcx.types.f64], tcx.types.f64),
-            sym::nearbyintf32 => (0, vec![tcx.types.f32], tcx.types.f32),
-            sym::nearbyintf64 => (0, vec![tcx.types.f64], tcx.types.f64),
-            sym::roundf32 => (0, vec![tcx.types.f32], tcx.types.f32),
-            sym::roundf64 => (0, vec![tcx.types.f64], tcx.types.f64),
-            sym::roundevenf32 => (0, vec![tcx.types.f32], tcx.types.f32),
-            sym::roundevenf64 => (0, vec![tcx.types.f64], tcx.types.f64),
+            sym::sqrtf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
+            sym::sqrtf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::powif32 => (0, 0, vec![tcx.types.f32, tcx.types.i32], tcx.types.f32),
+            sym::powif64 => (0, 0, vec![tcx.types.f64, tcx.types.i32], tcx.types.f64),
+            sym::sinf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
+            sym::sinf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::cosf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
+            sym::cosf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::powf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
+            sym::powf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
+            sym::expf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
+            sym::expf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::exp2f32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
+            sym::exp2f64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::logf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
+            sym::logf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::log10f32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
+            sym::log10f64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::log2f32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
+            sym::log2f64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::fmaf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32, tcx.types.f32], tcx.types.f32),
+            sym::fmaf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64, tcx.types.f64], tcx.types.f64),
+            sym::fabsf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
+            sym::fabsf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::minnumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
+            sym::minnumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
+            sym::maxnumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
+            sym::maxnumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
+            sym::copysignf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
+            sym::copysignf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
+            sym::floorf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
+            sym::floorf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::ceilf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
+            sym::ceilf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::truncf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
+            sym::truncf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::rintf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
+            sym::rintf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::nearbyintf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
+            sym::nearbyintf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::roundf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
+            sym::roundf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
+            sym::roundevenf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
+            sym::roundevenf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
 
             sym::volatile_load | sym::unaligned_volatile_load => {
-                (1, vec![Ty::new_imm_ptr(tcx, param(0))], param(0))
+                (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(0))
             }
             sym::volatile_store | sym::unaligned_volatile_store => {
-                (1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], Ty::new_unit(tcx))
+                (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], Ty::new_unit(tcx))
             }
 
             sym::ctpop
@@ -337,22 +343,24 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId, span: Spa
             | sym::cttz
             | sym::cttz_nonzero
             | sym::bswap
-            | sym::bitreverse => (1, vec![param(0)], param(0)),
+            | sym::bitreverse => (1, 0, vec![param(0)], param(0)),
 
             sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => {
-                (1, vec![param(0), param(0)], Ty::new_tup(tcx, &[param(0), tcx.types.bool]))
+                (1, 0, vec![param(0), param(0)], Ty::new_tup(tcx, &[param(0), tcx.types.bool]))
             }
 
             sym::ptr_guaranteed_cmp => (
                 1,
+                0,
                 vec![Ty::new_imm_ptr(tcx, param(0)), Ty::new_imm_ptr(tcx, param(0))],
                 tcx.types.u8,
             ),
 
             sym::const_allocate => {
-                (0, vec![tcx.types.usize, tcx.types.usize], Ty::new_mut_ptr(tcx, tcx.types.u8))
+                (0, 0, vec![tcx.types.usize, tcx.types.usize], Ty::new_mut_ptr(tcx, tcx.types.u8))
             }
             sym::const_deallocate => (
+                0,
                 0,
                 vec![Ty::new_mut_ptr(tcx, tcx.types.u8), tcx.types.usize, tcx.types.usize],
                 Ty::new_unit(tcx),
@@ -360,39 +368,41 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId, span: Spa
 
             sym::ptr_offset_from => (
                 1,
+                0,
                 vec![Ty::new_imm_ptr(tcx, param(0)), Ty::new_imm_ptr(tcx, param(0))],
                 tcx.types.isize,
             ),
             sym::ptr_offset_from_unsigned => (
                 1,
+                0,
                 vec![Ty::new_imm_ptr(tcx, param(0)), Ty::new_imm_ptr(tcx, param(0))],
                 tcx.types.usize,
             ),
             sym::unchecked_div | sym::unchecked_rem | sym::exact_div => {
-                (1, vec![param(0), param(0)], param(0))
+                (1, 0, vec![param(0), param(0)], param(0))
             }
             sym::unchecked_shl | sym::unchecked_shr | sym::rotate_left | sym::rotate_right => {
-                (1, vec![param(0), param(0)], param(0))
+                (1, 0, vec![param(0), param(0)], param(0))
             }
             sym::unchecked_add | sym::unchecked_sub | sym::unchecked_mul => {
-                (1, vec![param(0), param(0)], param(0))
+                (1, 0, vec![param(0), param(0)], param(0))
             }
             sym::wrapping_add | sym::wrapping_sub | sym::wrapping_mul => {
-                (1, vec![param(0), param(0)], param(0))
+                (1, 0, vec![param(0), param(0)], param(0))
             }
-            sym::saturating_add | sym::saturating_sub => (1, vec![param(0), param(0)], param(0)),
+            sym::saturating_add | sym::saturating_sub => (1, 0, vec![param(0), param(0)], param(0)),
             sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => {
-                (1, vec![param(0), param(0)], param(0))
+                (1, 0, vec![param(0), param(0)], param(0))
             }
-            sym::float_to_int_unchecked => (2, vec![param(0)], param(1)),
+            sym::float_to_int_unchecked => (2, 0, vec![param(0)], param(1)),
 
-            sym::assume => (0, vec![tcx.types.bool], Ty::new_unit(tcx)),
-            sym::likely => (0, vec![tcx.types.bool], tcx.types.bool),
-            sym::unlikely => (0, vec![tcx.types.bool], tcx.types.bool),
+            sym::assume => (0, 0, vec![tcx.types.bool], Ty::new_unit(tcx)),
+            sym::likely => (0, 0, vec![tcx.types.bool], tcx.types.bool),
+            sym::unlikely => (0, 0, vec![tcx.types.bool], tcx.types.bool),
 
-            sym::read_via_copy => (1, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)),
+            sym::read_via_copy => (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)),
             sym::write_via_move => {
-                (1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], Ty::new_unit(tcx))
+                (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], Ty::new_unit(tcx))
             }
 
             sym::discriminant_value => {
@@ -404,6 +414,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId, span: Spa
                 let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon };
                 (
                     1,
+                    0,
                     vec![Ty::new_imm_ref(
                         tcx,
                         ty::Region::new_bound(tcx, ty::INNERMOST, br),
@@ -430,6 +441,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId, span: Spa
                     Abi::Rust,
                 ));
                 (
+                    0,
                     0,
                     vec![Ty::new_fn_ptr(tcx, try_fn_ty), mut_u8, Ty::new_fn_ptr(tcx, catch_fn_ty)],
                     tcx.types.i32,
@@ -437,56 +449,56 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId, span: Spa
             }
 
             sym::va_start | sym::va_end => match mk_va_list_ty(hir::Mutability::Mut) {
-                Some((va_list_ref_ty, _)) => (0, vec![va_list_ref_ty], Ty::new_unit(tcx)),
+                Some((va_list_ref_ty, _)) => (0, 0, vec![va_list_ref_ty], Ty::new_unit(tcx)),
                 None => bug!("`va_list` language item needed for C-variadic intrinsics"),
             },
 
             sym::va_copy => match mk_va_list_ty(hir::Mutability::Not) {
                 Some((va_list_ref_ty, va_list_ty)) => {
                     let va_list_ptr_ty = Ty::new_mut_ptr(tcx, va_list_ty);
-                    (0, vec![va_list_ptr_ty, va_list_ref_ty], Ty::new_unit(tcx))
+                    (0, 0, vec![va_list_ptr_ty, va_list_ref_ty], Ty::new_unit(tcx))
                 }
                 None => bug!("`va_list` language item needed for C-variadic intrinsics"),
             },
 
             sym::va_arg => match mk_va_list_ty(hir::Mutability::Mut) {
-                Some((va_list_ref_ty, _)) => (1, vec![va_list_ref_ty], param(0)),
+                Some((va_list_ref_ty, _)) => (1, 0, vec![va_list_ref_ty], param(0)),
                 None => bug!("`va_list` language item needed for C-variadic intrinsics"),
             },
 
             sym::nontemporal_store => {
-                (1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], Ty::new_unit(tcx))
+                (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], Ty::new_unit(tcx))
             }
 
             sym::raw_eq => {
                 let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon };
                 let param_ty =
                     Ty::new_imm_ref(tcx, ty::Region::new_bound(tcx, ty::INNERMOST, br), param(0));
-                (1, vec![param_ty; 2], tcx.types.bool)
+                (1, 0, vec![param_ty; 2], tcx.types.bool)
             }
 
-            sym::black_box => (1, vec![param(0)], param(0)),
+            sym::black_box => (1, 0, vec![param(0)], param(0)),
 
-            sym::is_val_statically_known => (1, vec![param(0)], tcx.types.bool),
+            sym::is_val_statically_known => (1, 0, vec![param(0)], tcx.types.bool),
 
-            sym::const_eval_select => (4, vec![param(0), param(1), param(2)], param(3)),
+            sym::const_eval_select => (4, 0, vec![param(0), param(1), param(2)], param(3)),
 
             sym::vtable_size | sym::vtable_align => {
-                (0, vec![Ty::new_imm_ptr(tcx, Ty::new_unit(tcx))], tcx.types.usize)
+                (0, 0, vec![Ty::new_imm_ptr(tcx, Ty::new_unit(tcx))], tcx.types.usize)
             }
 
-            sym::debug_assertions => (0, Vec::new(), tcx.types.bool),
+            sym::debug_assertions => (0, 0, Vec::new(), tcx.types.bool),
 
             other => {
                 tcx.dcx().emit_err(UnrecognizedIntrinsicFunction { span, name: other });
                 return;
             }
         };
-        (n_tps, 0, inputs, output, unsafety)
+        (n_tps, 0, n_cts, inputs, output, unsafety)
     };
     let sig = tcx.mk_fn_sig(inputs, output, false, unsafety, Abi::RustIntrinsic);
     let sig = ty::Binder::bind_with_vars(sig, bound_vars);
-    equate_intrinsic_type(tcx, span, intrinsic_id, n_tps, n_lts, 0, sig)
+    equate_intrinsic_type(tcx, span, intrinsic_id, n_tps, n_lts, n_cts, sig)
 }
 
 /// Type-check `extern "platform-intrinsic" { ... }` functions.

From 531505f1826941db43c4ccd7643a549e78b53832 Mon Sep 17 00:00:00 2001
From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Date: Wed, 31 Jan 2024 14:28:40 +0000
Subject: [PATCH 16/58] Check signature of intrinsics with fallback bodies

---
 .../rustc_hir_analysis/src/check/check.rs     | 21 +++++-
 .../rustc_hir_analysis/src/check/intrinsic.rs | 18 +++--
 library/core/src/intrinsics.rs                |  2 +-
 tests/ui/feature-gates/feature-gate-abi.rs    |  2 +
 .../ui/feature-gates/feature-gate-abi.stderr  | 67 +++++++++++--------
 .../feature-gates/feature-gate-intrinsics.rs  |  1 +
 .../feature-gate-intrinsics.stderr            |  8 ++-
 tests/ui/intrinsics-always-extern.rs          |  1 +
 tests/ui/intrinsics-always-extern.stderr      | 10 ++-
 9 files changed, 92 insertions(+), 38 deletions(-)

diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 6bc3617660284..e213ebfb3441e 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -472,7 +472,18 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
         DefKind::Enum => {
             check_enum(tcx, def_id);
         }
-        DefKind::Fn => {} // entirely within check_item_body
+        DefKind::Fn => {
+            if let Some(name) = tcx.intrinsic(def_id) {
+                intrinsic::check_intrinsic_type(
+                    tcx,
+                    def_id,
+                    tcx.def_ident_span(def_id).unwrap(),
+                    name,
+                    Abi::Rust,
+                )
+            }
+            // Everything else is checked entirely within check_item_body
+        }
         DefKind::Impl { of_trait } => {
             if of_trait && let Some(impl_trait_ref) = tcx.impl_trait_ref(def_id) {
                 check_impl_items_against_trait(tcx, def_id, impl_trait_ref.instantiate_identity());
@@ -533,7 +544,13 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
             match abi {
                 Abi::RustIntrinsic => {
                     for item in items {
-                        intrinsic::check_intrinsic_type(tcx, item.id.owner_id.def_id, item.span);
+                        intrinsic::check_intrinsic_type(
+                            tcx,
+                            item.id.owner_id.def_id,
+                            item.span,
+                            item.ident.name,
+                            abi,
+                        );
                     }
                 }
 
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index fe1a5a289649d..b0cf1d1656da6 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -26,7 +26,8 @@ fn equate_intrinsic_type<'tcx>(
     sig: ty::PolyFnSig<'tcx>,
 ) {
     let (own_counts, span) = match tcx.hir_node_by_def_id(def_id) {
-        hir::Node::ForeignItem(hir::ForeignItem {
+        hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. })
+        | hir::Node::ForeignItem(hir::ForeignItem {
             kind: hir::ForeignItemKind::Fn(.., generics),
             ..
         }) => {
@@ -136,7 +137,13 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
 
 /// Remember to add all intrinsics here, in `compiler/rustc_codegen_llvm/src/intrinsic.rs`,
 /// and in `library/core/src/intrinsics.rs`.
-pub fn check_intrinsic_type(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId, span: Span) {
+pub fn check_intrinsic_type(
+    tcx: TyCtxt<'_>,
+    intrinsic_id: LocalDefId,
+    span: Span,
+    intrinsic_name: Symbol,
+    abi: Abi,
+) {
     let generics = tcx.generics_of(intrinsic_id);
     let param = |n| {
         if let Some(&ty::GenericParamDef {
@@ -148,7 +155,6 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId, span: Spa
             Ty::new_error_with_message(tcx, span, "expected param")
         }
     };
-    let intrinsic_name = tcx.item_name(intrinsic_id.into());
     let name_str = intrinsic_name.as_str();
 
     let bound_vars = tcx.mk_bound_variable_kinds(&[
@@ -479,7 +485,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId, span: Spa
 
             sym::black_box => (1, 0, vec![param(0)], param(0)),
 
-            sym::is_val_statically_known => (1, 0, vec![param(0)], tcx.types.bool),
+            sym::is_val_statically_known => (1, 1, vec![param(0)], tcx.types.bool),
 
             sym::const_eval_select => (4, 0, vec![param(0), param(1), param(2)], param(3)),
 
@@ -487,7 +493,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId, span: Spa
                 (0, 0, vec![Ty::new_imm_ptr(tcx, Ty::new_unit(tcx))], tcx.types.usize)
             }
 
-            sym::debug_assertions => (0, 0, Vec::new(), tcx.types.bool),
+            sym::debug_assertions => (0, 1, Vec::new(), tcx.types.bool),
 
             other => {
                 tcx.dcx().emit_err(UnrecognizedIntrinsicFunction { span, name: other });
@@ -496,7 +502,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId, span: Spa
         };
         (n_tps, 0, n_cts, inputs, output, unsafety)
     };
-    let sig = tcx.mk_fn_sig(inputs, output, false, unsafety, Abi::RustIntrinsic);
+    let sig = tcx.mk_fn_sig(inputs, output, false, unsafety, abi);
     let sig = ty::Binder::bind_with_vars(sig, bound_vars);
     equate_intrinsic_type(tcx, span, intrinsic_id, n_tps, n_lts, n_cts, sig)
 }
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 375fa1350b547..d56c3d3b6c176 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -2590,7 +2590,7 @@ pub const unsafe fn is_val_statically_known<T: Copy>(_arg: T) -> bool {
 #[rustc_const_unstable(feature = "delayed_debug_assertions", issue = "none")]
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[cfg_attr(not(bootstrap), rustc_intrinsic)]
-pub(crate) const fn debug_assertions() -> bool {
+pub(crate) const unsafe fn debug_assertions() -> bool {
     cfg!(debug_assertions)
 }
 
diff --git a/tests/ui/feature-gates/feature-gate-abi.rs b/tests/ui/feature-gates/feature-gate-abi.rs
index 712655f9775d6..39f98ac908bda 100644
--- a/tests/ui/feature-gates/feature-gate-abi.rs
+++ b/tests/ui/feature-gates/feature-gate-abi.rs
@@ -14,8 +14,10 @@ trait Tuple { }
 // Functions
 extern "rust-intrinsic" fn f1() {} //~ ERROR intrinsics are subject to change
                                    //~^ ERROR intrinsic must be in
+                                   //~| ERROR unrecognized intrinsic function: `f1`
 extern "platform-intrinsic" fn f2() {} //~ ERROR platform intrinsics are experimental
                                        //~^ ERROR intrinsic must be in
+                                       //~| ERROR unrecognized intrinsic function: `f2`
 extern "rust-call" fn f4(_: ()) {} //~ ERROR rust-call ABI is subject to change
 
 // Methods in trait definition
diff --git a/tests/ui/feature-gates/feature-gate-abi.stderr b/tests/ui/feature-gates/feature-gate-abi.stderr
index d031c2adf50cc..aa60434d9fe6c 100644
--- a/tests/ui/feature-gates/feature-gate-abi.stderr
+++ b/tests/ui/feature-gates/feature-gate-abi.stderr
@@ -8,7 +8,7 @@ LL | extern "rust-intrinsic" fn f1() {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:17:8
+  --> $DIR/feature-gate-abi.rs:18:8
    |
 LL | extern "platform-intrinsic" fn f2() {}
    |        ^^^^^^^^^^^^^^^^^^^^
@@ -18,7 +18,7 @@ LL | extern "platform-intrinsic" fn f2() {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:19:8
+  --> $DIR/feature-gate-abi.rs:21:8
    |
 LL | extern "rust-call" fn f4(_: ()) {}
    |        ^^^^^^^^^^^
@@ -28,7 +28,7 @@ LL | extern "rust-call" fn f4(_: ()) {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:23:12
+  --> $DIR/feature-gate-abi.rs:25:12
    |
 LL |     extern "rust-intrinsic" fn m1();
    |            ^^^^^^^^^^^^^^^^
@@ -37,7 +37,7 @@ LL |     extern "rust-intrinsic" fn m1();
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:25:12
+  --> $DIR/feature-gate-abi.rs:27:12
    |
 LL |     extern "platform-intrinsic" fn m2();
    |            ^^^^^^^^^^^^^^^^^^^^
@@ -47,7 +47,7 @@ LL |     extern "platform-intrinsic" fn m2();
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:27:12
+  --> $DIR/feature-gate-abi.rs:29:12
    |
 LL |     extern "rust-call" fn m4(_: ());
    |            ^^^^^^^^^^^
@@ -57,7 +57,7 @@ LL |     extern "rust-call" fn m4(_: ());
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:29:12
+  --> $DIR/feature-gate-abi.rs:31:12
    |
 LL |     extern "rust-call" fn dm4(_: ()) {}
    |            ^^^^^^^^^^^
@@ -67,7 +67,7 @@ LL |     extern "rust-call" fn dm4(_: ()) {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:36:12
+  --> $DIR/feature-gate-abi.rs:38:12
    |
 LL |     extern "rust-intrinsic" fn m1() {}
    |            ^^^^^^^^^^^^^^^^
@@ -76,7 +76,7 @@ LL |     extern "rust-intrinsic" fn m1() {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:38:12
+  --> $DIR/feature-gate-abi.rs:40:12
    |
 LL |     extern "platform-intrinsic" fn m2() {}
    |            ^^^^^^^^^^^^^^^^^^^^
@@ -86,7 +86,7 @@ LL |     extern "platform-intrinsic" fn m2() {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:40:12
+  --> $DIR/feature-gate-abi.rs:42:12
    |
 LL |     extern "rust-call" fn m4(_: ()) {}
    |            ^^^^^^^^^^^
@@ -96,7 +96,7 @@ LL |     extern "rust-call" fn m4(_: ()) {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:45:12
+  --> $DIR/feature-gate-abi.rs:47:12
    |
 LL |     extern "rust-intrinsic" fn im1() {}
    |            ^^^^^^^^^^^^^^^^
@@ -105,7 +105,7 @@ LL |     extern "rust-intrinsic" fn im1() {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:47:12
+  --> $DIR/feature-gate-abi.rs:49:12
    |
 LL |     extern "platform-intrinsic" fn im2() {}
    |            ^^^^^^^^^^^^^^^^^^^^
@@ -115,7 +115,7 @@ LL |     extern "platform-intrinsic" fn im2() {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:49:12
+  --> $DIR/feature-gate-abi.rs:51:12
    |
 LL |     extern "rust-call" fn im4(_: ()) {}
    |            ^^^^^^^^^^^
@@ -125,7 +125,7 @@ LL |     extern "rust-call" fn im4(_: ()) {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:53:18
+  --> $DIR/feature-gate-abi.rs:55:18
    |
 LL | type A1 = extern "rust-intrinsic" fn();
    |                  ^^^^^^^^^^^^^^^^
@@ -134,7 +134,7 @@ LL | type A1 = extern "rust-intrinsic" fn();
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:54:18
+  --> $DIR/feature-gate-abi.rs:56:18
    |
 LL | type A2 = extern "platform-intrinsic" fn();
    |                  ^^^^^^^^^^^^^^^^^^^^
@@ -144,7 +144,7 @@ LL | type A2 = extern "platform-intrinsic" fn();
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:55:18
+  --> $DIR/feature-gate-abi.rs:57:18
    |
 LL | type A4 = extern "rust-call" fn(_: ());
    |                  ^^^^^^^^^^^
@@ -154,7 +154,7 @@ LL | type A4 = extern "rust-call" fn(_: ());
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: intrinsics are subject to change
-  --> $DIR/feature-gate-abi.rs:58:8
+  --> $DIR/feature-gate-abi.rs:60:8
    |
 LL | extern "rust-intrinsic" {}
    |        ^^^^^^^^^^^^^^^^
@@ -163,7 +163,7 @@ LL | extern "rust-intrinsic" {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: platform intrinsics are experimental and possibly buggy
-  --> $DIR/feature-gate-abi.rs:59:8
+  --> $DIR/feature-gate-abi.rs:61:8
    |
 LL | extern "platform-intrinsic" {}
    |        ^^^^^^^^^^^^^^^^^^^^
@@ -173,7 +173,7 @@ LL | extern "platform-intrinsic" {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: rust-call ABI is subject to change
-  --> $DIR/feature-gate-abi.rs:60:8
+  --> $DIR/feature-gate-abi.rs:62:8
    |
 LL | extern "rust-call" {}
    |        ^^^^^^^^^^^
@@ -182,14 +182,26 @@ LL | extern "rust-call" {}
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
+error[E0093]: unrecognized intrinsic function: `f1`
+  --> $DIR/feature-gate-abi.rs:15:28
+   |
+LL | extern "rust-intrinsic" fn f1() {}
+   |                            ^^ unrecognized intrinsic
+
+error[E0093]: unrecognized intrinsic function: `f2`
+  --> $DIR/feature-gate-abi.rs:18:32
+   |
+LL | extern "platform-intrinsic" fn f2() {}
+   |                                ^^ unrecognized intrinsic
+
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:23:32
+  --> $DIR/feature-gate-abi.rs:25:32
    |
 LL |     extern "rust-intrinsic" fn m1();
    |                                ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:25:36
+  --> $DIR/feature-gate-abi.rs:27:36
    |
 LL |     extern "platform-intrinsic" fn m2();
    |                                    ^^
@@ -201,35 +213,36 @@ LL | extern "rust-intrinsic" fn f1() {}
    |                                 ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:17:37
+  --> $DIR/feature-gate-abi.rs:18:37
    |
 LL | extern "platform-intrinsic" fn f2() {}
    |                                     ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:36:37
+  --> $DIR/feature-gate-abi.rs:38:37
    |
 LL |     extern "rust-intrinsic" fn m1() {}
    |                                     ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:38:41
+  --> $DIR/feature-gate-abi.rs:40:41
    |
 LL |     extern "platform-intrinsic" fn m2() {}
    |                                         ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:45:38
+  --> $DIR/feature-gate-abi.rs:47:38
    |
 LL |     extern "rust-intrinsic" fn im1() {}
    |                                      ^^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:47:42
+  --> $DIR/feature-gate-abi.rs:49:42
    |
 LL |     extern "platform-intrinsic" fn im2() {}
    |                                          ^^
 
-error: aborting due to 27 previous errors
+error: aborting due to 29 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
+Some errors have detailed explanations: E0093, E0658.
+For more information about an error, try `rustc --explain E0093`.
diff --git a/tests/ui/feature-gates/feature-gate-intrinsics.rs b/tests/ui/feature-gates/feature-gate-intrinsics.rs
index e0dc3cc579d79..725d968d24c30 100644
--- a/tests/ui/feature-gates/feature-gate-intrinsics.rs
+++ b/tests/ui/feature-gates/feature-gate-intrinsics.rs
@@ -4,5 +4,6 @@ extern "rust-intrinsic" {   //~ ERROR intrinsics are subject to change
 
 extern "rust-intrinsic" fn baz() {} //~ ERROR intrinsics are subject to change
 //~^ ERROR intrinsic must be in
+//~| ERROR unrecognized intrinsic function: `baz`
 
 fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-intrinsics.stderr b/tests/ui/feature-gates/feature-gate-intrinsics.stderr
index ebd0f41715ea6..78c21843adb08 100644
--- a/tests/ui/feature-gates/feature-gate-intrinsics.stderr
+++ b/tests/ui/feature-gates/feature-gate-intrinsics.stderr
@@ -22,13 +22,19 @@ error[E0093]: unrecognized intrinsic function: `bar`
 LL |     fn bar();
    |     ^^^^^^^^^ unrecognized intrinsic
 
+error[E0093]: unrecognized intrinsic function: `baz`
+  --> $DIR/feature-gate-intrinsics.rs:5:28
+   |
+LL | extern "rust-intrinsic" fn baz() {}
+   |                            ^^^ unrecognized intrinsic
+
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
   --> $DIR/feature-gate-intrinsics.rs:5:34
    |
 LL | extern "rust-intrinsic" fn baz() {}
    |                                  ^^
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0093, E0658.
 For more information about an error, try `rustc --explain E0093`.
diff --git a/tests/ui/intrinsics-always-extern.rs b/tests/ui/intrinsics-always-extern.rs
index 22951147d7d87..0afd8353455f2 100644
--- a/tests/ui/intrinsics-always-extern.rs
+++ b/tests/ui/intrinsics-always-extern.rs
@@ -10,6 +10,7 @@ impl Foo for () {
 }
 
 extern "rust-intrinsic" fn hello() {//~ ERROR intrinsic must
+    //~^ ERROR unrecognized intrinsic function: `hello`
 }
 
 fn main() {
diff --git a/tests/ui/intrinsics-always-extern.stderr b/tests/ui/intrinsics-always-extern.stderr
index 24b6da16096e6..32468f99197f3 100644
--- a/tests/ui/intrinsics-always-extern.stderr
+++ b/tests/ui/intrinsics-always-extern.stderr
@@ -4,6 +4,12 @@ error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
 LL |     extern "rust-intrinsic" fn foo(&self);
    |                                ^^^
 
+error[E0093]: unrecognized intrinsic function: `hello`
+  --> $DIR/intrinsics-always-extern.rs:12:28
+   |
+LL | extern "rust-intrinsic" fn hello() {
+   |                            ^^^^^ unrecognized intrinsic
+
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
   --> $DIR/intrinsics-always-extern.rs:8:43
    |
@@ -17,8 +23,10 @@ error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
    |
 LL |   extern "rust-intrinsic" fn hello() {
    |  ____________________________________^
+LL | |
 LL | | }
    | |_^
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
+For more information about this error, try `rustc --explain E0093`.

From 8549c0a3e6b39b31f29f308d3b33744aaefa4080 Mon Sep 17 00:00:00 2001
From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Date: Wed, 31 Jan 2024 14:29:12 +0000
Subject: [PATCH 17/58] Add intrinsic body fallback to cranelift and use it

---
 .../rustc_codegen_cranelift/src/abi/mod.rs    | 10 +++-
 .../src/intrinsics/mod.rs                     | 57 ++++++++-----------
 2 files changed, 32 insertions(+), 35 deletions(-)

diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 0f0d828c8fc3f..fd1f081a0a8e7 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -387,15 +387,19 @@ pub(crate) fn codegen_terminator_call<'tcx>(
 
         match instance.def {
             InstanceDef::Intrinsic(_) => {
-                crate::intrinsics::codegen_intrinsic_call(
+                match crate::intrinsics::codegen_intrinsic_call(
                     fx,
                     instance,
                     args,
                     ret_place,
                     target,
                     source_info,
-                );
-                return;
+                ) {
+                    Ok(()) => return,
+                    // Unimplemented intrinsics must have a fallback body. The fallback body is obtained
+                    // by converting the `InstanceDef::Intrinsic` to an `InstanceDef::Item`.
+                    Err(()) => Some(Instance::new(instance.def_id(), instance.args)),
+                }
             }
             InstanceDef::DropGlue(_, None) => {
                 // empty drop glue - a nop.
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 819cb5ef137ce..5e64fec76e456 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -268,7 +268,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
     destination: CPlace<'tcx>,
     target: Option<BasicBlock>,
     source_info: mir::SourceInfo,
-) {
+) -> Result<(), ()> {
     let intrinsic = fx.tcx.item_name(instance.def_id());
     let instance_args = instance.args;
 
@@ -295,8 +295,9 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             destination,
             target,
             source_info,
-        );
+        )?;
     }
+    Ok(())
 }
 
 fn codegen_float_intrinsic_call<'tcx>(
@@ -430,25 +431,20 @@ fn codegen_regular_intrinsic_call<'tcx>(
     ret: CPlace<'tcx>,
     destination: Option<BasicBlock>,
     source_info: mir::SourceInfo,
-) {
+) -> Result<(), ()> {
+    assert_eq!(generic_args, instance.args);
     let usize_layout = fx.layout_of(fx.tcx.types.usize);
 
     match intrinsic {
         sym::abort => {
             fx.bcx.ins().trap(TrapCode::User(0));
-            return;
+            return Ok(());
         }
         sym::likely | sym::unlikely => {
             intrinsic_args!(fx, args => (a); intrinsic);
 
             ret.write_cvalue(fx, a);
         }
-        sym::is_val_statically_known => {
-            intrinsic_args!(fx, args => (_a); intrinsic);
-
-            let res = fx.bcx.ins().iconst(types::I8, 0);
-            ret.write_cvalue(fx, CValue::by_val(res, ret.layout()));
-        }
         sym::breakpoint => {
             intrinsic_args!(fx, args => (); intrinsic);
 
@@ -697,7 +693,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
                         })
                     });
                     crate::base::codegen_panic_nounwind(fx, &msg_str, Some(source_info.span));
-                    return;
+                    return Ok(());
                 }
             }
         }
@@ -792,7 +788,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
                     if fx.tcx.is_compiler_builtins(LOCAL_CRATE) {
                         // special case for compiler-builtins to avoid having to patch it
                         crate::trap::trap_unimplemented(fx, "128bit atomics not yet supported");
-                        return;
+                        return Ok(());
                     } else {
                         fx.tcx
                             .dcx()
@@ -802,7 +798,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
                     report_atomic_type_validation_error(fx, intrinsic, source_info.span, ty);
-                    return;
+                    return Ok(());
                 }
             }
             let clif_ty = fx.clif_type(ty).unwrap();
@@ -823,7 +819,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
                     if fx.tcx.is_compiler_builtins(LOCAL_CRATE) {
                         // special case for compiler-builtins to avoid having to patch it
                         crate::trap::trap_unimplemented(fx, "128bit atomics not yet supported");
-                        return;
+                        return Ok(());
                     } else {
                         fx.tcx
                             .dcx()
@@ -833,7 +829,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
                     report_atomic_type_validation_error(fx, intrinsic, source_info.span, ty);
-                    return;
+                    return Ok(());
                 }
             }
 
@@ -850,7 +846,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
                     report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
-                    return;
+                    return Ok(());
                 }
             }
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -872,7 +868,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
                     report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
-                    return;
+                    return Ok(());
                 }
             }
 
@@ -895,7 +891,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
                     report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
-                    return;
+                    return Ok(());
                 }
             }
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -917,7 +913,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
                     report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
-                    return;
+                    return Ok(());
                 }
             }
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -939,7 +935,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
                     report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
-                    return;
+                    return Ok(());
                 }
             }
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -960,7 +956,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
                     report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
-                    return;
+                    return Ok(());
                 }
             }
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -981,7 +977,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
                     report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
-                    return;
+                    return Ok(());
                 }
             }
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -1002,7 +998,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
                     report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
-                    return;
+                    return Ok(());
                 }
             }
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -1023,7 +1019,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
                     report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
-                    return;
+                    return Ok(());
                 }
             }
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -1044,7 +1040,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
                     report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
-                    return;
+                    return Ok(());
                 }
             }
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -1065,7 +1061,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
                     report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
-                    return;
+                    return Ok(());
                 }
             }
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -1086,7 +1082,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
                 _ => {
                     report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty);
-                    return;
+                    return Ok(());
                 }
             }
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -1261,13 +1257,10 @@ fn codegen_regular_intrinsic_call<'tcx>(
             );
         }
 
-        _ => {
-            fx.tcx
-                .dcx()
-                .span_fatal(source_info.span, format!("unsupported intrinsic {}", intrinsic));
-        }
+        _ => return Err(()),
     }
 
     let ret_block = fx.get_block(destination.unwrap());
     fx.bcx.ins().jump(ret_block, &[]);
+    Ok(())
 }

From 55200e75da337a17e0daa333e1f3e70b5aa18e8a Mon Sep 17 00:00:00 2001
From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Date: Wed, 31 Jan 2024 20:22:01 +0000
Subject: [PATCH 18/58] Do the entire ReturnDest computation within
 make_return_dest

---
 compiler/rustc_codegen_ssa/src/mir/block.rs | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index a4d97200cdbd0..df5a2c29ef063 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -820,12 +820,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         let mut llargs = Vec::with_capacity(arg_count);
 
         // Prepare the return value destination
-        let ret_dest = if target.is_some() {
-            let is_intrinsic = intrinsic.is_some();
-            self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs, is_intrinsic)
-        } else {
-            ReturnDest::Nothing
-        };
+        let ret_dest = self.make_return_dest(
+            bx,
+            destination,
+            &fn_abi.ret,
+            &mut llargs,
+            intrinsic.is_some(),
+            target.is_some(),
+        );
 
         if intrinsic == Some(sym::caller_location) {
             return if let Some(target) = target {
@@ -1632,7 +1634,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         fn_ret: &ArgAbi<'tcx, Ty<'tcx>>,
         llargs: &mut Vec<Bx::Value>,
         is_intrinsic: bool,
+        has_target: bool,
     ) -> ReturnDest<'tcx, Bx::Value> {
+        if !has_target {
+            return ReturnDest::Nothing;
+        }
         // If the return is ignored, we can just return a do-nothing `ReturnDest`.
         if fn_ret.is_ignore() {
             return ReturnDest::Nothing;

From 432635a9ea4a23cc0133a9b0a956ee033518ad55 Mon Sep 17 00:00:00 2001
From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Date: Wed, 31 Jan 2024 20:24:44 +0000
Subject: [PATCH 19/58] Create ret_dest as late as possible in all code paths

---
 compiler/rustc_codegen_ssa/src/mir/block.rs | 32 ++++++++++++---------
 1 file changed, 19 insertions(+), 13 deletions(-)

diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index df5a2c29ef063..0c4661ef16e3e 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -817,23 +817,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
         // The arguments we'll be passing. Plus one to account for outptr, if used.
         let arg_count = fn_abi.args.len() + fn_abi.ret.is_indirect() as usize;
-        let mut llargs = Vec::with_capacity(arg_count);
-
-        // Prepare the return value destination
-        let ret_dest = self.make_return_dest(
-            bx,
-            destination,
-            &fn_abi.ret,
-            &mut llargs,
-            intrinsic.is_some(),
-            target.is_some(),
-        );
 
         if intrinsic == Some(sym::caller_location) {
             return if let Some(target) = target {
                 let location =
                     self.get_caller_location(bx, mir::SourceInfo { span: fn_span, ..source_info });
 
+                let mut llargs = Vec::with_capacity(arg_count);
+                let ret_dest =
+                    self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs, true, true);
+                assert_eq!(llargs, []);
                 if let ReturnDest::IndirectOperand(tmp, _) = ret_dest {
                     location.val.store(bx, tmp);
                 }
@@ -847,6 +840,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         match intrinsic {
             None | Some(sym::drop_in_place) => {}
             Some(intrinsic) => {
+                let mut llargs = Vec::with_capacity(1);
+                let ret_dest = self.make_return_dest(
+                    bx,
+                    destination,
+                    &fn_abi.ret,
+                    &mut llargs,
+                    true,
+                    target.is_some(),
+                );
                 let dest = match ret_dest {
                     _ if fn_abi.ret.is_indirect() => llargs[0],
                     ReturnDest::Nothing => bx.const_undef(bx.type_ptr()),
@@ -902,6 +904,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             }
         }
 
+        let mut llargs = Vec::with_capacity(arg_count);
+        let destination = target.as_ref().map(|&target| {
+            (self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs, false, true), target)
+        });
+
         // Split the rust-call tupled arguments off.
         let (first_args, untuple) = if abi == Abi::RustCall && !args.is_empty() {
             let (tup, args) = args.split_last().unwrap();
@@ -1042,14 +1049,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             (_, Some(llfn)) => llfn,
             _ => span_bug!(span, "no instance or llfn for call"),
         };
-
         helper.do_call(
             self,
             bx,
             fn_abi,
             fn_ptr,
             &llargs,
-            target.as_ref().map(|&target| (ret_dest, target)),
+            destination,
             unwind,
             &copied_constant_arguments,
             mergeable_succ,

From 9a0743747f3b587ff0b4ba06bf51d3a079f37e50 Mon Sep 17 00:00:00 2001
From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Date: Wed, 31 Jan 2024 20:39:59 +0000
Subject: [PATCH 20/58] Teach llvm backend how to fall back to default bodies

---
 .../rustc_codegen_cranelift/src/abi/mod.rs    |  4 +-
 .../src/intrinsics/mod.rs                     | 16 ++---
 .../rustc_codegen_gcc/src/intrinsic/mod.rs    | 18 +++---
 compiler/rustc_codegen_llvm/src/intrinsic.rs  | 23 +++++---
 compiler/rustc_codegen_ssa/src/mir/block.rs   | 37 ++++++------
 .../rustc_codegen_ssa/src/mir/intrinsic.rs    | 58 +++++++++----------
 .../rustc_codegen_ssa/src/traits/intrinsic.rs |  4 +-
 .../rustc_hir_analysis/src/check/intrinsic.rs |  2 +-
 .../rustc_mir_transform/src/instsimplify.rs   |  7 ++-
 compiler/rustc_monomorphize/src/collector.rs  | 15 +++--
 library/core/src/intrinsics.rs                | 28 +++++----
 11 files changed, 109 insertions(+), 103 deletions(-)

diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index fd1f081a0a8e7..6e846d721f2e2 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -396,9 +396,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
                     source_info,
                 ) {
                     Ok(()) => return,
-                    // Unimplemented intrinsics must have a fallback body. The fallback body is obtained
-                    // by converting the `InstanceDef::Intrinsic` to an `InstanceDef::Item`.
-                    Err(()) => Some(Instance::new(instance.def_id(), instance.args)),
+                    Err(instance) => Some(instance),
                 }
             }
             InstanceDef::DropGlue(_, None) => {
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 5e64fec76e456..210a3da2c5d9d 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -268,7 +268,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
     destination: CPlace<'tcx>,
     target: Option<BasicBlock>,
     source_info: mir::SourceInfo,
-) -> Result<(), ()> {
+) -> Result<(), Instance<'tcx>> {
     let intrinsic = fx.tcx.item_name(instance.def_id());
     let instance_args = instance.args;
 
@@ -431,7 +431,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
     ret: CPlace<'tcx>,
     destination: Option<BasicBlock>,
     source_info: mir::SourceInfo,
-) -> Result<(), ()> {
+) -> Result<(), Instance<'tcx>> {
     assert_eq!(generic_args, instance.args);
     let usize_layout = fx.layout_of(fx.tcx.types.usize);
 
@@ -1229,14 +1229,6 @@ fn codegen_regular_intrinsic_call<'tcx>(
             ret.write_cvalue(fx, CValue::by_val(cmp, ret.layout()));
         }
 
-        sym::const_allocate => {
-            intrinsic_args!(fx, args => (_size, _align); intrinsic);
-
-            // returns a null pointer at runtime.
-            let null = fx.bcx.ins().iconst(fx.pointer_type, 0);
-            ret.write_cvalue(fx, CValue::by_val(null, ret.layout()));
-        }
-
         sym::const_deallocate => {
             intrinsic_args!(fx, args => (_ptr, _size, _align); intrinsic);
             // nop at runtime.
@@ -1257,7 +1249,9 @@ fn codegen_regular_intrinsic_call<'tcx>(
             );
         }
 
-        _ => return Err(()),
+        // Unimplemented intrinsics must have a fallback body. The fallback body is obtained
+        // by converting the `InstanceDef::Intrinsic` to an `InstanceDef::Item`.
+        _ => return Err(Instance::new(instance.def_id(), instance.args)),
     }
 
     let ret_block = fx.get_block(destination.unwrap());
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index eac8cb437794b..f162ef831b768 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -90,7 +90,7 @@ fn get_simple_intrinsic<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, name: Symbol) ->
 }
 
 impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
-    fn codegen_intrinsic_call(&mut self, instance: Instance<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, RValue<'gcc>>], llresult: RValue<'gcc>, span: Span) {
+    fn codegen_intrinsic_call(&mut self, instance: Instance<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, RValue<'gcc>>], llresult: RValue<'gcc>, span: Span) -> Result<(), Instance<'tcx>> {
         let tcx = self.tcx;
         let callee_ty = instance.ty(tcx, ty::ParamEnv::reveal_all());
 
@@ -137,7 +137,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
                         args[2].immediate(),
                         llresult,
                     );
-                    return;
+                    return Ok(());
                 }
                 sym::breakpoint => {
                     unimplemented!();
@@ -166,12 +166,12 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
                 sym::volatile_store => {
                     let dst = args[0].deref(self.cx());
                     args[1].val.volatile_store(self, dst);
-                    return;
+                    return Ok(());
                 }
                 sym::unaligned_volatile_store => {
                     let dst = args[0].deref(self.cx());
                     args[1].val.unaligned_volatile_store(self, dst);
-                    return;
+                    return Ok(());
                 }
                 sym::prefetch_read_data
                     | sym::prefetch_write_data
@@ -269,7 +269,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
                             },
                             None => {
                                 tcx.dcx().emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty });
-                                return;
+                                return Ok(());
                             }
                         }
                     }
@@ -339,7 +339,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
                     extended_asm.set_volatile_flag(true);
 
                     // We have copied the value to `result` already.
-                    return;
+                    return Ok(());
                 }
 
                 sym::ptr_mask => {
@@ -357,11 +357,12 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
                 _ if name_str.starts_with("simd_") => {
                     match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) {
                         Ok(llval) => llval,
-                        Err(()) => return,
+                        Err(()) => return Ok(()),
                     }
                 }
 
-                _ => bug!("unknown intrinsic '{}'", name),
+                // Fall back to default body
+                _ => return Err(Instance::new(instance.def_id(), instance.args)),
             };
 
         if !fn_abi.ret.is_ignore() {
@@ -376,6 +377,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
                     .store(self, result);
             }
         }
+        Ok(())
     }
 
     fn abort(&mut self) {
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index e3e48ecb3aa5f..4415c51acf684 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -86,7 +86,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
         args: &[OperandRef<'tcx, &'ll Value>],
         llresult: &'ll Value,
         span: Span,
-    ) {
+    ) -> Result<(), ty::Instance<'tcx>> {
         let tcx = self.tcx;
         let callee_ty = instance.ty(tcx, ty::ParamEnv::reveal_all());
 
@@ -141,7 +141,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                     args[2].immediate(),
                     llresult,
                 );
-                return;
+                return Ok(());
             }
             sym::breakpoint => self.call_intrinsic("llvm.debugtrap", &[]),
             sym::va_copy => {
@@ -194,17 +194,17 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                 if !result.layout.is_zst() {
                     self.store(load, result.llval, result.align);
                 }
-                return;
+                return Ok(());
             }
             sym::volatile_store => {
                 let dst = args[0].deref(self.cx());
                 args[1].val.volatile_store(self, dst);
-                return;
+                return Ok(());
             }
             sym::unaligned_volatile_store => {
                 let dst = args[0].deref(self.cx());
                 args[1].val.unaligned_volatile_store(self, dst);
-                return;
+                return Ok(());
             }
             sym::prefetch_read_data
             | sym::prefetch_write_data
@@ -305,7 +305,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                             name,
                             ty,
                         });
-                        return;
+                        return Ok(());
                     }
                 }
             }
@@ -387,7 +387,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                 .unwrap_or_else(|| bug!("failed to generate inline asm call for `black_box`"));
 
                 // We have copied the value to `result` already.
-                return;
+                return Ok(());
             }
 
             _ if name.as_str().starts_with("simd_") => {
@@ -395,11 +395,15 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                     self, name, callee_ty, fn_args, args, ret_ty, llret_ty, span,
                 ) {
                     Ok(llval) => llval,
-                    Err(()) => return,
+                    Err(()) => return Ok(()),
                 }
             }
 
-            _ => bug!("unknown intrinsic '{}' -- should it have been lowered earlier?", name),
+            _ => {
+                debug!("unknown intrinsic '{}' -- falling back to default body", name);
+                // Call the fallback body instead of generating the intrinsic code
+                return Err(ty::Instance::new(instance.def_id(), instance.args));
+            }
         };
 
         if !fn_abi.ret.is_ignore() {
@@ -411,6 +415,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                     .store(self, result);
             }
         }
+        Ok(())
     }
 
     fn abort(&mut self) {
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 0c4661ef16e3e..75d413dedad3e 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -837,8 +837,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             };
         }
 
-        match intrinsic {
-            None | Some(sym::drop_in_place) => {}
+        let instance = match intrinsic {
+            None | Some(sym::drop_in_place) => instance,
             Some(intrinsic) => {
                 let mut llargs = Vec::with_capacity(1);
                 let ret_dest = self.make_return_dest(
@@ -882,27 +882,24 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     })
                     .collect();
 
-                Self::codegen_intrinsic_call(
-                    bx,
-                    *instance.as_ref().unwrap(),
-                    fn_abi,
-                    &args,
-                    dest,
-                    span,
-                );
+                let instance = *instance.as_ref().unwrap();
+                match Self::codegen_intrinsic_call(bx, instance, fn_abi, &args, dest, span) {
+                    Ok(()) => {
+                        if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
+                            self.store_return(bx, ret_dest, &fn_abi.ret, dst.llval);
+                        }
 
-                if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
-                    self.store_return(bx, ret_dest, &fn_abi.ret, dst.llval);
+                        return if let Some(target) = target {
+                            helper.funclet_br(self, bx, target, mergeable_succ)
+                        } else {
+                            bx.unreachable();
+                            MergingSucc::False
+                        };
+                    }
+                    Err(instance) => Some(instance),
                 }
-
-                return if let Some(target) = target {
-                    helper.funclet_br(self, bx, target, mergeable_succ)
-                } else {
-                    bx.unreachable();
-                    MergingSucc::False
-                };
             }
-        }
+        };
 
         let mut llargs = Vec::with_capacity(arg_count);
         let destination = target.as_ref().map(|&target| {
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 8530bf9e2b363..d6a0dc6bbefd7 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -54,6 +54,7 @@ fn memset_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 }
 
 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
+    /// In the `Err` case, returns the instance that should be called instead.
     pub fn codegen_intrinsic_call(
         bx: &mut Bx,
         instance: ty::Instance<'tcx>,
@@ -61,7 +62,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         args: &[OperandRef<'tcx, Bx::Value>],
         llresult: Bx::Value,
         span: Span,
-    ) {
+    ) -> Result<(), ty::Instance<'tcx>> {
         let callee_ty = instance.ty(bx.tcx(), ty::ParamEnv::reveal_all());
 
         let ty::FnDef(def_id, fn_args) = *callee_ty.kind() else {
@@ -81,7 +82,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         let llval = match name {
             sym::abort => {
                 bx.abort();
-                return;
+                return Ok(());
             }
 
             sym::va_start => bx.va_start(args[0].immediate()),
@@ -150,7 +151,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     args[0].immediate(),
                     args[2].immediate(),
                 );
-                return;
+                return Ok(());
             }
             sym::write_bytes => {
                 memset_intrinsic(
@@ -161,7 +162,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     args[1].immediate(),
                     args[2].immediate(),
                 );
-                return;
+                return Ok(());
             }
 
             sym::volatile_copy_nonoverlapping_memory => {
@@ -174,7 +175,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     args[1].immediate(),
                     args[2].immediate(),
                 );
-                return;
+                return Ok(());
             }
             sym::volatile_copy_memory => {
                 copy_intrinsic(
@@ -186,7 +187,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     args[1].immediate(),
                     args[2].immediate(),
                 );
-                return;
+                return Ok(());
             }
             sym::volatile_set_memory => {
                 memset_intrinsic(
@@ -197,17 +198,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     args[1].immediate(),
                     args[2].immediate(),
                 );
-                return;
+                return Ok(());
             }
             sym::volatile_store => {
                 let dst = args[0].deref(bx.cx());
                 args[1].val.volatile_store(bx, dst);
-                return;
+                return Ok(());
             }
             sym::unaligned_volatile_store => {
                 let dst = args[0].deref(bx.cx());
                 args[1].val.unaligned_volatile_store(bx, dst);
-                return;
+                return Ok(());
             }
             sym::exact_div => {
                 let ty = arg_tys[0];
@@ -225,7 +226,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                             name,
                             ty,
                         });
-                        return;
+                        return Ok(());
                     }
                 }
             }
@@ -245,7 +246,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                             name,
                             ty: arg_tys[0],
                         });
-                        return;
+                        return Ok(());
                     }
                 }
             }
@@ -256,14 +257,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         span,
                         ty: arg_tys[0],
                     });
-                    return;
+                    return Ok(());
                 }
                 let Some((_width, signed)) = int_type_width_signed(ret_ty, bx.tcx()) else {
                     bx.tcx().dcx().emit_err(InvalidMonomorphization::FloatToIntUnchecked {
                         span,
                         ty: ret_ty,
                     });
-                    return;
+                    return Ok(());
                 };
                 if signed {
                     bx.fptosi(args[0].immediate(), llret_ty)
@@ -280,14 +281,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 }
             }
 
-            sym::const_allocate => {
-                // returns a null pointer at runtime.
-                bx.const_null(bx.type_ptr())
-            }
-
             sym::const_deallocate => {
                 // nop at runtime.
-                return;
+                return Ok(());
             }
 
             // This requires that atomic intrinsics follow a specific naming pattern:
@@ -350,10 +346,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                             bx.store(val, dest.llval, dest.align);
                             let dest = result.project_field(bx, 1);
                             bx.store(success, dest.llval, dest.align);
-                            return;
                         } else {
-                            return invalid_monomorphization(ty);
+                            invalid_monomorphization(ty);
                         }
+                        return Ok(());
                     }
 
                     "load" => {
@@ -383,7 +379,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                                 )
                             }
                         } else {
-                            return invalid_monomorphization(ty);
+                            invalid_monomorphization(ty);
+                            return Ok(());
                         }
                     }
 
@@ -399,10 +396,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                                 val = bx.ptrtoint(val, bx.type_isize());
                             }
                             bx.atomic_store(val, ptr, parse_ordering(bx, ordering), size);
-                            return;
                         } else {
-                            return invalid_monomorphization(ty);
+                            invalid_monomorphization(ty);
                         }
+                        return Ok(());
                     }
 
                     "fence" => {
@@ -410,7 +407,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                             parse_ordering(bx, ordering),
                             SynchronizationScope::CrossThread,
                         );
-                        return;
+                        return Ok(());
                     }
 
                     "singlethreadfence" => {
@@ -418,7 +415,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                             parse_ordering(bx, ordering),
                             SynchronizationScope::SingleThread,
                         );
-                        return;
+                        return Ok(());
                     }
 
                     // These are all AtomicRMW ops
@@ -449,7 +446,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                             }
                             bx.atomic_rmw(atom_op, ptr, val, parse_ordering(bx, ordering))
                         } else {
-                            return invalid_monomorphization(ty);
+                            invalid_monomorphization(ty);
+                            return Ok(());
                         }
                     }
                 }
@@ -458,7 +456,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             sym::nontemporal_store => {
                 let dst = args[0].deref(bx.cx());
                 args[1].val.nontemporal_store(bx, dst);
-                return;
+                return Ok(());
             }
 
             sym::ptr_guaranteed_cmp => {
@@ -493,8 +491,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
             _ => {
                 // Need to use backend-specific things in the implementation.
-                bx.codegen_intrinsic_call(instance, fn_abi, args, llresult, span);
-                return;
+                return bx.codegen_intrinsic_call(instance, fn_abi, args, llresult, span);
             }
         };
 
@@ -507,6 +504,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     .store(bx, result);
             }
         }
+        Ok(())
     }
 }
 
diff --git a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs
index 450672fb94122..502f0b3fcb510 100644
--- a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs
@@ -8,6 +8,8 @@ pub trait IntrinsicCallMethods<'tcx>: BackendTypes {
     /// Remember to add all intrinsics here, in `compiler/rustc_hir_analysis/src/check/mod.rs`,
     /// and in `library/core/src/intrinsics.rs`; if you need access to any LLVM intrinsics,
     /// add them to `compiler/rustc_codegen_llvm/src/context.rs`.
+    /// Returns `Err` if another instance should be called instead. This is used to invoke
+    /// intrinsic default bodies in case an intrinsic is not implemented by the backend.
     fn codegen_intrinsic_call(
         &mut self,
         instance: ty::Instance<'tcx>,
@@ -15,7 +17,7 @@ pub trait IntrinsicCallMethods<'tcx>: BackendTypes {
         args: &[OperandRef<'tcx, Self::Value>],
         llresult: Self::Value,
         span: Span,
-    );
+    ) -> Result<(), ty::Instance<'tcx>>;
 
     fn abort(&mut self);
     fn assume(&mut self, val: Self::Value);
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index b0cf1d1656da6..397112e8db7b3 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -363,7 +363,7 @@ pub fn check_intrinsic_type(
             ),
 
             sym::const_allocate => {
-                (0, 0, vec![tcx.types.usize, tcx.types.usize], Ty::new_mut_ptr(tcx, tcx.types.u8))
+                (0, 1, vec![tcx.types.usize, tcx.types.usize], Ty::new_mut_ptr(tcx, tcx.types.u8))
             }
             sym::const_deallocate => (
                 0,
diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs
index 81cf31e6bf43a..a9de37244c55a 100644
--- a/compiler/rustc_mir_transform/src/instsimplify.rs
+++ b/compiler/rustc_mir_transform/src/instsimplify.rs
@@ -296,9 +296,9 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
         if args.is_empty() {
             return;
         }
-        let ty = args.type_at(0);
 
-        let known_is_valid = intrinsic_assert_panics(self.tcx, self.param_env, ty, intrinsic_name);
+        let known_is_valid =
+            intrinsic_assert_panics(self.tcx, self.param_env, args[0], intrinsic_name);
         match known_is_valid {
             // We don't know the layout or it's not validity assertion at all, don't touch it
             None => {}
@@ -317,10 +317,11 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
 fn intrinsic_assert_panics<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    ty: Ty<'tcx>,
+    arg: ty::GenericArg<'tcx>,
     intrinsic_name: Symbol,
 ) -> Option<bool> {
     let requirement = ValidityRequirement::from_intrinsic(intrinsic_name)?;
+    let ty = arg.expect_ty();
     Some(!tcx.check_validity_requirement((requirement, param_env.and(ty))).ok()?)
 }
 
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 149e4c2cb08ef..a9926820caf77 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -956,19 +956,24 @@ fn visit_instance_use<'tcx>(
     if !should_codegen_locally(tcx, &instance) {
         return;
     }
-
-    // The intrinsics assert_inhabited, assert_zero_valid, and assert_mem_uninitialized_valid will
-    // be lowered in codegen to nothing or a call to panic_nounwind. So if we encounter any
-    // of those intrinsics, we need to include a mono item for panic_nounwind, else we may try to
-    // codegen a call to that function without generating code for the function itself.
     if let ty::InstanceDef::Intrinsic(def_id) = instance.def {
         let name = tcx.item_name(def_id);
         if let Some(_requirement) = ValidityRequirement::from_intrinsic(name) {
+            // The intrinsics assert_inhabited, assert_zero_valid, and assert_mem_uninitialized_valid will
+            // be lowered in codegen to nothing or a call to panic_nounwind. So if we encounter any
+            // of those intrinsics, we need to include a mono item for panic_nounwind, else we may try to
+            // codegen a call to that function without generating code for the function itself.
             let def_id = tcx.lang_items().get(LangItem::PanicNounwind).unwrap();
             let panic_instance = Instance::mono(tcx, def_id);
             if should_codegen_locally(tcx, &panic_instance) {
                 output.push(create_fn_mono_item(tcx, panic_instance, source));
             }
+        } else if tcx.has_attr(def_id, sym::rustc_intrinsic) {
+            // Codegen the fallback body of intrinsics with fallback bodies
+            let instance = ty::Instance::new(def_id, instance.args);
+            if should_codegen_locally(tcx, &instance) {
+                output.push(create_fn_mono_item(tcx, instance, source));
+            }
         }
     }
 
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index d56c3d3b6c176..3a178510e7911 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -2368,18 +2368,6 @@ extern "rust-intrinsic" {
     #[rustc_nounwind]
     pub fn ptr_guaranteed_cmp<T>(ptr: *const T, other: *const T) -> u8;
 
-    /// Allocates a block of memory at compile time.
-    /// At runtime, just returns a null pointer.
-    ///
-    /// # Safety
-    ///
-    /// - The `align` argument must be a power of two.
-    ///    - At compile time, a compile error occurs if this constraint is violated.
-    ///    - At runtime, it is not checked.
-    #[rustc_const_unstable(feature = "const_heap", issue = "79597")]
-    #[rustc_nounwind]
-    pub fn const_allocate(size: usize, align: usize) -> *mut u8;
-
     /// Deallocates a memory which allocated by `intrinsics::const_allocate` at compile time.
     /// At runtime, does nothing.
     ///
@@ -2594,6 +2582,22 @@ pub(crate) const unsafe fn debug_assertions() -> bool {
     cfg!(debug_assertions)
 }
 
+/// Allocates a block of memory at compile time.
+/// At runtime, just returns a null pointer.
+///
+/// # Safety
+///
+/// - The `align` argument must be a power of two.
+///    - At compile time, a compile error occurs if this constraint is violated.
+///    - At runtime, it is not checked.
+#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
+#[rustc_nounwind]
+#[cfg_attr(not(bootstrap), rustc_intrinsic)]
+pub const unsafe fn const_allocate(_size: usize, _align: usize) -> *mut u8 {
+    // const eval overrides this function, but runtime code should always just return null pointers.
+    crate::ptr::null_mut()
+}
+
 // Some functions are defined here because they accidentally got made
 // available in this module on stable. See <https://github.com/rust-lang/rust/issues/15702>.
 // (`transmute` also falls into this category, but it cannot be wrapped due to the

From 6b73fe2d0977f9b1a98242b8ecf359c7804640e4 Mon Sep 17 00:00:00 2001
From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Date: Wed, 31 Jan 2024 20:51:29 +0000
Subject: [PATCH 21/58] Give const_deallocate a default body

---
 .../src/intrinsics/mod.rs                     |  5 ---
 .../rustc_codegen_ssa/src/mir/intrinsic.rs    |  5 ---
 .../rustc_hir_analysis/src/check/intrinsic.rs |  2 +-
 library/core/src/intrinsics.rs                | 31 ++++++++++---------
 4 files changed, 18 insertions(+), 25 deletions(-)

diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 210a3da2c5d9d..476752c7230a7 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -1229,11 +1229,6 @@ fn codegen_regular_intrinsic_call<'tcx>(
             ret.write_cvalue(fx, CValue::by_val(cmp, ret.layout()));
         }
 
-        sym::const_deallocate => {
-            intrinsic_args!(fx, args => (_ptr, _size, _align); intrinsic);
-            // nop at runtime.
-        }
-
         sym::black_box => {
             intrinsic_args!(fx, args => (a); intrinsic);
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index d6a0dc6bbefd7..e4633acd81740 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -281,11 +281,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 }
             }
 
-            sym::const_deallocate => {
-                // nop at runtime.
-                return Ok(());
-            }
-
             // This requires that atomic intrinsics follow a specific naming pattern:
             // "atomic_<operation>[_<ordering>]"
             name if let Some(atomic) = name_str.strip_prefix("atomic_") => {
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 397112e8db7b3..6f5584225c19a 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -367,7 +367,7 @@ pub fn check_intrinsic_type(
             }
             sym::const_deallocate => (
                 0,
-                0,
+                1,
                 vec![Ty::new_mut_ptr(tcx, tcx.types.u8), tcx.types.usize, tcx.types.usize],
                 Ty::new_unit(tcx),
             ),
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 3a178510e7911..2cc01a5390b9d 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -2368,20 +2368,6 @@ extern "rust-intrinsic" {
     #[rustc_nounwind]
     pub fn ptr_guaranteed_cmp<T>(ptr: *const T, other: *const T) -> u8;
 
-    /// Deallocates a memory which allocated by `intrinsics::const_allocate` at compile time.
-    /// At runtime, does nothing.
-    ///
-    /// # Safety
-    ///
-    /// - The `align` argument must be a power of two.
-    ///    - At compile time, a compile error occurs if this constraint is violated.
-    ///    - At runtime, it is not checked.
-    /// - If the `ptr` is created in an another const, this intrinsic doesn't deallocate it.
-    /// - If the `ptr` is pointing to a local variable, this intrinsic doesn't deallocate it.
-    #[rustc_const_unstable(feature = "const_heap", issue = "79597")]
-    #[rustc_nounwind]
-    pub fn const_deallocate(ptr: *mut u8, size: usize, align: usize);
-
     /// Determines whether the raw bytes of the two values are equal.
     ///
     /// This is particularly handy for arrays, since it allows things like just
@@ -2591,6 +2577,7 @@ pub(crate) const unsafe fn debug_assertions() -> bool {
 ///    - At compile time, a compile error occurs if this constraint is violated.
 ///    - At runtime, it is not checked.
 #[rustc_const_unstable(feature = "const_heap", issue = "79597")]
+#[unstable(feature = "core_intrinsics", issue = "none")]
 #[rustc_nounwind]
 #[cfg_attr(not(bootstrap), rustc_intrinsic)]
 pub const unsafe fn const_allocate(_size: usize, _align: usize) -> *mut u8 {
@@ -2598,6 +2585,22 @@ pub const unsafe fn const_allocate(_size: usize, _align: usize) -> *mut u8 {
     crate::ptr::null_mut()
 }
 
+/// Deallocates a memory which allocated by `intrinsics::const_allocate` at compile time.
+/// At runtime, does nothing.
+///
+/// # Safety
+///
+/// - The `align` argument must be a power of two.
+///    - At compile time, a compile error occurs if this constraint is violated.
+///    - At runtime, it is not checked.
+/// - If the `ptr` is created in an another const, this intrinsic doesn't deallocate it.
+/// - If the `ptr` is pointing to a local variable, this intrinsic doesn't deallocate it.
+#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
+#[unstable(feature = "core_intrinsics", issue = "none")]
+#[rustc_nounwind]
+#[cfg_attr(not(bootstrap), rustc_intrinsic)]
+pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
+
 // Some functions are defined here because they accidentally got made
 // available in this module on stable. See <https://github.com/rust-lang/rust/issues/15702>.
 // (`transmute` also falls into this category, but it cannot be wrapped due to the

From f35a2bd401cad2ca15dea8c82489ef9c7b67c4f6 Mon Sep 17 00:00:00 2001
From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Date: Fri, 2 Feb 2024 14:47:59 +0000
Subject: [PATCH 22/58] Support safe intrinsics with fallback bodies

Turn `is_val_statically_known` into such an intrinsic to demonstrate. It is perfectly safe to call after all.
---
 compiler/rustc_hir_analysis/src/check/intrinsic.rs | 11 ++++++++---
 library/core/src/intrinsics.rs                     | 12 ++++--------
 src/tools/miri/tests/pass/intrinsics.rs            |  2 +-
 tests/codegen/is_val_statically_known.rs           |  4 ++--
 tests/ui/consts/is_val_statically_known.rs         |  2 +-
 5 files changed, 16 insertions(+), 15 deletions(-)

diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 6f5584225c19a..f0f6bfff64aaa 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -71,9 +71,13 @@ fn equate_intrinsic_type<'tcx>(
 
 /// Returns the unsafety of the given intrinsic.
 pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hir::Unsafety {
-    let has_safe_attr = match tcx.has_attr(intrinsic_id, sym::rustc_safe_intrinsic) {
-        true => hir::Unsafety::Normal,
-        false => hir::Unsafety::Unsafe,
+    let has_safe_attr = if tcx.has_attr(intrinsic_id, sym::rustc_intrinsic) {
+        tcx.fn_sig(intrinsic_id).skip_binder().unsafety()
+    } else {
+        match tcx.has_attr(intrinsic_id, sym::rustc_safe_intrinsic) {
+            true => hir::Unsafety::Normal,
+            false => hir::Unsafety::Unsafe,
+        }
     };
     let is_in_list = match tcx.item_name(intrinsic_id.into()) {
         // When adding a new intrinsic to this list,
@@ -117,6 +121,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
         | sym::forget
         | sym::black_box
         | sym::variant_count
+        | sym::is_val_statically_known
         | sym::ptr_mask
         | sym::debug_assertions => hir::Unsafety::Normal,
         _ => hir::Unsafety::Unsafe,
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 2cc01a5390b9d..fc6c1eab803d7 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -2513,9 +2513,7 @@ extern "rust-intrinsic" {
 /// use std::hint::unreachable_unchecked;
 /// use std::intrinsics::is_val_statically_known;
 ///
-/// unsafe {
-///    if !is_val_statically_known(0) { unreachable_unchecked(); }
-/// }
+/// if !is_val_statically_known(0) { unsafe { unreachable_unchecked(); } }
 /// ```
 ///
 /// This also means that the following code's behavior is unspecified; it
@@ -2527,9 +2525,7 @@ extern "rust-intrinsic" {
 /// # #![allow(internal_features)]
 /// use std::intrinsics::is_val_statically_known;
 ///
-/// unsafe {
-///     assert_eq!(is_val_statically_known(0), is_val_statically_known(0));
-/// }
+/// assert_eq!(is_val_statically_known(0), is_val_statically_known(0));
 /// ```
 ///
 /// Unsafe code may not rely on `is_val_statically_known` returning any
@@ -2544,7 +2540,7 @@ extern "rust-intrinsic" {
 #[rustc_nounwind]
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[cfg_attr(not(bootstrap), rustc_intrinsic)]
-pub const unsafe fn is_val_statically_known<T: Copy>(_arg: T) -> bool {
+pub const fn is_val_statically_known<T: Copy>(_arg: T) -> bool {
     false
 }
 
@@ -2564,7 +2560,7 @@ pub const unsafe fn is_val_statically_known<T: Copy>(_arg: T) -> bool {
 #[rustc_const_unstable(feature = "delayed_debug_assertions", issue = "none")]
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[cfg_attr(not(bootstrap), rustc_intrinsic)]
-pub(crate) const unsafe fn debug_assertions() -> bool {
+pub(crate) const fn debug_assertions() -> bool {
     cfg!(debug_assertions)
 }
 
diff --git a/src/tools/miri/tests/pass/intrinsics.rs b/src/tools/miri/tests/pass/intrinsics.rs
index 8e46bd7ad48fb..0dda5aadce20a 100644
--- a/src/tools/miri/tests/pass/intrinsics.rs
+++ b/src/tools/miri/tests/pass/intrinsics.rs
@@ -37,7 +37,7 @@ fn main() {
     let mut saw_false = false;
 
     for _ in 0..50 {
-        if unsafe { intrinsics::is_val_statically_known(0) } {
+        if intrinsics::is_val_statically_known(0) {
             saw_true = true;
         } else {
             saw_false = true;
diff --git a/tests/codegen/is_val_statically_known.rs b/tests/codegen/is_val_statically_known.rs
index 8f084f6c54bdc..95f6466b2548f 100644
--- a/tests/codegen/is_val_statically_known.rs
+++ b/tests/codegen/is_val_statically_known.rs
@@ -11,7 +11,7 @@ pub enum B {
 
 #[inline]
 pub fn _u32(a: u32) -> i32 {
-    if unsafe { is_val_statically_known(a) } { 1 } else { 0 }
+    if is_val_statically_known(a) { 1 } else { 0 }
 }
 
 // CHECK-LABEL: @_u32_true(
@@ -30,7 +30,7 @@ pub fn _u32_false(a: u32) -> i32 {
 
 #[inline]
 pub fn _bool(b: bool) -> i32 {
-    if unsafe { is_val_statically_known(b) } { 3 } else { 2 }
+    if is_val_statically_known(b) { 3 } else { 2 }
 }
 
 // CHECK-LABEL: @_bool_true(
diff --git a/tests/ui/consts/is_val_statically_known.rs b/tests/ui/consts/is_val_statically_known.rs
index b4056375543ef..7362978301a0d 100644
--- a/tests/ui/consts/is_val_statically_known.rs
+++ b/tests/ui/consts/is_val_statically_known.rs
@@ -4,7 +4,7 @@
 
 use std::intrinsics::is_val_statically_known;
 
-const CONST_TEST: bool = unsafe { is_val_statically_known(0) };
+const CONST_TEST: bool = is_val_statically_known(0);
 
 fn main() {
     if CONST_TEST {

From 164b9c3be074239aa1857b2e47a63201eb294fc8 Mon Sep 17 00:00:00 2001
From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Date: Fri, 2 Feb 2024 15:07:10 +0000
Subject: [PATCH 23/58] Add more tests

---
 .../ui/intrinsics/safe-intrinsic-mismatch.rs  | 12 +++++++
 .../intrinsics/safe-intrinsic-mismatch.stderr | 33 ++++++++++++++++---
 2 files changed, 40 insertions(+), 5 deletions(-)

diff --git a/tests/ui/intrinsics/safe-intrinsic-mismatch.rs b/tests/ui/intrinsics/safe-intrinsic-mismatch.rs
index b0688e530ae71..fcd6612f1259d 100644
--- a/tests/ui/intrinsics/safe-intrinsic-mismatch.rs
+++ b/tests/ui/intrinsics/safe-intrinsic-mismatch.rs
@@ -1,5 +1,6 @@
 #![feature(intrinsics)]
 #![feature(rustc_attrs)]
+#![feature(effects)]
 
 extern "rust-intrinsic" {
     fn size_of<T>() -> usize; //~ ERROR intrinsic safety mismatch
@@ -10,4 +11,15 @@ extern "rust-intrinsic" {
     //~^ ERROR intrinsic safety mismatch
 }
 
+#[rustc_intrinsic]
+const fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
+//~^ ERROR intrinsic safety mismatch
+//~| ERROR intrinsic has wrong type
+
+mod foo {
+    #[rustc_intrinsic]
+    unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
+    //~^ ERROR wrong number of const parameters
+}
+
 fn main() {}
diff --git a/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr b/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr
index b6961275e1885..0b579121ac18e 100644
--- a/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr
+++ b/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr
@@ -1,17 +1,17 @@
 error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `size_of`
-  --> $DIR/safe-intrinsic-mismatch.rs:5:5
+  --> $DIR/safe-intrinsic-mismatch.rs:6:5
    |
 LL |     fn size_of<T>() -> usize;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `assume`
-  --> $DIR/safe-intrinsic-mismatch.rs:9:5
+  --> $DIR/safe-intrinsic-mismatch.rs:10:5
    |
 LL |     fn assume(b: bool);
    |     ^^^^^^^^^^^^^^^^^^
 
 error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `size_of`
-  --> $DIR/safe-intrinsic-mismatch.rs:5:5
+  --> $DIR/safe-intrinsic-mismatch.rs:6:5
    |
 LL |     fn size_of<T>() -> usize;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -19,12 +19,35 @@ LL |     fn size_of<T>() -> usize;
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `assume`
-  --> $DIR/safe-intrinsic-mismatch.rs:9:5
+  --> $DIR/safe-intrinsic-mismatch.rs:10:5
    |
 LL |     fn assume(b: bool);
    |     ^^^^^^^^^^^^^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: aborting due to 4 previous errors
+error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `const_deallocate`
+  --> $DIR/safe-intrinsic-mismatch.rs:15:1
+   |
+LL | const fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: intrinsic has wrong type
+  --> $DIR/safe-intrinsic-mismatch.rs:15:26
+   |
+LL | const fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
+   |                          ^ expected unsafe fn, found normal fn
+   |
+   = note: expected signature `unsafe fn(_, _, _)`
+              found signature `fn(_, _, _)`
+
+error[E0094]: intrinsic has wrong number of const parameters: found 0, expected 1
+  --> $DIR/safe-intrinsic-mismatch.rs:21:31
+   |
+LL |     unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
+   |                               ^ expected 1 const parameter
+
+error: aborting due to 7 previous errors
 
+Some errors have detailed explanations: E0094, E0308.
+For more information about an error, try `rustc --explain E0094`.

From 376c7b98921b427699b99fc36496cb81ed40c946 Mon Sep 17 00:00:00 2001
From: CKingX <CKingX@users.noreply.github.com>
Date: Tue, 13 Feb 2024 12:08:30 -0800
Subject: [PATCH 24/58] Added sahf feature to windows targets

---
 compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs | 2 +-
 .../rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs  | 2 +-
 .../rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs     | 2 +-
 .../rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs     | 2 +-
 .../rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs    | 2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs
index d16e5905eac62..d6b44e7cfd4cb 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnu.rs
@@ -3,7 +3,7 @@ use crate::spec::{base, Cc, LinkerFlavor, Lld, Target};
 pub fn target() -> Target {
     let mut base = base::windows_gnu::opts();
     base.cpu = "x86-64".into();
-    base.features = "+cx16,+sse3".into();
+    base.features = "+cx16,+sse3,+sahf".into();
     base.plt_by_default = false;
     // Use high-entropy 64 bit address space for ASLR
     base.add_pre_link_args(
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs
index ea7f7df8120f9..b84a9a5a8a120 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_gnullvm.rs
@@ -3,7 +3,7 @@ use crate::spec::{base, Cc, LinkerFlavor, Lld, Target};
 pub fn target() -> Target {
     let mut base = base::windows_gnullvm::opts();
     base.cpu = "x86-64".into();
-    base.features = "+cx16,+sse3".into();
+    base.features = "+cx16,+sse3,+sahf".into();
     base.plt_by_default = false;
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
     base.max_atomic_width = Some(128);
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs
index e72e97db7756a..51807bdba5d7a 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_windows_msvc.rs
@@ -3,7 +3,7 @@ use crate::spec::{base, SanitizerSet, Target};
 pub fn target() -> Target {
     let mut base = base::windows_msvc::opts();
     base.cpu = "x86-64".into();
-    base.features = "+cx16,+sse3".into();
+    base.features = "+cx16,+sse3,+sahf".into();
     base.plt_by_default = false;
     base.max_atomic_width = Some(128);
     base.supported_sanitizers = SanitizerSet::ADDRESS;
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs
index ee95c67496d66..b37d33601e66b 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_gnu.rs
@@ -3,7 +3,7 @@ use crate::spec::{base, Cc, LinkerFlavor, Lld, Target};
 pub fn target() -> Target {
     let mut base = base::windows_uwp_gnu::opts();
     base.cpu = "x86-64".into();
-    base.features = "+cx16,+sse3".into();
+    base.features = "+cx16,+sse3,+sahf".into();
     base.plt_by_default = false;
     // Use high-entropy 64 bit address space for ASLR
     base.add_pre_link_args(
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs
index acdf969375ec5..fe2b4c8e92dcd 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_uwp_windows_msvc.rs
@@ -3,7 +3,7 @@ use crate::spec::{base, Target};
 pub fn target() -> Target {
     let mut base = base::windows_uwp_msvc::opts();
     base.cpu = "x86-64".into();
-    base.features = "+cx16,+sse3".into();
+    base.features = "+cx16,+sse3,+sahf".into();
     base.plt_by_default = false;
     base.max_atomic_width = Some(128);
 

From b16ff5c23a917f0be6683b9ff56155572ec363da Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 7 Feb 2024 02:35:49 +0000
Subject: [PATCH 25/58] Add `rustc_confusables` annotations to some stdlib APIs

Help with common API confusion, like asking for `push` when the data structure really has `append`.

```
error[E0599]: no method named `size` found for struct `Vec<{integer}>` in the current scope
  --> $DIR/rustc_confusables_std_cases.rs:17:7
   |
LL |     x.size();
   |       ^^^^
   |
help: you might have meant to use `len`
   |
LL |     x.len();
   |       ~~~
help: there is a method with a similar name
   |
LL |     x.resize();
   |       ~~~~~~
```

#59450
---
 .../rustc_hir_typeck/src/method/suggest.rs    | 59 ++++++++-------
 .../alloc/src/collections/binary_heap/mod.rs  |  2 +
 library/alloc/src/collections/btree/map.rs    |  3 +
 .../alloc/src/collections/btree/map/entry.rs  |  3 +
 library/alloc/src/collections/btree/set.rs    |  5 ++
 library/alloc/src/collections/linked_list.rs  | 10 +++
 .../alloc/src/collections/vec_deque/mod.rs    |  5 ++
 library/alloc/src/string.rs                   |  3 +
 library/alloc/src/vec/mod.rs                  |  3 +
 library/core/src/cell.rs                      |  2 +
 library/proc_macro/src/bridge/scoped_cell.rs  |  1 +
 library/std/src/collections/hash/map.rs       |  2 +
 library/std/src/collections/hash/set.rs       |  3 +
 library/std/src/ffi/os_str.rs                 |  1 +
 library/std/src/path.rs                       |  1 +
 library/std/src/thread/local.rs               |  2 +
 tests/ui/attributes/rustc_confusables.rs      |  2 +-
 tests/ui/attributes/rustc_confusables.stderr  |  7 +-
 .../attributes/rustc_confusables_std_cases.rs | 21 ++++++
 .../rustc_confusables_std_cases.stderr        | 74 +++++++++++++++++++
 20 files changed, 180 insertions(+), 29 deletions(-)
 create mode 100644 tests/ui/attributes/rustc_confusables_std_cases.rs
 create mode 100644 tests/ui/attributes/rustc_confusables_std_cases.stderr

diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 729ce1f00cd8b..da5666d82d3be 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -1107,32 +1107,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         err.note(format!(
                             "the {item_kind} was found for\n{type_candidates}{additional_types}"
                         ));
-                    } else {
-                        'outer: for inherent_impl_did in
-                            self.tcx.inherent_impls(adt.did()).into_iter().flatten()
-                        {
-                            for inherent_method in
-                                self.tcx.associated_items(inherent_impl_did).in_definition_order()
-                            {
-                                if let Some(attr) = self
-                                    .tcx
-                                    .get_attr(inherent_method.def_id, sym::rustc_confusables)
-                                    && let Some(candidates) = parse_confusables(attr)
-                                    && candidates.contains(&item_name.name)
-                                {
-                                    err.span_suggestion_verbose(
-                                        item_name.span,
-                                        format!(
-                                            "you might have meant to use `{}`",
-                                            inherent_method.name
-                                        ),
-                                        inherent_method.name,
-                                        Applicability::MaybeIncorrect,
-                                    );
-                                    break 'outer;
-                                }
-                            }
-                        }
                     }
                 }
             } else {
@@ -1158,6 +1132,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             label_span_not_found(&mut err);
         }
 
+        let mut confusable_suggested = None;
+        if let ty::Adt(adt, _) = rcvr_ty.kind() {
+            'outer: for inherent_impl_did in
+                self.tcx.inherent_impls(adt.did()).into_iter().flatten()
+            {
+                for inherent_method in
+                    self.tcx.associated_items(inherent_impl_did).in_definition_order()
+                {
+                    if let Some(attr) =
+                        self.tcx.get_attr(inherent_method.def_id, sym::rustc_confusables)
+                        && let Some(candidates) = parse_confusables(attr)
+                        && candidates.contains(&item_name.name)
+                    {
+                        {
+                            err.span_suggestion_verbose(
+                                item_name.span,
+                                format!("you might have meant to use `{}`", inherent_method.name),
+                                inherent_method.name,
+                                Applicability::MaybeIncorrect,
+                            );
+                            confusable_suggested = Some(inherent_method.name);
+                            break 'outer;
+                        }
+                    }
+                }
+            }
+        }
+
         // Don't suggest (for example) `expr.field.clone()` if `expr.clone()`
         // can't be called due to `typeof(expr): Clone` not holding.
         if unsatisfied_predicates.is_empty() {
@@ -1259,7 +1261,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         } else if let Some(similar_candidate) = similar_candidate {
             // Don't emit a suggestion if we found an actual method
             // that had unsatisfied trait bounds
-            if unsatisfied_predicates.is_empty() {
+            if unsatisfied_predicates.is_empty()
+                // ...or if we already suggested that name because of `rustc_confusable` annotation.
+                && Some(similar_candidate.name) != confusable_suggested
+            {
                 let def_kind = similar_candidate.kind.as_def_kind();
                 // Methods are defined within the context of a struct and their first parameter is always self,
                 // which represents the instance of the struct the method is being called on
diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs
index 00a101541c589..be94df1146fa6 100644
--- a/library/alloc/src/collections/binary_heap/mod.rs
+++ b/library/alloc/src/collections/binary_heap/mod.rs
@@ -607,6 +607,7 @@ impl<T: Ord, A: Allocator> BinaryHeap<T, A> {
     /// occurs when capacity is exhausted and needs a resize. The resize cost
     /// has been amortized in the previous figures.
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("append", "put")]
     pub fn push(&mut self, item: T) {
         let old_len = self.len();
         self.data.push(item);
@@ -1264,6 +1265,7 @@ impl<T, A: Allocator> BinaryHeap<T, A> {
     /// ```
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("length", "size")]
     pub fn len(&self) -> usize {
         self.data.len()
     }
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index 2b8ddf14ff30b..d062ee57234de 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -979,6 +979,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
     /// assert_eq!(map[&37], "c");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("push", "put", "set")]
     pub fn insert(&mut self, key: K, value: V) -> Option<V>
     where
         K: Ord,
@@ -1041,6 +1042,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
     /// assert_eq!(map.remove(&1), None);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("delete", "take")]
     pub fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
     where
         K: Borrow<Q> + Ord,
@@ -2495,6 +2497,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
         issue = "71835",
         implied_by = "const_btree_new"
     )]
+    #[rustc_confusables("length", "size")]
     pub const fn len(&self) -> usize {
         self.length
     }
diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs
index e9366eec9cec3..0a894258f469f 100644
--- a/library/alloc/src/collections/btree/map/entry.rs
+++ b/library/alloc/src/collections/btree/map/entry.rs
@@ -347,6 +347,7 @@ impl<'a, K: Ord, V, A: Allocator + Clone> VacantEntry<'a, K, V, A> {
     /// assert_eq!(map["poneyland"], 37);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("push", "put")]
     pub fn insert(mut self, value: V) -> &'a mut V {
         let out_ptr = match self.handle {
             None => {
@@ -524,6 +525,7 @@ impl<'a, K: Ord, V, A: Allocator + Clone> OccupiedEntry<'a, K, V, A> {
     /// assert_eq!(map["poneyland"], 15);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("push", "put")]
     pub fn insert(&mut self, value: V) -> V {
         mem::replace(self.get_mut(), value)
     }
@@ -546,6 +548,7 @@ impl<'a, K: Ord, V, A: Allocator + Clone> OccupiedEntry<'a, K, V, A> {
     /// // println!("{}", map["poneyland"]);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("delete", "take")]
     pub fn remove(self) -> V {
         self.remove_kv().1
     }
diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs
index 0e03551286e8a..ed91ae1a66e3d 100644
--- a/library/alloc/src/collections/btree/set.rs
+++ b/library/alloc/src/collections/btree/set.rs
@@ -790,6 +790,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
     /// ```
     #[must_use]
     #[stable(feature = "map_first_last", since = "1.66.0")]
+    #[rustc_confusables("front")]
     pub fn first(&self) -> Option<&T>
     where
         T: Ord,
@@ -816,6 +817,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
     /// ```
     #[must_use]
     #[stable(feature = "map_first_last", since = "1.66.0")]
+    #[rustc_confusables("back")]
     pub fn last(&self) -> Option<&T>
     where
         T: Ord,
@@ -896,6 +898,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
     /// assert_eq!(set.len(), 1);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("push", "put")]
     pub fn insert(&mut self, value: T) -> bool
     where
         T: Ord,
@@ -919,6 +922,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
     /// assert_eq!(set.get(&[][..]).unwrap().capacity(), 10);
     /// ```
     #[stable(feature = "set_recovery", since = "1.9.0")]
+    #[rustc_confusables("swap")]
     pub fn replace(&mut self, value: T) -> Option<T>
     where
         T: Ord,
@@ -1152,6 +1156,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
         issue = "71835",
         implied_by = "const_btree_new"
     )]
+    #[rustc_confusables("length", "size")]
     pub const fn len(&self) -> usize {
         self.map.len()
     }
diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs
index 9e109feb3d3e0..6dfb82ac807a0 100644
--- a/library/alloc/src/collections/linked_list.rs
+++ b/library/alloc/src/collections/linked_list.rs
@@ -656,6 +656,7 @@ impl<T, A: Allocator> LinkedList<T, A> {
     #[inline]
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("length", "size")]
     pub fn len(&self) -> usize {
         self.len
     }
@@ -740,6 +741,7 @@ impl<T, A: Allocator> LinkedList<T, A> {
     #[inline]
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("first")]
     pub fn front(&self) -> Option<&T> {
         unsafe { self.head.as_ref().map(|node| &node.as_ref().element) }
     }
@@ -890,6 +892,7 @@ impl<T, A: Allocator> LinkedList<T, A> {
     /// assert_eq!(3, *d.back().unwrap());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("push", "append")]
     pub fn push_back(&mut self, elt: T) {
         let node = Box::new_in(Node::new(elt), &self.alloc);
         let node_ptr = NonNull::from(Box::leak(node));
@@ -1004,6 +1007,7 @@ impl<T, A: Allocator> LinkedList<T, A> {
     /// assert_eq!(d.remove(0), 1);
     /// ```
     #[unstable(feature = "linked_list_remove", issue = "69210")]
+    #[rustc_confusables("delete", "take")]
     pub fn remove(&mut self, at: usize) -> T {
         let len = self.len();
         assert!(at < len, "Cannot remove at an index outside of the list bounds");
@@ -1478,6 +1482,7 @@ impl<'a, T, A: Allocator> Cursor<'a, T, A> {
     /// or None if the list is empty.
     #[must_use]
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
+    #[rustc_confusables("first")]
     pub fn front(&self) -> Option<&'a T> {
         self.list.front()
     }
@@ -1486,6 +1491,7 @@ impl<'a, T, A: Allocator> Cursor<'a, T, A> {
     /// or None if the list is empty.
     #[must_use]
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
+    #[rustc_confusables("last")]
     pub fn back(&self) -> Option<&'a T> {
         self.list.back()
     }
@@ -1788,6 +1794,7 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> {
     ///
     /// This operation should compute in *O*(1) time.
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
+    #[rustc_confusables("push", "append")]
     pub fn push_back(&mut self, elt: T) {
         // Safety: We know that `push_back` does not change the position in
         // memory of other nodes. This ensures that `self.current` remains
@@ -1834,6 +1841,7 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> {
     ///
     /// This operation should compute in *O*(1) time.
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
+    #[rustc_confusables("pop")]
     pub fn pop_back(&mut self) -> Option<T> {
         if self.list.is_empty() {
             None
@@ -1854,6 +1862,7 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> {
     /// or None if the list is empty.
     #[must_use]
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
+    #[rustc_confusables("first")]
     pub fn front(&self) -> Option<&T> {
         self.list.front()
     }
@@ -1870,6 +1879,7 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> {
     /// or None if the list is empty.
     #[must_use]
     #[unstable(feature = "linked_list_cursors", issue = "58533")]
+    #[rustc_confusables("last")]
     pub fn back(&self) -> Option<&T> {
         self.list.back()
     }
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index d062587b8f533..d9c9657d2eb91 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -1209,6 +1209,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// assert_eq!(deque.len(), 1);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("length", "size")]
     pub fn len(&self) -> usize {
         self.len
     }
@@ -1491,6 +1492,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// assert_eq!(d.front(), Some(&1));
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("first")]
     pub fn front(&self) -> Option<&T> {
         self.get(0)
     }
@@ -1535,6 +1537,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// assert_eq!(d.back(), Some(&2));
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("last")]
     pub fn back(&self) -> Option<&T> {
         self.get(self.len.wrapping_sub(1))
     }
@@ -1654,6 +1657,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// assert_eq!(3, *buf.back().unwrap());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("push", "put", "append")]
     pub fn push_back(&mut self, value: T) {
         if self.is_full() {
             self.grow();
@@ -1813,6 +1817,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// assert_eq!(buf, [1, 3]);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("delete", "take")]
     pub fn remove(&mut self, index: usize) -> Option<T> {
         if self.len <= index {
             return None;
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index 4d6968157dedd..6ad783bee27ec 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -1445,6 +1445,7 @@ impl String {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("delete", "take")]
     pub fn remove(&mut self, idx: usize) -> char {
         let ch = match self[idx..].chars().next() {
             Some(ch) => ch,
@@ -1639,6 +1640,7 @@ impl String {
     #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("set")]
     pub fn insert(&mut self, idx: usize, ch: char) {
         assert!(self.is_char_boundary(idx));
         let mut bits = [0; 4];
@@ -1738,6 +1740,7 @@ impl String {
     #[inline]
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("length", "size")]
     pub fn len(&self) -> usize {
         self.vec.len()
     }
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 08e3cdedc666b..b59699219eb84 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -1554,6 +1554,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[track_caller]
+    #[rustc_confusables("delete", "take")]
     pub fn remove(&mut self, index: usize) -> T {
         #[cold]
         #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
@@ -1915,6 +1916,7 @@ impl<T, A: Allocator> Vec<T, A> {
     #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("push_back", "put", "append")]
     pub fn push(&mut self, value: T) {
         // This will panic or abort if we would allocate > isize::MAX bytes
         // or if the length increment would overflow for zero-sized types.
@@ -2141,6 +2143,7 @@ impl<T, A: Allocator> Vec<T, A> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("length", "size")]
     pub fn len(&self) -> usize {
         self.len
     }
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index c77fa371cc74a..19b05448c8780 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -471,6 +471,7 @@ impl<T> Cell<T> {
     /// ```
     #[inline]
     #[stable(feature = "move_cell", since = "1.17.0")]
+    #[rustc_confusables("swap")]
     pub fn replace(&self, val: T) -> T {
         // SAFETY: This can cause data races if called from a separate thread,
         // but `Cell` is `!Sync` so this won't happen.
@@ -862,6 +863,7 @@ impl<T> RefCell<T> {
     #[inline]
     #[stable(feature = "refcell_replace", since = "1.24.0")]
     #[track_caller]
+    #[rustc_confusables("swap")]
     pub fn replace(&self, t: T) -> T {
         mem::replace(&mut *self.borrow_mut(), t)
     }
diff --git a/library/proc_macro/src/bridge/scoped_cell.rs b/library/proc_macro/src/bridge/scoped_cell.rs
index 2cde1f65adf9c..949cf6b6d34e0 100644
--- a/library/proc_macro/src/bridge/scoped_cell.rs
+++ b/library/proc_macro/src/bridge/scoped_cell.rs
@@ -43,6 +43,7 @@ impl<T: LambdaL> ScopedCell<T> {
     /// running `f`, which gets the old value, mutably.
     /// The old value will be restored after `f` exits, even
     /// by panic, including modifications made to it by `f`.
+    #[rustc_confusables("swap")]
     pub fn replace<'a, R>(
         &self,
         replacement: <T as ApplyL<'a>>::Out,
diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs
index 0d4c1fa05cc87..627befb63a1bb 100644
--- a/library/std/src/collections/hash/map.rs
+++ b/library/std/src/collections/hash/map.rs
@@ -1101,6 +1101,7 @@ where
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("push", "append")]
     pub fn insert(&mut self, k: K, v: V) -> Option<V> {
         self.base.insert(k, v)
     }
@@ -1155,6 +1156,7 @@ where
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("delete", "take")]
     pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V>
     where
         K: Borrow<Q>,
diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs
index dcb2fa0f771b0..371201ff44cbe 100644
--- a/library/std/src/collections/hash/set.rs
+++ b/library/std/src/collections/hash/set.rs
@@ -885,6 +885,7 @@ where
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("push", "append")]
     pub fn insert(&mut self, value: T) -> bool {
         self.base.insert(value)
     }
@@ -906,6 +907,7 @@ where
     /// ```
     #[inline]
     #[stable(feature = "set_recovery", since = "1.9.0")]
+    #[rustc_confusables("swap")]
     pub fn replace(&mut self, value: T) -> Option<T> {
         self.base.replace(value)
     }
@@ -930,6 +932,7 @@ where
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("delete", "take")]
     pub fn remove<Q: ?Sized>(&mut self, value: &Q) -> bool
     where
         T: Borrow<Q>,
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index 81973182148ef..26e40c1d63112 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -255,6 +255,7 @@ impl OsString {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
+    #[rustc_confusables("append", "put")]
     pub fn push<T: AsRef<OsStr>>(&mut self, s: T) {
         self.inner.push_slice(&s.as_ref().inner)
     }
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 60562f64c90d9..89fbd5c4c6454 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -1270,6 +1270,7 @@ impl PathBuf {
     /// assert_eq!(path, PathBuf::from("/etc"));
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("append", "put")]
     pub fn push<P: AsRef<Path>>(&mut self, path: P) {
         self._push(path.as_ref())
     }
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index 83d5d63556fc3..7bd4ad36985aa 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -435,6 +435,7 @@ impl<T: 'static> LocalKey<Cell<T>> {
     /// assert_eq!(X.replace(3), 2);
     /// ```
     #[stable(feature = "local_key_cell_methods", since = "1.73.0")]
+    #[rustc_confusables("swap")]
     pub fn replace(&'static self, value: T) -> T {
         self.with(|cell| cell.replace(value))
     }
@@ -606,6 +607,7 @@ impl<T: 'static> LocalKey<RefCell<T>> {
     /// X.with_borrow(|v| assert_eq!(*v, vec![1, 2, 3]));
     /// ```
     #[stable(feature = "local_key_cell_methods", since = "1.73.0")]
+    #[rustc_confusables("swap")]
     pub fn replace(&'static self, value: T) -> T {
         self.with(|cell| cell.replace(value))
     }
diff --git a/tests/ui/attributes/rustc_confusables.rs b/tests/ui/attributes/rustc_confusables.rs
index 352e91d065f40..8c8a8c7fc16ce 100644
--- a/tests/ui/attributes/rustc_confusables.rs
+++ b/tests/ui/attributes/rustc_confusables.rs
@@ -21,7 +21,7 @@ fn main() {
     //~^ ERROR no method named
     x.pulled();
     //~^ ERROR no method named
-    //~| HELP there is a method with a similar name
+    //~| HELP you might have meant to use `pull`
 }
 
 struct Bar;
diff --git a/tests/ui/attributes/rustc_confusables.stderr b/tests/ui/attributes/rustc_confusables.stderr
index 9fd4470cdbb9f..93c31fd5a34ef 100644
--- a/tests/ui/attributes/rustc_confusables.stderr
+++ b/tests/ui/attributes/rustc_confusables.stderr
@@ -60,7 +60,12 @@ error[E0599]: no method named `pulled` found for struct `rustc_confusables_acros
   --> $DIR/rustc_confusables.rs:22:7
    |
 LL |     x.pulled();
-   |       ^^^^^^ help: there is a method with a similar name: `pull`
+   |       ^^^^^^
+   |
+help: you might have meant to use `pull`
+   |
+LL |     x.pull();
+   |       ~~~~
 
 error: aborting due to 9 previous errors
 
diff --git a/tests/ui/attributes/rustc_confusables_std_cases.rs b/tests/ui/attributes/rustc_confusables_std_cases.rs
new file mode 100644
index 0000000000000..f408a09a81f49
--- /dev/null
+++ b/tests/ui/attributes/rustc_confusables_std_cases.rs
@@ -0,0 +1,21 @@
+use std::collections::BTreeSet;
+use std::collections::VecDeque;
+
+fn main() {
+    let mut x = BTreeSet::new();
+    x.push(1); //~ ERROR E0599
+    //~^ HELP you might have meant to use `insert`
+    let mut x = Vec::new();
+    x.push_back(1); //~ ERROR E0599
+    //~^ HELP you might have meant to use `push`
+    let mut x = VecDeque::new();
+    x.push(1); //~ ERROR E0599
+    //~^ HELP you might have meant to use `push_back`
+    let mut x = vec![1, 2, 3];
+    x.length(); //~ ERROR E0599
+    //~^ HELP you might have meant to use `len`
+    x.size(); //~ ERROR E0599
+    //~^ HELP you might have meant to use `len`
+    //~| HELP there is a method with a similar name
+    String::new().push(""); //~ ERROR E0308
+}
diff --git a/tests/ui/attributes/rustc_confusables_std_cases.stderr b/tests/ui/attributes/rustc_confusables_std_cases.stderr
new file mode 100644
index 0000000000000..ce3bf3921dcde
--- /dev/null
+++ b/tests/ui/attributes/rustc_confusables_std_cases.stderr
@@ -0,0 +1,74 @@
+error[E0599]: no method named `push` found for struct `BTreeSet` in the current scope
+  --> $DIR/rustc_confusables_std_cases.rs:6:7
+   |
+LL |     x.push(1);
+   |       ^^^^ method not found in `BTreeSet<_>`
+   |
+help: you might have meant to use `insert`
+   |
+LL |     x.insert(1);
+   |       ~~~~~~
+
+error[E0599]: no method named `push_back` found for struct `Vec<_>` in the current scope
+  --> $DIR/rustc_confusables_std_cases.rs:9:7
+   |
+LL |     x.push_back(1);
+   |       ^^^^^^^^^ method not found in `Vec<_>`
+   |
+help: you might have meant to use `push`
+   |
+LL |     x.push(1);
+   |       ~~~~
+
+error[E0599]: no method named `push` found for struct `VecDeque` in the current scope
+  --> $DIR/rustc_confusables_std_cases.rs:12:7
+   |
+LL |     x.push(1);
+   |       ^^^^ method not found in `VecDeque<_>`
+   |
+help: you might have meant to use `push_back`
+   |
+LL |     x.push_back(1);
+   |       ~~~~~~~~~
+
+error[E0599]: no method named `length` found for struct `Vec<{integer}>` in the current scope
+  --> $DIR/rustc_confusables_std_cases.rs:15:7
+   |
+LL |     x.length();
+   |       ^^^^^^
+   |
+help: you might have meant to use `len`
+   |
+LL |     x.len();
+   |       ~~~
+
+error[E0599]: no method named `size` found for struct `Vec<{integer}>` in the current scope
+  --> $DIR/rustc_confusables_std_cases.rs:17:7
+   |
+LL |     x.size();
+   |       ^^^^
+   |
+help: you might have meant to use `len`
+   |
+LL |     x.len();
+   |       ~~~
+help: there is a method with a similar name
+   |
+LL |     x.resize();
+   |       ~~~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/rustc_confusables_std_cases.rs:20:24
+   |
+LL |     String::new().push("");
+   |                   ---- ^^ expected `char`, found `&str`
+   |                   |
+   |                   arguments to this method are incorrect
+   |
+note: method defined here
+  --> $SRC_DIR/alloc/src/string.rs:LL:COL
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0308, E0599.
+For more information about an error, try `rustc --explain E0308`.

From 739edcef9684884172cf22767b745ac361bd56df Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 7 Feb 2024 05:13:06 +0000
Subject: [PATCH 26/58] On type error of method call arguments, look at
 confusables for suggestion

---
 .../rustc_hir_typeck/src/fn_ctxt/checks.rs    | 46 ++++++++++--
 .../rustc_hir_typeck/src/method/suggest.rs    | 74 ++++++++++++-------
 library/alloc/src/string.rs                   |  1 +
 .../attributes/rustc_confusables_std_cases.rs |  3 +
 .../rustc_confusables_std_cases.stderr        | 17 ++++-
 5 files changed, 106 insertions(+), 35 deletions(-)

diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 65b8505c09098..a5fed8fc95751 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -451,7 +451,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         call_expr: &'tcx hir::Expr<'tcx>,
     ) -> ErrorGuaranteed {
         // Next, let's construct the error
-        let (error_span, full_call_span, call_name, is_method) = match &call_expr.kind {
+        let (error_span, call_ident, full_call_span, call_name, is_method) = match &call_expr.kind {
             hir::ExprKind::Call(
                 hir::Expr { hir_id, span, kind: hir::ExprKind::Path(qpath), .. },
                 _,
@@ -463,12 +463,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         CtorOf::Struct => "struct",
                         CtorOf::Variant => "enum variant",
                     };
-                    (call_span, *span, name, false)
+                    (call_span, None, *span, name, false)
                 } else {
-                    (call_span, *span, "function", false)
+                    (call_span, None, *span, "function", false)
                 }
             }
-            hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, "function", false),
+            hir::ExprKind::Call(hir::Expr { span, .. }, _) => {
+                (call_span, None, *span, "function", false)
+            }
             hir::ExprKind::MethodCall(path_segment, _, _, span) => {
                 let ident_span = path_segment.ident.span;
                 let ident_span = if let Some(args) = path_segment.args {
@@ -476,7 +478,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 } else {
                     ident_span
                 };
-                (*span, ident_span, "method", true)
+                (*span, Some(path_segment.ident), ident_span, "method", true)
             }
             k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k),
         };
@@ -530,6 +532,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let callee_ty = callee_expr
             .and_then(|callee_expr| self.typeck_results.borrow().expr_ty_adjusted_opt(callee_expr));
 
+        let suggest_confusable = |err: &mut Diagnostic| {
+            if let Some(call_name) = call_ident
+                && let Some(callee_ty) = callee_ty
+            {
+                // FIXME: check in the following order
+                //        - methods marked as `rustc_confusables` with the provided arguments (done)
+                //        - methods marked as `rustc_confusables` with the right number of arguments
+                //        - methods marked as `rustc_confusables` (done)
+                //        - methods with the same argument type/count and short levenshtein distance
+                //        - methods with short levenshtein distance
+                //        - methods with the same argument type/count
+                self.confusable_method_name(
+                    err,
+                    callee_ty.peel_refs(),
+                    call_name,
+                    Some(provided_arg_tys.iter().map(|(ty, _)| *ty).collect()),
+                )
+                .or_else(|| {
+                    self.confusable_method_name(err, callee_ty.peel_refs(), call_name, None)
+                });
+            }
+        };
         // A "softer" version of the `demand_compatible`, which checks types without persisting them,
         // and treats error types differently
         // This will allow us to "probe" for other argument orders that would likely have been correct
@@ -694,6 +718,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         Some(mismatch_idx),
                         is_method,
                     );
+                    suggest_confusable(&mut err);
                     return err.emit();
                 }
             }
@@ -718,7 +743,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if cfg!(debug_assertions) {
                 span_bug!(error_span, "expected errors from argument matrix");
             } else {
-                return tcx.dcx().emit_err(errors::ArgMismatchIndeterminate { span: error_span });
+                let mut err =
+                    tcx.dcx().create_err(errors::ArgMismatchIndeterminate { span: error_span });
+                suggest_confusable(&mut err);
+                return err.emit();
             }
         }
 
@@ -733,7 +761,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let trace =
                 mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty);
             if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) {
-                reported = Some(self.err_ctxt().report_and_explain_type_error(trace, *e).emit());
+                let mut err = self.err_ctxt().report_and_explain_type_error(trace, *e);
+                suggest_confusable(&mut err);
+                reported = Some(err.emit());
                 return false;
             }
             true
@@ -801,6 +831,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 Some(expected_idx.as_usize()),
                 is_method,
             );
+            suggest_confusable(&mut err);
             return err.emit();
         }
 
@@ -828,6 +859,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .with_code(err_code.to_owned())
         };
 
+        suggest_confusable(&mut err);
         // As we encounter issues, keep track of what we want to provide for the suggestion
         let mut labels = vec![];
         // If there is a single error, we give a specific suggestion; otherwise, we change to
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index da5666d82d3be..814dc9076ffd0 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -1132,33 +1132,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             label_span_not_found(&mut err);
         }
 
-        let mut confusable_suggested = None;
-        if let ty::Adt(adt, _) = rcvr_ty.kind() {
-            'outer: for inherent_impl_did in
-                self.tcx.inherent_impls(adt.did()).into_iter().flatten()
-            {
-                for inherent_method in
-                    self.tcx.associated_items(inherent_impl_did).in_definition_order()
-                {
-                    if let Some(attr) =
-                        self.tcx.get_attr(inherent_method.def_id, sym::rustc_confusables)
-                        && let Some(candidates) = parse_confusables(attr)
-                        && candidates.contains(&item_name.name)
-                    {
-                        {
-                            err.span_suggestion_verbose(
-                                item_name.span,
-                                format!("you might have meant to use `{}`", inherent_method.name),
-                                inherent_method.name,
-                                Applicability::MaybeIncorrect,
-                            );
-                            confusable_suggested = Some(inherent_method.name);
-                            break 'outer;
-                        }
-                    }
-                }
-            }
-        }
+        let confusable_suggested = self.confusable_method_name(&mut err, rcvr_ty, item_name, None);
 
         // Don't suggest (for example) `expr.field.clone()` if `expr.clone()`
         // can't be called due to `typeof(expr): Clone` not holding.
@@ -1340,6 +1314,52 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         Some(err)
     }
 
+    pub(crate) fn confusable_method_name(
+        &self,
+        err: &mut Diagnostic,
+        rcvr_ty: Ty<'tcx>,
+        item_name: Ident,
+        args: Option<Vec<Ty<'tcx>>>,
+    ) -> Option<Symbol> {
+        if let ty::Adt(adt, _) = rcvr_ty.kind() {
+            for inherent_impl_did in self.tcx.inherent_impls(adt.did()).into_iter().flatten() {
+                for inherent_method in
+                    self.tcx.associated_items(inherent_impl_did).in_definition_order()
+                {
+                    if let Some(attr) =
+                        self.tcx.get_attr(inherent_method.def_id, sym::rustc_confusables)
+                        && let Some(candidates) = parse_confusables(attr)
+                        && candidates.contains(&item_name.name)
+                    {
+                        let mut matches_args = args.is_none();
+                        if let ty::AssocKind::Fn = inherent_method.kind
+                            && let Some(ref args) = args
+                        {
+                            let fn_sig =
+                                self.tcx.fn_sig(inherent_method.def_id).instantiate_identity();
+                            matches_args = fn_sig
+                                .inputs()
+                                .skip_binder()
+                                .iter()
+                                .skip(1)
+                                .zip(args.into_iter())
+                                .all(|(expected, found)| self.can_coerce(*expected, *found));
+                        }
+                        if matches_args {
+                            err.span_suggestion_verbose(
+                                item_name.span,
+                                format!("you might have meant to use `{}`", inherent_method.name),
+                                inherent_method.name,
+                                Applicability::MaybeIncorrect,
+                            );
+                            return Some(inherent_method.name);
+                        }
+                    }
+                }
+            }
+        }
+        None
+    }
     fn note_candidates_on_method_error(
         &self,
         rcvr_ty: Ty<'tcx>,
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index 6ad783bee27ec..6dadbc8e36428 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -1049,6 +1049,7 @@ impl String {
     #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("append", "push")]
     pub fn push_str(&mut self, string: &str) {
         self.vec.extend_from_slice(string.as_bytes())
     }
diff --git a/tests/ui/attributes/rustc_confusables_std_cases.rs b/tests/ui/attributes/rustc_confusables_std_cases.rs
index f408a09a81f49..eda35e4b633a3 100644
--- a/tests/ui/attributes/rustc_confusables_std_cases.rs
+++ b/tests/ui/attributes/rustc_confusables_std_cases.rs
@@ -18,4 +18,7 @@ fn main() {
     //~^ HELP you might have meant to use `len`
     //~| HELP there is a method with a similar name
     String::new().push(""); //~ ERROR E0308
+    //~^ HELP you might have meant to use `push_str`
+    String::new().append(""); //~ ERROR E0599
+    //~^ HELP you might have meant to use `push_str`
 }
diff --git a/tests/ui/attributes/rustc_confusables_std_cases.stderr b/tests/ui/attributes/rustc_confusables_std_cases.stderr
index ce3bf3921dcde..f69b79b4028a0 100644
--- a/tests/ui/attributes/rustc_confusables_std_cases.stderr
+++ b/tests/ui/attributes/rustc_confusables_std_cases.stderr
@@ -67,8 +67,23 @@ LL |     String::new().push("");
    |
 note: method defined here
   --> $SRC_DIR/alloc/src/string.rs:LL:COL
+help: you might have meant to use `push_str`
+   |
+LL |     String::new().push_str("");
+   |                   ~~~~~~~~
+
+error[E0599]: no method named `append` found for struct `String` in the current scope
+  --> $DIR/rustc_confusables_std_cases.rs:22:19
+   |
+LL |     String::new().append("");
+   |                   ^^^^^^ method not found in `String`
+   |
+help: you might have meant to use `push_str`
+   |
+LL |     String::new().push_str("");
+   |                   ~~~~~~~~
 
-error: aborting due to 6 previous errors
+error: aborting due to 7 previous errors
 
 Some errors have detailed explanations: E0308, E0599.
 For more information about an error, try `rustc --explain E0308`.

From c5e9be428c799f4e3b802e805493948ffb824187 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Fri, 9 Feb 2024 20:10:39 +0000
Subject: [PATCH 27/58] drive-by fmt cleanup

---
 compiler/rustc_middle/src/ty/print/pretty.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 5cf90e94907b0..f964241fd0b82 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -2929,7 +2929,7 @@ define_print_and_forward_display! {
 
     ty::ExistentialTraitRef<'tcx> {
         // Use a type that can't appear in defaults of type parameters.
-        let dummy_self = Ty::new_fresh(cx.tcx(),0);
+        let dummy_self = Ty::new_fresh(cx.tcx(), 0);
         let trait_ref = self.with_self_ty(cx.tcx(), dummy_self);
         p!(print(trait_ref.print_only_trait_path()))
     }

From 919b42943b77f7c08ad246baed37596f2cd98d16 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Fri, 9 Feb 2024 20:54:26 +0000
Subject: [PATCH 28/58] Provide more and more accurate suggestions when calling
 the wrong method

```
error[E0308]: mismatched types
  --> $DIR/rustc_confusables_std_cases.rs:20:14
   |
LL |     x.append(42);
   |       ------ ^^ expected `&mut Vec<{integer}>`, found integer
   |       |
   |       arguments to this method are incorrect
   |
   = note: expected mutable reference `&mut Vec<{integer}>`
                           found type `{integer}`
note: method defined here
  --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
help: you might have meant to use `push`
   |
LL |     x.push(42);
   |       ~~~~
```
---
 .../rustc_hir_typeck/src/fn_ctxt/checks.rs    | 106 ++++++++++++++++--
 compiler/rustc_hir_typeck/src/method/probe.rs |  24 +++-
 .../rustc_hir_typeck/src/method/suggest.rs    |  65 ++++++++---
 .../attributes/rustc_confusables_std_cases.rs |   2 +
 .../rustc_confusables_std_cases.stderr        |  23 +++-
 5 files changed, 189 insertions(+), 31 deletions(-)

diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index a5fed8fc95751..a5cf541509b19 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1,7 +1,11 @@
 use crate::coercion::CoerceMany;
 use crate::errors::SuggestPtrNullMut;
 use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx};
+use crate::fn_ctxt::infer::FnCall;
 use crate::gather_locals::Declaration;
+use crate::method::probe::IsSuggestion;
+use crate::method::probe::Mode::MethodCall;
+use crate::method::probe::ProbeScope::TraitsInScope;
 use crate::method::MethodCallee;
 use crate::TupleArgumentsFlag::*;
 use crate::{errors, Expectation::*};
@@ -532,25 +536,111 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let callee_ty = callee_expr
             .and_then(|callee_expr| self.typeck_results.borrow().expr_ty_adjusted_opt(callee_expr));
 
+        // Obtain another method on `Self` that have similar name.
+        let similar_assoc = |call_name: Ident| -> Option<(ty::AssocItem, ty::FnSig<'_>)> {
+            if let Some(callee_ty) = callee_ty
+                && let Ok(Some(assoc)) = self.probe_op(
+                    call_name.span,
+                    MethodCall,
+                    Some(call_name),
+                    None,
+                    IsSuggestion(true),
+                    callee_ty.peel_refs(),
+                    callee_expr.unwrap().hir_id,
+                    TraitsInScope,
+                    |mut ctxt| ctxt.probe_for_similar_candidate(),
+                )
+                && let ty::AssocKind::Fn = assoc.kind
+                && assoc.fn_has_self_parameter
+            {
+                let fn_sig =
+                    if let ty::Adt(_, args) = callee_ty.peel_refs().kind() {
+                        let args = ty::GenericArgs::identity_for_item(tcx, assoc.def_id)
+                            .rebase_onto(tcx, assoc.container_id(tcx), args);
+                        tcx.fn_sig(assoc.def_id).instantiate(tcx, args)
+                    } else {
+                        tcx.fn_sig(assoc.def_id).instantiate_identity()
+                    };
+                let fn_sig =
+                    self.instantiate_binder_with_fresh_vars(call_name.span, FnCall, fn_sig);
+                Some((assoc, fn_sig));
+            }
+            None
+        };
+
         let suggest_confusable = |err: &mut Diagnostic| {
             if let Some(call_name) = call_ident
                 && let Some(callee_ty) = callee_ty
             {
-                // FIXME: check in the following order
-                //        - methods marked as `rustc_confusables` with the provided arguments (done)
-                //        - methods marked as `rustc_confusables` with the right number of arguments
-                //        - methods marked as `rustc_confusables` (done)
-                //        - methods with the same argument type/count and short levenshtein distance
-                //        - methods with short levenshtein distance
-                //        - methods with the same argument type/count
+                let input_types: Vec<Ty<'_>> = provided_arg_tys.iter().map(|(ty, _)| *ty).collect();
+                // Check for other methods in the following order
+                //  - methods marked as `rustc_confusables` with the provided arguments
+                //  - methods with the same argument type/count and short levenshtein distance
+                //  - methods marked as `rustc_confusables` (done)
+                //  - methods with short levenshtein distance
+
+                // Look for commonly confusable method names considering arguments.
                 self.confusable_method_name(
                     err,
                     callee_ty.peel_refs(),
                     call_name,
-                    Some(provided_arg_tys.iter().map(|(ty, _)| *ty).collect()),
+                    Some(input_types.clone()),
                 )
                 .or_else(|| {
+                    // Look for method names with short levenshtein distance, considering arguments.
+                    if let Some((assoc, fn_sig)) = similar_assoc(call_name)
+                        && fn_sig.inputs()[1..]
+                            .iter()
+                            .zip(input_types.iter())
+                            .all(|(expected, found)| self.can_coerce(*expected, *found))
+                        && fn_sig.inputs()[1..].len() == input_types.len()
+                    {
+                        err.span_suggestion_verbose(
+                            call_name.span,
+                            format!("you might have meant to use `{}`", assoc.name),
+                            assoc.name,
+                            Applicability::MaybeIncorrect,
+                        );
+                        return Some(assoc.name);
+                    }
+                    None
+                })
+                .or_else(|| {
+                    // Look for commonly confusable method names disregarding arguments.
                     self.confusable_method_name(err, callee_ty.peel_refs(), call_name, None)
+                })
+                .or_else(|| {
+                    // Look for similarly named methods with levenshtein distance with the right
+                    // number of arguments.
+                    if let Some((assoc, fn_sig)) = similar_assoc(call_name)
+                        && fn_sig.inputs()[1..].len() == input_types.len()
+                    {
+                        err.span_note(
+                            tcx.def_span(assoc.def_id),
+                            format!(
+                                "there's is a method with similar name `{}`, but the arguments \
+                                 don't match",
+                                assoc.name,
+                            ),
+                        );
+                        return Some(assoc.name);
+                    }
+                    None
+                })
+                .or_else(|| {
+                    // Fallthrough: look for similarly named methods with levenshtein distance.
+                    if let Some((assoc, _)) = similar_assoc(call_name) {
+                        err.span_note(
+                            tcx.def_span(assoc.def_id),
+                            format!(
+                                "there's is a method with similar name `{}`, but their argument \
+                                 count doesn't match",
+                                assoc.name,
+                            ),
+                        );
+                        return Some(assoc.name);
+                    }
+                    None
                 });
             }
         };
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index d7edc70bce82e..9b405c867f328 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -54,7 +54,7 @@ pub use self::PickKind::*;
 #[derive(Clone, Copy, Debug)]
 pub struct IsSuggestion(pub bool);
 
-struct ProbeContext<'a, 'tcx> {
+pub(crate) struct ProbeContext<'a, 'tcx> {
     fcx: &'a FnCtxt<'a, 'tcx>,
     span: Span,
     mode: Mode,
@@ -355,7 +355,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         .unwrap()
     }
 
-    fn probe_op<OP, R>(
+    pub(crate) fn probe_op<OP, R>(
         &'a self,
         span: Span,
         mode: Mode,
@@ -1751,7 +1751,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
     /// Similarly to `probe_for_return_type`, this method attempts to find the best matching
     /// candidate method where the method name may have been misspelled. Similarly to other
     /// edit distance based suggestions, we provide at most one such suggestion.
-    fn probe_for_similar_candidate(&mut self) -> Result<Option<ty::AssocItem>, MethodError<'tcx>> {
+    pub(crate) fn probe_for_similar_candidate(
+        &mut self,
+    ) -> Result<Option<ty::AssocItem>, MethodError<'tcx>> {
         debug!("probing for method names similar to {:?}", self.method_name);
 
         self.probe(|_| {
@@ -1943,7 +1945,21 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         let hir_id = self.fcx.tcx.local_def_id_to_hir_id(local_def_id);
         let attrs = self.fcx.tcx.hir().attrs(hir_id);
         for attr in attrs {
-            let sym::doc = attr.name_or_empty() else {
+            if sym::doc == attr.name_or_empty() {
+            } else if sym::rustc_confusables == attr.name_or_empty() {
+                let Some(confusables) = attr.meta_item_list() else {
+                    continue;
+                };
+                // #[rustc_confusables("foo", "bar"))]
+                for n in confusables {
+                    if let Some(lit) = n.lit()
+                        && name.as_str() == lit.symbol.as_str()
+                    {
+                        return true;
+                    }
+                }
+                continue;
+            } else {
                 continue;
             };
             let Some(values) = attr.meta_item_list() else {
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 814dc9076ffd0..65ec8b3f06227 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -23,6 +23,7 @@ use rustc_hir::PatKind::Binding;
 use rustc_hir::PathSegment;
 use rustc_hir::{ExprKind, Node, QPath};
 use rustc_infer::infer::{
+    self,
     type_variable::{TypeVariableOrigin, TypeVariableOriginKind},
     RegionVariableOrigin,
 };
@@ -1132,7 +1133,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             label_span_not_found(&mut err);
         }
 
-        let confusable_suggested = self.confusable_method_name(&mut err, rcvr_ty, item_name, None);
+        let confusable_suggested = self.confusable_method_name(
+            &mut err,
+            rcvr_ty,
+            item_name,
+            args.map(|args| {
+                args.iter()
+                    .map(|expr| {
+                        self.node_ty_opt(expr.hir_id).unwrap_or_else(|| {
+                            self.next_ty_var(TypeVariableOrigin {
+                                kind: TypeVariableOriginKind::MiscVariable,
+                                span: expr.span,
+                            })
+                        })
+                    })
+                    .collect()
+            }),
+        );
 
         // Don't suggest (for example) `expr.field.clone()` if `expr.clone()`
         // can't be called due to `typeof(expr): Clone` not holding.
@@ -1319,9 +1336,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         err: &mut Diagnostic,
         rcvr_ty: Ty<'tcx>,
         item_name: Ident,
-        args: Option<Vec<Ty<'tcx>>>,
+        call_args: Option<Vec<Ty<'tcx>>>,
     ) -> Option<Symbol> {
-        if let ty::Adt(adt, _) = rcvr_ty.kind() {
+        if let ty::Adt(adt, adt_args) = rcvr_ty.kind() {
             for inherent_impl_did in self.tcx.inherent_impls(adt.did()).into_iter().flatten() {
                 for inherent_method in
                     self.tcx.associated_items(inherent_impl_did).in_definition_order()
@@ -1330,22 +1347,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         self.tcx.get_attr(inherent_method.def_id, sym::rustc_confusables)
                         && let Some(candidates) = parse_confusables(attr)
                         && candidates.contains(&item_name.name)
+                        && let ty::AssocKind::Fn = inherent_method.kind
                     {
-                        let mut matches_args = args.is_none();
-                        if let ty::AssocKind::Fn = inherent_method.kind
-                            && let Some(ref args) = args
-                        {
-                            let fn_sig =
-                                self.tcx.fn_sig(inherent_method.def_id).instantiate_identity();
-                            matches_args = fn_sig
-                                .inputs()
-                                .skip_binder()
+                        let args =
+                            ty::GenericArgs::identity_for_item(self.tcx, inherent_method.def_id)
+                                .rebase_onto(
+                                    self.tcx,
+                                    inherent_method.container_id(self.tcx),
+                                    adt_args,
+                                );
+                        let fn_sig =
+                            self.tcx.fn_sig(inherent_method.def_id).instantiate(self.tcx, args);
+                        let fn_sig = self.instantiate_binder_with_fresh_vars(
+                            item_name.span,
+                            infer::FnCall,
+                            fn_sig,
+                        );
+                        if let Some(ref args) = call_args
+                            && fn_sig.inputs()[1..]
                                 .iter()
-                                .skip(1)
                                 .zip(args.into_iter())
-                                .all(|(expected, found)| self.can_coerce(*expected, *found));
-                        }
-                        if matches_args {
+                                .all(|(expected, found)| self.can_coerce(*expected, *found))
+                            && fn_sig.inputs()[1..].len() == args.len()
+                        {
                             err.span_suggestion_verbose(
                                 item_name.span,
                                 format!("you might have meant to use `{}`", inherent_method.name),
@@ -1353,6 +1377,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 Applicability::MaybeIncorrect,
                             );
                             return Some(inherent_method.name);
+                        } else if let None = call_args {
+                            err.span_note(
+                                self.tcx.def_span(inherent_method.def_id),
+                                format!(
+                                    "you might have meant to use method `{}`",
+                                    inherent_method.name,
+                                ),
+                            );
+                            return Some(inherent_method.name);
                         }
                     }
                 }
diff --git a/tests/ui/attributes/rustc_confusables_std_cases.rs b/tests/ui/attributes/rustc_confusables_std_cases.rs
index eda35e4b633a3..95093f5e72cd1 100644
--- a/tests/ui/attributes/rustc_confusables_std_cases.rs
+++ b/tests/ui/attributes/rustc_confusables_std_cases.rs
@@ -17,6 +17,8 @@ fn main() {
     x.size(); //~ ERROR E0599
     //~^ HELP you might have meant to use `len`
     //~| HELP there is a method with a similar name
+    x.append(42); //~ ERROR E0308
+    //~^ HELP you might have meant to use `push`
     String::new().push(""); //~ ERROR E0308
     //~^ HELP you might have meant to use `push_str`
     String::new().append(""); //~ ERROR E0599
diff --git a/tests/ui/attributes/rustc_confusables_std_cases.stderr b/tests/ui/attributes/rustc_confusables_std_cases.stderr
index f69b79b4028a0..7d2410bb0ef04 100644
--- a/tests/ui/attributes/rustc_confusables_std_cases.stderr
+++ b/tests/ui/attributes/rustc_confusables_std_cases.stderr
@@ -58,7 +58,24 @@ LL |     x.resize();
    |       ~~~~~~
 
 error[E0308]: mismatched types
-  --> $DIR/rustc_confusables_std_cases.rs:20:24
+  --> $DIR/rustc_confusables_std_cases.rs:20:14
+   |
+LL |     x.append(42);
+   |       ------ ^^ expected `&mut Vec<{integer}>`, found integer
+   |       |
+   |       arguments to this method are incorrect
+   |
+   = note: expected mutable reference `&mut Vec<{integer}>`
+                           found type `{integer}`
+note: method defined here
+  --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+help: you might have meant to use `push`
+   |
+LL |     x.push(42);
+   |       ~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/rustc_confusables_std_cases.rs:22:24
    |
 LL |     String::new().push("");
    |                   ---- ^^ expected `char`, found `&str`
@@ -73,7 +90,7 @@ LL |     String::new().push_str("");
    |                   ~~~~~~~~
 
 error[E0599]: no method named `append` found for struct `String` in the current scope
-  --> $DIR/rustc_confusables_std_cases.rs:22:19
+  --> $DIR/rustc_confusables_std_cases.rs:24:19
    |
 LL |     String::new().append("");
    |                   ^^^^^^ method not found in `String`
@@ -83,7 +100,7 @@ help: you might have meant to use `push_str`
 LL |     String::new().push_str("");
    |                   ~~~~~~~~
 
-error: aborting due to 7 previous errors
+error: aborting due to 8 previous errors
 
 Some errors have detailed explanations: E0308, E0599.
 For more information about an error, try `rustc --explain E0308`.

From 84683fd0e5da32df627c523946a93f7eb8940f36 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Sat, 10 Feb 2024 03:33:20 +0000
Subject: [PATCH 29/58] Consider methods from traits when suggesting typos

Do not provide a structured suggestion when the arguments don't match.

```
error[E0599]: no method named `test_mut` found for struct `Vec<{integer}>` in the current scope
  --> $DIR/auto-ref-slice-plus-ref.rs:7:7
   |
LL |     a.test_mut();
   |       ^^^^^^^^
   |
   = help: items from traits can only be used if the trait is implemented and in scope
note: `MyIter` defines an item `test_mut`, perhaps you need to implement it
  --> $DIR/auto-ref-slice-plus-ref.rs:14:1
   |
LL | trait MyIter {
   | ^^^^^^^^^^^^
help: there is a method `get_mut` with a similar name, but with different arguments
  --> $SRC_DIR/core/src/slice/mod.rs:LL:COL
```

Consider methods beyond inherent ones when suggesting typos.

```
error[E0599]: no method named `owned` found for reference `&dyn Foo` in the current scope
  --> $DIR/object-pointer-types.rs:11:7
   |
LL |     fn owned(self: Box<Self>);
   |                    --------- the method might not be found because of this arbitrary self type
...
LL |     x.owned();
   |       ^^^^^ help: there is a method with a similar name: `to_owned`
```

Fix #101013.
---
 .../rustc_hir_typeck/src/fn_ctxt/checks.rs    | 10 +--
 compiler/rustc_hir_typeck/src/method/probe.rs |  2 +
 .../rustc_hir_typeck/src/method/suggest.rs    | 88 ++++++++++++++++---
 .../associated-item-enum.stderr               |  2 +-
 .../attributes/rustc_confusables_std_cases.rs |  2 +-
 .../rustc_confusables_std_cases.stderr        |  6 +-
 tests/ui/auto-ref-slice-plus-ref.stderr       |  4 +-
 .../issue-33784.stderr                        |  4 +
 tests/ui/hygiene/no_implicit_prelude.stderr   |  4 +-
 .../no-method-suggested-traits.stderr         | 36 ++++++--
 tests/ui/issues/issue-28344.stderr            | 16 ++--
 tests/ui/issues/issue-39175.stderr            |  4 +-
 tests/ui/issues/issue-56175.stderr            | 12 ++-
 tests/ui/object-pointer-types.stderr          |  2 +-
 .../rust-2018/trait-import-suggestions.stderr | 18 ++--
 .../future-prelude-collision-shadow.stderr    |  6 +-
 .../dont-suggest-pin-array-dot-set.stderr     |  5 +-
 tests/ui/suggestions/suggest-methods.rs       |  5 +-
 tests/ui/suggestions/suggest-methods.stderr   | 16 ++--
 .../suggest-tryinto-edition-change.rs         |  1 -
 .../suggest-tryinto-edition-change.stderr     | 12 ++-
 tests/ui/traits/issue-117794.stderr           |  8 +-
 tests/ui/traits/item-privacy.stderr           | 28 +++++-
 23 files changed, 223 insertions(+), 68 deletions(-)

diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index a5cf541509b19..ea40b5cf7dc38 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -553,14 +553,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 && let ty::AssocKind::Fn = assoc.kind
                 && assoc.fn_has_self_parameter
             {
-                let fn_sig =
-                    if let ty::Adt(_, args) = callee_ty.peel_refs().kind() {
-                        let args = ty::GenericArgs::identity_for_item(tcx, assoc.def_id)
-                            .rebase_onto(tcx, assoc.container_id(tcx), args);
-                        tcx.fn_sig(assoc.def_id).instantiate(tcx, args)
-                    } else {
-                        tcx.fn_sig(assoc.def_id).instantiate_identity()
-                    };
+                let args = self.infcx.fresh_args_for_item(call_name.span, assoc.def_id);
+                let fn_sig = tcx.fn_sig(assoc.def_id).instantiate(tcx, args);
                 let fn_sig =
                     self.instantiate_binder_with_fresh_vars(call_name.span, FnCall, fn_sig);
                 Some((assoc, fn_sig));
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 9b405c867f328..bdc796aca3a46 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -1769,6 +1769,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
             );
             pcx.allow_similar_names = true;
             pcx.assemble_inherent_candidates();
+            pcx.assemble_extension_candidates_for_all_traits();
 
             let method_names = pcx.candidate_method_names(|_| true);
             pcx.allow_similar_names = false;
@@ -1778,6 +1779,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                     pcx.reset();
                     pcx.method_name = Some(method_name);
                     pcx.assemble_inherent_candidates();
+                    pcx.assemble_extension_candidates_for_all_traits();
                     pcx.pick_core().and_then(|pick| pick.ok()).map(|pick| pick.item)
                 })
                 .collect();
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 65ec8b3f06227..3d34323db41e3 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -1257,27 +1257,89 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 && Some(similar_candidate.name) != confusable_suggested
             {
                 let def_kind = similar_candidate.kind.as_def_kind();
-                // Methods are defined within the context of a struct and their first parameter is always self,
-                // which represents the instance of the struct the method is being called on
-                // Associated functions don’t take self as a parameter and
-                // they are not methods because they don’t have an instance of the struct to work with.
-                if def_kind == DefKind::AssocFn && similar_candidate.fn_has_self_parameter {
+                let an = self.tcx.def_kind_descr_article(def_kind, similar_candidate.def_id);
+                // Methods are defined within the context of a struct and their first parameter
+                // is always `self`, which represents the instance of the struct the method is
+                // being called on Associated functions don’t take self as a parameter and they are
+                // not methods because they don’t have an instance of the struct to work with.
+                if def_kind == DefKind::AssocFn {
+                    let ty_args = self.infcx.fresh_args_for_item(span, similar_candidate.def_id);
+                    let fn_sig = tcx.fn_sig(similar_candidate.def_id).instantiate(tcx, ty_args);
+                    let fn_sig =
+                        self.instantiate_binder_with_fresh_vars(span, infer::FnCall, fn_sig);
+                    if similar_candidate.fn_has_self_parameter {
+                        if let Some(args) = args
+                            && fn_sig.inputs()[1..].len() == args.len()
+                        {
+                            // We found a method with the same number of arguments as the method
+                            // call expression the user wrote.
+                            err.span_suggestion(
+                                span,
+                                format!("there is {an} method with a similar name"),
+                                similar_candidate.name,
+                                Applicability::MaybeIncorrect,
+                            );
+                        } else {
+                            // We found a method but either the expression is not a method call or
+                            // the argument count didn't match.
+                            err.span_help(
+                                tcx.def_span(similar_candidate.def_id),
+                                format!(
+                                    "there is {an} method `{}` with a similar name{}",
+                                    similar_candidate.name,
+                                    if let None = args {
+                                        ""
+                                    } else {
+                                        ", but with different arguments"
+                                    },
+                                ),
+                            );
+                        }
+                    } else if let Some(args) = args
+                        && fn_sig.inputs().len() == args.len()
+                    {
+                        // We have fn call expression and the argument count match the associated
+                        // function we found.
+                        err.span_suggestion(
+                            span,
+                            format!(
+                                "there is {an} {} with a similar name",
+                                self.tcx.def_kind_descr(def_kind, similar_candidate.def_id)
+                            ),
+                            similar_candidate.name,
+                            Applicability::MaybeIncorrect,
+                        );
+                    } else {
+                        err.span_help(
+                            tcx.def_span(similar_candidate.def_id),
+                            format!(
+                                "there is {an} {} `{}` with a similar name",
+                                self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
+                                similar_candidate.name,
+                            ),
+                        );
+                    }
+                } else if let Mode::Path = mode {
+                    // We have an associated item syntax and we found something that isn't an fn.
                     err.span_suggestion(
                         span,
-                        "there is a method with a similar name",
+                        format!(
+                            "there is {an} {} with a similar name",
+                            self.tcx.def_kind_descr(def_kind, similar_candidate.def_id)
+                        ),
                         similar_candidate.name,
                         Applicability::MaybeIncorrect,
                     );
                 } else {
-                    err.span_suggestion(
-                        span,
+                    // The expression is a function or method call, but the item we found is an
+                    // associated const or type.
+                    err.span_help(
+                        tcx.def_span(similar_candidate.def_id),
                         format!(
-                            "there is {} {} with a similar name",
-                            self.tcx.def_kind_descr_article(def_kind, similar_candidate.def_id),
-                            self.tcx.def_kind_descr(def_kind, similar_candidate.def_id)
+                            "there is {an} {} `{}` with a similar name",
+                            self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
+                            similar_candidate.name,
                         ),
-                        similar_candidate.name,
-                        Applicability::MaybeIncorrect,
                     );
                 }
             }
diff --git a/tests/ui/associated-item/associated-item-enum.stderr b/tests/ui/associated-item/associated-item-enum.stderr
index ebf3c5499a68b..9e9f5c0daadf6 100644
--- a/tests/ui/associated-item/associated-item-enum.stderr
+++ b/tests/ui/associated-item/associated-item-enum.stderr
@@ -20,7 +20,7 @@ LL |     Enum::mispellable_trait();
    |           ^^^^^^^^^^^^^^^^^
    |           |
    |           variant or associated item not found in `Enum`
-   |           help: there is an associated function with a similar name: `misspellable`
+   |           help: there is an associated function with a similar name: `misspellable_trait`
 
 error[E0599]: no variant or associated item named `MISPELLABLE` found for enum `Enum` in the current scope
   --> $DIR/associated-item-enum.rs:19:11
diff --git a/tests/ui/attributes/rustc_confusables_std_cases.rs b/tests/ui/attributes/rustc_confusables_std_cases.rs
index 95093f5e72cd1..d9121695950b2 100644
--- a/tests/ui/attributes/rustc_confusables_std_cases.rs
+++ b/tests/ui/attributes/rustc_confusables_std_cases.rs
@@ -16,7 +16,7 @@ fn main() {
     //~^ HELP you might have meant to use `len`
     x.size(); //~ ERROR E0599
     //~^ HELP you might have meant to use `len`
-    //~| HELP there is a method with a similar name
+    //~| HELP there is a method `resize` with a similar name
     x.append(42); //~ ERROR E0308
     //~^ HELP you might have meant to use `push`
     String::new().push(""); //~ ERROR E0308
diff --git a/tests/ui/attributes/rustc_confusables_std_cases.stderr b/tests/ui/attributes/rustc_confusables_std_cases.stderr
index 7d2410bb0ef04..45d571f435cbd 100644
--- a/tests/ui/attributes/rustc_confusables_std_cases.stderr
+++ b/tests/ui/attributes/rustc_confusables_std_cases.stderr
@@ -48,14 +48,12 @@ error[E0599]: no method named `size` found for struct `Vec<{integer}>` in the cu
 LL |     x.size();
    |       ^^^^
    |
+help: there is a method `resize` with a similar name, but with different arguments
+  --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 help: you might have meant to use `len`
    |
 LL |     x.len();
    |       ~~~
-help: there is a method with a similar name
-   |
-LL |     x.resize();
-   |       ~~~~~~
 
 error[E0308]: mismatched types
   --> $DIR/rustc_confusables_std_cases.rs:20:14
diff --git a/tests/ui/auto-ref-slice-plus-ref.stderr b/tests/ui/auto-ref-slice-plus-ref.stderr
index e2883050720d6..806c1ee064ffa 100644
--- a/tests/ui/auto-ref-slice-plus-ref.stderr
+++ b/tests/ui/auto-ref-slice-plus-ref.stderr
@@ -2,7 +2,7 @@ error[E0599]: no method named `test_mut` found for struct `Vec<{integer}>` in th
   --> $DIR/auto-ref-slice-plus-ref.rs:7:7
    |
 LL |     a.test_mut();
-   |       ^^^^^^^^ help: there is a method with a similar name: `get_mut`
+   |       ^^^^^^^^
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `MyIter` defines an item `test_mut`, perhaps you need to implement it
@@ -10,6 +10,8 @@ note: `MyIter` defines an item `test_mut`, perhaps you need to implement it
    |
 LL | trait MyIter {
    | ^^^^^^^^^^^^
+help: there is a method `get_mut` with a similar name, but with different arguments
+  --> $SRC_DIR/core/src/slice/mod.rs:LL:COL
 
 error[E0599]: no method named `test` found for struct `Vec<{integer}>` in the current scope
   --> $DIR/auto-ref-slice-plus-ref.rs:8:7
diff --git a/tests/ui/confuse-field-and-method/issue-33784.stderr b/tests/ui/confuse-field-and-method/issue-33784.stderr
index aaf953a66d528..f6678dc85430d 100644
--- a/tests/ui/confuse-field-and-method/issue-33784.stderr
+++ b/tests/ui/confuse-field-and-method/issue-33784.stderr
@@ -8,6 +8,10 @@ help: to call the function stored in `closure`, surround the field access with p
    |
 LL |     (p.closure)();
    |     +         +
+help: there is a method with a similar name
+   |
+LL |     p.clone();
+   |       ~~~~~
 
 error[E0599]: no method named `fn_ptr` found for reference `&&Obj<{closure@$DIR/issue-33784.rs:25:43: 25:45}>` in the current scope
   --> $DIR/issue-33784.rs:29:7
diff --git a/tests/ui/hygiene/no_implicit_prelude.stderr b/tests/ui/hygiene/no_implicit_prelude.stderr
index 96187b1c50161..646863a884c88 100644
--- a/tests/ui/hygiene/no_implicit_prelude.stderr
+++ b/tests/ui/hygiene/no_implicit_prelude.stderr
@@ -20,9 +20,11 @@ LL |     fn f() { ::bar::m!(); }
    |              ----------- in this macro invocation
 ...
 LL |         ().clone()
-   |            ^^^^^ method not found in `()`
+   |            ^^^^^
    |
    = help: items from traits can only be used if the trait is in scope
+help: there is a method `clone_from` with a similar name, but with different arguments
+  --> $SRC_DIR/core/src/clone.rs:LL:COL
    = note: this error originates in the macro `::bar::m` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: the following trait is implemented but not in scope; perhaps add a `use` for it:
    |
diff --git a/tests/ui/impl-trait/no-method-suggested-traits.stderr b/tests/ui/impl-trait/no-method-suggested-traits.stderr
index 160cc044078ed..cf1bf59ab201e 100644
--- a/tests/ui/impl-trait/no-method-suggested-traits.stderr
+++ b/tests/ui/impl-trait/no-method-suggested-traits.stderr
@@ -2,7 +2,7 @@ error[E0599]: no method named `method` found for type `u32` in the current scope
   --> $DIR/no-method-suggested-traits.rs:23:10
    |
 LL |     1u32.method();
-   |          ^^^^^^ method not found in `u32`
+   |          ^^^^^^
    |
    = help: items from traits can only be used if the trait is in scope
 help: the following traits are implemented but not in scope; perhaps add a `use` for one of them:
@@ -15,12 +15,16 @@ LL + use no_method_suggested_traits::foo::PubPub;
    |
 LL + use no_method_suggested_traits::qux::PrivPub;
    |
+help: there is a method with a similar name
+   |
+LL |     1u32.method2();
+   |          ~~~~~~~
 
 error[E0599]: no method named `method` found for struct `Rc<&mut Box<&u32>>` in the current scope
   --> $DIR/no-method-suggested-traits.rs:26:44
    |
 LL |     std::rc::Rc::new(&mut Box::new(&1u32)).method();
-   |                                            ^^^^^^ method not found in `Rc<&mut Box<&u32>>`
+   |                                            ^^^^^^
    |
    = help: items from traits can only be used if the trait is in scope
 help: the following traits are implemented but not in scope; perhaps add a `use` for one of them:
@@ -33,6 +37,10 @@ LL + use no_method_suggested_traits::foo::PubPub;
    |
 LL + use no_method_suggested_traits::qux::PrivPub;
    |
+help: there is a method with a similar name
+   |
+LL |     std::rc::Rc::new(&mut Box::new(&1u32)).method2();
+   |                                            ~~~~~~~
 
 error[E0599]: no method named `method` found for type `char` in the current scope
   --> $DIR/no-method-suggested-traits.rs:30:9
@@ -41,31 +49,39 @@ LL |         fn method(&self) {}
    |            ------ the method is available for `char` here
 ...
 LL |     'a'.method();
-   |         ^^^^^^ method not found in `char`
+   |         ^^^^^^
    |
    = help: items from traits can only be used if the trait is in scope
 help: the following trait is implemented but not in scope; perhaps add a `use` for it:
    |
 LL + use foo::Bar;
    |
+help: there is a method with a similar name
+   |
+LL |     'a'.method2();
+   |         ~~~~~~~
 
 error[E0599]: no method named `method` found for struct `Rc<&mut Box<&char>>` in the current scope
   --> $DIR/no-method-suggested-traits.rs:32:43
    |
 LL |     std::rc::Rc::new(&mut Box::new(&'a')).method();
-   |                                           ^^^^^^ method not found in `Rc<&mut Box<&char>>`
+   |                                           ^^^^^^
    |
    = help: items from traits can only be used if the trait is in scope
 help: the following trait is implemented but not in scope; perhaps add a `use` for it:
    |
 LL + use foo::Bar;
    |
+help: there is a method with a similar name
+   |
+LL |     std::rc::Rc::new(&mut Box::new(&'a')).method2();
+   |                                           ~~~~~~~
 
 error[E0599]: no method named `method` found for type `i32` in the current scope
   --> $DIR/no-method-suggested-traits.rs:35:10
    |
 LL |     1i32.method();
-   |          ^^^^^^ method not found in `i32`
+   |          ^^^^^^
    |
   ::: $DIR/auxiliary/no_method_suggested_traits.rs:8:12
    |
@@ -77,18 +93,26 @@ help: the following trait is implemented but not in scope; perhaps add a `use` f
    |
 LL + use no_method_suggested_traits::foo::PubPub;
    |
+help: there is a method with a similar name
+   |
+LL |     1i32.method3();
+   |          ~~~~~~~
 
 error[E0599]: no method named `method` found for struct `Rc<&mut Box<&i32>>` in the current scope
   --> $DIR/no-method-suggested-traits.rs:37:44
    |
 LL |     std::rc::Rc::new(&mut Box::new(&1i32)).method();
-   |                                            ^^^^^^ method not found in `Rc<&mut Box<&i32>>`
+   |                                            ^^^^^^
    |
    = help: items from traits can only be used if the trait is in scope
 help: the following trait is implemented but not in scope; perhaps add a `use` for it:
    |
 LL + use no_method_suggested_traits::foo::PubPub;
    |
+help: there is a method with a similar name
+   |
+LL |     std::rc::Rc::new(&mut Box::new(&1i32)).method3();
+   |                                            ~~~~~~~
 
 error[E0599]: no method named `method` found for struct `Foo` in the current scope
   --> $DIR/no-method-suggested-traits.rs:40:9
diff --git a/tests/ui/issues/issue-28344.stderr b/tests/ui/issues/issue-28344.stderr
index 71d642109ac8c..a1b9f0ffd57eb 100644
--- a/tests/ui/issues/issue-28344.stderr
+++ b/tests/ui/issues/issue-28344.stderr
@@ -22,10 +22,10 @@ error[E0599]: no function or associated item named `bitor` found for trait objec
   --> $DIR/issue-28344.rs:4:25
    |
 LL |     let x: u8 = BitXor::bitor(0 as u8, 0 as u8);
-   |                         ^^^^^
-   |                         |
-   |                         function or associated item not found in `dyn BitXor<_>`
-   |                         help: there is a method with a similar name: `bitxor`
+   |                         ^^^^^ function or associated item not found in `dyn BitXor<_>`
+   |
+help: there is a method `bitxor` with a similar name, but with different arguments
+  --> $SRC_DIR/core/src/ops/bit.rs:LL:COL
 
 warning: trait objects without an explicit `dyn` are deprecated
   --> $DIR/issue-28344.rs:10:13
@@ -50,10 +50,10 @@ error[E0599]: no function or associated item named `bitor` found for trait objec
   --> $DIR/issue-28344.rs:10:21
    |
 LL |     let g = BitXor::bitor;
-   |                     ^^^^^
-   |                     |
-   |                     function or associated item not found in `dyn BitXor<_>`
-   |                     help: there is a method with a similar name: `bitxor`
+   |                     ^^^^^ function or associated item not found in `dyn BitXor<_>`
+   |
+help: there is a method `bitxor` with a similar name, but with different arguments
+  --> $SRC_DIR/core/src/ops/bit.rs:LL:COL
 
 error: aborting due to 4 previous errors; 2 warnings emitted
 
diff --git a/tests/ui/issues/issue-39175.stderr b/tests/ui/issues/issue-39175.stderr
index 1bc11dab327ab..bdc9e422e861f 100644
--- a/tests/ui/issues/issue-39175.stderr
+++ b/tests/ui/issues/issue-39175.stderr
@@ -2,9 +2,11 @@ error[E0599]: no method named `exec` found for mutable reference `&mut Command`
   --> $DIR/issue-39175.rs:14:39
    |
 LL |     Command::new("echo").arg("hello").exec();
-   |                                       ^^^^ method not found in `&mut Command`
+   |                                       ^^^^
    |
    = help: items from traits can only be used if the trait is in scope
+help: there is a method `pre_exec` with a similar name, but with different arguments
+  --> $SRC_DIR/std/src/os/unix/process.rs:LL:COL
 help: the following trait is implemented but not in scope; perhaps add a `use` for it:
    |
 LL + use std::os::unix::process::CommandExt;
diff --git a/tests/ui/issues/issue-56175.stderr b/tests/ui/issues/issue-56175.stderr
index 1ddee1f4895bb..d8c757c158350 100644
--- a/tests/ui/issues/issue-56175.stderr
+++ b/tests/ui/issues/issue-56175.stderr
@@ -2,7 +2,7 @@ error[E0599]: no method named `trait_method` found for struct `FooStruct` in the
   --> $DIR/issue-56175.rs:5:33
    |
 LL |     reexported_trait::FooStruct.trait_method();
-   |                                 ^^^^^^^^^^^^ method not found in `FooStruct`
+   |                                 ^^^^^^^^^^^^
    |
   ::: $DIR/auxiliary/reexported-trait.rs:3:12
    |
@@ -14,12 +14,16 @@ help: the following trait is implemented but not in scope; perhaps add a `use` f
    |
 LL + use reexported_trait::Trait;
    |
+help: there is a method with a similar name
+   |
+LL |     reexported_trait::FooStruct.trait_method_b();
+   |                                 ~~~~~~~~~~~~~~
 
 error[E0599]: no method named `trait_method_b` found for struct `FooStruct` in the current scope
   --> $DIR/issue-56175.rs:7:33
    |
 LL |     reexported_trait::FooStruct.trait_method_b();
-   |                                 ^^^^^^^^^^^^^^ method not found in `FooStruct`
+   |                                 ^^^^^^^^^^^^^^
    |
   ::: $DIR/auxiliary/reexported-trait.rs:7:12
    |
@@ -31,6 +35,10 @@ help: the following trait is implemented but not in scope; perhaps add a `use` f
    |
 LL + use reexported_trait::TraitBRename;
    |
+help: there is a method with a similar name
+   |
+LL |     reexported_trait::FooStruct.trait_method();
+   |                                 ~~~~~~~~~~~~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/object-pointer-types.stderr b/tests/ui/object-pointer-types.stderr
index 2c8df3b616fb8..fe21bf3aedefc 100644
--- a/tests/ui/object-pointer-types.stderr
+++ b/tests/ui/object-pointer-types.stderr
@@ -5,7 +5,7 @@ LL |     fn owned(self: Box<Self>);
    |                    --------- the method might not be found because of this arbitrary self type
 ...
 LL |     x.owned();
-   |       ^^^^^ method not found in `&dyn Foo`
+   |       ^^^^^ help: there is a method with a similar name: `to_owned`
 
 error[E0599]: no method named `owned` found for mutable reference `&mut dyn Foo` in the current scope
   --> $DIR/object-pointer-types.rs:17:7
diff --git a/tests/ui/rust-2018/trait-import-suggestions.stderr b/tests/ui/rust-2018/trait-import-suggestions.stderr
index 325c5976e7c89..a9d625df9ba6c 100644
--- a/tests/ui/rust-2018/trait-import-suggestions.stderr
+++ b/tests/ui/rust-2018/trait-import-suggestions.stderr
@@ -5,13 +5,17 @@ LL |             fn foobar(&self) { }
    |                ------ the method is available for `u32` here
 ...
 LL |         x.foobar();
-   |           ^^^^^^ method not found in `u32`
+   |           ^^^^^^
    |
    = help: items from traits can only be used if the trait is in scope
 help: the following trait is implemented but not in scope; perhaps add a `use` for it:
    |
 LL +     use crate::foo::foobar::Foobar;
    |
+help: there is a method with a similar name
+   |
+LL |         x.bar();
+   |           ~~~
 
 error[E0599]: no method named `bar` found for type `u32` in the current scope
   --> $DIR/trait-import-suggestions.rs:28:7
@@ -20,19 +24,23 @@ LL |         fn bar(&self) { }
    |            --- the method is available for `u32` here
 ...
 LL |     x.bar();
-   |       ^^^ method not found in `u32`
+   |       ^^^
    |
    = help: items from traits can only be used if the trait is in scope
 help: the following trait is implemented but not in scope; perhaps add a `use` for it:
    |
 LL + use crate::foo::Bar;
    |
+help: there is a method with a similar name
+   |
+LL |     x.foobar();
+   |       ~~~~~~
 
 error[E0599]: no method named `baz` found for type `u32` in the current scope
   --> $DIR/trait-import-suggestions.rs:29:7
    |
 LL |     x.baz();
-   |       ^^^ method not found in `u32`
+   |       ^^^ help: there is a method with a similar name: `bar`
 
 error[E0599]: no function or associated item named `from_str` found for type `u32` in the current scope
   --> $DIR/trait-import-suggestions.rs:30:18
@@ -47,8 +55,8 @@ LL + use std::str::FromStr;
    |
 help: there is an associated function with a similar name
    |
-LL |     let y = u32::from_str_radix("33");
-   |                  ~~~~~~~~~~~~~~
+LL |     let y = u32::from("33");
+   |                  ~~~~
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/rust-2021/future-prelude-collision-shadow.stderr b/tests/ui/rust-2021/future-prelude-collision-shadow.stderr
index d2b2e5b2fd774..1ca5708e753be 100644
--- a/tests/ui/rust-2021/future-prelude-collision-shadow.stderr
+++ b/tests/ui/rust-2021/future-prelude-collision-shadow.stderr
@@ -2,7 +2,7 @@ error[E0599]: no method named `try_into` found for type `u8` in the current scop
   --> $DIR/future-prelude-collision-shadow.rs:27:26
    |
 LL |         let _: u32 = 3u8.try_into().unwrap();
-   |                          ^^^^^^^^ method not found in `u8`
+   |                          ^^^^^^^^
    |
    = help: items from traits can only be used if the trait is in scope
    = note: 'std::convert::TryInto' is included in the prelude starting in Edition 2021
@@ -12,6 +12,10 @@ LL +     use crate::m::TryIntoU32;
    |
 LL +     use std::convert::TryInto;
    |
+help: there is a method with a similar name
+   |
+LL |         let _: u32 = 3u8.into().unwrap();
+   |                          ~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/suggestions/dont-suggest-pin-array-dot-set.stderr b/tests/ui/suggestions/dont-suggest-pin-array-dot-set.stderr
index 8f738465d38d7..b1a618e7176e3 100644
--- a/tests/ui/suggestions/dont-suggest-pin-array-dot-set.stderr
+++ b/tests/ui/suggestions/dont-suggest-pin-array-dot-set.stderr
@@ -2,7 +2,10 @@ error[E0599]: no method named `set` found for array `[u8; 1]` in the current sco
   --> $DIR/dont-suggest-pin-array-dot-set.rs:14:7
    |
 LL |     a.set(0, 3);
-   |       ^^^ help: there is a method with a similar name: `get`
+   |       ^^^
+   |
+help: there is a method `get` with a similar name, but with different arguments
+  --> $SRC_DIR/core/src/slice/mod.rs:LL:COL
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/suggestions/suggest-methods.rs b/tests/ui/suggestions/suggest-methods.rs
index f40b9ed99b827..f809579544727 100644
--- a/tests/ui/suggestions/suggest-methods.rs
+++ b/tests/ui/suggestions/suggest-methods.rs
@@ -7,6 +7,7 @@ impl Foo {
 
 trait FooT {
     fn bag(&self);
+    //~^ HELP there is a method
 }
 
 impl FooT for Foo {
@@ -19,12 +20,14 @@ fn main() {
 
     let s = "foo".to_string();
     let _ = s.is_emtpy(); //~ ERROR no method named
+    //~^ HELP there is a method
 
     // Generates a warning for `count_zeros()`. `count_ones()` is also a close
     // match, but the former is closer.
     let _ = 63u32.count_eos(); //~ ERROR no method named
+    //~^ HELP there is a method
 
-    // Does not generate a warning
     let _ = 63u32.count_o(); //~ ERROR no method named
+    //~^ HELP there is a method
 
 }
diff --git a/tests/ui/suggestions/suggest-methods.stderr b/tests/ui/suggestions/suggest-methods.stderr
index 03cb9c7792285..293009f289bef 100644
--- a/tests/ui/suggestions/suggest-methods.stderr
+++ b/tests/ui/suggestions/suggest-methods.stderr
@@ -1,26 +1,32 @@
 error[E0599]: no method named `bat` found for struct `Foo` in the current scope
-  --> $DIR/suggest-methods.rs:18:7
+  --> $DIR/suggest-methods.rs:19:7
    |
 LL | struct Foo;
    | ---------- method `bat` not found for this struct
 ...
 LL |     f.bat(1.0);
-   |       ^^^ help: there is a method with a similar name: `bar`
+   |       ^^^
+   |
+help: there is a method `bag` with a similar name, but with different arguments
+  --> $DIR/suggest-methods.rs:9:5
+   |
+LL |     fn bag(&self);
+   |     ^^^^^^^^^^^^^^
 
 error[E0599]: no method named `is_emtpy` found for struct `String` in the current scope
-  --> $DIR/suggest-methods.rs:21:15
+  --> $DIR/suggest-methods.rs:22:15
    |
 LL |     let _ = s.is_emtpy();
    |               ^^^^^^^^ help: there is a method with a similar name: `is_empty`
 
 error[E0599]: no method named `count_eos` found for type `u32` in the current scope
-  --> $DIR/suggest-methods.rs:25:19
+  --> $DIR/suggest-methods.rs:27:19
    |
 LL |     let _ = 63u32.count_eos();
    |                   ^^^^^^^^^ help: there is a method with a similar name: `count_zeros`
 
 error[E0599]: no method named `count_o` found for type `u32` in the current scope
-  --> $DIR/suggest-methods.rs:28:19
+  --> $DIR/suggest-methods.rs:30:19
    |
 LL |     let _ = 63u32.count_o();
    |                   ^^^^^^^ help: there is a method with a similar name: `count_ones`
diff --git a/tests/ui/suggestions/suggest-tryinto-edition-change.rs b/tests/ui/suggestions/suggest-tryinto-edition-change.rs
index 70c4b210d3a7b..4abdd6b136417 100644
--- a/tests/ui/suggestions/suggest-tryinto-edition-change.rs
+++ b/tests/ui/suggestions/suggest-tryinto-edition-change.rs
@@ -5,7 +5,6 @@
 fn test() {
     let _i: i16 = 0_i32.try_into().unwrap();
     //~^ ERROR no method named `try_into` found for type `i32` in the current scope
-    //~| NOTE method not found in `i32`
     //~| NOTE 'std::convert::TryInto' is included in the prelude starting in Edition 2021
 
     let _i: i16 = TryFrom::try_from(0_i32).unwrap();
diff --git a/tests/ui/suggestions/suggest-tryinto-edition-change.stderr b/tests/ui/suggestions/suggest-tryinto-edition-change.stderr
index 057e37dbe109f..01fabbadbffe4 100644
--- a/tests/ui/suggestions/suggest-tryinto-edition-change.stderr
+++ b/tests/ui/suggestions/suggest-tryinto-edition-change.stderr
@@ -1,5 +1,5 @@
 error[E0433]: failed to resolve: use of undeclared type `TryFrom`
-  --> $DIR/suggest-tryinto-edition-change.rs:11:19
+  --> $DIR/suggest-tryinto-edition-change.rs:10:19
    |
 LL |     let _i: i16 = TryFrom::try_from(0_i32).unwrap();
    |                   ^^^^^^^ use of undeclared type `TryFrom`
@@ -14,7 +14,7 @@ LL + use std::convert::TryFrom;
    |
 
 error[E0433]: failed to resolve: use of undeclared type `TryInto`
-  --> $DIR/suggest-tryinto-edition-change.rs:17:19
+  --> $DIR/suggest-tryinto-edition-change.rs:16:19
    |
 LL |     let _i: i16 = TryInto::try_into(0_i32).unwrap();
    |                   ^^^^^^^ use of undeclared type `TryInto`
@@ -29,7 +29,7 @@ LL + use std::convert::TryInto;
    |
 
 error[E0433]: failed to resolve: use of undeclared type `FromIterator`
-  --> $DIR/suggest-tryinto-edition-change.rs:23:22
+  --> $DIR/suggest-tryinto-edition-change.rs:22:22
    |
 LL |     let _v: Vec<_> = FromIterator::from_iter(&[1]);
    |                      ^^^^^^^^^^^^ use of undeclared type `FromIterator`
@@ -51,7 +51,7 @@ error[E0599]: no method named `try_into` found for type `i32` in the current sco
   --> $DIR/suggest-tryinto-edition-change.rs:6:25
    |
 LL |     let _i: i16 = 0_i32.try_into().unwrap();
-   |                         ^^^^^^^^ method not found in `i32`
+   |                         ^^^^^^^^
   --> $SRC_DIR/core/src/convert/mod.rs:LL:COL
    |
    = note: the method is available for `i32` here
@@ -62,6 +62,10 @@ help: the following trait is implemented but not in scope; perhaps add a `use` f
    |
 LL + use std::convert::TryInto;
    |
+help: there is a method with a similar name
+   |
+LL |     let _i: i16 = 0_i32.into().unwrap();
+   |                         ~~~~
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/traits/issue-117794.stderr b/tests/ui/traits/issue-117794.stderr
index af63b47f07d91..66561ffa4ce4d 100644
--- a/tests/ui/traits/issue-117794.stderr
+++ b/tests/ui/traits/issue-117794.stderr
@@ -2,7 +2,13 @@ error[E0599]: no method named `b` found for reference `&Self` in the current sco
   --> $DIR/issue-117794.rs:5:14
    |
 LL |         self.b(|| 0)
-   |              ^ help: there is a method with a similar name: `a`
+   |              ^
+   |
+help: there is a method `a` with a similar name, but with different arguments
+  --> $DIR/issue-117794.rs:4:5
+   |
+LL |     fn a(&self) -> impl Foo {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/traits/item-privacy.stderr b/tests/ui/traits/item-privacy.stderr
index 244cc2fc592a8..ede1764efdcaf 100644
--- a/tests/ui/traits/item-privacy.stderr
+++ b/tests/ui/traits/item-privacy.stderr
@@ -5,13 +5,17 @@ LL | struct S;
    | -------- method `a` not found for this struct
 ...
 LL |     S.a();
-   |       ^ method not found in `S`
+   |       ^
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 help: the following trait is implemented but not in scope; perhaps add a `use` for it:
    |
 LL + use method::A;
    |
+help: there is a method with a similar name
+   |
+LL |     S.b();
+   |       ~
 
 error[E0599]: no method named `b` found for struct `S` in the current scope
   --> $DIR/item-privacy.rs:68:7
@@ -23,13 +27,17 @@ LL |         fn b(&self) { }
    |            - the method is available for `S` here
 ...
 LL |     S.b();
-   |       ^ method not found in `S`
+   |       ^
    |
    = help: items from traits can only be used if the trait is in scope
 help: the following trait is implemented but not in scope; perhaps add a `use` for it:
    |
 LL + use method::B;
    |
+help: there is a method with a similar name
+   |
+LL |     S.c();
+   |       ~
 
 error[E0624]: method `a` is private
   --> $DIR/item-privacy.rs:72:7
@@ -54,6 +62,10 @@ help: the following trait is implemented but not in scope; perhaps add a `use` f
    |
 LL + use method::A;
    |
+help: there is an associated constant with a similar name
+   |
+LL |     S::B(&S);
+   |        ~
 
 error[E0599]: no function or associated item named `b` found for struct `S` in the current scope
   --> $DIR/item-privacy.rs:80:8
@@ -69,6 +81,10 @@ help: the following trait is implemented but not in scope; perhaps add a `use` f
    |
 LL + use method::B;
    |
+help: there is an associated constant with a similar name
+   |
+LL |     S::B(&S);
+   |        ~
 
 error[E0624]: method `a` is private
   --> $DIR/item-privacy.rs:84:14
@@ -93,6 +109,10 @@ help: the following trait is implemented but not in scope; perhaps add a `use` f
    |
 LL + use assoc_const::A;
    |
+help: there is an associated constant with a similar name
+   |
+LL |     S::B;
+   |        ~
 
 error[E0599]: no associated item named `B` found for struct `S` in the current scope
   --> $DIR/item-privacy.rs:98:8
@@ -108,6 +128,10 @@ help: the following trait is implemented but not in scope; perhaps add a `use` f
    |
 LL + use assoc_const::B;
    |
+help: there is a method with a similar name
+   |
+LL |     S::b;
+   |        ~
 
 error[E0624]: associated constant `A` is private
   --> $DIR/item-privacy.rs:101:14

From 274d929ef5b0361a8aba5130096c7da01df1faec Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Sat, 10 Feb 2024 03:37:08 +0000
Subject: [PATCH 30/58] Make confusable suggestions `verbose`

---
 .../rustc_hir_typeck/src/method/suggest.rs    |  6 ++--
 .../associated-item-enum.stderr               | 30 +++++++++++--------
 tests/ui/attributes/rustc_confusables.stderr  |  7 ++++-
 tests/ui/block-result/issue-3563.stderr       |  7 ++++-
 tests/ui/methods/issues/issue-105732.stderr   |  7 ++++-
 .../method-not-found-but-doc-alias.stderr     |  7 ++++-
 tests/ui/object-pointer-types.stderr          |  7 ++++-
 tests/ui/parser/emoji-identifiers.stderr      |  9 +++---
 .../typo-suggestion-mistyped-in-path.stderr   | 10 ++++---
 .../rust-2018/trait-import-suggestions.stderr |  7 ++++-
 .../arbitrary_self_type_mut_difference.stderr | 12 ++++++--
 tests/ui/suggestions/issue-109291.stderr      |  9 +++---
 tests/ui/suggestions/suggest-methods.stderr   | 21 +++++++++++--
 .../trait-upcasting/subtrait-method.stderr    | 30 +++++++++++++++----
 14 files changed, 126 insertions(+), 43 deletions(-)

diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 3d34323db41e3..3bc1df4fc3dcd 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -1273,7 +1273,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         {
                             // We found a method with the same number of arguments as the method
                             // call expression the user wrote.
-                            err.span_suggestion(
+                            err.span_suggestion_verbose(
                                 span,
                                 format!("there is {an} method with a similar name"),
                                 similar_candidate.name,
@@ -1300,7 +1300,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     {
                         // We have fn call expression and the argument count match the associated
                         // function we found.
-                        err.span_suggestion(
+                        err.span_suggestion_verbose(
                             span,
                             format!(
                                 "there is {an} {} with a similar name",
@@ -1321,7 +1321,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                 } else if let Mode::Path = mode {
                     // We have an associated item syntax and we found something that isn't an fn.
-                    err.span_suggestion(
+                    err.span_suggestion_verbose(
                         span,
                         format!(
                             "there is {an} {} with a similar name",
diff --git a/tests/ui/associated-item/associated-item-enum.stderr b/tests/ui/associated-item/associated-item-enum.stderr
index 9e9f5c0daadf6..a966468e3dd47 100644
--- a/tests/ui/associated-item/associated-item-enum.stderr
+++ b/tests/ui/associated-item/associated-item-enum.stderr
@@ -5,10 +5,12 @@ LL | enum Enum { Variant }
    | --------- variant or associated item `mispellable` not found for this enum
 ...
 LL |     Enum::mispellable();
-   |           ^^^^^^^^^^^
-   |           |
-   |           variant or associated item not found in `Enum`
-   |           help: there is an associated function with a similar name: `misspellable`
+   |           ^^^^^^^^^^^ variant or associated item not found in `Enum`
+   |
+help: there is an associated function with a similar name
+   |
+LL |     Enum::misspellable();
+   |           ~~~~~~~~~~~~
 
 error[E0599]: no variant or associated item named `mispellable_trait` found for enum `Enum` in the current scope
   --> $DIR/associated-item-enum.rs:18:11
@@ -17,10 +19,12 @@ LL | enum Enum { Variant }
    | --------- variant or associated item `mispellable_trait` not found for this enum
 ...
 LL |     Enum::mispellable_trait();
-   |           ^^^^^^^^^^^^^^^^^
-   |           |
-   |           variant or associated item not found in `Enum`
-   |           help: there is an associated function with a similar name: `misspellable_trait`
+   |           ^^^^^^^^^^^^^^^^^ variant or associated item not found in `Enum`
+   |
+help: there is an associated function with a similar name
+   |
+LL |     Enum::misspellable_trait();
+   |           ~~~~~~~~~~~~~~~~~~
 
 error[E0599]: no variant or associated item named `MISPELLABLE` found for enum `Enum` in the current scope
   --> $DIR/associated-item-enum.rs:19:11
@@ -29,10 +33,12 @@ LL | enum Enum { Variant }
    | --------- variant or associated item `MISPELLABLE` not found for this enum
 ...
 LL |     Enum::MISPELLABLE;
-   |           ^^^^^^^^^^^
-   |           |
-   |           variant or associated item not found in `Enum`
-   |           help: there is an associated constant with a similar name: `MISSPELLABLE`
+   |           ^^^^^^^^^^^ variant or associated item not found in `Enum`
+   |
+help: there is an associated constant with a similar name
+   |
+LL |     Enum::MISSPELLABLE;
+   |           ~~~~~~~~~~~~
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/attributes/rustc_confusables.stderr b/tests/ui/attributes/rustc_confusables.stderr
index 93c31fd5a34ef..60dc0e396ba83 100644
--- a/tests/ui/attributes/rustc_confusables.stderr
+++ b/tests/ui/attributes/rustc_confusables.stderr
@@ -31,7 +31,12 @@ error[E0599]: no method named `inser` found for struct `rustc_confusables_across
   --> $DIR/rustc_confusables.rs:12:7
    |
 LL |     x.inser();
-   |       ^^^^^ help: there is a method with a similar name: `insert`
+   |       ^^^^^
+   |
+help: there is a method with a similar name
+   |
+LL |     x.insert();
+   |       ~~~~~~
 
 error[E0599]: no method named `foo` found for struct `rustc_confusables_across_crate::BTreeSet` in the current scope
   --> $DIR/rustc_confusables.rs:15:7
diff --git a/tests/ui/block-result/issue-3563.stderr b/tests/ui/block-result/issue-3563.stderr
index c473a84413eb7..3381ae5f65771 100644
--- a/tests/ui/block-result/issue-3563.stderr
+++ b/tests/ui/block-result/issue-3563.stderr
@@ -2,7 +2,12 @@ error[E0599]: no method named `b` found for reference `&Self` in the current sco
   --> $DIR/issue-3563.rs:3:17
    |
 LL |         || self.b()
-   |                 ^ help: there is a method with a similar name: `a`
+   |                 ^
+   |
+help: there is a method with a similar name
+   |
+LL |         || self.a()
+   |                 ~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/methods/issues/issue-105732.stderr b/tests/ui/methods/issues/issue-105732.stderr
index 19ccd2de685a1..906bd6c863602 100644
--- a/tests/ui/methods/issues/issue-105732.stderr
+++ b/tests/ui/methods/issues/issue-105732.stderr
@@ -10,7 +10,12 @@ error[E0599]: no method named `g` found for reference `&Self` in the current sco
   --> $DIR/issue-105732.rs:10:14
    |
 LL |         self.g();
-   |              ^ help: there is a method with a similar name: `f`
+   |              ^
+   |
+help: there is a method with a similar name
+   |
+LL |         self.f();
+   |              ~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/methods/method-not-found-but-doc-alias.stderr b/tests/ui/methods/method-not-found-but-doc-alias.stderr
index 9746c404013d9..d8c2ea00137dd 100644
--- a/tests/ui/methods/method-not-found-but-doc-alias.stderr
+++ b/tests/ui/methods/method-not-found-but-doc-alias.stderr
@@ -5,7 +5,12 @@ LL | struct Foo;
    | ---------- method `quux` not found for this struct
 ...
 LL |     Foo.quux();
-   |         ^^^^ help: there is a method with a similar name: `bar`
+   |         ^^^^
+   |
+help: there is a method with a similar name
+   |
+LL |     Foo.bar();
+   |         ~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/object-pointer-types.stderr b/tests/ui/object-pointer-types.stderr
index fe21bf3aedefc..e581d2d40bd15 100644
--- a/tests/ui/object-pointer-types.stderr
+++ b/tests/ui/object-pointer-types.stderr
@@ -5,7 +5,12 @@ LL |     fn owned(self: Box<Self>);
    |                    --------- the method might not be found because of this arbitrary self type
 ...
 LL |     x.owned();
-   |       ^^^^^ help: there is a method with a similar name: `to_owned`
+   |       ^^^^^
+   |
+help: there is a method with a similar name
+   |
+LL |     x.to_owned();
+   |       ~~~~~~~~
 
 error[E0599]: no method named `owned` found for mutable reference `&mut dyn Foo` in the current scope
   --> $DIR/object-pointer-types.rs:17:7
diff --git a/tests/ui/parser/emoji-identifiers.stderr b/tests/ui/parser/emoji-identifiers.stderr
index 8250dd1ea2e92..4191333c98454 100644
--- a/tests/ui/parser/emoji-identifiers.stderr
+++ b/tests/ui/parser/emoji-identifiers.stderr
@@ -71,16 +71,17 @@ LL | struct 👀;
    | --------- function or associated item `full_of✨` not found for this struct
 ...
 LL |     👀::full_of✨()
-   |         ^^^^^^^^^
-   |         |
-   |         function or associated item not found in `👀`
-   |         help: there is an associated function with a similar name: `full_of_✨`
+   |         ^^^^^^^^^ function or associated item not found in `👀`
    |
 note: if you're trying to build a new `👀`, consider using `👀::full_of_✨` which returns `👀`
   --> $DIR/emoji-identifiers.rs:4:5
    |
 LL |     fn full_of_✨() -> 👀 {
    |     ^^^^^^^^^^^^^^^^^^^^^
+help: there is an associated function with a similar name
+   |
+LL |     👀::full_of_✨()
+   |         ~~~~~~~~~~
 
 error[E0425]: cannot find function `i_like_to_😄_a_lot` in this scope
   --> $DIR/emoji-identifiers.rs:13:13
diff --git a/tests/ui/resolve/typo-suggestion-mistyped-in-path.stderr b/tests/ui/resolve/typo-suggestion-mistyped-in-path.stderr
index 89b69e1409967..b006121750025 100644
--- a/tests/ui/resolve/typo-suggestion-mistyped-in-path.stderr
+++ b/tests/ui/resolve/typo-suggestion-mistyped-in-path.stderr
@@ -14,10 +14,12 @@ LL | struct Struct;
    | ------------- function or associated item `fob` not found for this struct
 ...
 LL |     Struct::fob();
-   |             ^^^
-   |             |
-   |             function or associated item not found in `Struct`
-   |             help: there is an associated function with a similar name: `foo`
+   |             ^^^ function or associated item not found in `Struct`
+   |
+help: there is an associated function with a similar name
+   |
+LL |     Struct::foo();
+   |             ~~~
 
 error[E0433]: failed to resolve: use of undeclared type `Struc`
   --> $DIR/typo-suggestion-mistyped-in-path.rs:27:5
diff --git a/tests/ui/rust-2018/trait-import-suggestions.stderr b/tests/ui/rust-2018/trait-import-suggestions.stderr
index a9d625df9ba6c..36cce0aab5110 100644
--- a/tests/ui/rust-2018/trait-import-suggestions.stderr
+++ b/tests/ui/rust-2018/trait-import-suggestions.stderr
@@ -40,7 +40,12 @@ error[E0599]: no method named `baz` found for type `u32` in the current scope
   --> $DIR/trait-import-suggestions.rs:29:7
    |
 LL |     x.baz();
-   |       ^^^ help: there is a method with a similar name: `bar`
+   |       ^^^
+   |
+help: there is a method with a similar name
+   |
+LL |     x.bar();
+   |       ~~~
 
 error[E0599]: no function or associated item named `from_str` found for type `u32` in the current scope
   --> $DIR/trait-import-suggestions.rs:30:18
diff --git a/tests/ui/self/arbitrary_self_type_mut_difference.stderr b/tests/ui/self/arbitrary_self_type_mut_difference.stderr
index a56d58694aa35..2a7192a83f5b4 100644
--- a/tests/ui/self/arbitrary_self_type_mut_difference.stderr
+++ b/tests/ui/self/arbitrary_self_type_mut_difference.stderr
@@ -2,25 +2,33 @@ error[E0599]: no method named `x` found for struct `Pin<&S>` in the current scop
   --> $DIR/arbitrary_self_type_mut_difference.rs:11:18
    |
 LL |     Pin::new(&S).x();
-   |                  ^ help: there is a method with a similar name: `y`
+   |                  ^
    |
 note: method is available for `Pin<&mut S>`
   --> $DIR/arbitrary_self_type_mut_difference.rs:6:5
    |
 LL |     fn x(self: Pin<&mut Self>) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: there is a method with a similar name
+   |
+LL |     Pin::new(&S).y();
+   |                  ~
 
 error[E0599]: no method named `y` found for struct `Pin<&mut S>` in the current scope
   --> $DIR/arbitrary_self_type_mut_difference.rs:12:22
    |
 LL |     Pin::new(&mut S).y();
-   |                      ^ help: there is a method with a similar name: `x`
+   |                      ^
    |
 note: method is available for `Pin<&S>`
   --> $DIR/arbitrary_self_type_mut_difference.rs:7:5
    |
 LL |     fn y(self: Pin<&Self>) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^
+help: there is a method with a similar name
+   |
+LL |     Pin::new(&mut S).x();
+   |                      ~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/suggestions/issue-109291.stderr b/tests/ui/suggestions/issue-109291.stderr
index c787be4de7c56..7a2821a069b62 100644
--- a/tests/ui/suggestions/issue-109291.stderr
+++ b/tests/ui/suggestions/issue-109291.stderr
@@ -2,10 +2,7 @@ error[E0599]: no function or associated item named `forced_capture` found for st
   --> $DIR/issue-109291.rs:2:65
    |
 LL |     println!("Custom backtrace: {}", std::backtrace::Backtrace::forced_capture());
-   |                                                                 ^^^^^^^^^^^^^^
-   |                                                                 |
-   |                                                                 function or associated item not found in `Backtrace`
-   |                                                                 help: there is an associated function with a similar name: `force_capture`
+   |                                                                 ^^^^^^^^^^^^^^ function or associated item not found in `Backtrace`
    |
 note: if you're trying to build a new `Backtrace` consider using one of the following associated functions:
       Backtrace::capture
@@ -13,6 +10,10 @@ note: if you're trying to build a new `Backtrace` consider using one of the foll
       Backtrace::disabled
       Backtrace::create
   --> $SRC_DIR/std/src/backtrace.rs:LL:COL
+help: there is an associated function with a similar name
+   |
+LL |     println!("Custom backtrace: {}", std::backtrace::Backtrace::force_capture());
+   |                                                                 ~~~~~~~~~~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/suggestions/suggest-methods.stderr b/tests/ui/suggestions/suggest-methods.stderr
index 293009f289bef..5115a07242691 100644
--- a/tests/ui/suggestions/suggest-methods.stderr
+++ b/tests/ui/suggestions/suggest-methods.stderr
@@ -17,19 +17,34 @@ error[E0599]: no method named `is_emtpy` found for struct `String` in the curren
   --> $DIR/suggest-methods.rs:22:15
    |
 LL |     let _ = s.is_emtpy();
-   |               ^^^^^^^^ help: there is a method with a similar name: `is_empty`
+   |               ^^^^^^^^
+   |
+help: there is a method with a similar name
+   |
+LL |     let _ = s.is_empty();
+   |               ~~~~~~~~
 
 error[E0599]: no method named `count_eos` found for type `u32` in the current scope
   --> $DIR/suggest-methods.rs:27:19
    |
 LL |     let _ = 63u32.count_eos();
-   |                   ^^^^^^^^^ help: there is a method with a similar name: `count_zeros`
+   |                   ^^^^^^^^^
+   |
+help: there is a method with a similar name
+   |
+LL |     let _ = 63u32.count_zeros();
+   |                   ~~~~~~~~~~~
 
 error[E0599]: no method named `count_o` found for type `u32` in the current scope
   --> $DIR/suggest-methods.rs:30:19
    |
 LL |     let _ = 63u32.count_o();
-   |                   ^^^^^^^ help: there is a method with a similar name: `count_ones`
+   |                   ^^^^^^^
+   |
+help: there is a method with a similar name
+   |
+LL |     let _ = 63u32.count_ones();
+   |                   ~~~~~~~~~~
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/traits/trait-upcasting/subtrait-method.stderr b/tests/ui/traits/trait-upcasting/subtrait-method.stderr
index 918159e845b9e..f3eb86c7681e8 100644
--- a/tests/ui/traits/trait-upcasting/subtrait-method.stderr
+++ b/tests/ui/traits/trait-upcasting/subtrait-method.stderr
@@ -2,7 +2,7 @@ error[E0599]: no method named `c` found for reference `&dyn Bar` in the current
   --> $DIR/subtrait-method.rs:55:9
    |
 LL |     bar.c();
-   |         ^ help: there is a method with a similar name: `a`
+   |         ^
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `Baz` defines an item `c`, perhaps you need to implement it
@@ -10,12 +10,16 @@ note: `Baz` defines an item `c`, perhaps you need to implement it
    |
 LL | trait Baz: Bar {
    | ^^^^^^^^^^^^^^
+help: there is a method with a similar name
+   |
+LL |     bar.a();
+   |         ~
 
 error[E0599]: no method named `b` found for reference `&dyn Foo` in the current scope
   --> $DIR/subtrait-method.rs:59:9
    |
 LL |     foo.b();
-   |         ^ help: there is a method with a similar name: `a`
+   |         ^
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `Bar` defines an item `b`, perhaps you need to implement it
@@ -23,12 +27,16 @@ note: `Bar` defines an item `b`, perhaps you need to implement it
    |
 LL | trait Bar: Foo {
    | ^^^^^^^^^^^^^^
+help: there is a method with a similar name
+   |
+LL |     foo.a();
+   |         ~
 
 error[E0599]: no method named `c` found for reference `&dyn Foo` in the current scope
   --> $DIR/subtrait-method.rs:61:9
    |
 LL |     foo.c();
-   |         ^ help: there is a method with a similar name: `a`
+   |         ^
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `Baz` defines an item `c`, perhaps you need to implement it
@@ -36,12 +44,16 @@ note: `Baz` defines an item `c`, perhaps you need to implement it
    |
 LL | trait Baz: Bar {
    | ^^^^^^^^^^^^^^
+help: there is a method with a similar name
+   |
+LL |     foo.a();
+   |         ~
 
 error[E0599]: no method named `b` found for reference `&dyn Foo` in the current scope
   --> $DIR/subtrait-method.rs:65:9
    |
 LL |     foo.b();
-   |         ^ help: there is a method with a similar name: `a`
+   |         ^
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `Bar` defines an item `b`, perhaps you need to implement it
@@ -49,12 +61,16 @@ note: `Bar` defines an item `b`, perhaps you need to implement it
    |
 LL | trait Bar: Foo {
    | ^^^^^^^^^^^^^^
+help: there is a method with a similar name
+   |
+LL |     foo.a();
+   |         ~
 
 error[E0599]: no method named `c` found for reference `&dyn Foo` in the current scope
   --> $DIR/subtrait-method.rs:67:9
    |
 LL |     foo.c();
-   |         ^ help: there is a method with a similar name: `a`
+   |         ^
    |
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `Baz` defines an item `c`, perhaps you need to implement it
@@ -62,6 +78,10 @@ note: `Baz` defines an item `c`, perhaps you need to implement it
    |
 LL | trait Baz: Bar {
    | ^^^^^^^^^^^^^^
+help: there is a method with a similar name
+   |
+LL |     foo.a();
+   |         ~
 
 error: aborting due to 5 previous errors
 

From e4820c577724a9d25ccaa2471501f7872639b340 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Tue, 13 Feb 2024 22:07:39 +0000
Subject: [PATCH 31/58] fix test

---
 tests/ui/atomic-from-mut-not-available.stderr | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/tests/ui/atomic-from-mut-not-available.stderr b/tests/ui/atomic-from-mut-not-available.stderr
index a3edf18935603..0f37784be78f5 100644
--- a/tests/ui/atomic-from-mut-not-available.stderr
+++ b/tests/ui/atomic-from-mut-not-available.stderr
@@ -7,6 +7,10 @@ LL |     core::sync::atomic::AtomicU64::from_mut(&mut 0u64);
 note: if you're trying to build a new `AtomicU64`, consider using `AtomicU64::new` which returns `AtomicU64`
   --> $SRC_DIR/core/src/sync/atomic.rs:LL:COL
    = note: this error originates in the macro `atomic_int` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: there is an associated function with a similar name
+   |
+LL |     core::sync::atomic::AtomicU64::from(&mut 0u64);
+   |                                    ~~~~
 
 error: aborting due to 1 previous error
 

From f5cd3df477b0e56014baec5a3a60edb309b18e62 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Tue, 13 Feb 2024 22:28:46 +0000
Subject: [PATCH 32/58] Better account for associated const found for fn call
 expr

---
 .../rustc_hir_typeck/src/method/suggest.rs     |  4 +++-
 tests/ui/traits/item-privacy.stderr            | 18 ++++++++++--------
 2 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 3bc1df4fc3dcd..385293594a90e 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -1319,7 +1319,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             ),
                         );
                     }
-                } else if let Mode::Path = mode {
+                } else if let Mode::Path = mode
+                    && args.unwrap_or(&[]).is_empty()
+                {
                     // We have an associated item syntax and we found something that isn't an fn.
                     err.span_suggestion_verbose(
                         span,
diff --git a/tests/ui/traits/item-privacy.stderr b/tests/ui/traits/item-privacy.stderr
index ede1764efdcaf..a946995297648 100644
--- a/tests/ui/traits/item-privacy.stderr
+++ b/tests/ui/traits/item-privacy.stderr
@@ -58,14 +58,15 @@ LL |     S::a(&S);
    |        ^ function or associated item not found in `S`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
+help: there is an associated constant `B` with a similar name
+  --> $DIR/item-privacy.rs:29:9
+   |
+LL |         const B: u8 = 0;
+   |         ^^^^^^^^^^^
 help: the following trait is implemented but not in scope; perhaps add a `use` for it:
    |
 LL + use method::A;
    |
-help: there is an associated constant with a similar name
-   |
-LL |     S::B(&S);
-   |        ~
 
 error[E0599]: no function or associated item named `b` found for struct `S` in the current scope
   --> $DIR/item-privacy.rs:80:8
@@ -77,14 +78,15 @@ LL |     S::b(&S);
    |        ^ function or associated item not found in `S`
    |
    = help: items from traits can only be used if the trait is in scope
+help: there is an associated constant `B` with a similar name
+  --> $DIR/item-privacy.rs:29:9
+   |
+LL |         const B: u8 = 0;
+   |         ^^^^^^^^^^^
 help: the following trait is implemented but not in scope; perhaps add a `use` for it:
    |
 LL + use method::B;
    |
-help: there is an associated constant with a similar name
-   |
-LL |     S::B(&S);
-   |        ~
 
 error[E0624]: method `a` is private
   --> $DIR/item-privacy.rs:84:14

From ac23b72c4351bab265b4fc072c6de0e1dfb9d1b2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Tue, 13 Feb 2024 23:05:23 +0000
Subject: [PATCH 33/58] Tweak wording of "implemented trait isn't imported"
 suggestion

---
 .../rustc_hir_typeck/src/method/suggest.rs    | 27 ++++++++++++++-----
 ...project-to-specializable-projection.stderr |  2 +-
 tests/ui/coherence/coherence_inherent.stderr  |  2 +-
 .../ui/coherence/coherence_inherent_cc.stderr |  2 +-
 tests/ui/hygiene/no_implicit_prelude.stderr   |  2 +-
 tests/ui/hygiene/trait_items.stderr           |  2 +-
 .../no-method-suggested-traits.stderr         | 12 ++++-----
 tests/ui/imports/overlapping_pub_trait.rs     |  2 +-
 tests/ui/imports/overlapping_pub_trait.stderr |  2 +-
 tests/ui/imports/unnamed_pub_trait.rs         |  2 +-
 tests/ui/imports/unnamed_pub_trait.stderr     |  2 +-
 tests/ui/issues/issue-10465.stderr            |  2 +-
 tests/ui/issues/issue-39175.stderr            |  2 +-
 tests/ui/issues/issue-56175.stderr            |  4 +--
 .../rust-2018/trait-import-suggestions.stderr |  6 ++---
 .../uniform-paths/issue-87932.stderr          |  2 +-
 .../future-prelude-collision-shadow.stderr    |  2 +-
 .../ui/shadowed/shadowed-trait-methods.stderr |  2 +-
 .../dont-wrap-ambiguous-receivers.rs          |  2 +-
 .../dont-wrap-ambiguous-receivers.stderr      |  2 +-
 .../import-trait-for-method-call.stderr       |  2 +-
 .../suggest-tryinto-edition-change.stderr     |  2 +-
 .../suggestions/use-placement-typeck.stderr   |  2 +-
 tests/ui/traits/item-privacy.stderr           | 12 ++++-----
 tests/ui/traits/method-private.stderr         |  2 +-
 tests/ui/typeck/issue-43189.stderr            |  2 +-
 tests/ui/underscore-imports/shadow.stderr     |  2 +-
 27 files changed, 59 insertions(+), 46 deletions(-)

diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 385293594a90e..e36c77bdfcd81 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -188,7 +188,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     .span_if_local(def_id)
                     .unwrap_or_else(|| self.tcx.def_span(def_id));
                 err.span_label(sp, format!("private {kind} defined here"));
-                self.suggest_valid_traits(&mut err, out_of_scope_traits, true);
+                self.suggest_valid_traits(&mut err, item_name, out_of_scope_traits, true);
                 err.emit();
             }
 
@@ -2779,6 +2779,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn suggest_valid_traits(
         &self,
         err: &mut Diagnostic,
+        item_name: Ident,
         valid_out_of_scope_traits: Vec<DefId>,
         explain: bool,
     ) -> bool {
@@ -2797,9 +2798,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 err.help("items from traits can only be used if the trait is in scope");
             }
             let msg = format!(
-                "the following {traits_are} implemented but not in scope; \
-                 perhaps add a `use` for {one_of_them}:",
-                traits_are = if candidates.len() == 1 { "trait is" } else { "traits are" },
+                "{this_trait_is} implemented but not in scope; perhaps you want to import \
+                 {one_of_them}",
+                this_trait_is = if candidates.len() == 1 {
+                    format!(
+                        "trait `{}` which provides `{item_name}` is",
+                        self.tcx.item_name(candidates[0]),
+                    )
+                } else {
+                    format!("the following traits which provide `{item_name}` are")
+                },
                 one_of_them = if candidates.len() == 1 { "it" } else { "one of them" },
             );
 
@@ -3007,7 +3015,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
             }
         }
-        if self.suggest_valid_traits(err, valid_out_of_scope_traits, true) {
+        if self.suggest_valid_traits(err, item_name, valid_out_of_scope_traits, true) {
             return;
         }
 
@@ -3293,7 +3301,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 [] => {}
                 [trait_info] if trait_info.def_id.is_local() => {
                     if impls_trait(trait_info.def_id) {
-                        self.suggest_valid_traits(err, vec![trait_info.def_id], false);
+                        self.suggest_valid_traits(err, item_name, vec![trait_info.def_id], false);
                     } else {
                         err.subdiagnostic(CandidateTraitNote {
                             span: self.tcx.def_span(trait_info.def_id),
@@ -3317,7 +3325,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     ));
                     for (i, trait_info) in trait_infos.iter().enumerate() {
                         if impls_trait(trait_info.def_id) {
-                            self.suggest_valid_traits(err, vec![trait_info.def_id], false);
+                            self.suggest_valid_traits(
+                                err,
+                                item_name,
+                                vec![trait_info.def_id],
+                                false,
+                            );
                         }
                         msg.push_str(&format!(
                             "\ncandidate #{}: `{}`",
diff --git a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr
index b7336485eb84d..3d82f572a1a69 100644
--- a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr
+++ b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr
@@ -30,7 +30,7 @@ LL |         match fut.as_mut().poll(ctx) {
    = note: the method is available for `Pin<&mut impl Future<Output = ()>>` here
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `Future` which provides `poll` is implemented but not in scope; perhaps you want to import it
    |
 LL + use std::future::Future;
    |
diff --git a/tests/ui/coherence/coherence_inherent.stderr b/tests/ui/coherence/coherence_inherent.stderr
index da8c03847eda1..17b49279de7b6 100644
--- a/tests/ui/coherence/coherence_inherent.stderr
+++ b/tests/ui/coherence/coherence_inherent.stderr
@@ -5,7 +5,7 @@ LL |         s.the_fn();
    |           ^^^^^^ method not found in `&TheStruct`
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `TheTrait` which provides `the_fn` is implemented but not in scope; perhaps you want to import it
    |
 LL +     use Lib::TheTrait;
    |
diff --git a/tests/ui/coherence/coherence_inherent_cc.stderr b/tests/ui/coherence/coherence_inherent_cc.stderr
index d34f6fa213bec..b3c1125d63e38 100644
--- a/tests/ui/coherence/coherence_inherent_cc.stderr
+++ b/tests/ui/coherence/coherence_inherent_cc.stderr
@@ -5,7 +5,7 @@ LL |         s.the_fn();
    |           ^^^^^^ method not found in `&TheStruct`
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `TheTrait` which provides `the_fn` is implemented but not in scope; perhaps you want to import it
    |
 LL +     use coherence_inherent_cc_lib::TheTrait;
    |
diff --git a/tests/ui/hygiene/no_implicit_prelude.stderr b/tests/ui/hygiene/no_implicit_prelude.stderr
index 646863a884c88..5de6e3db327b1 100644
--- a/tests/ui/hygiene/no_implicit_prelude.stderr
+++ b/tests/ui/hygiene/no_implicit_prelude.stderr
@@ -26,7 +26,7 @@ LL |         ().clone()
 help: there is a method `clone_from` with a similar name, but with different arguments
   --> $SRC_DIR/core/src/clone.rs:LL:COL
    = note: this error originates in the macro `::bar::m` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `Clone` which provides `clone` is implemented but not in scope; perhaps you want to import it
    |
 LL +     use std::clone::Clone;
    |
diff --git a/tests/ui/hygiene/trait_items.stderr b/tests/ui/hygiene/trait_items.stderr
index 016ee8f71f981..0e276bf69d6ec 100644
--- a/tests/ui/hygiene/trait_items.stderr
+++ b/tests/ui/hygiene/trait_items.stderr
@@ -12,7 +12,7 @@ LL |     pub macro m() { ().f() }
    |
    = help: items from traits can only be used if the trait is in scope
    = note: this error originates in the macro `::baz::m` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `T` which provides `f` is implemented but not in scope; perhaps you want to import it
    |
 LL +     use foo::T;
    |
diff --git a/tests/ui/impl-trait/no-method-suggested-traits.stderr b/tests/ui/impl-trait/no-method-suggested-traits.stderr
index cf1bf59ab201e..b9a6a281b84f5 100644
--- a/tests/ui/impl-trait/no-method-suggested-traits.stderr
+++ b/tests/ui/impl-trait/no-method-suggested-traits.stderr
@@ -5,7 +5,7 @@ LL |     1u32.method();
    |          ^^^^^^
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following traits are implemented but not in scope; perhaps add a `use` for one of them:
+help: the following traits which provide `method` are implemented but not in scope; perhaps you want to import one of them
    |
 LL + use foo::Bar;
    |
@@ -27,7 +27,7 @@ LL |     std::rc::Rc::new(&mut Box::new(&1u32)).method();
    |                                            ^^^^^^
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following traits are implemented but not in scope; perhaps add a `use` for one of them:
+help: the following traits which provide `method` are implemented but not in scope; perhaps you want to import one of them
    |
 LL + use foo::Bar;
    |
@@ -52,7 +52,7 @@ LL |     'a'.method();
    |         ^^^^^^
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `Bar` which provides `method` is implemented but not in scope; perhaps you want to import it
    |
 LL + use foo::Bar;
    |
@@ -68,7 +68,7 @@ LL |     std::rc::Rc::new(&mut Box::new(&'a')).method();
    |                                           ^^^^^^
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `Bar` which provides `method` is implemented but not in scope; perhaps you want to import it
    |
 LL + use foo::Bar;
    |
@@ -89,7 +89,7 @@ LL |         fn method(&self) {}
    |            ------ the method is available for `i32` here
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `PubPub` which provides `method` is implemented but not in scope; perhaps you want to import it
    |
 LL + use no_method_suggested_traits::foo::PubPub;
    |
@@ -105,7 +105,7 @@ LL |     std::rc::Rc::new(&mut Box::new(&1i32)).method();
    |                                            ^^^^^^
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `PubPub` which provides `method` is implemented but not in scope; perhaps you want to import it
    |
 LL + use no_method_suggested_traits::foo::PubPub;
    |
diff --git a/tests/ui/imports/overlapping_pub_trait.rs b/tests/ui/imports/overlapping_pub_trait.rs
index 69aba3ae9b4e7..23a1975bbb8fa 100644
--- a/tests/ui/imports/overlapping_pub_trait.rs
+++ b/tests/ui/imports/overlapping_pub_trait.rs
@@ -4,7 +4,7 @@
  * This crate declares two public paths, `m::Tr` and `prelude::_`. Make sure we prefer the former.
  */
 extern crate overlapping_pub_trait_source;
-//~^ HELP the following trait is implemented but not in scope; perhaps add a `use` for it:
+//~^ HELP trait `Tr` which provides `method` is implemented but not in scope; perhaps you want to import it
 //~| SUGGESTION overlapping_pub_trait_source::m::Tr
 
 fn main() {
diff --git a/tests/ui/imports/overlapping_pub_trait.stderr b/tests/ui/imports/overlapping_pub_trait.stderr
index a82a4101ce0ba..51a8bec85b7d4 100644
--- a/tests/ui/imports/overlapping_pub_trait.stderr
+++ b/tests/ui/imports/overlapping_pub_trait.stderr
@@ -10,7 +10,7 @@ LL |     pub trait Tr { fn method(&self); }
    |                       ------ the method is available for `S` here
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `Tr` which provides `method` is implemented but not in scope; perhaps you want to import it
    |
 LL + use overlapping_pub_trait_source::m::Tr;
    |
diff --git a/tests/ui/imports/unnamed_pub_trait.rs b/tests/ui/imports/unnamed_pub_trait.rs
index c38fb17b97649..3d8cad844cd89 100644
--- a/tests/ui/imports/unnamed_pub_trait.rs
+++ b/tests/ui/imports/unnamed_pub_trait.rs
@@ -5,7 +5,7 @@
  * importing it by name, and instead we suggest importing it by glob.
  */
 extern crate unnamed_pub_trait_source;
-//~^ HELP the following trait is implemented but not in scope; perhaps add a `use` for it:
+//~^ HELP trait `Tr` which provides `method` is implemented but not in scope; perhaps you want to import it
 //~| SUGGESTION unnamed_pub_trait_source::prelude::*; // trait Tr
 
 fn main() {
diff --git a/tests/ui/imports/unnamed_pub_trait.stderr b/tests/ui/imports/unnamed_pub_trait.stderr
index 41772b8e694d3..7d6b7742981ce 100644
--- a/tests/ui/imports/unnamed_pub_trait.stderr
+++ b/tests/ui/imports/unnamed_pub_trait.stderr
@@ -10,7 +10,7 @@ LL |     pub trait Tr { fn method(&self); }
    |                       ------ the method is available for `S` here
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `Tr` which provides `method` is implemented but not in scope; perhaps you want to import it
    |
 LL + use unnamed_pub_trait_source::prelude::*; // trait Tr
    |
diff --git a/tests/ui/issues/issue-10465.stderr b/tests/ui/issues/issue-10465.stderr
index c6bc0786af1eb..0f46ebe505aa9 100644
--- a/tests/ui/issues/issue-10465.stderr
+++ b/tests/ui/issues/issue-10465.stderr
@@ -5,7 +5,7 @@ LL |             b.foo();
    |               ^^^ method not found in `&B`
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `A` which provides `foo` is implemented but not in scope; perhaps you want to import it
    |
 LL +         use a::A;
    |
diff --git a/tests/ui/issues/issue-39175.stderr b/tests/ui/issues/issue-39175.stderr
index bdc9e422e861f..bbe8badb65231 100644
--- a/tests/ui/issues/issue-39175.stderr
+++ b/tests/ui/issues/issue-39175.stderr
@@ -7,7 +7,7 @@ LL |     Command::new("echo").arg("hello").exec();
    = help: items from traits can only be used if the trait is in scope
 help: there is a method `pre_exec` with a similar name, but with different arguments
   --> $SRC_DIR/std/src/os/unix/process.rs:LL:COL
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `CommandExt` which provides `exec` is implemented but not in scope; perhaps you want to import it
    |
 LL + use std::os::unix::process::CommandExt;
    |
diff --git a/tests/ui/issues/issue-56175.stderr b/tests/ui/issues/issue-56175.stderr
index d8c757c158350..882d4e99327b4 100644
--- a/tests/ui/issues/issue-56175.stderr
+++ b/tests/ui/issues/issue-56175.stderr
@@ -10,7 +10,7 @@ LL |         fn trait_method(&self) {
    |            ------------ the method is available for `FooStruct` here
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `Trait` which provides `trait_method` is implemented but not in scope; perhaps you want to import it
    |
 LL + use reexported_trait::Trait;
    |
@@ -31,7 +31,7 @@ LL |         fn trait_method_b(&self) {
    |            -------------- the method is available for `FooStruct` here
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `TraitB` which provides `trait_method_b` is implemented but not in scope; perhaps you want to import it
    |
 LL + use reexported_trait::TraitBRename;
    |
diff --git a/tests/ui/rust-2018/trait-import-suggestions.stderr b/tests/ui/rust-2018/trait-import-suggestions.stderr
index 36cce0aab5110..9d7b68041e201 100644
--- a/tests/ui/rust-2018/trait-import-suggestions.stderr
+++ b/tests/ui/rust-2018/trait-import-suggestions.stderr
@@ -8,7 +8,7 @@ LL |         x.foobar();
    |           ^^^^^^
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `Foobar` which provides `foobar` is implemented but not in scope; perhaps you want to import it
    |
 LL +     use crate::foo::foobar::Foobar;
    |
@@ -27,7 +27,7 @@ LL |     x.bar();
    |       ^^^
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `Bar` which provides `bar` is implemented but not in scope; perhaps you want to import it
    |
 LL + use crate::foo::Bar;
    |
@@ -54,7 +54,7 @@ LL |     let y = u32::from_str("33");
    |                  ^^^^^^^^ function or associated item not found in `u32`
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `FromStr` which provides `from_str` is implemented but not in scope; perhaps you want to import it
    |
 LL + use std::str::FromStr;
    |
diff --git a/tests/ui/rust-2018/uniform-paths/issue-87932.stderr b/tests/ui/rust-2018/uniform-paths/issue-87932.stderr
index 4a874a834bb7e..3e6fc3ff2a562 100644
--- a/tests/ui/rust-2018/uniform-paths/issue-87932.stderr
+++ b/tests/ui/rust-2018/uniform-paths/issue-87932.stderr
@@ -8,7 +8,7 @@ LL |     A::deserialize();
    |        ^^^^^^^^^^^ function or associated item not found in `A`
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `Deserialize` which provides `deserialize` is implemented but not in scope; perhaps you want to import it
    |
 LL + use <crate::A as issue_87932_a::Deserialize>::deserialize::_a::Deserialize;
    |
diff --git a/tests/ui/rust-2021/future-prelude-collision-shadow.stderr b/tests/ui/rust-2021/future-prelude-collision-shadow.stderr
index 1ca5708e753be..a8fcf43cd63a3 100644
--- a/tests/ui/rust-2021/future-prelude-collision-shadow.stderr
+++ b/tests/ui/rust-2021/future-prelude-collision-shadow.stderr
@@ -6,7 +6,7 @@ LL |         let _: u32 = 3u8.try_into().unwrap();
    |
    = help: items from traits can only be used if the trait is in scope
    = note: 'std::convert::TryInto' is included in the prelude starting in Edition 2021
-help: the following traits are implemented but not in scope; perhaps add a `use` for one of them:
+help: the following traits which provide `try_into` are implemented but not in scope; perhaps you want to import one of them
    |
 LL +     use crate::m::TryIntoU32;
    |
diff --git a/tests/ui/shadowed/shadowed-trait-methods.stderr b/tests/ui/shadowed/shadowed-trait-methods.stderr
index 0bcf32790bcc1..2c990fababf9f 100644
--- a/tests/ui/shadowed/shadowed-trait-methods.stderr
+++ b/tests/ui/shadowed/shadowed-trait-methods.stderr
@@ -8,7 +8,7 @@ LL |     ().f()
    |        ^ method not found in `()`
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `T` which provides `f` is implemented but not in scope; perhaps you want to import it
    |
 LL + use foo::T;
    |
diff --git a/tests/ui/suggestions/dont-wrap-ambiguous-receivers.rs b/tests/ui/suggestions/dont-wrap-ambiguous-receivers.rs
index baa2128eb8e36..06aed9ac98f4b 100644
--- a/tests/ui/suggestions/dont-wrap-ambiguous-receivers.rs
+++ b/tests/ui/suggestions/dont-wrap-ambiguous-receivers.rs
@@ -1,5 +1,5 @@
 mod banana {
-    //~^ HELP the following traits are implemented but not in scope
+    //~^ HELP the following traits which provide `pick` are implemented but not in scope
     pub struct Chaenomeles;
 
     pub trait Apple {
diff --git a/tests/ui/suggestions/dont-wrap-ambiguous-receivers.stderr b/tests/ui/suggestions/dont-wrap-ambiguous-receivers.stderr
index 974aedd13cf54..41ca7d0f8ea34 100644
--- a/tests/ui/suggestions/dont-wrap-ambiguous-receivers.stderr
+++ b/tests/ui/suggestions/dont-wrap-ambiguous-receivers.stderr
@@ -8,7 +8,7 @@ LL |     banana::Chaenomeles.pick()
    |                         ^^^^ method not found in `Chaenomeles`
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following traits are implemented but not in scope; perhaps add a `use` for one of them:
+help: the following traits which provide `pick` are implemented but not in scope; perhaps you want to import one of them
    |
 LL + use banana::Apple;
    |
diff --git a/tests/ui/suggestions/import-trait-for-method-call.stderr b/tests/ui/suggestions/import-trait-for-method-call.stderr
index 3f54daf136f6d..58b07fe7a42c1 100644
--- a/tests/ui/suggestions/import-trait-for-method-call.stderr
+++ b/tests/ui/suggestions/import-trait-for-method-call.stderr
@@ -8,7 +8,7 @@ LL |     h.finish()
    = note: the method is available for `DefaultHasher` here
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `Hasher` which provides `finish` is implemented but not in scope; perhaps you want to import it
    |
 LL + use std::hash::Hasher;
    |
diff --git a/tests/ui/suggestions/suggest-tryinto-edition-change.stderr b/tests/ui/suggestions/suggest-tryinto-edition-change.stderr
index 01fabbadbffe4..a25a3f44ad2ca 100644
--- a/tests/ui/suggestions/suggest-tryinto-edition-change.stderr
+++ b/tests/ui/suggestions/suggest-tryinto-edition-change.stderr
@@ -58,7 +58,7 @@ LL |     let _i: i16 = 0_i32.try_into().unwrap();
    |
    = help: items from traits can only be used if the trait is in scope
    = note: 'std::convert::TryInto' is included in the prelude starting in Edition 2021
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `TryInto` which provides `try_into` is implemented but not in scope; perhaps you want to import it
    |
 LL + use std::convert::TryInto;
    |
diff --git a/tests/ui/suggestions/use-placement-typeck.stderr b/tests/ui/suggestions/use-placement-typeck.stderr
index d8f2d58a24878..dc2bd96bb21e7 100644
--- a/tests/ui/suggestions/use-placement-typeck.stderr
+++ b/tests/ui/suggestions/use-placement-typeck.stderr
@@ -11,7 +11,7 @@ LL |     pub struct S;
    |     ------------ method `abc` not found for this struct
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `Foo` which provides `abc` is implemented but not in scope; perhaps you want to import it
    |
 LL + use m::Foo;
    |
diff --git a/tests/ui/traits/item-privacy.stderr b/tests/ui/traits/item-privacy.stderr
index a946995297648..00d75b14227e5 100644
--- a/tests/ui/traits/item-privacy.stderr
+++ b/tests/ui/traits/item-privacy.stderr
@@ -8,7 +8,7 @@ LL |     S.a();
    |       ^
    |
    = help: items from traits can only be used if the trait is implemented and in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `A` which provides `a` is implemented but not in scope; perhaps you want to import it
    |
 LL + use method::A;
    |
@@ -30,7 +30,7 @@ LL |     S.b();
    |       ^
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `B` which provides `b` is implemented but not in scope; perhaps you want to import it
    |
 LL + use method::B;
    |
@@ -63,7 +63,7 @@ help: there is an associated constant `B` with a similar name
    |
 LL |         const B: u8 = 0;
    |         ^^^^^^^^^^^
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `A` which provides `a` is implemented but not in scope; perhaps you want to import it
    |
 LL + use method::A;
    |
@@ -83,7 +83,7 @@ help: there is an associated constant `B` with a similar name
    |
 LL |         const B: u8 = 0;
    |         ^^^^^^^^^^^
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `B` which provides `b` is implemented but not in scope; perhaps you want to import it
    |
 LL + use method::B;
    |
@@ -107,7 +107,7 @@ LL |     S::A;
    |        ^ associated item not found in `S`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `A` which provides `A` is implemented but not in scope; perhaps you want to import it
    |
 LL + use assoc_const::A;
    |
@@ -126,7 +126,7 @@ LL |     S::B;
    |        ^ associated item not found in `S`
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `B` which provides `B` is implemented but not in scope; perhaps you want to import it
    |
 LL + use assoc_const::B;
    |
diff --git a/tests/ui/traits/method-private.stderr b/tests/ui/traits/method-private.stderr
index d19f0bc086b28..274767331bd9e 100644
--- a/tests/ui/traits/method-private.stderr
+++ b/tests/ui/traits/method-private.stderr
@@ -8,7 +8,7 @@ LL |     foo.method();
    |         ^^^^^^ private method
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `Bar` which provides `method` is implemented but not in scope; perhaps you want to import it
    |
 LL + use inner::Bar;
    |
diff --git a/tests/ui/typeck/issue-43189.stderr b/tests/ui/typeck/issue-43189.stderr
index 2e12651699d45..8432cbeca2a4b 100644
--- a/tests/ui/typeck/issue-43189.stderr
+++ b/tests/ui/typeck/issue-43189.stderr
@@ -10,7 +10,7 @@ LL |     fn a(&self) {}
    |        - the method is available for `()` here
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `A` which provides `a` is implemented but not in scope; perhaps you want to import it
    |
 LL + use xcrate_issue_43189_b::xcrate_issue_43189_a::A;
    |
diff --git a/tests/ui/underscore-imports/shadow.stderr b/tests/ui/underscore-imports/shadow.stderr
index da26316389289..4743d14dfb9e6 100644
--- a/tests/ui/underscore-imports/shadow.stderr
+++ b/tests/ui/underscore-imports/shadow.stderr
@@ -5,7 +5,7 @@ LL |         x.deref();
    |           ^^^^^ method not found in `&()`
    |
    = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+help: trait `Deref` which provides `deref` is implemented but not in scope; perhaps you want to import it
    |
 LL +     use std::ops::Deref;
    |

From b49aa7c34ed76831a085db1caec6f4cb772a7209 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 14 Feb 2024 16:04:40 +0000
Subject: [PATCH 34/58] Add `flatmap`/`flat_map` -> `and_then` suggestions

---
 library/core/src/option.rs | 1 +
 library/core/src/result.rs | 1 +
 2 files changed, 2 insertions(+)

diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 0e5eb03239ce6..53c9ae498c081 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -1403,6 +1403,7 @@ impl<T> Option<T> {
     #[doc(alias = "flatmap")]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("flat_map", "flatmap")]
     pub fn and_then<U, F>(self, f: F) -> Option<U>
     where
         F: FnOnce(T) -> Option<U>,
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index 80f7fe75e8230..6879ac03f70bc 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -1315,6 +1315,7 @@ impl<T, E> Result<T, E> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_confusables("flat_map", "flatmap")]
     pub fn and_then<U, F: FnOnce(T) -> Result<U, E>>(self, op: F) -> Result<U, E> {
         match self {
             Ok(t) => op(t),

From 997351dd71548cfd9c60cf5e6bf7491a7866e379 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 14 Feb 2024 18:11:19 +0000
Subject: [PATCH 35/58] review comments: clean up

---
 .../rustc_hir_typeck/src/fn_ctxt/checks.rs    | 137 ++++++-------
 .../rustc_hir_typeck/src/method/suggest.rs    | 189 ++++++++++--------
 2 files changed, 166 insertions(+), 160 deletions(-)

diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index ea40b5cf7dc38..30b9749168ce6 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -563,80 +563,73 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         let suggest_confusable = |err: &mut Diagnostic| {
-            if let Some(call_name) = call_ident
-                && let Some(callee_ty) = callee_ty
+            let call_name = call_ident?;
+            let callee_ty = callee_ty?;
+            let input_types: Vec<Ty<'_>> = provided_arg_tys.iter().map(|(ty, _)| *ty).collect();
+            // Check for other methods in the following order
+            //  - methods marked as `rustc_confusables` with the provided arguments
+            //  - methods with the same argument type/count and short levenshtein distance
+            //  - methods marked as `rustc_confusables` (done)
+            //  - methods with short levenshtein distance
+
+            // Look for commonly confusable method names considering arguments.
+            if let Some(name) = self.confusable_method_name(
+                err,
+                callee_ty.peel_refs(),
+                call_name,
+                Some(input_types.clone()),
+            ) {
+                return Some(name);
+            }
+            // Look for method names with short levenshtein distance, considering arguments.
+            if let Some((assoc, fn_sig)) = similar_assoc(call_name)
+                && fn_sig.inputs()[1..]
+                    .iter()
+                    .zip(input_types.iter())
+                    .all(|(expected, found)| self.can_coerce(*expected, *found))
+                && fn_sig.inputs()[1..].len() == input_types.len()
             {
-                let input_types: Vec<Ty<'_>> = provided_arg_tys.iter().map(|(ty, _)| *ty).collect();
-                // Check for other methods in the following order
-                //  - methods marked as `rustc_confusables` with the provided arguments
-                //  - methods with the same argument type/count and short levenshtein distance
-                //  - methods marked as `rustc_confusables` (done)
-                //  - methods with short levenshtein distance
-
-                // Look for commonly confusable method names considering arguments.
-                self.confusable_method_name(
-                    err,
-                    callee_ty.peel_refs(),
-                    call_name,
-                    Some(input_types.clone()),
-                )
-                .or_else(|| {
-                    // Look for method names with short levenshtein distance, considering arguments.
-                    if let Some((assoc, fn_sig)) = similar_assoc(call_name)
-                        && fn_sig.inputs()[1..]
-                            .iter()
-                            .zip(input_types.iter())
-                            .all(|(expected, found)| self.can_coerce(*expected, *found))
-                        && fn_sig.inputs()[1..].len() == input_types.len()
-                    {
-                        err.span_suggestion_verbose(
-                            call_name.span,
-                            format!("you might have meant to use `{}`", assoc.name),
-                            assoc.name,
-                            Applicability::MaybeIncorrect,
-                        );
-                        return Some(assoc.name);
-                    }
-                    None
-                })
-                .or_else(|| {
-                    // Look for commonly confusable method names disregarding arguments.
-                    self.confusable_method_name(err, callee_ty.peel_refs(), call_name, None)
-                })
-                .or_else(|| {
-                    // Look for similarly named methods with levenshtein distance with the right
-                    // number of arguments.
-                    if let Some((assoc, fn_sig)) = similar_assoc(call_name)
-                        && fn_sig.inputs()[1..].len() == input_types.len()
-                    {
-                        err.span_note(
-                            tcx.def_span(assoc.def_id),
-                            format!(
-                                "there's is a method with similar name `{}`, but the arguments \
-                                 don't match",
-                                assoc.name,
-                            ),
-                        );
-                        return Some(assoc.name);
-                    }
-                    None
-                })
-                .or_else(|| {
-                    // Fallthrough: look for similarly named methods with levenshtein distance.
-                    if let Some((assoc, _)) = similar_assoc(call_name) {
-                        err.span_note(
-                            tcx.def_span(assoc.def_id),
-                            format!(
-                                "there's is a method with similar name `{}`, but their argument \
-                                 count doesn't match",
-                                assoc.name,
-                            ),
-                        );
-                        return Some(assoc.name);
-                    }
-                    None
-                });
+                err.span_suggestion_verbose(
+                    call_name.span,
+                    format!("you might have meant to use `{}`", assoc.name),
+                    assoc.name,
+                    Applicability::MaybeIncorrect,
+                );
+                return Some(assoc.name);
+            }
+            // Look for commonly confusable method names disregarding arguments.
+            if let Some(name) =
+                self.confusable_method_name(err, callee_ty.peel_refs(), call_name, None)
+            {
+                return Some(name);
+            }
+            // Look for similarly named methods with levenshtein distance with the right
+            // number of arguments.
+            if let Some((assoc, fn_sig)) = similar_assoc(call_name)
+                && fn_sig.inputs()[1..].len() == input_types.len()
+            {
+                err.span_note(
+                    tcx.def_span(assoc.def_id),
+                    format!(
+                        "there's is a method with similar name `{}`, but the arguments don't match",
+                        assoc.name,
+                    ),
+                );
+                return Some(assoc.name);
             }
+            // Fallthrough: look for similarly named methods with levenshtein distance.
+            if let Some((assoc, _)) = similar_assoc(call_name) {
+                err.span_note(
+                    tcx.def_span(assoc.def_id),
+                    format!(
+                        "there's is a method with similar name `{}`, but their argument count \
+                         doesn't match",
+                        assoc.name,
+                    ),
+                );
+                return Some(assoc.name);
+            }
+            None
         };
         // A "softer" version of the `demand_compatible`, which checks types without persisting them,
         // and treats error types differently
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index e36c77bdfcd81..1b67596da5231 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -1256,94 +1256,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // ...or if we already suggested that name because of `rustc_confusable` annotation.
                 && Some(similar_candidate.name) != confusable_suggested
             {
-                let def_kind = similar_candidate.kind.as_def_kind();
-                let an = self.tcx.def_kind_descr_article(def_kind, similar_candidate.def_id);
-                // Methods are defined within the context of a struct and their first parameter
-                // is always `self`, which represents the instance of the struct the method is
-                // being called on Associated functions don’t take self as a parameter and they are
-                // not methods because they don’t have an instance of the struct to work with.
-                if def_kind == DefKind::AssocFn {
-                    let ty_args = self.infcx.fresh_args_for_item(span, similar_candidate.def_id);
-                    let fn_sig = tcx.fn_sig(similar_candidate.def_id).instantiate(tcx, ty_args);
-                    let fn_sig =
-                        self.instantiate_binder_with_fresh_vars(span, infer::FnCall, fn_sig);
-                    if similar_candidate.fn_has_self_parameter {
-                        if let Some(args) = args
-                            && fn_sig.inputs()[1..].len() == args.len()
-                        {
-                            // We found a method with the same number of arguments as the method
-                            // call expression the user wrote.
-                            err.span_suggestion_verbose(
-                                span,
-                                format!("there is {an} method with a similar name"),
-                                similar_candidate.name,
-                                Applicability::MaybeIncorrect,
-                            );
-                        } else {
-                            // We found a method but either the expression is not a method call or
-                            // the argument count didn't match.
-                            err.span_help(
-                                tcx.def_span(similar_candidate.def_id),
-                                format!(
-                                    "there is {an} method `{}` with a similar name{}",
-                                    similar_candidate.name,
-                                    if let None = args {
-                                        ""
-                                    } else {
-                                        ", but with different arguments"
-                                    },
-                                ),
-                            );
-                        }
-                    } else if let Some(args) = args
-                        && fn_sig.inputs().len() == args.len()
-                    {
-                        // We have fn call expression and the argument count match the associated
-                        // function we found.
-                        err.span_suggestion_verbose(
-                            span,
-                            format!(
-                                "there is {an} {} with a similar name",
-                                self.tcx.def_kind_descr(def_kind, similar_candidate.def_id)
-                            ),
-                            similar_candidate.name,
-                            Applicability::MaybeIncorrect,
-                        );
-                    } else {
-                        err.span_help(
-                            tcx.def_span(similar_candidate.def_id),
-                            format!(
-                                "there is {an} {} `{}` with a similar name",
-                                self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
-                                similar_candidate.name,
-                            ),
-                        );
-                    }
-                } else if let Mode::Path = mode
-                    && args.unwrap_or(&[]).is_empty()
-                {
-                    // We have an associated item syntax and we found something that isn't an fn.
-                    err.span_suggestion_verbose(
-                        span,
-                        format!(
-                            "there is {an} {} with a similar name",
-                            self.tcx.def_kind_descr(def_kind, similar_candidate.def_id)
-                        ),
-                        similar_candidate.name,
-                        Applicability::MaybeIncorrect,
-                    );
-                } else {
-                    // The expression is a function or method call, but the item we found is an
-                    // associated const or type.
-                    err.span_help(
-                        tcx.def_span(similar_candidate.def_id),
-                        format!(
-                            "there is {an} {} `{}` with a similar name",
-                            self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
-                            similar_candidate.name,
-                        ),
-                    );
-                }
+                self.find_likely_intended_associated_item(
+                    &mut err,
+                    similar_candidate,
+                    span,
+                    args,
+                    mode,
+                );
             }
         }
         // If an appropriate error source is not found, check method chain for possible candiates
@@ -1395,6 +1314,100 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         Some(err)
     }
 
+    fn find_likely_intended_associated_item(
+        &self,
+        err: &mut Diagnostic,
+        similar_candidate: ty::AssocItem,
+        span: Span,
+        args: Option<&'tcx [hir::Expr<'tcx>]>,
+        mode: Mode,
+    ) {
+        let tcx = self.tcx;
+        let def_kind = similar_candidate.kind.as_def_kind();
+        let an = self.tcx.def_kind_descr_article(def_kind, similar_candidate.def_id);
+        // Methods are defined within the context of a struct and their first parameter
+        // is always `self`, which represents the instance of the struct the method is
+        // being called on Associated functions don’t take self as a parameter and they are
+        // not methods because they don’t have an instance of the struct to work with.
+        if def_kind == DefKind::AssocFn {
+            let ty_args = self.infcx.fresh_args_for_item(span, similar_candidate.def_id);
+            let fn_sig = tcx.fn_sig(similar_candidate.def_id).instantiate(tcx, ty_args);
+            let fn_sig = self.instantiate_binder_with_fresh_vars(span, infer::FnCall, fn_sig);
+            if similar_candidate.fn_has_self_parameter {
+                if let Some(args) = args
+                    && fn_sig.inputs()[1..].len() == args.len()
+                {
+                    // We found a method with the same number of arguments as the method
+                    // call expression the user wrote.
+                    err.span_suggestion_verbose(
+                        span,
+                        format!("there is {an} method with a similar name"),
+                        similar_candidate.name,
+                        Applicability::MaybeIncorrect,
+                    );
+                } else {
+                    // We found a method but either the expression is not a method call or
+                    // the argument count didn't match.
+                    err.span_help(
+                        tcx.def_span(similar_candidate.def_id),
+                        format!(
+                            "there is {an} method `{}` with a similar name{}",
+                            similar_candidate.name,
+                            if let None = args { "" } else { ", but with different arguments" },
+                        ),
+                    );
+                }
+            } else if let Some(args) = args
+                && fn_sig.inputs().len() == args.len()
+            {
+                // We have fn call expression and the argument count match the associated
+                // function we found.
+                err.span_suggestion_verbose(
+                    span,
+                    format!(
+                        "there is {an} {} with a similar name",
+                        self.tcx.def_kind_descr(def_kind, similar_candidate.def_id)
+                    ),
+                    similar_candidate.name,
+                    Applicability::MaybeIncorrect,
+                );
+            } else {
+                err.span_help(
+                    tcx.def_span(similar_candidate.def_id),
+                    format!(
+                        "there is {an} {} `{}` with a similar name",
+                        self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
+                        similar_candidate.name,
+                    ),
+                );
+            }
+        } else if let Mode::Path = mode
+            && args.unwrap_or(&[]).is_empty()
+        {
+            // We have an associated item syntax and we found something that isn't an fn.
+            err.span_suggestion_verbose(
+                span,
+                format!(
+                    "there is {an} {} with a similar name",
+                    self.tcx.def_kind_descr(def_kind, similar_candidate.def_id)
+                ),
+                similar_candidate.name,
+                Applicability::MaybeIncorrect,
+            );
+        } else {
+            // The expression is a function or method call, but the item we found is an
+            // associated const or type.
+            err.span_help(
+                tcx.def_span(similar_candidate.def_id),
+                format!(
+                    "there is {an} {} `{}` with a similar name",
+                    self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
+                    similar_candidate.name,
+                ),
+            );
+        }
+    }
+
     pub(crate) fn confusable_method_name(
         &self,
         err: &mut Diagnostic,

From 04884bc1c742105c21dbd53c64676e64c444bb84 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 14 Feb 2024 18:23:01 +0000
Subject: [PATCH 36/58] Deduplicate some logic and reword output

---
 .../rustc_hir_typeck/src/method/suggest.rs    | 38 ++++++-------------
 .../associated-item-enum.stderr               |  6 +--
 tests/ui/attributes/rustc_confusables.rs      |  2 +-
 tests/ui/attributes/rustc_confusables.stderr  |  2 +-
 tests/ui/block-result/issue-3563.stderr       |  2 +-
 .../issue-33784.stderr                        |  2 +-
 .../no-method-suggested-traits.stderr         | 12 +++---
 tests/ui/issues/issue-56175.stderr            |  4 +-
 tests/ui/methods/issues/issue-105732.stderr   |  2 +-
 .../method-not-found-but-doc-alias.stderr     |  2 +-
 tests/ui/object-pointer-types.stderr          |  2 +-
 tests/ui/parser/emoji-identifiers.stderr      |  2 +-
 .../typo-suggestion-mistyped-in-path.stderr   |  2 +-
 .../rust-2018/trait-import-suggestions.stderr |  8 ++--
 .../future-prelude-collision-shadow.stderr    |  2 +-
 .../arbitrary_self_type_mut_difference.stderr |  4 +-
 tests/ui/suggestions/issue-109291.stderr      |  2 +-
 tests/ui/suggestions/suggest-methods.stderr   |  6 +--
 .../suggest-tryinto-edition-change.stderr     |  2 +-
 tests/ui/traits/item-privacy.stderr           |  8 ++--
 .../trait-upcasting/subtrait-method.stderr    | 10 ++---
 21 files changed, 52 insertions(+), 68 deletions(-)

diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 1b67596da5231..4bd88c35408e9 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -1325,6 +1325,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let tcx = self.tcx;
         let def_kind = similar_candidate.kind.as_def_kind();
         let an = self.tcx.def_kind_descr_article(def_kind, similar_candidate.def_id);
+        let msg = format!(
+            "there is {an} {} `{}` with a similar name",
+            self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
+            similar_candidate.name,
+        );
         // Methods are defined within the context of a struct and their first parameter
         // is always `self`, which represents the instance of the struct the method is
         // being called on Associated functions don’t take self as a parameter and they are
@@ -1341,7 +1346,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // call expression the user wrote.
                     err.span_suggestion_verbose(
                         span,
-                        format!("there is {an} method with a similar name"),
+                        msg,
                         similar_candidate.name,
                         Applicability::MaybeIncorrect,
                     );
@@ -1351,8 +1356,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     err.span_help(
                         tcx.def_span(similar_candidate.def_id),
                         format!(
-                            "there is {an} method `{}` with a similar name{}",
-                            similar_candidate.name,
+                            "{msg}{}",
                             if let None = args { "" } else { ", but with different arguments" },
                         ),
                     );
@@ -1364,22 +1368,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // function we found.
                 err.span_suggestion_verbose(
                     span,
-                    format!(
-                        "there is {an} {} with a similar name",
-                        self.tcx.def_kind_descr(def_kind, similar_candidate.def_id)
-                    ),
+                    msg,
                     similar_candidate.name,
                     Applicability::MaybeIncorrect,
                 );
             } else {
-                err.span_help(
-                    tcx.def_span(similar_candidate.def_id),
-                    format!(
-                        "there is {an} {} `{}` with a similar name",
-                        self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
-                        similar_candidate.name,
-                    ),
-                );
+                err.span_help(tcx.def_span(similar_candidate.def_id), msg);
             }
         } else if let Mode::Path = mode
             && args.unwrap_or(&[]).is_empty()
@@ -1387,24 +1381,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // We have an associated item syntax and we found something that isn't an fn.
             err.span_suggestion_verbose(
                 span,
-                format!(
-                    "there is {an} {} with a similar name",
-                    self.tcx.def_kind_descr(def_kind, similar_candidate.def_id)
-                ),
+                msg,
                 similar_candidate.name,
                 Applicability::MaybeIncorrect,
             );
         } else {
             // The expression is a function or method call, but the item we found is an
             // associated const or type.
-            err.span_help(
-                tcx.def_span(similar_candidate.def_id),
-                format!(
-                    "there is {an} {} `{}` with a similar name",
-                    self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
-                    similar_candidate.name,
-                ),
-            );
+            err.span_help(tcx.def_span(similar_candidate.def_id), msg);
         }
     }
 
diff --git a/tests/ui/associated-item/associated-item-enum.stderr b/tests/ui/associated-item/associated-item-enum.stderr
index a966468e3dd47..3b00588f1d1a5 100644
--- a/tests/ui/associated-item/associated-item-enum.stderr
+++ b/tests/ui/associated-item/associated-item-enum.stderr
@@ -7,7 +7,7 @@ LL | enum Enum { Variant }
 LL |     Enum::mispellable();
    |           ^^^^^^^^^^^ variant or associated item not found in `Enum`
    |
-help: there is an associated function with a similar name
+help: there is an associated function `misspellable` with a similar name
    |
 LL |     Enum::misspellable();
    |           ~~~~~~~~~~~~
@@ -21,7 +21,7 @@ LL | enum Enum { Variant }
 LL |     Enum::mispellable_trait();
    |           ^^^^^^^^^^^^^^^^^ variant or associated item not found in `Enum`
    |
-help: there is an associated function with a similar name
+help: there is an associated function `misspellable_trait` with a similar name
    |
 LL |     Enum::misspellable_trait();
    |           ~~~~~~~~~~~~~~~~~~
@@ -35,7 +35,7 @@ LL | enum Enum { Variant }
 LL |     Enum::MISPELLABLE;
    |           ^^^^^^^^^^^ variant or associated item not found in `Enum`
    |
-help: there is an associated constant with a similar name
+help: there is an associated constant `MISSPELLABLE` with a similar name
    |
 LL |     Enum::MISSPELLABLE;
    |           ~~~~~~~~~~~~
diff --git a/tests/ui/attributes/rustc_confusables.rs b/tests/ui/attributes/rustc_confusables.rs
index 8c8a8c7fc16ce..bf90416933d48 100644
--- a/tests/ui/attributes/rustc_confusables.rs
+++ b/tests/ui/attributes/rustc_confusables.rs
@@ -11,7 +11,7 @@ fn main() {
     let x = BTreeSet {};
     x.inser();
     //~^ ERROR no method named
-    //~| HELP there is a method with a similar name
+    //~| HELP there is a method `insert` with a similar name
     x.foo();
     //~^ ERROR no method named
     x.push();
diff --git a/tests/ui/attributes/rustc_confusables.stderr b/tests/ui/attributes/rustc_confusables.stderr
index 60dc0e396ba83..9e37d5f50837d 100644
--- a/tests/ui/attributes/rustc_confusables.stderr
+++ b/tests/ui/attributes/rustc_confusables.stderr
@@ -33,7 +33,7 @@ error[E0599]: no method named `inser` found for struct `rustc_confusables_across
 LL |     x.inser();
    |       ^^^^^
    |
-help: there is a method with a similar name
+help: there is a method `insert` with a similar name
    |
 LL |     x.insert();
    |       ~~~~~~
diff --git a/tests/ui/block-result/issue-3563.stderr b/tests/ui/block-result/issue-3563.stderr
index 3381ae5f65771..22606a52f851e 100644
--- a/tests/ui/block-result/issue-3563.stderr
+++ b/tests/ui/block-result/issue-3563.stderr
@@ -4,7 +4,7 @@ error[E0599]: no method named `b` found for reference `&Self` in the current sco
 LL |         || self.b()
    |                 ^
    |
-help: there is a method with a similar name
+help: there is a method `a` with a similar name
    |
 LL |         || self.a()
    |                 ~
diff --git a/tests/ui/confuse-field-and-method/issue-33784.stderr b/tests/ui/confuse-field-and-method/issue-33784.stderr
index f6678dc85430d..8acd1f8ff1ee9 100644
--- a/tests/ui/confuse-field-and-method/issue-33784.stderr
+++ b/tests/ui/confuse-field-and-method/issue-33784.stderr
@@ -8,7 +8,7 @@ help: to call the function stored in `closure`, surround the field access with p
    |
 LL |     (p.closure)();
    |     +         +
-help: there is a method with a similar name
+help: there is a method `clone` with a similar name
    |
 LL |     p.clone();
    |       ~~~~~
diff --git a/tests/ui/impl-trait/no-method-suggested-traits.stderr b/tests/ui/impl-trait/no-method-suggested-traits.stderr
index b9a6a281b84f5..7a4dc366618e2 100644
--- a/tests/ui/impl-trait/no-method-suggested-traits.stderr
+++ b/tests/ui/impl-trait/no-method-suggested-traits.stderr
@@ -15,7 +15,7 @@ LL + use no_method_suggested_traits::foo::PubPub;
    |
 LL + use no_method_suggested_traits::qux::PrivPub;
    |
-help: there is a method with a similar name
+help: there is a method `method2` with a similar name
    |
 LL |     1u32.method2();
    |          ~~~~~~~
@@ -37,7 +37,7 @@ LL + use no_method_suggested_traits::foo::PubPub;
    |
 LL + use no_method_suggested_traits::qux::PrivPub;
    |
-help: there is a method with a similar name
+help: there is a method `method2` with a similar name
    |
 LL |     std::rc::Rc::new(&mut Box::new(&1u32)).method2();
    |                                            ~~~~~~~
@@ -56,7 +56,7 @@ help: trait `Bar` which provides `method` is implemented but not in scope; perha
    |
 LL + use foo::Bar;
    |
-help: there is a method with a similar name
+help: there is a method `method2` with a similar name
    |
 LL |     'a'.method2();
    |         ~~~~~~~
@@ -72,7 +72,7 @@ help: trait `Bar` which provides `method` is implemented but not in scope; perha
    |
 LL + use foo::Bar;
    |
-help: there is a method with a similar name
+help: there is a method `method2` with a similar name
    |
 LL |     std::rc::Rc::new(&mut Box::new(&'a')).method2();
    |                                           ~~~~~~~
@@ -93,7 +93,7 @@ help: trait `PubPub` which provides `method` is implemented but not in scope; pe
    |
 LL + use no_method_suggested_traits::foo::PubPub;
    |
-help: there is a method with a similar name
+help: there is a method `method3` with a similar name
    |
 LL |     1i32.method3();
    |          ~~~~~~~
@@ -109,7 +109,7 @@ help: trait `PubPub` which provides `method` is implemented but not in scope; pe
    |
 LL + use no_method_suggested_traits::foo::PubPub;
    |
-help: there is a method with a similar name
+help: there is a method `method3` with a similar name
    |
 LL |     std::rc::Rc::new(&mut Box::new(&1i32)).method3();
    |                                            ~~~~~~~
diff --git a/tests/ui/issues/issue-56175.stderr b/tests/ui/issues/issue-56175.stderr
index 882d4e99327b4..6ed35c3a3d3a4 100644
--- a/tests/ui/issues/issue-56175.stderr
+++ b/tests/ui/issues/issue-56175.stderr
@@ -14,7 +14,7 @@ help: trait `Trait` which provides `trait_method` is implemented but not in scop
    |
 LL + use reexported_trait::Trait;
    |
-help: there is a method with a similar name
+help: there is a method `trait_method_b` with a similar name
    |
 LL |     reexported_trait::FooStruct.trait_method_b();
    |                                 ~~~~~~~~~~~~~~
@@ -35,7 +35,7 @@ help: trait `TraitB` which provides `trait_method_b` is implemented but not in s
    |
 LL + use reexported_trait::TraitBRename;
    |
-help: there is a method with a similar name
+help: there is a method `trait_method` with a similar name
    |
 LL |     reexported_trait::FooStruct.trait_method();
    |                                 ~~~~~~~~~~~~
diff --git a/tests/ui/methods/issues/issue-105732.stderr b/tests/ui/methods/issues/issue-105732.stderr
index 906bd6c863602..a4924b3e663b7 100644
--- a/tests/ui/methods/issues/issue-105732.stderr
+++ b/tests/ui/methods/issues/issue-105732.stderr
@@ -12,7 +12,7 @@ error[E0599]: no method named `g` found for reference `&Self` in the current sco
 LL |         self.g();
    |              ^
    |
-help: there is a method with a similar name
+help: there is a method `f` with a similar name
    |
 LL |         self.f();
    |              ~
diff --git a/tests/ui/methods/method-not-found-but-doc-alias.stderr b/tests/ui/methods/method-not-found-but-doc-alias.stderr
index d8c2ea00137dd..c49ffa8971f75 100644
--- a/tests/ui/methods/method-not-found-but-doc-alias.stderr
+++ b/tests/ui/methods/method-not-found-but-doc-alias.stderr
@@ -7,7 +7,7 @@ LL | struct Foo;
 LL |     Foo.quux();
    |         ^^^^
    |
-help: there is a method with a similar name
+help: there is a method `bar` with a similar name
    |
 LL |     Foo.bar();
    |         ~~~
diff --git a/tests/ui/object-pointer-types.stderr b/tests/ui/object-pointer-types.stderr
index e581d2d40bd15..7d915ebdab657 100644
--- a/tests/ui/object-pointer-types.stderr
+++ b/tests/ui/object-pointer-types.stderr
@@ -7,7 +7,7 @@ LL |     fn owned(self: Box<Self>);
 LL |     x.owned();
    |       ^^^^^
    |
-help: there is a method with a similar name
+help: there is a method `to_owned` with a similar name
    |
 LL |     x.to_owned();
    |       ~~~~~~~~
diff --git a/tests/ui/parser/emoji-identifiers.stderr b/tests/ui/parser/emoji-identifiers.stderr
index 4191333c98454..340886a1a62f2 100644
--- a/tests/ui/parser/emoji-identifiers.stderr
+++ b/tests/ui/parser/emoji-identifiers.stderr
@@ -78,7 +78,7 @@ note: if you're trying to build a new `👀`, consider using `👀::full_of_✨`
    |
 LL |     fn full_of_✨() -> 👀 {
    |     ^^^^^^^^^^^^^^^^^^^^^
-help: there is an associated function with a similar name
+help: there is an associated function `full_of_✨` with a similar name
    |
 LL |     👀::full_of_✨()
    |         ~~~~~~~~~~
diff --git a/tests/ui/resolve/typo-suggestion-mistyped-in-path.stderr b/tests/ui/resolve/typo-suggestion-mistyped-in-path.stderr
index b006121750025..f4fb7fd955f2b 100644
--- a/tests/ui/resolve/typo-suggestion-mistyped-in-path.stderr
+++ b/tests/ui/resolve/typo-suggestion-mistyped-in-path.stderr
@@ -16,7 +16,7 @@ LL | struct Struct;
 LL |     Struct::fob();
    |             ^^^ function or associated item not found in `Struct`
    |
-help: there is an associated function with a similar name
+help: there is an associated function `foo` with a similar name
    |
 LL |     Struct::foo();
    |             ~~~
diff --git a/tests/ui/rust-2018/trait-import-suggestions.stderr b/tests/ui/rust-2018/trait-import-suggestions.stderr
index 9d7b68041e201..852628885794a 100644
--- a/tests/ui/rust-2018/trait-import-suggestions.stderr
+++ b/tests/ui/rust-2018/trait-import-suggestions.stderr
@@ -12,7 +12,7 @@ help: trait `Foobar` which provides `foobar` is implemented but not in scope; pe
    |
 LL +     use crate::foo::foobar::Foobar;
    |
-help: there is a method with a similar name
+help: there is a method `bar` with a similar name
    |
 LL |         x.bar();
    |           ~~~
@@ -31,7 +31,7 @@ help: trait `Bar` which provides `bar` is implemented but not in scope; perhaps
    |
 LL + use crate::foo::Bar;
    |
-help: there is a method with a similar name
+help: there is a method `foobar` with a similar name
    |
 LL |     x.foobar();
    |       ~~~~~~
@@ -42,7 +42,7 @@ error[E0599]: no method named `baz` found for type `u32` in the current scope
 LL |     x.baz();
    |       ^^^
    |
-help: there is a method with a similar name
+help: there is a method `bar` with a similar name
    |
 LL |     x.bar();
    |       ~~~
@@ -58,7 +58,7 @@ help: trait `FromStr` which provides `from_str` is implemented but not in scope;
    |
 LL + use std::str::FromStr;
    |
-help: there is an associated function with a similar name
+help: there is an associated function `from` with a similar name
    |
 LL |     let y = u32::from("33");
    |                  ~~~~
diff --git a/tests/ui/rust-2021/future-prelude-collision-shadow.stderr b/tests/ui/rust-2021/future-prelude-collision-shadow.stderr
index a8fcf43cd63a3..d9c0fa47eca02 100644
--- a/tests/ui/rust-2021/future-prelude-collision-shadow.stderr
+++ b/tests/ui/rust-2021/future-prelude-collision-shadow.stderr
@@ -12,7 +12,7 @@ LL +     use crate::m::TryIntoU32;
    |
 LL +     use std::convert::TryInto;
    |
-help: there is a method with a similar name
+help: there is a method `into` with a similar name
    |
 LL |         let _: u32 = 3u8.into().unwrap();
    |                          ~~~~
diff --git a/tests/ui/self/arbitrary_self_type_mut_difference.stderr b/tests/ui/self/arbitrary_self_type_mut_difference.stderr
index 2a7192a83f5b4..ffc61ee0d7838 100644
--- a/tests/ui/self/arbitrary_self_type_mut_difference.stderr
+++ b/tests/ui/self/arbitrary_self_type_mut_difference.stderr
@@ -9,7 +9,7 @@ note: method is available for `Pin<&mut S>`
    |
 LL |     fn x(self: Pin<&mut Self>) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: there is a method with a similar name
+help: there is a method `y` with a similar name
    |
 LL |     Pin::new(&S).y();
    |                  ~
@@ -25,7 +25,7 @@ note: method is available for `Pin<&S>`
    |
 LL |     fn y(self: Pin<&Self>) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^
-help: there is a method with a similar name
+help: there is a method `x` with a similar name
    |
 LL |     Pin::new(&mut S).x();
    |                      ~
diff --git a/tests/ui/suggestions/issue-109291.stderr b/tests/ui/suggestions/issue-109291.stderr
index 7a2821a069b62..a173bbbb4900c 100644
--- a/tests/ui/suggestions/issue-109291.stderr
+++ b/tests/ui/suggestions/issue-109291.stderr
@@ -10,7 +10,7 @@ note: if you're trying to build a new `Backtrace` consider using one of the foll
       Backtrace::disabled
       Backtrace::create
   --> $SRC_DIR/std/src/backtrace.rs:LL:COL
-help: there is an associated function with a similar name
+help: there is an associated function `force_capture` with a similar name
    |
 LL |     println!("Custom backtrace: {}", std::backtrace::Backtrace::force_capture());
    |                                                                 ~~~~~~~~~~~~~
diff --git a/tests/ui/suggestions/suggest-methods.stderr b/tests/ui/suggestions/suggest-methods.stderr
index 5115a07242691..5bacad8c6e89f 100644
--- a/tests/ui/suggestions/suggest-methods.stderr
+++ b/tests/ui/suggestions/suggest-methods.stderr
@@ -19,7 +19,7 @@ error[E0599]: no method named `is_emtpy` found for struct `String` in the curren
 LL |     let _ = s.is_emtpy();
    |               ^^^^^^^^
    |
-help: there is a method with a similar name
+help: there is a method `is_empty` with a similar name
    |
 LL |     let _ = s.is_empty();
    |               ~~~~~~~~
@@ -30,7 +30,7 @@ error[E0599]: no method named `count_eos` found for type `u32` in the current sc
 LL |     let _ = 63u32.count_eos();
    |                   ^^^^^^^^^
    |
-help: there is a method with a similar name
+help: there is a method `count_zeros` with a similar name
    |
 LL |     let _ = 63u32.count_zeros();
    |                   ~~~~~~~~~~~
@@ -41,7 +41,7 @@ error[E0599]: no method named `count_o` found for type `u32` in the current scop
 LL |     let _ = 63u32.count_o();
    |                   ^^^^^^^
    |
-help: there is a method with a similar name
+help: there is a method `count_ones` with a similar name
    |
 LL |     let _ = 63u32.count_ones();
    |                   ~~~~~~~~~~
diff --git a/tests/ui/suggestions/suggest-tryinto-edition-change.stderr b/tests/ui/suggestions/suggest-tryinto-edition-change.stderr
index a25a3f44ad2ca..db7c40101cdc2 100644
--- a/tests/ui/suggestions/suggest-tryinto-edition-change.stderr
+++ b/tests/ui/suggestions/suggest-tryinto-edition-change.stderr
@@ -62,7 +62,7 @@ help: trait `TryInto` which provides `try_into` is implemented but not in scope;
    |
 LL + use std::convert::TryInto;
    |
-help: there is a method with a similar name
+help: there is a method `into` with a similar name
    |
 LL |     let _i: i16 = 0_i32.into().unwrap();
    |                         ~~~~
diff --git a/tests/ui/traits/item-privacy.stderr b/tests/ui/traits/item-privacy.stderr
index 00d75b14227e5..d08bb4745bf57 100644
--- a/tests/ui/traits/item-privacy.stderr
+++ b/tests/ui/traits/item-privacy.stderr
@@ -12,7 +12,7 @@ help: trait `A` which provides `a` is implemented but not in scope; perhaps you
    |
 LL + use method::A;
    |
-help: there is a method with a similar name
+help: there is a method `b` with a similar name
    |
 LL |     S.b();
    |       ~
@@ -34,7 +34,7 @@ help: trait `B` which provides `b` is implemented but not in scope; perhaps you
    |
 LL + use method::B;
    |
-help: there is a method with a similar name
+help: there is a method `c` with a similar name
    |
 LL |     S.c();
    |       ~
@@ -111,7 +111,7 @@ help: trait `A` which provides `A` is implemented but not in scope; perhaps you
    |
 LL + use assoc_const::A;
    |
-help: there is an associated constant with a similar name
+help: there is an associated constant `B` with a similar name
    |
 LL |     S::B;
    |        ~
@@ -130,7 +130,7 @@ help: trait `B` which provides `B` is implemented but not in scope; perhaps you
    |
 LL + use assoc_const::B;
    |
-help: there is a method with a similar name
+help: there is a method `b` with a similar name
    |
 LL |     S::b;
    |        ~
diff --git a/tests/ui/traits/trait-upcasting/subtrait-method.stderr b/tests/ui/traits/trait-upcasting/subtrait-method.stderr
index f3eb86c7681e8..0408be6986bd7 100644
--- a/tests/ui/traits/trait-upcasting/subtrait-method.stderr
+++ b/tests/ui/traits/trait-upcasting/subtrait-method.stderr
@@ -10,7 +10,7 @@ note: `Baz` defines an item `c`, perhaps you need to implement it
    |
 LL | trait Baz: Bar {
    | ^^^^^^^^^^^^^^
-help: there is a method with a similar name
+help: there is a method `a` with a similar name
    |
 LL |     bar.a();
    |         ~
@@ -27,7 +27,7 @@ note: `Bar` defines an item `b`, perhaps you need to implement it
    |
 LL | trait Bar: Foo {
    | ^^^^^^^^^^^^^^
-help: there is a method with a similar name
+help: there is a method `a` with a similar name
    |
 LL |     foo.a();
    |         ~
@@ -44,7 +44,7 @@ note: `Baz` defines an item `c`, perhaps you need to implement it
    |
 LL | trait Baz: Bar {
    | ^^^^^^^^^^^^^^
-help: there is a method with a similar name
+help: there is a method `a` with a similar name
    |
 LL |     foo.a();
    |         ~
@@ -61,7 +61,7 @@ note: `Bar` defines an item `b`, perhaps you need to implement it
    |
 LL | trait Bar: Foo {
    | ^^^^^^^^^^^^^^
-help: there is a method with a similar name
+help: there is a method `a` with a similar name
    |
 LL |     foo.a();
    |         ~
@@ -78,7 +78,7 @@ note: `Baz` defines an item `c`, perhaps you need to implement it
    |
 LL | trait Baz: Bar {
    | ^^^^^^^^^^^^^^
-help: there is a method with a similar name
+help: there is a method `a` with a similar name
    |
 LL |     foo.a();
    |         ~

From 6139f994bc732c6a08d58f3c3ad7c4e9b8f602a1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 14 Feb 2024 19:20:56 +0000
Subject: [PATCH 37/58] fix test

---
 tests/ui/atomic-from-mut-not-available.stderr | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/ui/atomic-from-mut-not-available.stderr b/tests/ui/atomic-from-mut-not-available.stderr
index 0f37784be78f5..a4514524f48f5 100644
--- a/tests/ui/atomic-from-mut-not-available.stderr
+++ b/tests/ui/atomic-from-mut-not-available.stderr
@@ -7,7 +7,7 @@ LL |     core::sync::atomic::AtomicU64::from_mut(&mut 0u64);
 note: if you're trying to build a new `AtomicU64`, consider using `AtomicU64::new` which returns `AtomicU64`
   --> $SRC_DIR/core/src/sync/atomic.rs:LL:COL
    = note: this error originates in the macro `atomic_int` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: there is an associated function with a similar name
+help: there is an associated function `from` with a similar name
    |
 LL |     core::sync::atomic::AtomicU64::from(&mut 0u64);
    |                                    ~~~~

From 9a950a52342f5f09eb419c7d950f46c0d8064b21 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 14 Feb 2024 19:27:53 +0000
Subject: [PATCH 38/58] review comment: remove unnused return value

---
 .../rustc_hir_typeck/src/fn_ctxt/checks.rs    | 23 +++++++++++--------
 1 file changed, 13 insertions(+), 10 deletions(-)

diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 30b9749168ce6..ed26bfe94690d 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -563,8 +563,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         let suggest_confusable = |err: &mut Diagnostic| {
-            let call_name = call_ident?;
-            let callee_ty = callee_ty?;
+            let Some(call_name) = call_ident else {
+                return;
+            };
+            let Some(callee_ty) = callee_ty else {
+                return;
+            };
             let input_types: Vec<Ty<'_>> = provided_arg_tys.iter().map(|(ty, _)| *ty).collect();
             // Check for other methods in the following order
             //  - methods marked as `rustc_confusables` with the provided arguments
@@ -573,13 +577,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             //  - methods with short levenshtein distance
 
             // Look for commonly confusable method names considering arguments.
-            if let Some(name) = self.confusable_method_name(
+            if let Some(_name) = self.confusable_method_name(
                 err,
                 callee_ty.peel_refs(),
                 call_name,
                 Some(input_types.clone()),
             ) {
-                return Some(name);
+                return;
             }
             // Look for method names with short levenshtein distance, considering arguments.
             if let Some((assoc, fn_sig)) = similar_assoc(call_name)
@@ -595,13 +599,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     assoc.name,
                     Applicability::MaybeIncorrect,
                 );
-                return Some(assoc.name);
+                return;
             }
             // Look for commonly confusable method names disregarding arguments.
-            if let Some(name) =
+            if let Some(_name) =
                 self.confusable_method_name(err, callee_ty.peel_refs(), call_name, None)
             {
-                return Some(name);
+                return;
             }
             // Look for similarly named methods with levenshtein distance with the right
             // number of arguments.
@@ -615,7 +619,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         assoc.name,
                     ),
                 );
-                return Some(assoc.name);
+                return;
             }
             // Fallthrough: look for similarly named methods with levenshtein distance.
             if let Some((assoc, _)) = similar_assoc(call_name) {
@@ -627,9 +631,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         assoc.name,
                     ),
                 );
-                return Some(assoc.name);
+                return;
             }
-            None
         };
         // A "softer" version of the `demand_compatible`, which checks types without persisting them,
         // and treats error types differently

From 5233bc91da2f48f5bc79c688b5cfad846a8127da Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <n.nethercote@gmail.com>
Date: Wed, 14 Feb 2024 14:50:49 +1100
Subject: [PATCH 39/58] Add an `ErrorGuaranteed` to `ast::TyKind::Err`.

This makes it more like `hir::TyKind::Err`, and avoids a
`span_delayed_bug` call in `LoweringContext::lower_ty_direct`.

It also requires adding `ast::TyKind::Dummy`, now that
`ast::TyKind::Err` can't be used for that purpose in the absence of an
error emission.

There are a couple of cases that aren't as neat as I would have liked,
marked with `FIXME` comments.
---
 compiler/rustc_ast/src/ast.rs                 |  6 +++--
 compiler/rustc_ast/src/mut_visit.rs           |  9 +++++--
 compiler/rustc_ast/src/visit.rs               |  2 +-
 compiler/rustc_ast_lowering/src/lib.rs        |  3 ++-
 .../rustc_ast_passes/src/ast_validation.rs    |  3 ++-
 compiler/rustc_ast_pretty/src/pprust/state.rs |  7 ++++-
 compiler/rustc_expand/src/base.rs             |  9 ++++---
 .../rustc_parse/src/parser/diagnostics.rs     | 20 +++++++-------
 compiler/rustc_parse/src/parser/item.rs       | 26 +++++++++++++++----
 compiler/rustc_parse/src/parser/path.rs       |  7 ++---
 compiler/rustc_parse/src/parser/ty.rs         | 10 ++++---
 compiler/rustc_passes/src/hir_stats.rs        |  5 ++--
 .../clippy/clippy_utils/src/ast_utils.rs      |  2 +-
 src/tools/rustfmt/src/types.rs                |  2 +-
 14 files changed, 75 insertions(+), 36 deletions(-)

diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 098e2606a3be9..08fc8e3c6cca8 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2136,10 +2136,12 @@ pub enum TyKind {
     ImplicitSelf,
     /// A macro in the type position.
     MacCall(P<MacCall>),
-    /// Placeholder for a kind that has failed to be defined.
-    Err,
     /// Placeholder for a `va_list`.
     CVarArgs,
+    /// Sometimes we need a dummy value when no error has occurred.
+    Dummy,
+    /// Placeholder for a kind that has failed to be defined.
+    Err(ErrorGuaranteed),
 }
 
 impl TyKind {
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index d482ada170ee3..c42c41999732c 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -481,7 +481,12 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
     let Ty { id, kind, span, tokens } = ty.deref_mut();
     vis.visit_id(id);
     match kind {
-        TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err | TyKind::Never | TyKind::CVarArgs => {}
+        TyKind::Infer
+        | TyKind::ImplicitSelf
+        | TyKind::Err(_)
+        | TyKind::Dummy
+        | TyKind::Never
+        | TyKind::CVarArgs => {}
         TyKind::Slice(ty) => vis.visit_ty(ty),
         TyKind::Ptr(mt) => vis.visit_mt(mt),
         TyKind::Ref(lt, mt) => {
@@ -1649,7 +1654,7 @@ impl DummyAstNode for Ty {
     fn dummy() -> Self {
         Ty {
             id: DUMMY_NODE_ID,
-            kind: TyKind::Err,
+            kind: TyKind::Dummy,
             span: Default::default(),
             tokens: Default::default(),
         }
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 4aaaa0ba42457..83f6746bdeb23 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -447,7 +447,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
             walk_list!(visitor, visit_param_bound, bounds, BoundKind::Impl);
         }
         TyKind::Typeof(expression) => visitor.visit_anon_const(expression),
-        TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {}
+        TyKind::Infer | TyKind::ImplicitSelf | TyKind::Dummy | TyKind::Err(_) => {}
         TyKind::MacCall(mac) => visitor.visit_mac_call(mac),
         TyKind::Never | TyKind::CVarArgs => {}
         TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => {
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 6b5fc01424085..c1b7af94b02a0 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1285,7 +1285,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> {
         let kind = match &t.kind {
             TyKind::Infer => hir::TyKind::Infer,
-            TyKind::Err => hir::TyKind::Err(self.dcx().has_errors().unwrap()),
+            TyKind::Err(guar) => hir::TyKind::Err(*guar),
             // Lower the anonymous structs or unions in a nested lowering context.
             //
             // ```
@@ -1503,6 +1503,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 );
                 hir::TyKind::Err(guar)
             }
+            TyKind::Dummy => panic!("`TyKind::Dummy` should never be lowered"),
         };
 
         hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.lower_node_id(t.id) }
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index ebc5c17a4c4f2..fa0f532619611 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -881,7 +881,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                         &item.vis,
                         errors::VisibilityNotPermittedNote::TraitImpl,
                     );
-                    if let TyKind::Err = self_ty.kind {
+                    // njn: use Dummy here
+                    if let TyKind::Err(_) = self_ty.kind {
                         this.dcx().emit_err(errors::ObsoleteAuto { span: item.span });
                     }
                     if let (&Unsafe::Yes(span), &ImplPolarity::Negative(sp)) = (unsafety, polarity)
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index cda746894e865..480506272d2ba 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1048,11 +1048,16 @@ impl<'a> State<'a> {
             ast::TyKind::Infer => {
                 self.word("_");
             }
-            ast::TyKind::Err => {
+            ast::TyKind::Err(_) => {
                 self.popen();
                 self.word("/*ERROR*/");
                 self.pclose();
             }
+            ast::TyKind::Dummy => {
+                self.popen();
+                self.word("/*DUMMY*/");
+                self.pclose();
+            }
             ast::TyKind::ImplicitSelf => {
                 self.word("Self");
             }
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index cfeb31fc4c813..20cfc72f6d362 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -567,10 +567,13 @@ impl DummyResult {
     }
 
     /// A plain dummy type.
-    pub fn raw_ty(sp: Span, is_error: bool) -> P<ast::Ty> {
+    pub fn raw_ty(sp: Span) -> P<ast::Ty> {
+        // FIXME(nnethercote): you might expect `ast::TyKind::Dummy` to be used here, but some
+        // values produced here end up being lowered to HIR, which `ast::TyKind::Dummy` does not
+        // support, so we use an empty tuple instead.
         P(ast::Ty {
             id: ast::DUMMY_NODE_ID,
-            kind: if is_error { ast::TyKind::Err } else { ast::TyKind::Tup(ThinVec::new()) },
+            kind: ast::TyKind::Tup(ThinVec::new()),
             span: sp,
             tokens: None,
         })
@@ -611,7 +614,7 @@ impl MacResult for DummyResult {
     }
 
     fn make_ty(self: Box<DummyResult>) -> Option<P<ast::Ty>> {
-        Some(DummyResult::raw_ty(self.span, self.is_error))
+        Some(DummyResult::raw_ty(self.span))
     }
 
     fn make_arms(self: Box<DummyResult>) -> Option<SmallVec<[ast::Arm; 1]>> {
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 445d5b2ce790c..69518287f38ec 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -46,14 +46,14 @@ use std::ops::{Deref, DerefMut};
 use thin_vec::{thin_vec, ThinVec};
 
 /// Creates a placeholder argument.
-pub(super) fn dummy_arg(ident: Ident) -> Param {
+pub(super) fn dummy_arg(ident: Ident, guar: ErrorGuaranteed) -> Param {
     let pat = P(Pat {
         id: ast::DUMMY_NODE_ID,
         kind: PatKind::Ident(BindingAnnotation::NONE, ident, None),
         span: ident.span,
         tokens: None,
     });
-    let ty = Ty { kind: TyKind::Err, span: ident.span, id: ast::DUMMY_NODE_ID, tokens: None };
+    let ty = Ty { kind: TyKind::Err(guar), span: ident.span, id: ast::DUMMY_NODE_ID, tokens: None };
     Param {
         attrs: AttrVec::default(),
         id: ast::DUMMY_NODE_ID,
@@ -1540,14 +1540,14 @@ impl<'a> Parser<'a> {
     pub(super) fn maybe_recover_from_question_mark(&mut self, ty: P<Ty>) -> P<Ty> {
         if self.token == token::Question {
             self.bump();
-            self.dcx().emit_err(QuestionMarkInType {
+            let guar = self.dcx().emit_err(QuestionMarkInType {
                 span: self.prev_token.span,
                 sugg: QuestionMarkInTypeSugg {
                     left: ty.span.shrink_to_lo(),
                     right: self.prev_token.span,
                 },
             });
-            self.mk_ty(ty.span.to(self.prev_token.span), TyKind::Err)
+            self.mk_ty(ty.span.to(self.prev_token.span), TyKind::Err(guar))
         } else {
             ty
         }
@@ -2304,8 +2304,8 @@ impl<'a> Parser<'a> {
 
     pub(super) fn recover_bad_self_param(&mut self, mut param: Param) -> PResult<'a, Param> {
         let span = param.pat.span;
-        param.ty.kind = TyKind::Err;
-        self.dcx().emit_err(SelfParamNotFirst { span });
+        let guar = self.dcx().emit_err(SelfParamNotFirst { span });
+        param.ty.kind = TyKind::Err(guar);
         Ok(param)
     }
 
@@ -2437,7 +2437,7 @@ impl<'a> Parser<'a> {
     pub(super) fn deduplicate_recovered_params_names(&self, fn_inputs: &mut ThinVec<Param>) {
         let mut seen_inputs = FxHashSet::default();
         for input in fn_inputs.iter_mut() {
-            let opt_ident = if let (PatKind::Ident(_, ident, _), TyKind::Err) =
+            let opt_ident = if let (PatKind::Ident(_, ident, _), TyKind::Err(_)) =
                 (&input.pat.kind, &input.ty.kind)
             {
                 Some(*ident)
@@ -2644,8 +2644,10 @@ impl<'a> Parser<'a> {
                         "::",
                         Applicability::MaybeIncorrect,
                     );
-                    err.emit();
-                    return Ok(GenericArg::Type(self.mk_ty(start.to(expr.span), TyKind::Err)));
+                    let guar = err.emit();
+                    return Ok(GenericArg::Type(
+                        self.mk_ty(start.to(expr.span), TyKind::Err(guar)),
+                    ));
                 } else if token::Comma == self.token.kind || self.token.kind.should_end_const_arg()
                 {
                     // Avoid the following output by checking that we consumed a full const arg:
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 8050b34956ce9..a0605b8a44c3a 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -591,7 +591,23 @@ impl<'a> Parser<'a> {
         let ty_second = if self.token == token::DotDot {
             // We need to report this error after `cfg` expansion for compatibility reasons
             self.bump(); // `..`, do not add it to expected tokens
-            Some(self.mk_ty(self.prev_token.span, TyKind::Err))
+
+            // FIXME(nnethercote): AST validation later detects this
+            // `TyKind::Err` and emits an errors. So why the unchecked
+            // ErrorGuaranteed?
+            // - A `span_delayed_bug` doesn't work here, because rustfmt can
+            //   hit this path but then not hit the follow-up path in the AST
+            //   validator that issues the error, which results in ICEs.
+            // - `TyKind::Dummy` doesn't work, because it ends up reaching HIR
+            //   lowering, which results in ICEs. Changing `TyKind::Dummy` to
+            //   `TyKind::Err` during AST validation might fix that, but that's
+            //   not possible because AST validation doesn't allow mutability.
+            //
+            // #121072 will hopefully remove all this special handling of the
+            // obsolete `impl Trait for ..` and then this can go away.
+            #[allow(deprecated)]
+            let guar = rustc_errors::ErrorGuaranteed::unchecked_error_guaranteed();
+            Some(self.mk_ty(self.prev_token.span, TyKind::Err(guar)))
         } else if has_for || self.token.can_begin_type() {
             Some(self.parse_ty()?)
         } else {
@@ -2628,13 +2644,13 @@ impl<'a> Parser<'a> {
             p.recover_diff_marker();
             let snapshot = p.create_snapshot_for_diagnostic();
             let param = p.parse_param_general(req_name, first_param).or_else(|e| {
-                e.emit();
+                let guar = e.emit();
                 let lo = p.prev_token.span;
                 p.restore_snapshot(snapshot);
                 // Skip every token until next possible arg or end.
                 p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(Delimiter::Parenthesis)]);
                 // Create a placeholder argument for proper arg count (issue #34264).
-                Ok(dummy_arg(Ident::new(kw::Empty, lo.to(p.prev_token.span))))
+                Ok(dummy_arg(Ident::new(kw::Empty, lo.to(p.prev_token.span)), guar))
             });
             // ...now that we've parsed the first argument, `self` is no longer allowed.
             first_param = false;
@@ -2671,8 +2687,8 @@ impl<'a> Parser<'a> {
                     return if let Some(ident) =
                         this.parameter_without_type(&mut err, pat, is_name_required, first_param)
                     {
-                        err.emit();
-                        Ok((dummy_arg(ident), TrailingToken::None))
+                        let guar = err.emit();
+                        Ok((dummy_arg(ident, guar), TrailingToken::None))
                     } else {
                         Err(err)
                     };
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index e7cad74b4dd14..681039999a652 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -678,8 +678,9 @@ impl<'a> Parser<'a> {
                 c.into()
             }
             Some(GenericArg::Lifetime(lt)) => {
-                self.dcx().emit_err(errors::AssocLifetime { span, lifetime: lt.ident.span });
-                self.mk_ty(span, ast::TyKind::Err).into()
+                let guar =
+                    self.dcx().emit_err(errors::AssocLifetime { span, lifetime: lt.ident.span });
+                self.mk_ty(span, ast::TyKind::Err(guar)).into()
             }
             None => {
                 let after_eq = eq.shrink_to_hi();
@@ -779,7 +780,7 @@ impl<'a> Parser<'a> {
                     // type to determine if error recovery has occurred and if the input is not a
                     // syntactically valid type after all.
                     if let ast::TyKind::Slice(inner_ty) | ast::TyKind::Array(inner_ty, _) = &ty.kind
-                        && let ast::TyKind::Err = inner_ty.kind
+                        && let ast::TyKind::Err(_) = inner_ty.kind
                         && let Some(snapshot) = snapshot
                         && let Some(expr) =
                             self.recover_unbraced_const_arg_that_can_begin_ty(snapshot)
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 157fb9e505af7..f79f2a813b223 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -346,8 +346,10 @@ impl<'a> Parser<'a> {
                 AllowCVariadic::No => {
                     // FIXME(Centril): Should we just allow `...` syntactically
                     // anywhere in a type and use semantic restrictions instead?
-                    self.dcx().emit_err(NestedCVariadicType { span: lo.to(self.prev_token.span) });
-                    TyKind::Err
+                    let guar = self
+                        .dcx()
+                        .emit_err(NestedCVariadicType { span: lo.to(self.prev_token.span) });
+                    TyKind::Err(guar)
                 }
             }
         } else {
@@ -493,8 +495,8 @@ impl<'a> Parser<'a> {
             {
                 // Recover from `[LIT; EXPR]` and `[LIT]`
                 self.bump();
-                err.emit();
-                self.mk_ty(self.prev_token.span, TyKind::Err)
+                let guar = err.emit();
+                self.mk_ty(self.prev_token.span, TyKind::Err(guar))
             }
             Err(err) => return Err(err),
         };
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index d02e86dd45697..96429bb778882 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -616,8 +616,9 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
                 Infer,
                 ImplicitSelf,
                 MacCall,
-                Err,
-                CVarArgs
+                CVarArgs,
+                Dummy,
+                Err
             ]
         );
 
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index adc35bd82ae39..0467a8a65709a 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -690,7 +690,7 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool {
     match (&l.kind, &r.kind) {
         (Paren(l), _) => eq_ty(l, r),
         (_, Paren(r)) => eq_ty(l, r),
-        (Never, Never) | (Infer, Infer) | (ImplicitSelf, ImplicitSelf) | (Err, Err) | (CVarArgs, CVarArgs) => true,
+        (Never, Never) | (Infer, Infer) | (ImplicitSelf, ImplicitSelf) | (Err(_), Err(_)) | (CVarArgs, CVarArgs) => true,
         (Slice(l), Slice(r)) => eq_ty(l, r),
         (Array(le, ls), Array(re, rs)) => eq_ty(le, re) && eq_expr(&ls.value, &rs.value),
         (Ptr(l), Ptr(r)) => l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty),
diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs
index 4cd8e6a703e53..7f220a456a8ee 100644
--- a/src/tools/rustfmt/src/types.rs
+++ b/src/tools/rustfmt/src/types.rs
@@ -859,7 +859,7 @@ impl Rewrite for ast::Ty {
                 })
             }
             ast::TyKind::CVarArgs => Some("...".to_owned()),
-            ast::TyKind::Err => Some(context.snippet(self.span).to_owned()),
+            ast::TyKind::Dummy | ast::TyKind::Err(_) => Some(context.snippet(self.span).to_owned()),
             ast::TyKind::Typeof(ref anon_const) => rewrite_call(
                 context,
                 "typeof",

From 746a58d4359786e4aebb372a30829706fa5a968f Mon Sep 17 00:00:00 2001
From: Markus Reiter <me@reitermark.us>
Date: Mon, 29 Jan 2024 23:59:09 +0100
Subject: [PATCH 40/58] Use generic `NonZero` internally.

---
 compiler/rustc_attr/src/builtin.rs            |   6 +-
 compiler/rustc_attr/src/lib.rs                |   1 +
 .../src/interpret/validity.rs                 |   4 +-
 .../rustc_const_eval/src/interpret/visitor.rs |   4 +-
 compiler/rustc_const_eval/src/lib.rs          |   1 +
 compiler/rustc_data_structures/src/lib.rs     |   1 +
 .../src/stable_hasher.rs                      |   5 +-
 .../src/sync/worker_local.rs                  |   6 +-
 .../src/tagged_ptr/copy.rs                    |   9 +-
 compiler/rustc_errors/src/diagnostic_impls.rs |   2 +-
 compiler/rustc_errors/src/lib.rs              |   5 +-
 compiler/rustc_feature/src/lib.rs             |  17 +-
 compiler/rustc_hir_analysis/src/check/mod.rs  |   4 +-
 compiler/rustc_hir_analysis/src/lib.rs        |   1 +
 compiler/rustc_interface/src/lib.rs           |   1 +
 compiler/rustc_interface/src/tests.rs         |   4 +-
 compiler/rustc_interface/src/util.rs          |   2 +-
 compiler/rustc_lint/src/lib.rs                |   1 +
 compiler/rustc_lint/src/lints.rs              |   5 +-
 compiler/rustc_metadata/src/lib.rs            |   1 +
 compiler/rustc_metadata/src/rmeta/decoder.rs  |  14 +-
 compiler/rustc_metadata/src/rmeta/encoder.rs  |   8 +-
 compiler/rustc_metadata/src/rmeta/mod.rs      |  20 +-
 compiler/rustc_metadata/src/rmeta/table.rs    |   6 +-
 compiler/rustc_middle/src/lib.rs              |   1 +
 compiler/rustc_middle/src/middle/stability.rs |   8 +-
 .../rustc_middle/src/mir/interpret/mod.rs     |   8 +-
 .../rustc_middle/src/mir/interpret/pointer.rs |   6 +-
 compiler/rustc_middle/src/ty/consts/int.rs    |  27 +-
 compiler/rustc_middle/src/ty/generic_args.rs  |   4 +-
 compiler/rustc_middle/src/ty/layout.rs        |   4 +-
 compiler/rustc_middle/src/ty/mod.rs           |   4 +-
 compiler/rustc_passes/src/lib.rs              |   1 +
 compiler/rustc_passes/src/stability.rs        |   4 +-
 compiler/rustc_query_impl/src/lib.rs          |   1 +
 compiler/rustc_query_impl/src/plumbing.rs     |   4 +-
 compiler/rustc_query_system/src/lib.rs        |   1 +
 compiler/rustc_query_system/src/query/job.rs  |   4 +-
 compiler/rustc_serialize/src/lib.rs           |   1 +
 compiler/rustc_serialize/src/serialize.rs     |   7 +-
 compiler/rustc_session/src/config.rs          |   4 +-
 compiler/rustc_session/src/errors.rs          |   4 +-
 compiler/rustc_session/src/lib.rs             |   1 +
 compiler/rustc_session/src/options.rs         |  13 +-
 .../alloc/src/collections/binary_heap/mod.rs  |  10 +-
 .../src/collections/vec_deque/into_iter.rs    |  10 +-
 .../alloc/src/collections/vec_deque/iter.rs   |   6 +-
 .../src/collections/vec_deque/iter_mut.rs     |   6 +-
 library/alloc/src/lib.rs                      |   1 +
 library/alloc/src/vec/in_place_collect.rs     |   6 +-
 library/alloc/src/vec/into_iter.rs            |  14 +-
 library/alloc/tests/lib.rs                    |   1 +
 library/alloc/tests/vec.rs                    |   8 +-
 library/alloc/tests/vec_deque.rs              |   6 +-
 library/core/src/array/iter.rs                |  10 +-
 library/core/src/ascii.rs                     |   6 +-
 library/core/src/char/mod.rs                  |   6 +-
 library/core/src/cmp/bytewise.rs              |   4 +-
 library/core/src/escape.rs                    |   6 +-
 .../core/src/iter/adapters/array_chunks.rs    |   8 +-
 .../core/src/iter/adapters/by_ref_sized.rs    |   6 +-
 library/core/src/iter/adapters/chain.rs       |  10 +-
 library/core/src/iter/adapters/cloned.rs      |   6 +-
 library/core/src/iter/adapters/copied.rs      |  10 +-
 library/core/src/iter/adapters/cycle.rs       |   6 +-
 library/core/src/iter/adapters/enumerate.rs   |  10 +-
 library/core/src/iter/adapters/filter.rs      |   6 +-
 library/core/src/iter/adapters/filter_map.rs  |   6 +-
 library/core/src/iter/adapters/flatten.rs     |  46 +--
 library/core/src/iter/adapters/inspect.rs     |   6 +-
 library/core/src/iter/adapters/map.rs         |   6 +-
 library/core/src/iter/adapters/map_while.rs   |   6 +-
 library/core/src/iter/adapters/mod.rs         |   6 +-
 library/core/src/iter/adapters/rev.rs         |   6 +-
 library/core/src/iter/adapters/scan.rs        |   6 +-
 library/core/src/iter/adapters/skip.rs        |  14 +-
 library/core/src/iter/adapters/skip_while.rs  |   6 +-
 library/core/src/iter/adapters/take.rs        |  14 +-
 library/core/src/iter/adapters/take_while.rs  |   6 +-
 library/core/src/iter/adapters/zip.rs         |   6 +-
 library/core/src/iter/range.rs                |  26 +-
 library/core/src/iter/sources/repeat.rs       |   6 +-
 library/core/src/iter/sources/repeat_n.rs     |   8 +-
 library/core/src/iter/traits/double_ended.rs  |  10 +-
 library/core/src/iter/traits/iterator.rs      |  10 +-
 library/core/src/iter/traits/marker.rs        |   6 +-
 library/core/src/num/nonzero.rs               |  10 +-
 library/core/src/ops/index_range.rs           |  10 +-
 library/core/src/ptr/alignment.rs             |   4 +-
 library/core/src/ptr/non_null.rs              |   4 +-
 library/core/src/slice/iter.rs                |   2 +-
 library/core/src/slice/iter/macros.rs         |   8 +-
 library/core/src/slice/mod.rs                 |   4 +-
 library/core/src/str/iter.rs                  |   4 +-
 library/core/tests/array.rs                   |  10 +-
 library/core/tests/iter/adapters/chain.rs     |  17 +-
 library/core/tests/iter/adapters/enumerate.rs |   4 +-
 library/core/tests/iter/adapters/flatten.rs   |   6 +-
 library/core/tests/iter/adapters/skip.rs      |   8 +-
 library/core/tests/iter/adapters/take.rs      |  16 +-
 library/core/tests/iter/range.rs              |   4 +-
 library/core/tests/iter/traits/iterator.rs    |  27 +-
 library/core/tests/lib.rs                     |   1 +
 library/core/tests/nonzero.rs                 | 265 +++++++++---------
 library/core/tests/ptr.rs                     |   6 +-
 library/core/tests/result.rs                  |  13 +-
 library/core/tests/slice.rs                   |   6 +-
 library/proc_macro/src/bridge/handle.rs       |   6 +-
 library/proc_macro/src/bridge/rpc.rs          |   6 +-
 library/proc_macro/src/bridge/symbol.rs       |   8 +-
 library/proc_macro/src/lib.rs                 |   1 +
 library/std/src/sys/pal/hermit/thread.rs      |   6 +-
 library/std/src/sys/pal/itron/thread.rs       |   3 +-
 library/std/src/sys/pal/sgx/abi/tls/mod.rs    |   8 +-
 .../std/src/sys/pal/sgx/abi/usercalls/raw.rs  |  17 +-
 library/std/src/sys/pal/sgx/rwlock.rs         |  14 +-
 library/std/src/sys/pal/sgx/thread.rs         |   4 +-
 library/std/src/sys/pal/sgx/waitqueue/mod.rs  |   6 +-
 library/std/src/sys/pal/teeos/thread.rs       |   4 +-
 library/std/src/sys/pal/uefi/thread.rs        |   6 +-
 .../pal/unix/process/process_common/tests.rs  |   4 +-
 .../sys/pal/unix/process/process_fuchsia.rs   |   8 +-
 .../src/sys/pal/unix/process/process_unix.rs  |   4 +-
 .../pal/unix/process/process_unsupported.rs   |   4 +-
 .../sys/pal/unix/process/process_vxworks.rs   |   4 +-
 library/std/src/sys/pal/unix/thread.rs        |  18 +-
 .../std/src/sys/pal/unsupported/process.rs    |   4 +-
 library/std/src/sys/pal/unsupported/thread.rs |   4 +-
 library/std/src/sys/pal/wasi/thread.rs        |   4 +-
 .../std/src/sys/pal/wasm/atomics/thread.rs    |   4 +-
 library/std/src/sys/pal/windows/args.rs       |  16 +-
 library/std/src/sys/pal/windows/process.rs    |   4 +-
 library/std/src/sys/pal/windows/thread.rs     |   6 +-
 library/std/src/sys/pal/xous/thread.rs        |   6 +-
 library/std/src/sys_common/wstr.rs            |  13 +-
 library/std/src/thread/mod.rs                 |   9 +-
 src/tools/miri/src/bin/miri.rs                |   5 +-
 src/tools/miri/src/borrow_tracker/mod.rs      |  14 +-
 src/tools/miri/src/concurrency/init_once.rs   |   1 -
 src/tools/miri/src/concurrency/sync.rs        |   9 +-
 src/tools/miri/src/diagnostics.rs             |   4 +-
 src/tools/miri/src/helpers.rs                 |   4 +-
 src/tools/miri/src/lib.rs                     |   1 +
 src/tools/miri/src/shims/foreign_items.rs     |   2 +-
 144 files changed, 658 insertions(+), 609 deletions(-)

diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index a3783db5f80d6..f414ff746bb82 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -13,7 +13,7 @@ use rustc_session::parse::feature_err;
 use rustc_session::{RustcVersion, Session};
 use rustc_span::hygiene::Transparency;
 use rustc_span::{symbol::sym, symbol::Symbol, Span};
-use std::num::NonZeroU32;
+use std::num::NonZero;
 
 use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
 
@@ -113,7 +113,7 @@ pub enum StabilityLevel {
         /// Reason for the current stability level.
         reason: UnstableReason,
         /// Relevant `rust-lang/rust` issue.
-        issue: Option<NonZeroU32>,
+        issue: Option<NonZero<u32>>,
         is_soft: bool,
         /// If part of a feature is stabilized and a new feature is added for the remaining parts,
         /// then the `implied_by` attribute is used to indicate which now-stable feature previously
@@ -442,7 +442,7 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
                 // is a name/value pair string literal.
                 issue_num = match issue.unwrap().as_str() {
                     "none" => None,
-                    issue => match issue.parse::<NonZeroU32>() {
+                    issue => match issue.parse::<NonZero<u32>>() {
                         Ok(num) => Some(num),
                         Err(err) => {
                             sess.dcx().emit_err(
diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs
index dd87a5c4dc384..fada69c4e6df1 100644
--- a/compiler/rustc_attr/src/lib.rs
+++ b/compiler/rustc_attr/src/lib.rs
@@ -7,6 +7,7 @@
 #![allow(internal_features)]
 #![feature(rustdoc_internals)]
 #![doc(rust_logo)]
+#![feature(generic_nonzero)]
 #![feature(let_chains)]
 
 #[macro_use]
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index eb9f3fee1650a..d9edcf6ea9700 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -5,7 +5,7 @@
 //! to be const-safe.
 
 use std::fmt::Write;
-use std::num::NonZeroUsize;
+use std::num::NonZero;
 
 use either::{Left, Right};
 
@@ -782,7 +782,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
     fn visit_union(
         &mut self,
         op: &OpTy<'tcx, M::Provenance>,
-        _fields: NonZeroUsize,
+        _fields: NonZero<usize>,
     ) -> InterpResult<'tcx> {
         // Special check for CTFE validation, preventing `UnsafeCell` inside unions in immutable memory.
         if self.ctfe_mode.is_some_and(|c| !c.allow_immutable_unsafe_cell()) {
diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs
index 340a496a68990..b200ecbf73af5 100644
--- a/compiler/rustc_const_eval/src/interpret/visitor.rs
+++ b/compiler/rustc_const_eval/src/interpret/visitor.rs
@@ -7,7 +7,7 @@ use rustc_middle::ty;
 use rustc_target::abi::FieldIdx;
 use rustc_target::abi::{FieldsShape, VariantIdx, Variants};
 
-use std::num::NonZeroUsize;
+use std::num::NonZero;
 
 use super::{InterpCx, MPlaceTy, Machine, Projectable};
 
@@ -43,7 +43,7 @@ pub trait ValueVisitor<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized {
     }
     /// Visits the given value as a union. No automatic recursion can happen here.
     #[inline(always)]
-    fn visit_union(&mut self, _v: &Self::V, _fields: NonZeroUsize) -> InterpResult<'tcx> {
+    fn visit_union(&mut self, _v: &Self::V, _fields: NonZero<usize>) -> InterpResult<'tcx> {
         Ok(())
     }
     /// Visits the given value as the pointer of a `Box`. There is nothing to recurse into.
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index 839cfd8d85acf..fd8be45e25d52 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -11,6 +11,7 @@ Rust MIR: a lowered representation of Rust.
 #![feature(assert_matches)]
 #![feature(box_patterns)]
 #![feature(decl_macro)]
+#![feature(generic_nonzero)]
 #![feature(let_chains)]
 #![feature(slice_ptr_get)]
 #![feature(never_type)]
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 2b799d6f5d3b8..b82a9a909e6d0 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -20,6 +20,7 @@
 #![feature(cfg_match)]
 #![feature(core_intrinsics)]
 #![feature(extend_one)]
+#![feature(generic_nonzero)]
 #![feature(hash_raw_entry)]
 #![feature(hasher_prefixfree_extras)]
 #![feature(lazy_cell)]
diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs
index 52304c72a2f8d..15691804a94b2 100644
--- a/compiler/rustc_data_structures/src/stable_hasher.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher.rs
@@ -6,6 +6,7 @@ use std::fmt;
 use std::hash::{BuildHasher, Hash, Hasher};
 use std::marker::PhantomData;
 use std::mem;
+use std::num::NonZero;
 
 #[cfg(test)]
 mod tests;
@@ -338,14 +339,14 @@ impl<CTX, T> HashStable<CTX> for PhantomData<T> {
     fn hash_stable(&self, _ctx: &mut CTX, _hasher: &mut StableHasher) {}
 }
 
-impl<CTX> HashStable<CTX> for ::std::num::NonZeroU32 {
+impl<CTX> HashStable<CTX> for NonZero<u32> {
     #[inline]
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
         self.get().hash_stable(ctx, hasher)
     }
 }
 
-impl<CTX> HashStable<CTX> for ::std::num::NonZeroUsize {
+impl<CTX> HashStable<CTX> for NonZero<usize> {
     #[inline]
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
         self.get().hash_stable(ctx, hasher)
diff --git a/compiler/rustc_data_structures/src/sync/worker_local.rs b/compiler/rustc_data_structures/src/sync/worker_local.rs
index b34d3dd904400..50a614a1b0279 100644
--- a/compiler/rustc_data_structures/src/sync/worker_local.rs
+++ b/compiler/rustc_data_structures/src/sync/worker_local.rs
@@ -1,7 +1,7 @@
 use parking_lot::Mutex;
 use std::cell::Cell;
 use std::cell::OnceCell;
-use std::num::NonZeroUsize;
+use std::num::NonZero;
 use std::ops::Deref;
 use std::ptr;
 use std::sync::Arc;
@@ -31,7 +31,7 @@ impl RegistryId {
 }
 
 struct RegistryData {
-    thread_limit: NonZeroUsize,
+    thread_limit: NonZero<usize>,
     threads: Mutex<usize>,
 }
 
@@ -61,7 +61,7 @@ thread_local! {
 
 impl Registry {
     /// Creates a registry which can hold up to `thread_limit` threads.
-    pub fn new(thread_limit: NonZeroUsize) -> Self {
+    pub fn new(thread_limit: NonZero<usize>) -> Self {
         Registry(Arc::new(RegistryData { thread_limit, threads: Mutex::new(0) }))
     }
 
diff --git a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs
index e893a2c781346..8af4042ad875b 100644
--- a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs
+++ b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs
@@ -4,7 +4,7 @@ use std::fmt;
 use std::hash::{Hash, Hasher};
 use std::marker::PhantomData;
 use std::mem::ManuallyDrop;
-use std::num::NonZeroUsize;
+use std::num::NonZero;
 use std::ops::{Deref, DerefMut};
 use std::ptr::NonNull;
 
@@ -134,7 +134,7 @@ where
 
         ptr.map_addr(|addr| {
             // Safety:
-            // - The pointer is `NonNull` => it's address is `NonZeroUsize`
+            // - The pointer is `NonNull` => it's address is `NonZero<usize>`
             // - `P::BITS` least significant bits are always zero (`Pointer` contract)
             // - `T::BITS <= P::BITS` (from `Self::ASSERTION`)
             //
@@ -143,14 +143,15 @@ where
             // `{non_zero} | packed_tag` can't make the value zero.
 
             let packed = (addr.get() >> T::BITS) | packed_tag;
-            unsafe { NonZeroUsize::new_unchecked(packed) }
+            unsafe { NonZero::<usize>::new_unchecked(packed) }
         })
     }
 
     /// Retrieves the original raw pointer from `self.packed`.
     #[inline]
     pub(super) fn pointer_raw(&self) -> NonNull<P::Target> {
-        self.packed.map_addr(|addr| unsafe { NonZeroUsize::new_unchecked(addr.get() << T::BITS) })
+        self.packed
+            .map_addr(|addr| unsafe { NonZero::<usize>::new_unchecked(addr.get() << T::BITS) })
     }
 
     /// This provides a reference to the `P` pointer itself, rather than the
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index e936ebc7185fa..eaf75539f59b9 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -79,7 +79,7 @@ into_diagnostic_arg_using_display!(
     ast::ParamKindOrd,
     std::io::Error,
     Box<dyn std::error::Error>,
-    std::num::NonZeroU32,
+    std::num::NonZero<u32>,
     hir::Target,
     Edition,
     Ident,
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index d876f28040da1..9f8aee614d74e 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -16,6 +16,7 @@
 #![feature(box_patterns)]
 #![feature(error_reporter)]
 #![feature(extract_if)]
+#![feature(generic_nonzero)]
 #![feature(let_chains)]
 #![feature(negative_impls)]
 #![feature(never_type)]
@@ -77,7 +78,7 @@ use std::error::Report;
 use std::fmt;
 use std::hash::Hash;
 use std::io::Write;
-use std::num::NonZeroUsize;
+use std::num::NonZero;
 use std::ops::DerefMut;
 use std::panic;
 use std::path::{Path, PathBuf};
@@ -545,7 +546,7 @@ pub struct DiagCtxtFlags {
     pub can_emit_warnings: bool,
     /// If Some, the Nth error-level diagnostic is upgraded to bug-level.
     /// (rustc: see `-Z treat-err-as-bug`)
-    pub treat_err_as_bug: Option<NonZeroUsize>,
+    pub treat_err_as_bug: Option<NonZero<usize>>,
     /// Eagerly emit delayed bugs as errors, so that the compiler debugger may
     /// see all of the errors being emitted at once.
     pub eagerly_emit_delayed_bugs: bool,
diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs
index f1c8f2e2dde5c..02ce5d3534c43 100644
--- a/compiler/rustc_feature/src/lib.rs
+++ b/compiler/rustc_feature/src/lib.rs
@@ -12,6 +12,7 @@
 //! symbol to the `accepted` or `removed` modules respectively.
 
 #![allow(internal_features)]
+#![feature(generic_nonzero)]
 #![feature(rustdoc_internals)]
 #![doc(rust_logo)]
 #![feature(lazy_cell)]
@@ -25,13 +26,13 @@ mod unstable;
 mod tests;
 
 use rustc_span::symbol::Symbol;
-use std::num::NonZeroU32;
+use std::num::NonZero;
 
 #[derive(Debug, Clone)]
 pub struct Feature {
     pub name: Symbol,
     pub since: &'static str,
-    issue: Option<NonZeroU32>,
+    issue: Option<NonZero<u32>>,
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -85,7 +86,7 @@ impl UnstableFeatures {
     }
 }
 
-fn find_lang_feature_issue(feature: Symbol) -> Option<NonZeroU32> {
+fn find_lang_feature_issue(feature: Symbol) -> Option<NonZero<u32>> {
     // Search in all the feature lists.
     if let Some(f) = UNSTABLE_FEATURES.iter().find(|f| f.feature.name == feature) {
         return f.feature.issue;
@@ -99,21 +100,21 @@ fn find_lang_feature_issue(feature: Symbol) -> Option<NonZeroU32> {
     panic!("feature `{feature}` is not declared anywhere");
 }
 
-const fn to_nonzero(n: Option<u32>) -> Option<NonZeroU32> {
-    // Can be replaced with `n.and_then(NonZeroU32::new)` if that is ever usable
+const fn to_nonzero(n: Option<u32>) -> Option<NonZero<u32>> {
+    // Can be replaced with `n.and_then(NonZero::new)` if that is ever usable
     // in const context. Requires https://github.com/rust-lang/rfcs/pull/2632.
     match n {
         None => None,
-        Some(n) => NonZeroU32::new(n),
+        Some(n) => NonZero::<u32>::new(n),
     }
 }
 
 pub enum GateIssue {
     Language,
-    Library(Option<NonZeroU32>),
+    Library(Option<NonZero<u32>>),
 }
 
-pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZeroU32> {
+pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZero<u32>> {
     match issue {
         GateIssue::Language => find_lang_feature_issue(feature),
         GateIssue::Library(lib) => lib,
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 2f8e065df3303..6b064b36cf19b 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -74,7 +74,7 @@ pub mod wfcheck;
 
 pub use check::check_abi;
 
-use std::num::NonZeroU32;
+use std::num::NonZero;
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::ErrorGuaranteed;
@@ -270,7 +270,7 @@ fn default_body_is_unstable(
     item_did: DefId,
     feature: Symbol,
     reason: Option<Symbol>,
-    issue: Option<NonZeroU32>,
+    issue: Option<NonZero<u32>>,
 ) {
     let missing_item_name = tcx.associated_item(item_did).name;
     let (mut some_note, mut none_note, mut reason_str) = (false, false, String::new());
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 1cd77050217a2..d507fb39e192b 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -63,6 +63,7 @@ This API is completely unstable and subject to change.
 #![feature(rustdoc_internals)]
 #![allow(internal_features)]
 #![feature(control_flow_enum)]
+#![feature(generic_nonzero)]
 #![feature(if_let_guard)]
 #![feature(is_sorted)]
 #![feature(iter_intersperse)]
diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs
index 7d69e49b209f5..24c2e29053488 100644
--- a/compiler/rustc_interface/src/lib.rs
+++ b/compiler/rustc_interface/src/lib.rs
@@ -1,5 +1,6 @@
 #![feature(decl_macro)]
 #![feature(error_iter)]
+#![feature(generic_nonzero)]
 #![feature(lazy_cell)]
 #![feature(let_chains)]
 #![feature(thread_spawn_unchecked)]
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index bfc4fc07d4cc7..a9c614df7adef 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -20,7 +20,7 @@ use rustc_span::{FileName, SourceFileHashAlgorithm};
 use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, RelocModel};
 use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel};
 use std::collections::{BTreeMap, BTreeSet};
-use std::num::NonZeroUsize;
+use std::num::NonZero;
 use std::path::{Path, PathBuf};
 use std::sync::Arc;
 
@@ -827,7 +827,7 @@ fn test_unstable_options_tracking_hash() {
     tracked!(tls_model, Some(TlsModel::GeneralDynamic));
     tracked!(translate_remapped_path_to_local_path, false);
     tracked!(trap_unreachable, Some(false));
-    tracked!(treat_err_as_bug, NonZeroUsize::new(1));
+    tracked!(treat_err_as_bug, NonZero::<usize>::new(1));
     tracked!(tune_cpu, Some(String::from("abc")));
     tracked!(uninit_const_chunk_threshold, 123);
     tracked!(unleash_the_miri_inside_of_you, true);
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 76b9e8de75fb0..00cf84138bac6 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -107,7 +107,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
     use rustc_query_impl::QueryCtxt;
     use rustc_query_system::query::{deadlock, QueryContext};
 
-    let registry = sync::Registry::new(std::num::NonZeroUsize::new(threads).unwrap());
+    let registry = sync::Registry::new(std::num::NonZero::<usize>::new(threads).unwrap());
 
     if !sync::is_dyn_thread_safe() {
         return run_in_thread_with_globals(edition, || {
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 5f769e9ad8a5b..85f9d3bd63ec7 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -31,6 +31,7 @@
 #![feature(array_windows)]
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
+#![feature(generic_nonzero)]
 #![feature(if_let_guard)]
 #![feature(iter_order_by)]
 #![feature(let_chains)]
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 7445e2e80b407..da59ffebdc5a9 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -1,7 +1,6 @@
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::untranslatable_diagnostic)]
-
-use std::num::NonZeroU32;
+use std::num::NonZero;
 
 use crate::errors::RequestedLevel;
 use crate::fluent_generated as fluent;
@@ -402,7 +401,7 @@ pub struct BuiltinIncompleteFeaturesHelp;
 #[derive(Subdiagnostic)]
 #[note(lint_note)]
 pub struct BuiltinFeatureIssueNote {
-    pub n: NonZeroU32,
+    pub n: NonZero<u32>,
 }
 
 pub struct BuiltinUnpermittedTypeInit<'a> {
diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs
index 2e7130f356579..70ad859895724 100644
--- a/compiler/rustc_metadata/src/lib.rs
+++ b/compiler/rustc_metadata/src/lib.rs
@@ -5,6 +5,7 @@
 #![feature(decl_macro)]
 #![feature(extract_if)]
 #![feature(coroutines)]
+#![feature(generic_nonzero)]
 #![feature(iter_from_coroutine)]
 #![feature(let_chains)]
 #![feature(if_let_guard)]
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 72e9744295bc9..8a031e4f3a301 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -327,7 +327,7 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> {
     }
 
     #[inline]
-    fn read_lazy_offset_then<T>(&mut self, f: impl Fn(NonZeroUsize) -> T) -> T {
+    fn read_lazy_offset_then<T>(&mut self, f: impl Fn(NonZero<usize>) -> T) -> T {
         let distance = self.read_usize();
         let position = match self.lazy_state {
             LazyState::NoNode => bug!("read_lazy_with_meta: outside of a metadata node"),
@@ -338,7 +338,7 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> {
             }
             LazyState::Previous(last_pos) => last_pos.get() + distance,
         };
-        let position = NonZeroUsize::new(position).unwrap();
+        let position = NonZero::<usize>::new(position).unwrap();
         self.lazy_state = LazyState::Previous(position);
         f(position)
     }
@@ -685,15 +685,17 @@ impl MetadataBlob {
     }
 
     pub(crate) fn get_rustc_version(&self) -> String {
-        LazyValue::<String>::from_position(NonZeroUsize::new(METADATA_HEADER.len() + 8).unwrap())
-            .decode(self)
+        LazyValue::<String>::from_position(
+            NonZero::<usize>::new(METADATA_HEADER.len() + 8).unwrap(),
+        )
+        .decode(self)
     }
 
-    fn root_pos(&self) -> NonZeroUsize {
+    fn root_pos(&self) -> NonZero<usize> {
         let offset = METADATA_HEADER.len();
         let pos_bytes = self.blob()[offset..][..8].try_into().unwrap();
         let pos = u64::from_le_bytes(pos_bytes);
-        NonZeroUsize::new(pos as usize).unwrap()
+        NonZero::<usize>::new(pos as usize).unwrap()
     }
 
     pub(crate) fn get_header(&self) -> CrateHeader {
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 4a24c038f7ae0..51d747efdd36b 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -421,7 +421,7 @@ macro_rules! record_defaulted_array {
 }
 
 impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
-    fn emit_lazy_distance(&mut self, position: NonZeroUsize) {
+    fn emit_lazy_distance(&mut self, position: NonZero<usize>) {
         let pos = position.get();
         let distance = match self.lazy_state {
             LazyState::NoNode => bug!("emit_lazy_distance: outside of a metadata node"),
@@ -439,7 +439,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 position.get() - last_pos.get()
             }
         };
-        self.lazy_state = LazyState::Previous(NonZeroUsize::new(pos).unwrap());
+        self.lazy_state = LazyState::Previous(NonZero::<usize>::new(pos).unwrap());
         self.emit_usize(distance);
     }
 
@@ -447,7 +447,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     where
         T::Value<'tcx>: Encodable<EncodeContext<'a, 'tcx>>,
     {
-        let pos = NonZeroUsize::new(self.position()).unwrap();
+        let pos = NonZero::<usize>::new(self.position()).unwrap();
 
         assert_eq!(self.lazy_state, LazyState::NoNode);
         self.lazy_state = LazyState::NodeStart(pos);
@@ -466,7 +466,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     where
         T::Value<'tcx>: Encodable<EncodeContext<'a, 'tcx>>,
     {
-        let pos = NonZeroUsize::new(self.position()).unwrap();
+        let pos = NonZero::<usize>::new(self.position()).unwrap();
 
         assert_eq!(self.lazy_state, LazyState::NoNode);
         self.lazy_state = LazyState::NodeStart(pos);
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 4d0a6cb60ee76..81d834e0456a5 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -37,7 +37,7 @@ use rustc_target::abi::{FieldIdx, VariantIdx};
 use rustc_target::spec::{PanicStrategy, TargetTriple};
 
 use std::marker::PhantomData;
-use std::num::NonZeroUsize;
+use std::num::NonZero;
 
 use decoder::DecodeContext;
 pub(crate) use decoder::{CrateMetadata, CrateNumMap, MetadataBlob};
@@ -83,7 +83,7 @@ pub const METADATA_HEADER: &[u8] = &[b'r', b'u', b's', b't', 0, 0, 0, METADATA_V
 /// order than they were encoded in.
 #[must_use]
 struct LazyValue<T> {
-    position: NonZeroUsize,
+    position: NonZero<usize>,
     _marker: PhantomData<fn() -> T>,
 }
 
@@ -92,7 +92,7 @@ impl<T: ParameterizedOverTcx> ParameterizedOverTcx for LazyValue<T> {
 }
 
 impl<T> LazyValue<T> {
-    fn from_position(position: NonZeroUsize) -> LazyValue<T> {
+    fn from_position(position: NonZero<usize>) -> LazyValue<T> {
         LazyValue { position, _marker: PhantomData }
     }
 }
@@ -108,7 +108,7 @@ impl<T> LazyValue<T> {
 /// the minimal distance the length of the sequence, i.e.
 /// it's assumed there's no 0-byte element in the sequence.
 struct LazyArray<T> {
-    position: NonZeroUsize,
+    position: NonZero<usize>,
     num_elems: usize,
     _marker: PhantomData<fn() -> T>,
 }
@@ -119,12 +119,12 @@ impl<T: ParameterizedOverTcx> ParameterizedOverTcx for LazyArray<T> {
 
 impl<T> Default for LazyArray<T> {
     fn default() -> LazyArray<T> {
-        LazyArray::from_position_and_num_elems(NonZeroUsize::new(1).unwrap(), 0)
+        LazyArray::from_position_and_num_elems(NonZero::<usize>::new(1).unwrap(), 0)
     }
 }
 
 impl<T> LazyArray<T> {
-    fn from_position_and_num_elems(position: NonZeroUsize, num_elems: usize) -> LazyArray<T> {
+    fn from_position_and_num_elems(position: NonZero<usize>, num_elems: usize) -> LazyArray<T> {
         LazyArray { position, num_elems, _marker: PhantomData }
     }
 }
@@ -135,7 +135,7 @@ impl<T> LazyArray<T> {
 /// `LazyArray<T>`, but without requiring encoding or decoding all the values
 /// eagerly and in-order.
 struct LazyTable<I, T> {
-    position: NonZeroUsize,
+    position: NonZero<usize>,
     /// The encoded size of the elements of a table is selected at runtime to drop
     /// trailing zeroes. This is the number of bytes used for each table element.
     width: usize,
@@ -150,7 +150,7 @@ impl<I: 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for LazyTable<I,
 
 impl<I, T> LazyTable<I, T> {
     fn from_position_and_encoded_size(
-        position: NonZeroUsize,
+        position: NonZero<usize>,
         width: usize,
         len: usize,
     ) -> LazyTable<I, T> {
@@ -187,11 +187,11 @@ enum LazyState {
 
     /// Inside a metadata node, and before any `Lazy`s.
     /// The position is that of the node itself.
-    NodeStart(NonZeroUsize),
+    NodeStart(NonZero<usize>),
 
     /// Inside a metadata node, with a previous `Lazy`s.
     /// The position is where that previous `Lazy` would start.
-    Previous(NonZeroUsize),
+    Previous(NonZero<usize>),
 }
 
 type SyntaxContextTable = LazyTable<u32, Option<LazyValue<SyntaxContextData>>>;
diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs
index 306bf07a97608..00752ad15a33a 100644
--- a/compiler/rustc_metadata/src/rmeta/table.rs
+++ b/compiler/rustc_metadata/src/rmeta/table.rs
@@ -339,7 +339,7 @@ impl<T> FixedSizeEncoding for Option<LazyValue<T>> {
 
     #[inline]
     fn from_bytes(b: &[u8; 8]) -> Self {
-        let position = NonZeroUsize::new(u64::from_bytes(b) as usize)?;
+        let position = NonZero::<usize>::new(u64::from_bytes(b) as usize)?;
         Some(LazyValue::from_position(position))
     }
 
@@ -366,7 +366,7 @@ impl<T> LazyArray<T> {
     }
 
     fn from_bytes_impl(position: &[u8; 8], meta: &[u8; 8]) -> Option<LazyArray<T>> {
-        let position = NonZeroUsize::new(u64::from_bytes(position) as usize)?;
+        let position = NonZero::<usize>::new(u64::from_bytes(position) as usize)?;
         let len = u64::from_bytes(meta) as usize;
         Some(LazyArray::from_position_and_num_elems(position, len))
     }
@@ -497,7 +497,7 @@ impl<I: Idx, const N: usize, T: FixedSizeEncoding<ByteArray = [u8; N]>> TableBui
         }
 
         LazyTable::from_position_and_encoded_size(
-            NonZeroUsize::new(pos).unwrap(),
+            NonZero::<usize>::new(pos).unwrap(),
             width,
             self.blocks.len(),
         )
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 2aaece1060a1f..9c0846e9fb199 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -34,6 +34,7 @@
 #![feature(discriminant_kind)]
 #![feature(exhaustive_patterns)]
 #![feature(coroutines)]
+#![feature(generic_nonzero)]
 #![feature(if_let_guard)]
 #![feature(inline_const)]
 #![feature(iter_from_coroutine)]
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index afb6937b43b94..15ef00629b986 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -21,7 +21,7 @@ use rustc_session::parse::feature_err_issue;
 use rustc_session::Session;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
-use std::num::NonZeroU32;
+use std::num::NonZero;
 
 #[derive(PartialEq, Clone, Copy, Debug)]
 pub enum StabilityLevel {
@@ -102,7 +102,7 @@ pub fn report_unstable(
     sess: &Session,
     feature: Symbol,
     reason: Option<Symbol>,
-    issue: Option<NonZeroU32>,
+    issue: Option<NonZero<u32>>,
     suggestion: Option<(Span, String, String, Applicability)>,
     is_soft: bool,
     span: Span,
@@ -235,7 +235,7 @@ pub enum EvalResult {
     Deny {
         feature: Symbol,
         reason: Option<Symbol>,
-        issue: Option<NonZeroU32>,
+        issue: Option<NonZero<u32>>,
         suggestion: Option<(Span, String, String, Applicability)>,
         is_soft: bool,
     },
@@ -433,7 +433,7 @@ impl<'tcx> TyCtxt<'tcx> {
                 // the `-Z force-unstable-if-unmarked` flag present (we're
                 // compiling a compiler crate), then let this missing feature
                 // annotation slide.
-                if feature == sym::rustc_private && issue == NonZeroU32::new(27812) {
+                if feature == sym::rustc_private && issue == NonZero::<u32>::new(27812) {
                     if self.sess.opts.unstable_opts.force_unstable_if_unmarked {
                         return EvalResult::Allow;
                     }
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index 0da3524e05564..4ef02a86e30e2 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -122,7 +122,7 @@ mod value;
 use std::fmt;
 use std::io;
 use std::io::{Read, Write};
-use std::num::{NonZeroU32, NonZeroU64};
+use std::num::NonZero;
 use std::sync::atomic::{AtomicU32, Ordering};
 
 use rustc_ast::LitKind;
@@ -205,7 +205,7 @@ pub enum LitToConstError {
 }
 
 #[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
-pub struct AllocId(pub NonZeroU64);
+pub struct AllocId(pub NonZero<u64>);
 
 // We want the `Debug` output to be readable as it is used by `derive(Debug)` for
 // all the Miri types.
@@ -260,7 +260,7 @@ pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>>(
 }
 
 // Used to avoid infinite recursion when decoding cyclic allocations.
-type DecodingSessionId = NonZeroU32;
+type DecodingSessionId = NonZero<u32>;
 
 #[derive(Clone)]
 enum State {
@@ -500,7 +500,7 @@ impl<'tcx> AllocMap<'tcx> {
         AllocMap {
             alloc_map: Default::default(),
             dedup: Default::default(),
-            next_id: AllocId(NonZeroU64::new(1).unwrap()),
+            next_id: AllocId(NonZero::<u64>::new(1).unwrap()),
         }
     }
     fn reserve(&mut self) -> AllocId {
diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs
index dabf6297aa9c8..15e12c456793b 100644
--- a/compiler/rustc_middle/src/mir/interpret/pointer.rs
+++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs
@@ -3,7 +3,7 @@ use super::{AllocId, InterpResult};
 use rustc_macros::HashStable;
 use rustc_target::abi::{HasDataLayout, Size};
 
-use std::{fmt, num::NonZeroU64};
+use std::{fmt, num::NonZero};
 
 ////////////////////////////////////////////////////////////////////////////////
 // Pointer arithmetic
@@ -129,7 +129,7 @@ pub trait Provenance: Copy + fmt::Debug + 'static {
 /// The type of provenance in the compile-time interpreter.
 /// This is a packed representation of an `AllocId` and an `immutable: bool`.
 #[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
-pub struct CtfeProvenance(NonZeroU64);
+pub struct CtfeProvenance(NonZero<u64>);
 
 impl From<AllocId> for CtfeProvenance {
     fn from(value: AllocId) -> Self {
@@ -155,7 +155,7 @@ impl CtfeProvenance {
     /// Returns the `AllocId` of this provenance.
     #[inline(always)]
     pub fn alloc_id(self) -> AllocId {
-        AllocId(NonZeroU64::new(self.0.get() & !IMMUTABLE_MASK).unwrap())
+        AllocId(NonZero::<u64>::new(self.0.get() & !IMMUTABLE_MASK).unwrap())
     }
 
     /// Returns whether this provenance is immutable.
diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs
index 515d564e81db7..15f69d2333c73 100644
--- a/compiler/rustc_middle/src/ty/consts/int.rs
+++ b/compiler/rustc_middle/src/ty/consts/int.rs
@@ -4,7 +4,7 @@ use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg};
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use rustc_target::abi::Size;
 use std::fmt;
-use std::num::NonZeroU8;
+use std::num::NonZero;
 
 use crate::ty::TyCtxt;
 
@@ -132,7 +132,7 @@ pub struct ScalarInt {
     /// The first `size` bytes of `data` are the value.
     /// Do not try to read less or more bytes than that. The remaining bytes must be 0.
     data: u128,
-    size: NonZeroU8,
+    size: NonZero<u8>,
 }
 
 // Cannot derive these, as the derives take references to the fields, and we
@@ -161,14 +161,14 @@ impl<D: Decoder> Decodable<D> for ScalarInt {
         let mut data = [0u8; 16];
         let size = d.read_u8();
         data[..size as usize].copy_from_slice(d.read_raw_bytes(size as usize));
-        ScalarInt { data: u128::from_le_bytes(data), size: NonZeroU8::new(size).unwrap() }
+        ScalarInt { data: u128::from_le_bytes(data), size: NonZero::<u8>::new(size).unwrap() }
     }
 }
 
 impl ScalarInt {
-    pub const TRUE: ScalarInt = ScalarInt { data: 1_u128, size: NonZeroU8::new(1).unwrap() };
+    pub const TRUE: ScalarInt = ScalarInt { data: 1_u128, size: NonZero::<u8>::new(1).unwrap() };
 
-    pub const FALSE: ScalarInt = ScalarInt { data: 0_u128, size: NonZeroU8::new(1).unwrap() };
+    pub const FALSE: ScalarInt = ScalarInt { data: 0_u128, size: NonZero::<u8>::new(1).unwrap() };
 
     #[inline]
     pub fn size(self) -> Size {
@@ -196,7 +196,7 @@ impl ScalarInt {
 
     #[inline]
     pub fn null(size: Size) -> Self {
-        Self { data: 0, size: NonZeroU8::new(size.bytes() as u8).unwrap() }
+        Self { data: 0, size: NonZero::<u8>::new(size.bytes() as u8).unwrap() }
     }
 
     #[inline]
@@ -208,7 +208,7 @@ impl ScalarInt {
     pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> {
         let data = i.into();
         if size.truncate(data) == data {
-            Some(Self { data, size: NonZeroU8::new(size.bytes() as u8).unwrap() })
+            Some(Self { data, size: NonZero::<u8>::new(size.bytes() as u8).unwrap() })
         } else {
             None
         }
@@ -220,7 +220,7 @@ impl ScalarInt {
         // `into` performed sign extension, we have to truncate
         let truncated = size.truncate(i as u128);
         if size.sign_extend(truncated) as i128 == i {
-            Some(Self { data: truncated, size: NonZeroU8::new(size.bytes() as u8).unwrap() })
+            Some(Self { data: truncated, size: NonZero::<u8>::new(size.bytes() as u8).unwrap() })
         } else {
             None
         }
@@ -388,7 +388,7 @@ macro_rules! from {
                 fn from(u: $ty) -> Self {
                     Self {
                         data: u128::from(u),
-                        size: NonZeroU8::new(std::mem::size_of::<$ty>() as u8).unwrap(),
+                        size: NonZero::<u8>::new(std::mem::size_of::<$ty>() as u8).unwrap(),
                     }
                 }
             }
@@ -427,7 +427,10 @@ impl TryFrom<ScalarInt> for bool {
 impl From<char> for ScalarInt {
     #[inline]
     fn from(c: char) -> Self {
-        Self { data: c as u128, size: NonZeroU8::new(std::mem::size_of::<char>() as u8).unwrap() }
+        Self {
+            data: c as u128,
+            size: NonZero::<u8>::new(std::mem::size_of::<char>() as u8).unwrap(),
+        }
     }
 }
 
@@ -454,7 +457,7 @@ impl From<Single> for ScalarInt {
     #[inline]
     fn from(f: Single) -> Self {
         // We trust apfloat to give us properly truncated data.
-        Self { data: f.to_bits(), size: NonZeroU8::new((Single::BITS / 8) as u8).unwrap() }
+        Self { data: f.to_bits(), size: NonZero::<u8>::new((Single::BITS / 8) as u8).unwrap() }
     }
 }
 
@@ -470,7 +473,7 @@ impl From<Double> for ScalarInt {
     #[inline]
     fn from(f: Double) -> Self {
         // We trust apfloat to give us properly truncated data.
-        Self { data: f.to_bits(), size: NonZeroU8::new((Double::BITS / 8) as u8).unwrap() }
+        Self { data: f.to_bits(), size: NonZero::<u8>::new((Double::BITS / 8) as u8).unwrap() }
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs
index 84de12b23a06e..c931c2064b0c5 100644
--- a/compiler/rustc_middle/src/ty/generic_args.rs
+++ b/compiler/rustc_middle/src/ty/generic_args.rs
@@ -18,7 +18,7 @@ use core::intrinsics;
 use std::cmp::Ordering;
 use std::marker::PhantomData;
 use std::mem;
-use std::num::NonZeroUsize;
+use std::num::NonZero;
 use std::ops::{ControlFlow, Deref};
 use std::ptr::NonNull;
 
@@ -144,7 +144,7 @@ impl<'tcx> GenericArg<'tcx> {
     #[inline]
     pub fn unpack(self) -> GenericArgKind<'tcx> {
         let ptr = unsafe {
-            self.ptr.map_addr(|addr| NonZeroUsize::new_unchecked(addr.get() & !TAG_MASK))
+            self.ptr.map_addr(|addr| NonZero::<usize>::new_unchecked(addr.get() & !TAG_MASK))
         };
         // SAFETY: use of `Interned::new_unchecked` here is ok because these
         // pointers were originally created from `Interned` types in `pack()`,
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 8d8d06b7c0b7f..d9fa99535b1b5 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -20,7 +20,7 @@ use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Targ
 
 use std::cmp;
 use std::fmt;
-use std::num::NonZeroUsize;
+use std::num::NonZero;
 use std::ops::Bound;
 
 pub trait IntegerExt {
@@ -761,7 +761,7 @@ where
                 };
                 tcx.mk_layout(LayoutS {
                     variants: Variants::Single { index: variant_index },
-                    fields: match NonZeroUsize::new(fields) {
+                    fields: match NonZero::<usize>::new(fields) {
                         Some(fields) => FieldsShape::Union(fields),
                         None => FieldsShape::Arbitrary { offsets: IndexVec::new(), memory_index: IndexVec::new() },
                     },
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 15bddb2a64fb8..3eea0d428eeb9 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -61,7 +61,7 @@ use std::fmt::Debug;
 use std::hash::{Hash, Hasher};
 use std::marker::PhantomData;
 use std::mem;
-use std::num::NonZeroUsize;
+use std::num::NonZero;
 use std::ops::ControlFlow;
 use std::ptr::NonNull;
 use std::{fmt, str};
@@ -618,7 +618,7 @@ impl<'tcx> Term<'tcx> {
     #[inline]
     pub fn unpack(self) -> TermKind<'tcx> {
         let ptr = unsafe {
-            self.ptr.map_addr(|addr| NonZeroUsize::new_unchecked(addr.get() & !TAG_MASK))
+            self.ptr.map_addr(|addr| NonZero::<usize>::new_unchecked(addr.get() & !TAG_MASK))
         };
         // SAFETY: use of `Interned::new_unchecked` here is ok because these
         // pointers were originally created from `Interned` types in `pack()`,
diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs
index e795537e84ad7..7227b185f4d3b 100644
--- a/compiler/rustc_passes/src/lib.rs
+++ b/compiler/rustc_passes/src/lib.rs
@@ -8,6 +8,7 @@
 #![doc(rust_logo)]
 #![feature(rustdoc_internals)]
 #![allow(internal_features)]
+#![feature(generic_nonzero)]
 #![feature(let_chains)]
 #![feature(map_try_insert)]
 #![feature(try_blocks)]
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 17ad08b0569b6..312a136c897c6 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -27,7 +27,7 @@ use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
 
 use std::mem::replace;
-use std::num::NonZeroU32;
+use std::num::NonZero;
 
 #[derive(PartialEq)]
 enum AnnotationKind {
@@ -645,7 +645,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
             let stability = Stability {
                 level: attr::StabilityLevel::Unstable {
                     reason: UnstableReason::Default,
-                    issue: NonZeroU32::new(27812),
+                    issue: NonZero::<u32>::new(27812),
                     is_soft: false,
                     implied_by: None,
                 },
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index 0fe5b9c664a35..33116737a4203 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -3,6 +3,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
 #![feature(rustdoc_internals)]
+#![feature(generic_nonzero)]
 #![feature(min_specialization)]
 #![feature(rustc_attrs)]
 #![allow(rustc::potential_query_instability, unused_parens)]
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index a827717d9bbd1..8cbcce986a1a3 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -30,7 +30,7 @@ use rustc_serialize::Decodable;
 use rustc_serialize::Encodable;
 use rustc_session::Limit;
 use rustc_span::def_id::LOCAL_CRATE;
-use std::num::NonZeroU64;
+use std::num::NonZero;
 use thin_vec::ThinVec;
 
 #[derive(Copy, Clone)]
@@ -68,7 +68,7 @@ impl QueryContext for QueryCtxt<'_> {
     #[inline]
     fn next_job_id(self) -> QueryJobId {
         QueryJobId(
-            NonZeroU64::new(
+            NonZero::<u64>::new(
                 self.query_system.jobs.fetch_add(1, std::sync::atomic::Ordering::Relaxed),
             )
             .unwrap(),
diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs
index 416f556f57d28..6a959a99e5d42 100644
--- a/compiler/rustc_query_system/src/lib.rs
+++ b/compiler/rustc_query_system/src/lib.rs
@@ -1,5 +1,6 @@
 #![feature(assert_matches)]
 #![feature(core_intrinsics)]
+#![feature(generic_nonzero)]
 #![feature(hash_raw_entry)]
 #![feature(min_specialization)]
 #![feature(let_chains)]
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index 8d7c0ca014490..bf89bc7f7c3c4 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -11,7 +11,7 @@ use rustc_span::Span;
 
 use std::hash::Hash;
 use std::io::Write;
-use std::num::NonZeroU64;
+use std::num::NonZero;
 
 #[cfg(parallel_compiler)]
 use {
@@ -36,7 +36,7 @@ pub type QueryMap = FxHashMap<QueryJobId, QueryJobInfo>;
 
 /// A value uniquely identifying an active query job.
 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
-pub struct QueryJobId(pub NonZeroU64);
+pub struct QueryJobId(pub NonZero<u64>);
 
 impl QueryJobId {
     fn query(self, map: &QueryMap) -> QueryStackFrame {
diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs
index 95833f532f4d8..bb822c611a170 100644
--- a/compiler/rustc_serialize/src/lib.rs
+++ b/compiler/rustc_serialize/src/lib.rs
@@ -11,6 +11,7 @@
 #![feature(associated_type_bounds)]
 #![feature(const_option)]
 #![feature(core_intrinsics)]
+#![feature(generic_nonzero)]
 #![feature(inline_const)]
 #![feature(min_specialization)]
 #![feature(never_type)]
diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs
index 287e317b10f33..a38a4a916fb82 100644
--- a/compiler/rustc_serialize/src/serialize.rs
+++ b/compiler/rustc_serialize/src/serialize.rs
@@ -6,6 +6,7 @@ use std::cell::{Cell, RefCell};
 use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque};
 use std::hash::{BuildHasher, Hash};
 use std::marker::PhantomData;
+use std::num::NonZero;
 use std::path;
 use std::rc::Rc;
 use std::sync::Arc;
@@ -216,15 +217,15 @@ impl<D: Decoder> Decodable<D> for ! {
     }
 }
 
-impl<S: Encoder> Encodable<S> for ::std::num::NonZeroU32 {
+impl<S: Encoder> Encodable<S> for NonZero<u32> {
     fn encode(&self, s: &mut S) {
         s.emit_u32(self.get());
     }
 }
 
-impl<D: Decoder> Decodable<D> for ::std::num::NonZeroU32 {
+impl<D: Decoder> Decodable<D> for NonZero<u32> {
     fn decode(d: &mut D) -> Self {
-        ::std::num::NonZeroU32::new(d.read_u32()).unwrap()
+        NonZero::<u32>::new(d.read_u32()).unwrap()
     }
 }
 
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index d35f951e2aea3..b89dfab2ca97d 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -3226,7 +3226,7 @@ pub(crate) mod dep_tracking {
     };
     use std::collections::BTreeMap;
     use std::hash::{DefaultHasher, Hash};
-    use std::num::NonZeroUsize;
+    use std::num::NonZero;
     use std::path::PathBuf;
 
     pub trait DepTrackingHash {
@@ -3268,7 +3268,7 @@ pub(crate) mod dep_tracking {
     impl_dep_tracking_hash_via_hash!(
         bool,
         usize,
-        NonZeroUsize,
+        NonZero<usize>,
         u64,
         Hash64,
         String,
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index c36cec6f35327..192dbb05530f3 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -1,4 +1,4 @@
-use std::num::NonZeroU32;
+use std::num::NonZero;
 
 use rustc_ast::token;
 use rustc_ast::util::literal::LitError;
@@ -26,7 +26,7 @@ impl<'a> IntoDiagnostic<'a> for FeatureGateError {
 #[derive(Subdiagnostic)]
 #[note(session_feature_diagnostic_for_issue)]
 pub struct FeatureDiagnosticForIssue {
-    pub n: NonZeroU32,
+    pub n: NonZero<u32>,
 }
 
 #[derive(Subdiagnostic)]
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs
index 58e1394c09071..c63af90a7f312 100644
--- a/compiler/rustc_session/src/lib.rs
+++ b/compiler/rustc_session/src/lib.rs
@@ -1,3 +1,4 @@
+#![feature(generic_nonzero)]
 #![feature(let_chains)]
 #![feature(lazy_cell)]
 #![feature(option_get_or_insert_default)]
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index ea93ac5841fe9..1a046667bd718 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -21,7 +21,7 @@ use rustc_span::SourceFileHashAlgorithm;
 use std::collections::BTreeMap;
 
 use std::hash::{DefaultHasher, Hasher};
-use std::num::{IntErrorKind, NonZeroUsize};
+use std::num::{IntErrorKind, NonZero};
 use std::path::PathBuf;
 use std::str;
 
@@ -617,7 +617,7 @@ mod parse {
     pub(crate) fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool {
         match v.and_then(|s| s.parse().ok()) {
             Some(0) => {
-                *slot = std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get);
+                *slot = std::thread::available_parallelism().map_or(1, NonZero::<usize>::get);
                 true
             }
             Some(i) => {
@@ -991,7 +991,10 @@ mod parse {
         true
     }
 
-    pub(crate) fn parse_treat_err_as_bug(slot: &mut Option<NonZeroUsize>, v: Option<&str>) -> bool {
+    pub(crate) fn parse_treat_err_as_bug(
+        slot: &mut Option<NonZero<usize>>,
+        v: Option<&str>,
+    ) -> bool {
         match v {
             Some(s) => match s.parse() {
                 Ok(val) => {
@@ -1004,7 +1007,7 @@ mod parse {
                 }
             },
             None => {
-                *slot = NonZeroUsize::new(1);
+                *slot = NonZero::<usize>::new(1);
                 true
             }
         }
@@ -1950,7 +1953,7 @@ written to standard error output)"),
         "translate remapped paths into local paths when possible (default: yes)"),
     trap_unreachable: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "generate trap instructions for unreachable intrinsics (default: use target setting, usually yes)"),
-    treat_err_as_bug: Option<NonZeroUsize> = (None, parse_treat_err_as_bug, [TRACKED],
+    treat_err_as_bug: Option<NonZero<usize>> = (None, parse_treat_err_as_bug, [TRACKED],
         "treat the `val`th error that occurs as bug (default if not specified: 0 - don't treat errors as bugs. \
         default if specified without a value: 1 - treat the first error as bug)"),
     trim_diagnostic_paths: bool = (true, parse_bool, [UNTRACKED],
diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs
index 00a101541c589..3a82fb0df8833 100644
--- a/library/alloc/src/collections/binary_heap/mod.rs
+++ b/library/alloc/src/collections/binary_heap/mod.rs
@@ -147,7 +147,7 @@ use core::alloc::Allocator;
 use core::fmt;
 use core::iter::{FusedIterator, InPlaceIterable, SourceIter, TrustedFused, TrustedLen};
 use core::mem::{self, swap, ManuallyDrop};
-use core::num::NonZeroUsize;
+use core::num::NonZero;
 use core::ops::{Deref, DerefMut};
 use core::ptr;
 
@@ -296,7 +296,7 @@ pub struct PeekMut<
     heap: &'a mut BinaryHeap<T, A>,
     // If a set_len + sift_down are required, this is Some. If a &mut T has not
     // yet been exposed to peek_mut()'s caller, it's None.
-    original_len: Option<NonZeroUsize>,
+    original_len: Option<NonZero<usize>>,
 }
 
 #[stable(feature = "collection_debug", since = "1.17.0")]
@@ -350,7 +350,7 @@ impl<T: Ord, A: Allocator> DerefMut for PeekMut<'_, T, A> {
             // the standard library as "leak amplification".
             unsafe {
                 // SAFETY: len > 1 so len != 0.
-                self.original_len = Some(NonZeroUsize::new_unchecked(len));
+                self.original_len = Some(NonZero::<usize>::new_unchecked(len));
                 // SAFETY: len > 1 so all this does for now is leak elements,
                 // which is safe.
                 self.heap.data.set_len(1);
@@ -1576,8 +1576,8 @@ unsafe impl<T, A: Allocator> SourceIter for IntoIter<T, A> {
 #[unstable(issue = "none", feature = "inplace_iteration")]
 #[doc(hidden)]
 unsafe impl<I, A: Allocator> InPlaceIterable for IntoIter<I, A> {
-    const EXPAND_BY: Option<NonZeroUsize> = NonZeroUsize::new(1);
-    const MERGE_BY: Option<NonZeroUsize> = NonZeroUsize::new(1);
+    const EXPAND_BY: Option<NonZero<usize>> = NonZero::<usize>::new(1);
+    const MERGE_BY: Option<NonZero<usize>> = NonZero::<usize>::new(1);
 }
 
 unsafe impl<I> AsVecIntoIter for IntoIter<I> {
diff --git a/library/alloc/src/collections/vec_deque/into_iter.rs b/library/alloc/src/collections/vec_deque/into_iter.rs
index d9e274df0f5f2..02ab3f79b0641 100644
--- a/library/alloc/src/collections/vec_deque/into_iter.rs
+++ b/library/alloc/src/collections/vec_deque/into_iter.rs
@@ -1,5 +1,5 @@
 use core::iter::{FusedIterator, TrustedLen};
-use core::num::NonZeroUsize;
+use core::num::NonZero;
 use core::{array, fmt, mem::MaybeUninit, ops::Try, ptr};
 
 use crate::alloc::{Allocator, Global};
@@ -54,7 +54,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
     }
 
     #[inline]
-    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         let len = self.inner.len;
         let rem = if len < n {
             self.inner.clear();
@@ -63,7 +63,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
             self.inner.drain(..n);
             0
         };
-        NonZeroUsize::new(rem).map_or(Ok(()), Err)
+        NonZero::<usize>::new(rem).map_or(Ok(()), Err)
     }
 
     #[inline]
@@ -183,7 +183,7 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         let len = self.inner.len;
         let rem = if len < n {
             self.inner.clear();
@@ -192,7 +192,7 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
             self.inner.truncate(len - n);
             0
         };
-        NonZeroUsize::new(rem).map_or(Ok(()), Err)
+        NonZero::<usize>::new(rem).map_or(Ok(()), Err)
     }
 
     fn try_rfold<B, F, R>(&mut self, mut init: B, mut f: F) -> R
diff --git a/library/alloc/src/collections/vec_deque/iter.rs b/library/alloc/src/collections/vec_deque/iter.rs
index 646a2a991e701..5a5e7f70854d8 100644
--- a/library/alloc/src/collections/vec_deque/iter.rs
+++ b/library/alloc/src/collections/vec_deque/iter.rs
@@ -1,5 +1,5 @@
 use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce};
-use core::num::NonZeroUsize;
+use core::num::NonZero;
 use core::ops::Try;
 use core::{fmt, mem, slice};
 
@@ -56,7 +56,7 @@ impl<'a, T> Iterator for Iter<'a, T> {
         }
     }
 
-    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         let remaining = self.i1.advance_by(n);
         match remaining {
             Ok(()) => return Ok(()),
@@ -128,7 +128,7 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
         }
     }
 
-    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         match self.i2.advance_back_by(n) {
             Ok(()) => return Ok(()),
             Err(n) => {
diff --git a/library/alloc/src/collections/vec_deque/iter_mut.rs b/library/alloc/src/collections/vec_deque/iter_mut.rs
index 7defbb1090ffd..5061931afb7b7 100644
--- a/library/alloc/src/collections/vec_deque/iter_mut.rs
+++ b/library/alloc/src/collections/vec_deque/iter_mut.rs
@@ -1,5 +1,5 @@
 use core::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce};
-use core::num::NonZeroUsize;
+use core::num::NonZero;
 use core::ops::Try;
 use core::{fmt, mem, slice};
 
@@ -48,7 +48,7 @@ impl<'a, T> Iterator for IterMut<'a, T> {
         }
     }
 
-    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         match self.i1.advance_by(n) {
             Ok(()) => return Ok(()),
             Err(remaining) => {
@@ -119,7 +119,7 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> {
         }
     }
 
-    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         match self.i2.advance_back_by(n) {
             Ok(()) => return Ok(()),
             Err(remaining) => {
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 3341b564d1f65..b84273848ee95 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -128,6 +128,7 @@
 #![feature(extend_one)]
 #![feature(fmt_internals)]
 #![feature(fn_traits)]
+#![feature(generic_nonzero)]
 #![feature(hasher_prefixfree_extras)]
 #![feature(hint_assert_unchecked)]
 #![feature(inline_const)]
diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs
index 5dc3c69e49320..07eb91c900597 100644
--- a/library/alloc/src/vec/in_place_collect.rs
+++ b/library/alloc/src/vec/in_place_collect.rs
@@ -160,14 +160,14 @@ use core::alloc::Layout;
 use core::iter::{InPlaceIterable, SourceIter, TrustedRandomAccessNoCoerce};
 use core::marker::PhantomData;
 use core::mem::{self, ManuallyDrop, SizedTypeProperties};
-use core::num::NonZeroUsize;
+use core::num::NonZero;
 use core::ptr::{self, NonNull};
 
 use super::{InPlaceDrop, InPlaceDstDataSrcBufDrop, SpecFromIter, SpecFromIterNested, Vec};
 
 const fn in_place_collectible<DEST, SRC>(
-    step_merge: Option<NonZeroUsize>,
-    step_expand: Option<NonZeroUsize>,
+    step_merge: Option<NonZero<usize>>,
+    step_expand: Option<NonZero<usize>>,
 ) -> bool {
     // Require matching alignments because an alignment-changing realloc is inefficient on many
     // system allocators and better implementations would require the unstable Allocator trait.
diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs
index 7800560da94f9..76d1b7b72a12f 100644
--- a/library/alloc/src/vec/into_iter.rs
+++ b/library/alloc/src/vec/into_iter.rs
@@ -12,7 +12,7 @@ use core::iter::{
 };
 use core::marker::PhantomData;
 use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties};
-use core::num::NonZeroUsize;
+use core::num::NonZero;
 #[cfg(not(no_global_oom_handling))]
 use core::ops::Deref;
 use core::ptr::{self, NonNull};
@@ -234,7 +234,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
     }
 
     #[inline]
-    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         let step_size = self.len().min(n);
         let to_drop = ptr::slice_from_raw_parts_mut(self.ptr.as_ptr(), step_size);
         if T::IS_ZST {
@@ -248,7 +248,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
         unsafe {
             ptr::drop_in_place(to_drop);
         }
-        NonZeroUsize::new(n - step_size).map_or(Ok(()), Err)
+        NonZero::<usize>::new(n - step_size).map_or(Ok(()), Err)
     }
 
     #[inline]
@@ -336,7 +336,7 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         let step_size = self.len().min(n);
         if T::IS_ZST {
             // SAFETY: same as for advance_by()
@@ -350,7 +350,7 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
         unsafe {
             ptr::drop_in_place(to_drop);
         }
-        NonZeroUsize::new(n - step_size).map_or(Ok(()), Err)
+        NonZero::<usize>::new(n - step_size).map_or(Ok(()), Err)
     }
 }
 
@@ -457,8 +457,8 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for IntoIter<T, A> {
 #[unstable(issue = "none", feature = "inplace_iteration")]
 #[doc(hidden)]
 unsafe impl<T, A: Allocator> InPlaceIterable for IntoIter<T, A> {
-    const EXPAND_BY: Option<NonZeroUsize> = NonZeroUsize::new(1);
-    const MERGE_BY: Option<NonZeroUsize> = NonZeroUsize::new(1);
+    const EXPAND_BY: Option<NonZero<usize>> = NonZero::<usize>::new(1);
+    const MERGE_BY: Option<NonZero<usize>> = NonZero::<usize>::new(1);
 }
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs
index ca17dab55b027..c4e89a58a05ac 100644
--- a/library/alloc/tests/lib.rs
+++ b/library/alloc/tests/lib.rs
@@ -13,6 +13,7 @@
 #![feature(core_intrinsics)]
 #![feature(extract_if)]
 #![feature(exact_size_is_empty)]
+#![feature(generic_nonzero)]
 #![feature(linked_list_cursors)]
 #![feature(map_try_insert)]
 #![feature(new_uninit)]
diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs
index 38a68df79cc73..e872ace883c03 100644
--- a/library/alloc/tests/vec.rs
+++ b/library/alloc/tests/vec.rs
@@ -1,5 +1,5 @@
 use core::alloc::{Allocator, Layout};
-use core::num::NonZeroUsize;
+use core::num::NonZero;
 use core::ptr::NonNull;
 use core::{assert_eq, assert_ne};
 use std::alloc::System;
@@ -1089,9 +1089,9 @@ fn test_into_iter_advance_by() {
     assert_eq!(i.advance_back_by(1), Ok(()));
     assert_eq!(i.as_slice(), [2, 3, 4]);
 
-    assert_eq!(i.advance_back_by(usize::MAX), Err(NonZeroUsize::new(usize::MAX - 3).unwrap()));
+    assert_eq!(i.advance_back_by(usize::MAX), Err(NonZero::<usize>::new(usize::MAX - 3).unwrap()));
 
-    assert_eq!(i.advance_by(usize::MAX), Err(NonZeroUsize::new(usize::MAX).unwrap()));
+    assert_eq!(i.advance_by(usize::MAX), Err(NonZero::<usize>::new(usize::MAX).unwrap()));
 
     assert_eq!(i.advance_by(0), Ok(()));
     assert_eq!(i.advance_back_by(0), Ok(()));
@@ -1192,7 +1192,7 @@ fn test_from_iter_specialization_with_iterator_adapters() {
         .map(|(a, b)| a + b)
         .map_while(Option::Some)
         .skip(1)
-        .map(|e| if e != usize::MAX { Ok(std::num::NonZeroUsize::new(e)) } else { Err(()) });
+        .map(|e| if e != usize::MAX { Ok(NonZero::<usize>::new(e)) } else { Err(()) });
     assert_in_place_trait(&iter);
     let sink = iter.collect::<Result<Vec<_>, _>>().unwrap();
     let sinkptr = sink.as_ptr();
diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs
index f6fb1f73e5cf9..079750abd69fb 100644
--- a/library/alloc/tests/vec_deque.rs
+++ b/library/alloc/tests/vec_deque.rs
@@ -1,4 +1,4 @@
-use core::num::NonZeroUsize;
+use core::num::NonZero;
 use std::assert_matches::assert_matches;
 use std::collections::TryReserveErrorKind::*;
 use std::collections::{vec_deque::Drain, VecDeque};
@@ -445,9 +445,9 @@ fn test_into_iter() {
         assert_eq!(it.next_back(), Some(3));
 
         let mut it = VecDeque::from(vec![1, 2, 3, 4, 5]).into_iter();
-        assert_eq!(it.advance_by(10), Err(NonZeroUsize::new(5).unwrap()));
+        assert_eq!(it.advance_by(10), Err(NonZero::<usize>::new(5).unwrap()));
         let mut it = VecDeque::from(vec![1, 2, 3, 4, 5]).into_iter();
-        assert_eq!(it.advance_back_by(10), Err(NonZeroUsize::new(5).unwrap()));
+        assert_eq!(it.advance_back_by(10), Err(NonZero::<usize>::new(5).unwrap()));
     }
 }
 
diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs
index 2b22488b8ffc5..e50ae1b0d70af 100644
--- a/library/core/src/array/iter.rs
+++ b/library/core/src/array/iter.rs
@@ -1,6 +1,6 @@
 //! Defines the `IntoIter` owned iterator for arrays.
 
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::{
     fmt,
     intrinsics::transmute_unchecked,
@@ -280,7 +280,7 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> {
         self.next_back()
     }
 
-    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         // This also moves the start, which marks them as conceptually "dropped",
         // so if anything goes bad then our drop impl won't double-free them.
         let range_to_drop = self.alive.take_prefix(n);
@@ -292,7 +292,7 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> {
             ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(slice));
         }
 
-        NonZeroUsize::new(remaining).map_or(Ok(()), Err)
+        NonZero::<usize>::new(remaining).map_or(Ok(()), Err)
     }
 
     #[inline]
@@ -335,7 +335,7 @@ impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
         })
     }
 
-    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         // This also moves the end, which marks them as conceptually "dropped",
         // so if anything goes bad then our drop impl won't double-free them.
         let range_to_drop = self.alive.take_suffix(n);
@@ -347,7 +347,7 @@ impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
             ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(slice));
         }
 
-        NonZeroUsize::new(remaining).map_or(Ok(()), Err)
+        NonZero::<usize>::new(remaining).map_or(Ok(()), Err)
     }
 }
 
diff --git a/library/core/src/ascii.rs b/library/core/src/ascii.rs
index 02867789b79dd..c29e5565d514a 100644
--- a/library/core/src/ascii.rs
+++ b/library/core/src/ascii.rs
@@ -12,7 +12,7 @@
 use crate::escape;
 use crate::fmt;
 use crate::iter::FusedIterator;
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 
 mod ascii_char;
 #[unstable(feature = "ascii_char", issue = "110998")]
@@ -133,7 +133,7 @@ impl Iterator for EscapeDefault {
     }
 
     #[inline]
-    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         self.0.advance_by(n)
     }
 }
@@ -146,7 +146,7 @@ impl DoubleEndedIterator for EscapeDefault {
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         self.0.advance_back_by(n)
     }
 }
diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs
index 5c42912874c66..12bca0b438cc3 100644
--- a/library/core/src/char/mod.rs
+++ b/library/core/src/char/mod.rs
@@ -43,7 +43,7 @@ use crate::error::Error;
 use crate::escape;
 use crate::fmt::{self, Write};
 use crate::iter::FusedIterator;
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 
 pub(crate) use self::methods::EscapeDebugExtArgs;
 
@@ -185,7 +185,7 @@ impl Iterator for EscapeUnicode {
     }
 
     #[inline]
-    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         self.0.advance_by(n)
     }
 }
@@ -260,7 +260,7 @@ impl Iterator for EscapeDefault {
     }
 
     #[inline]
-    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         self.0.advance_by(n)
     }
 }
diff --git a/library/core/src/cmp/bytewise.rs b/library/core/src/cmp/bytewise.rs
index 2548d9e24c9db..b19eef8e25587 100644
--- a/library/core/src/cmp/bytewise.rs
+++ b/library/core/src/cmp/bytewise.rs
@@ -33,7 +33,7 @@ is_bytewise_comparable!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128,
 // so we can compare them directly.
 is_bytewise_comparable!(bool, char, super::Ordering);
 
-// SAFETY: Similarly, the non-zero types have a niche, but no undef and no pointers,
+// SAFETY: Similarly, the `NonZero` type has a niche, but no undef and no pointers,
 // and they compare like their underlying numeric type.
 is_bytewise_comparable!(
     NonZeroU8,
@@ -50,7 +50,7 @@ is_bytewise_comparable!(
     NonZeroIsize,
 );
 
-// SAFETY: The NonZero types have the "null" optimization guaranteed, and thus
+// SAFETY: The `NonZero` type has the "null" optimization guaranteed, and thus
 // are also safe to equality-compare bitwise inside an `Option`.
 // The way `PartialOrd` is defined for `Option` means that this wouldn't work
 // for `<` or `>` on the signed types, but since we only do `==` it's fine.
diff --git a/library/core/src/escape.rs b/library/core/src/escape.rs
index 60b5df752ca85..143e277283e2c 100644
--- a/library/core/src/escape.rs
+++ b/library/core/src/escape.rs
@@ -1,7 +1,7 @@
 //! Helper code for character escaping.
 
 use crate::ascii;
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ops::Range;
 
 const HEX_DIGITS: [ascii::Char; 16] = *b"0123456789abcdef".as_ascii().unwrap();
@@ -106,11 +106,11 @@ impl<const N: usize> EscapeIterInner<N> {
         self.alive.next_back().map(|i| self.data[usize::from(i)].to_u8())
     }
 
-    pub fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    pub fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         self.alive.advance_by(n)
     }
 
-    pub fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    pub fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         self.alive.advance_back_by(n)
     }
 }
diff --git a/library/core/src/iter/adapters/array_chunks.rs b/library/core/src/iter/adapters/array_chunks.rs
index 946d0051ccec3..2e437b41dcebc 100644
--- a/library/core/src/iter/adapters/array_chunks.rs
+++ b/library/core/src/iter/adapters/array_chunks.rs
@@ -3,7 +3,7 @@ use crate::iter::adapters::SourceIter;
 use crate::iter::{
     ByRefSized, FusedIterator, InPlaceIterable, TrustedFused, TrustedRandomAccessNoCoerce,
 };
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ops::{ControlFlow, NeverShortCircuit, Try};
 
 /// An iterator over `N` elements of the iterator at a time.
@@ -253,9 +253,9 @@ where
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe impl<I: InPlaceIterable + Iterator, const N: usize> InPlaceIterable for ArrayChunks<I, N> {
-    const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
-    const MERGE_BY: Option<NonZeroUsize> = const {
-        match (I::MERGE_BY, NonZeroUsize::new(N)) {
+    const EXPAND_BY: Option<NonZero<usize>> = I::EXPAND_BY;
+    const MERGE_BY: Option<NonZero<usize>> = const {
+        match (I::MERGE_BY, NonZero::<usize>::new(N)) {
             (Some(m), Some(n)) => m.checked_mul(n),
             _ => None,
         }
diff --git a/library/core/src/iter/adapters/by_ref_sized.rs b/library/core/src/iter/adapters/by_ref_sized.rs
index 4e0e19ddc7822..d084bede1eba6 100644
--- a/library/core/src/iter/adapters/by_ref_sized.rs
+++ b/library/core/src/iter/adapters/by_ref_sized.rs
@@ -1,4 +1,4 @@
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ops::{NeverShortCircuit, Try};
 
 /// Like `Iterator::by_ref`, but requiring `Sized` so it can forward generics.
@@ -27,7 +27,7 @@ impl<I: Iterator> Iterator for ByRefSized<'_, I> {
     }
 
     #[inline]
-    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         I::advance_by(self.0, n)
     }
 
@@ -63,7 +63,7 @@ impl<I: DoubleEndedIterator> DoubleEndedIterator for ByRefSized<'_, I> {
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         I::advance_back_by(self.0, n)
     }
 
diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs
index c748336cd7fa0..7edfee7bf6c5f 100644
--- a/library/core/src/iter/adapters/chain.rs
+++ b/library/core/src/iter/adapters/chain.rs
@@ -1,5 +1,5 @@
 use crate::iter::{FusedIterator, TrustedLen};
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ops::Try;
 
 /// An iterator that links two iterators together, in a chain.
@@ -96,7 +96,7 @@ where
     }
 
     #[inline]
-    fn advance_by(&mut self, mut n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_by(&mut self, mut n: usize) -> Result<(), NonZero<usize>> {
         if let Some(ref mut a) = self.a {
             n = match a.advance_by(n) {
                 Ok(()) => return Ok(()),
@@ -110,7 +110,7 @@ where
             // we don't fuse the second iterator
         }
 
-        NonZeroUsize::new(n).map_or(Ok(()), Err)
+        NonZero::<usize>::new(n).map_or(Ok(()), Err)
     }
 
     #[inline]
@@ -182,7 +182,7 @@ where
     }
 
     #[inline]
-    fn advance_back_by(&mut self, mut n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_back_by(&mut self, mut n: usize) -> Result<(), NonZero<usize>> {
         if let Some(ref mut b) = self.b {
             n = match b.advance_back_by(n) {
                 Ok(()) => return Ok(()),
@@ -196,7 +196,7 @@ where
             // we don't fuse the second iterator
         }
 
-        NonZeroUsize::new(n).map_or(Ok(()), Err)
+        NonZero::<usize>::new(n).map_or(Ok(()), Err)
     }
 
     #[inline]
diff --git a/library/core/src/iter/adapters/cloned.rs b/library/core/src/iter/adapters/cloned.rs
index 3de91267cf5d9..1a106ef97942b 100644
--- a/library/core/src/iter/adapters/cloned.rs
+++ b/library/core/src/iter/adapters/cloned.rs
@@ -3,7 +3,7 @@ use crate::iter::adapters::{
 };
 use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen, UncheckedIterator};
 use crate::ops::Try;
-use core::num::NonZeroUsize;
+use core::num::NonZero;
 
 /// An iterator that clones the elements of an underlying iterator.
 ///
@@ -185,6 +185,6 @@ where
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe impl<I: InPlaceIterable> InPlaceIterable for Cloned<I> {
-    const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
-    const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
+    const EXPAND_BY: Option<NonZero<usize>> = I::EXPAND_BY;
+    const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
 }
diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs
index 52a5add1132a4..6d82d1581f79d 100644
--- a/library/core/src/iter/adapters/copied.rs
+++ b/library/core/src/iter/adapters/copied.rs
@@ -4,7 +4,7 @@ use crate::iter::adapters::{
 use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen};
 use crate::mem::MaybeUninit;
 use crate::mem::SizedTypeProperties;
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ops::Try;
 use crate::{array, ptr};
 
@@ -90,7 +90,7 @@ where
     }
 
     #[inline]
-    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         self.it.advance_by(n)
     }
 
@@ -131,7 +131,7 @@ where
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         self.it.advance_back_by(n)
     }
 }
@@ -272,6 +272,6 @@ where
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe impl<I: InPlaceIterable> InPlaceIterable for Copied<I> {
-    const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
-    const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
+    const EXPAND_BY: Option<NonZero<usize>> = I::EXPAND_BY;
+    const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
 }
diff --git a/library/core/src/iter/adapters/cycle.rs b/library/core/src/iter/adapters/cycle.rs
index 51bd09b6effe1..7919c040dba9b 100644
--- a/library/core/src/iter/adapters/cycle.rs
+++ b/library/core/src/iter/adapters/cycle.rs
@@ -1,4 +1,4 @@
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::{iter::FusedIterator, ops::Try};
 
 /// An iterator that repeats endlessly.
@@ -82,7 +82,7 @@ where
 
     #[inline]
     #[rustc_inherit_overflow_checks]
-    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         let mut n = match self.iter.advance_by(n) {
             Ok(()) => return Ok(()),
             Err(rem) => rem.get(),
@@ -97,7 +97,7 @@ where
             };
         }
 
-        NonZeroUsize::new(n).map_or(Ok(()), Err)
+        NonZero::<usize>::new(n).map_or(Ok(()), Err)
     }
 
     // No `fold` override, because `fold` doesn't make much sense for `Cycle`,
diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs
index 92f465ccdb4e8..ef46040f0a703 100644
--- a/library/core/src/iter/adapters/enumerate.rs
+++ b/library/core/src/iter/adapters/enumerate.rs
@@ -2,7 +2,7 @@ use crate::iter::adapters::{
     zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce,
 };
 use crate::iter::{FusedIterator, InPlaceIterable, TrustedFused, TrustedLen};
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ops::Try;
 
 /// An iterator that yields the current count and the element during iteration.
@@ -115,7 +115,7 @@ where
 
     #[inline]
     #[rustc_inherit_overflow_checks]
-    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         let remaining = self.iter.advance_by(n);
         let advanced = match remaining {
             Ok(()) => n,
@@ -206,7 +206,7 @@ where
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         // we do not need to update the count since that only tallies the number of items
         // consumed from the front. consuming items from the back can never reduce that.
         self.iter.advance_back_by(n)
@@ -265,8 +265,8 @@ where
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe impl<I: InPlaceIterable> InPlaceIterable for Enumerate<I> {
-    const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
-    const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
+    const EXPAND_BY: Option<NonZero<usize>> = I::EXPAND_BY;
+    const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
 }
 
 #[stable(feature = "default_iters", since = "1.70.0")]
diff --git a/library/core/src/iter/adapters/filter.rs b/library/core/src/iter/adapters/filter.rs
index 882f3e3bc60f5..a7f1fde6975c0 100644
--- a/library/core/src/iter/adapters/filter.rs
+++ b/library/core/src/iter/adapters/filter.rs
@@ -1,6 +1,6 @@
 use crate::fmt;
 use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedFused};
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ops::Try;
 use core::array;
 use core::mem::{ManuallyDrop, MaybeUninit};
@@ -209,6 +209,6 @@ where
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe impl<I: InPlaceIterable, P> InPlaceIterable for Filter<I, P> {
-    const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
-    const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
+    const EXPAND_BY: Option<NonZero<usize>> = I::EXPAND_BY;
+    const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
 }
diff --git a/library/core/src/iter/adapters/filter_map.rs b/library/core/src/iter/adapters/filter_map.rs
index 81ac0eaa67e95..64bd5b3e2b668 100644
--- a/library/core/src/iter/adapters/filter_map.rs
+++ b/library/core/src/iter/adapters/filter_map.rs
@@ -1,6 +1,6 @@
 use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedFused};
 use crate::mem::{ManuallyDrop, MaybeUninit};
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ops::{ControlFlow, Try};
 use crate::{array, fmt};
 
@@ -210,6 +210,6 @@ where
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe impl<I: InPlaceIterable, F> InPlaceIterable for FilterMap<I, F> {
-    const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
-    const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
+    const EXPAND_BY: Option<NonZero<usize>> = I::EXPAND_BY;
+    const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
 }
diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs
index 7d6f746845e31..42396157d863d 100644
--- a/library/core/src/iter/adapters/flatten.rs
+++ b/library/core/src/iter/adapters/flatten.rs
@@ -4,7 +4,7 @@ use crate::iter::{
     TrustedLen,
 };
 use crate::iter::{Once, OnceWith};
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ops::{ControlFlow, Try};
 use crate::result;
 use crate::{array, fmt, option};
@@ -90,7 +90,7 @@ where
     }
 
     #[inline]
-    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         self.inner.advance_by(n)
     }
 
@@ -135,7 +135,7 @@ where
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         self.inner.advance_back_by(n)
     }
 }
@@ -165,13 +165,13 @@ where
     I: InPlaceIterable,
     U: BoundedSize + IntoIterator,
 {
-    const EXPAND_BY: Option<NonZeroUsize> = const {
+    const EXPAND_BY: Option<NonZero<usize>> = const {
         match (I::EXPAND_BY, U::UPPER_BOUND) {
             (Some(m), Some(n)) => m.checked_mul(n),
             _ => None,
         }
     };
-    const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
+    const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
 }
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
@@ -200,7 +200,7 @@ where
 #[rustc_specialization_trait]
 #[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe trait BoundedSize {
-    const UPPER_BOUND: Option<NonZeroUsize> = NonZeroUsize::new(1);
+    const UPPER_BOUND: Option<NonZero<usize>> = NonZero::<usize>::new(1);
 }
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
@@ -217,31 +217,31 @@ unsafe impl<T> BoundedSize for Once<T> {}
 unsafe impl<T> BoundedSize for OnceWith<T> {}
 #[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe impl<T, const N: usize> BoundedSize for [T; N] {
-    const UPPER_BOUND: Option<NonZeroUsize> = NonZeroUsize::new(N);
+    const UPPER_BOUND: Option<NonZero<usize>> = NonZero::<usize>::new(N);
 }
 #[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe impl<T, const N: usize> BoundedSize for array::IntoIter<T, N> {
-    const UPPER_BOUND: Option<NonZeroUsize> = NonZeroUsize::new(N);
+    const UPPER_BOUND: Option<NonZero<usize>> = NonZero::<usize>::new(N);
 }
 #[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe impl<I: BoundedSize, P> BoundedSize for Filter<I, P> {
-    const UPPER_BOUND: Option<NonZeroUsize> = I::UPPER_BOUND;
+    const UPPER_BOUND: Option<NonZero<usize>> = I::UPPER_BOUND;
 }
 #[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe impl<I: BoundedSize, P> BoundedSize for FilterMap<I, P> {
-    const UPPER_BOUND: Option<NonZeroUsize> = I::UPPER_BOUND;
+    const UPPER_BOUND: Option<NonZero<usize>> = I::UPPER_BOUND;
 }
 #[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe impl<I: BoundedSize, F> BoundedSize for Map<I, F> {
-    const UPPER_BOUND: Option<NonZeroUsize> = I::UPPER_BOUND;
+    const UPPER_BOUND: Option<NonZero<usize>> = I::UPPER_BOUND;
 }
 #[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe impl<I: BoundedSize> BoundedSize for Copied<I> {
-    const UPPER_BOUND: Option<NonZeroUsize> = I::UPPER_BOUND;
+    const UPPER_BOUND: Option<NonZero<usize>> = I::UPPER_BOUND;
 }
 #[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe impl<I: BoundedSize> BoundedSize for Cloned<I> {
-    const UPPER_BOUND: Option<NonZeroUsize> = I::UPPER_BOUND;
+    const UPPER_BOUND: Option<NonZero<usize>> = I::UPPER_BOUND;
 }
 
 /// An iterator that flattens one level of nesting in an iterator of things
@@ -322,7 +322,7 @@ where
     }
 
     #[inline]
-    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         self.inner.advance_by(n)
     }
 
@@ -367,7 +367,7 @@ where
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         self.inner.advance_back_by(n)
     }
 }
@@ -394,13 +394,13 @@ where
     I: InPlaceIterable + Iterator,
     <I as Iterator>::Item: IntoIterator + BoundedSize,
 {
-    const EXPAND_BY: Option<NonZeroUsize> = const {
+    const EXPAND_BY: Option<NonZero<usize>> = const {
         match (I::EXPAND_BY, I::Item::UPPER_BOUND) {
             (Some(m), Some(n)) => m.checked_mul(n),
             _ => None,
         }
     };
-    const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
+    const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
 }
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
@@ -669,7 +669,7 @@ where
 
     #[inline]
     #[rustc_inherit_overflow_checks]
-    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         #[inline]
         #[rustc_inherit_overflow_checks]
         fn advance<U: Iterator>(n: usize, iter: &mut U) -> ControlFlow<(), usize> {
@@ -680,7 +680,9 @@ where
         }
 
         match self.iter_try_fold(n, advance) {
-            ControlFlow::Continue(remaining) => NonZeroUsize::new(remaining).map_or(Ok(()), Err),
+            ControlFlow::Continue(remaining) => {
+                NonZero::<usize>::new(remaining).map_or(Ok(()), Err)
+            }
             _ => Ok(()),
         }
     }
@@ -759,7 +761,7 @@ where
 
     #[inline]
     #[rustc_inherit_overflow_checks]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         #[inline]
         #[rustc_inherit_overflow_checks]
         fn advance<U: DoubleEndedIterator>(n: usize, iter: &mut U) -> ControlFlow<(), usize> {
@@ -770,7 +772,9 @@ where
         }
 
         match self.iter_try_rfold(n, advance) {
-            ControlFlow::Continue(remaining) => NonZeroUsize::new(remaining).map_or(Ok(()), Err),
+            ControlFlow::Continue(remaining) => {
+                NonZero::<usize>::new(remaining).map_or(Ok(()), Err)
+            }
             _ => Ok(()),
         }
     }
diff --git a/library/core/src/iter/adapters/inspect.rs b/library/core/src/iter/adapters/inspect.rs
index fd2d830b693d1..1c4656a649a37 100644
--- a/library/core/src/iter/adapters/inspect.rs
+++ b/library/core/src/iter/adapters/inspect.rs
@@ -1,6 +1,6 @@
 use crate::fmt;
 use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedFused};
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ops::Try;
 
 /// An iterator that calls a function with a reference to each element before
@@ -168,6 +168,6 @@ where
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe impl<I: InPlaceIterable, F> InPlaceIterable for Inspect<I, F> {
-    const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
-    const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
+    const EXPAND_BY: Option<NonZero<usize>> = I::EXPAND_BY;
+    const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
 }
diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs
index c882c9e7f3f51..6e163e20d8ec4 100644
--- a/library/core/src/iter/adapters/map.rs
+++ b/library/core/src/iter/adapters/map.rs
@@ -3,7 +3,7 @@ use crate::iter::adapters::{
     zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce,
 };
 use crate::iter::{FusedIterator, InPlaceIterable, TrustedFused, TrustedLen, UncheckedIterator};
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ops::Try;
 
 /// An iterator that maps the values of `iter` with `f`.
@@ -237,6 +237,6 @@ where
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe impl<I: InPlaceIterable, F> InPlaceIterable for Map<I, F> {
-    const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
-    const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
+    const EXPAND_BY: Option<NonZero<usize>> = I::EXPAND_BY;
+    const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
 }
diff --git a/library/core/src/iter/adapters/map_while.rs b/library/core/src/iter/adapters/map_while.rs
index bcae73cbe09cf..9ad50048c25ea 100644
--- a/library/core/src/iter/adapters/map_while.rs
+++ b/library/core/src/iter/adapters/map_while.rs
@@ -1,6 +1,6 @@
 use crate::fmt;
 use crate::iter::{adapters::SourceIter, InPlaceIterable};
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ops::{ControlFlow, Try};
 
 /// An iterator that only accepts elements while `predicate` returns `Some(_)`.
@@ -84,6 +84,6 @@ where
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe impl<I: InPlaceIterable, P> InPlaceIterable for MapWhile<I, P> {
-    const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
-    const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
+    const EXPAND_BY: Option<NonZero<usize>> = I::EXPAND_BY;
+    const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
 }
diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs
index 4037e2e2839c0..cc514bd914f14 100644
--- a/library/core/src/iter/adapters/mod.rs
+++ b/library/core/src/iter/adapters/mod.rs
@@ -1,5 +1,5 @@
 use crate::iter::InPlaceIterable;
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try};
 
 mod array_chunks;
@@ -234,6 +234,6 @@ unsafe impl<I, R> InPlaceIterable for GenericShunt<'_, I, R>
 where
     I: InPlaceIterable,
 {
-    const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
-    const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
+    const EXPAND_BY: Option<NonZero<usize>> = I::EXPAND_BY;
+    const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
 }
diff --git a/library/core/src/iter/adapters/rev.rs b/library/core/src/iter/adapters/rev.rs
index 4aaf7c61f50d6..06ab15d5e900d 100644
--- a/library/core/src/iter/adapters/rev.rs
+++ b/library/core/src/iter/adapters/rev.rs
@@ -1,5 +1,5 @@
 use crate::iter::{FusedIterator, TrustedLen};
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ops::Try;
 
 /// A double-ended iterator with the direction inverted.
@@ -39,7 +39,7 @@ where
     }
 
     #[inline]
-    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         self.iter.advance_back_by(n)
     }
 
@@ -84,7 +84,7 @@ where
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         self.iter.advance_by(n)
     }
 
diff --git a/library/core/src/iter/adapters/scan.rs b/library/core/src/iter/adapters/scan.rs
index 635bad199ff95..d261a535b183a 100644
--- a/library/core/src/iter/adapters/scan.rs
+++ b/library/core/src/iter/adapters/scan.rs
@@ -1,6 +1,6 @@
 use crate::fmt;
 use crate::iter::{adapters::SourceIter, InPlaceIterable};
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ops::{ControlFlow, Try};
 
 /// An iterator to maintain state while iterating another iterator.
@@ -94,6 +94,6 @@ where
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe impl<St, F, I: InPlaceIterable> InPlaceIterable for Scan<I, St, F> {
-    const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
-    const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
+    const EXPAND_BY: Option<NonZero<usize>> = I::EXPAND_BY;
+    const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
 }
diff --git a/library/core/src/iter/adapters/skip.rs b/library/core/src/iter/adapters/skip.rs
index f5188dd458df9..20a3b616f81e5 100644
--- a/library/core/src/iter/adapters/skip.rs
+++ b/library/core/src/iter/adapters/skip.rs
@@ -5,7 +5,7 @@ use crate::iter::{
     adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen, TrustedRandomAccess,
     TrustedRandomAccessNoCoerce,
 };
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ops::{ControlFlow, Try};
 
 /// An iterator that skips over `n` elements of `iter`.
@@ -134,7 +134,7 @@ where
 
     #[inline]
     #[rustc_inherit_overflow_checks]
-    fn advance_by(&mut self, mut n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_by(&mut self, mut n: usize) -> Result<(), NonZero<usize>> {
         let skip_inner = self.n;
         let skip_and_advance = skip_inner.saturating_add(n);
 
@@ -154,7 +154,7 @@ where
             }
         }
 
-        NonZeroUsize::new(n).map_or(Ok(()), Err)
+        NonZero::<usize>::new(n).map_or(Ok(()), Err)
     }
 
     #[doc(hidden)]
@@ -234,11 +234,11 @@ where
     impl_fold_via_try_fold! { rfold -> try_rfold }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         let min = crate::cmp::min(self.len(), n);
         let rem = self.iter.advance_back_by(min);
         assert!(rem.is_ok(), "ExactSizeIterator contract violation");
-        NonZeroUsize::new(n - min).map_or(Ok(()), Err)
+        NonZero::<usize>::new(n - min).map_or(Ok(()), Err)
     }
 }
 
@@ -264,8 +264,8 @@ where
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe impl<I: InPlaceIterable> InPlaceIterable for Skip<I> {
-    const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
-    const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
+    const EXPAND_BY: Option<NonZero<usize>> = I::EXPAND_BY;
+    const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
 }
 
 #[doc(hidden)]
diff --git a/library/core/src/iter/adapters/skip_while.rs b/library/core/src/iter/adapters/skip_while.rs
index 3a661973e5fe0..8001e6e64713a 100644
--- a/library/core/src/iter/adapters/skip_while.rs
+++ b/library/core/src/iter/adapters/skip_while.rs
@@ -1,6 +1,6 @@
 use crate::fmt;
 use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedFused};
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ops::Try;
 
 /// An iterator that rejects elements while `predicate` returns `true`.
@@ -124,6 +124,6 @@ where
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe impl<I: InPlaceIterable, F> InPlaceIterable for SkipWhile<I, F> {
-    const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
-    const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
+    const EXPAND_BY: Option<NonZero<usize>> = I::EXPAND_BY;
+    const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
 }
diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs
index 80e06066d28f9..e668e66253607 100644
--- a/library/core/src/iter/adapters/take.rs
+++ b/library/core/src/iter/adapters/take.rs
@@ -3,7 +3,7 @@ use crate::iter::{
     adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedFused, TrustedLen,
     TrustedRandomAccess,
 };
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ops::{ControlFlow, Try};
 
 /// An iterator that only iterates over the first `n` iterations of `iter`.
@@ -117,7 +117,7 @@ where
 
     #[inline]
     #[rustc_inherit_overflow_checks]
-    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         let min = self.n.min(n);
         let rem = match self.iter.advance_by(min) {
             Ok(()) => 0,
@@ -125,7 +125,7 @@ where
         };
         let advanced = min - rem;
         self.n -= advanced;
-        NonZeroUsize::new(n - advanced).map_or(Ok(()), Err)
+        NonZero::<usize>::new(n - advanced).map_or(Ok(()), Err)
     }
 }
 
@@ -145,8 +145,8 @@ where
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe impl<I: InPlaceIterable> InPlaceIterable for Take<I> {
-    const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
-    const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
+    const EXPAND_BY: Option<NonZero<usize>> = I::EXPAND_BY;
+    const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
 }
 
 #[stable(feature = "double_ended_take_iterator", since = "1.38.0")]
@@ -219,7 +219,7 @@ where
 
     #[inline]
     #[rustc_inherit_overflow_checks]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         // The amount by which the inner iterator needs to be shortened for it to be
         // at most as long as the take() amount.
         let trim_inner = self.iter.len().saturating_sub(self.n);
@@ -235,7 +235,7 @@ where
         let advanced_by_inner = advance_by - remainder;
         let advanced_by = advanced_by_inner - trim_inner;
         self.n -= advanced_by;
-        NonZeroUsize::new(n - advanced_by).map_or(Ok(()), Err)
+        NonZero::<usize>::new(n - advanced_by).map_or(Ok(()), Err)
     }
 }
 
diff --git a/library/core/src/iter/adapters/take_while.rs b/library/core/src/iter/adapters/take_while.rs
index e55d55a6d2377..d3f09ab356ad8 100644
--- a/library/core/src/iter/adapters/take_while.rs
+++ b/library/core/src/iter/adapters/take_while.rs
@@ -1,6 +1,6 @@
 use crate::fmt;
 use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedFused};
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ops::{ControlFlow, Try};
 
 /// An iterator that only accepts elements while `predicate` returns `true`.
@@ -125,6 +125,6 @@ where
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe impl<I: InPlaceIterable, F> InPlaceIterable for TakeWhile<I, F> {
-    const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
-    const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
+    const EXPAND_BY: Option<NonZero<usize>> = I::EXPAND_BY;
+    const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
 }
diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs
index b33400fab476f..2e885f06b5272 100644
--- a/library/core/src/iter/adapters/zip.rs
+++ b/library/core/src/iter/adapters/zip.rs
@@ -2,7 +2,7 @@ use crate::cmp;
 use crate::fmt::{self, Debug};
 use crate::iter::{FusedIterator, TrustedFused};
 use crate::iter::{InPlaceIterable, SourceIter, TrustedLen, UncheckedIterator};
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 
 /// An iterator that iterates two other iterators simultaneously.
 ///
@@ -489,8 +489,8 @@ where
 // Since SourceIter forwards the left hand side we do the same here
 #[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe impl<A: InPlaceIterable, B> InPlaceIterable for Zip<A, B> {
-    const EXPAND_BY: Option<NonZeroUsize> = A::EXPAND_BY;
-    const MERGE_BY: Option<NonZeroUsize> = A::MERGE_BY;
+    const EXPAND_BY: Option<NonZero<usize>> = A::EXPAND_BY;
+    const MERGE_BY: Option<NonZero<usize>> = A::MERGE_BY;
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs
index 0e03d0c2d4e4f..7a4748dcc0d8c 100644
--- a/library/core/src/iter/range.rs
+++ b/library/core/src/iter/range.rs
@@ -2,7 +2,7 @@ use crate::ascii::Char as AsciiChar;
 use crate::convert::TryFrom;
 use crate::mem;
 use crate::net::{Ipv4Addr, Ipv6Addr};
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ops::{self, Try};
 
 use super::{
@@ -629,12 +629,12 @@ trait RangeIteratorImpl {
     // Iterator
     fn spec_next(&mut self) -> Option<Self::Item>;
     fn spec_nth(&mut self, n: usize) -> Option<Self::Item>;
-    fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize>;
+    fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>>;
 
     // DoubleEndedIterator
     fn spec_next_back(&mut self) -> Option<Self::Item>;
     fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item>;
-    fn spec_advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize>;
+    fn spec_advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>>;
 }
 
 impl<A: Step> RangeIteratorImpl for ops::Range<A> {
@@ -666,7 +666,7 @@ impl<A: Step> RangeIteratorImpl for ops::Range<A> {
     }
 
     #[inline]
-    default fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    default fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         let available = if self.start <= self.end {
             Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX)
         } else {
@@ -678,7 +678,7 @@ impl<A: Step> RangeIteratorImpl for ops::Range<A> {
         self.start =
             Step::forward_checked(self.start.clone(), taken).expect("`Step` invariants not upheld");
 
-        NonZeroUsize::new(n - taken).map_or(Ok(()), Err)
+        NonZero::<usize>::new(n - taken).map_or(Ok(()), Err)
     }
 
     #[inline]
@@ -707,7 +707,7 @@ impl<A: Step> RangeIteratorImpl for ops::Range<A> {
     }
 
     #[inline]
-    default fn spec_advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    default fn spec_advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         let available = if self.start <= self.end {
             Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX)
         } else {
@@ -719,7 +719,7 @@ impl<A: Step> RangeIteratorImpl for ops::Range<A> {
         self.end =
             Step::backward_checked(self.end.clone(), taken).expect("`Step` invariants not upheld");
 
-        NonZeroUsize::new(n - taken).map_or(Ok(()), Err)
+        NonZero::<usize>::new(n - taken).map_or(Ok(()), Err)
     }
 }
 
@@ -751,7 +751,7 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> {
     }
 
     #[inline]
-    fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         let available = if self.start <= self.end {
             Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX)
         } else {
@@ -766,7 +766,7 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> {
         // Otherwise 0 is returned which always safe to use.
         self.start = unsafe { Step::forward_unchecked(self.start, taken) };
 
-        NonZeroUsize::new(n - taken).map_or(Ok(()), Err)
+        NonZero::<usize>::new(n - taken).map_or(Ok(()), Err)
     }
 
     #[inline]
@@ -795,7 +795,7 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> {
     }
 
     #[inline]
-    fn spec_advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn spec_advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         let available = if self.start <= self.end {
             Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX)
         } else {
@@ -807,7 +807,7 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> {
         // SAFETY: same as the spec_advance_by() implementation
         self.end = unsafe { Step::backward_unchecked(self.end, taken) };
 
-        NonZeroUsize::new(n - taken).map_or(Ok(()), Err)
+        NonZero::<usize>::new(n - taken).map_or(Ok(()), Err)
     }
 }
 
@@ -871,7 +871,7 @@ impl<A: Step> Iterator for ops::Range<A> {
     }
 
     #[inline]
-    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         self.spec_advance_by(n)
     }
 
@@ -949,7 +949,7 @@ impl<A: Step> DoubleEndedIterator for ops::Range<A> {
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         self.spec_advance_back_by(n)
     }
 }
diff --git a/library/core/src/iter/sources/repeat.rs b/library/core/src/iter/sources/repeat.rs
index 67051f6e97bdd..0168b11c7394a 100644
--- a/library/core/src/iter/sources/repeat.rs
+++ b/library/core/src/iter/sources/repeat.rs
@@ -1,5 +1,5 @@
 use crate::iter::{FusedIterator, TrustedLen};
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 
 /// Creates a new iterator that endlessly repeats a single element.
 ///
@@ -81,7 +81,7 @@ impl<A: Clone> Iterator for Repeat<A> {
     }
 
     #[inline]
-    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         // Advancing an infinite iterator of a single element is a no-op.
         let _ = n;
         Ok(())
@@ -110,7 +110,7 @@ impl<A: Clone> DoubleEndedIterator for Repeat<A> {
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         // Advancing an infinite iterator of a single element is a no-op.
         let _ = n;
         Ok(())
diff --git a/library/core/src/iter/sources/repeat_n.rs b/library/core/src/iter/sources/repeat_n.rs
index db2f8b7ac283f..77bb8372a446a 100644
--- a/library/core/src/iter/sources/repeat_n.rs
+++ b/library/core/src/iter/sources/repeat_n.rs
@@ -1,6 +1,6 @@
 use crate::iter::{FusedIterator, TrustedLen};
 use crate::mem::ManuallyDrop;
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 
 /// Creates a new iterator that repeats a single element a given number of times.
 ///
@@ -136,7 +136,7 @@ impl<A: Clone> Iterator for RepeatN<A> {
     }
 
     #[inline]
-    fn advance_by(&mut self, skip: usize) -> Result<(), NonZeroUsize> {
+    fn advance_by(&mut self, skip: usize) -> Result<(), NonZero<usize>> {
         let len = self.count;
 
         if skip >= len {
@@ -145,7 +145,7 @@ impl<A: Clone> Iterator for RepeatN<A> {
 
         if skip > len {
             // SAFETY: we just checked that the difference is positive
-            Err(unsafe { NonZeroUsize::new_unchecked(skip - len) })
+            Err(unsafe { NonZero::<usize>::new_unchecked(skip - len) })
         } else {
             self.count = len - skip;
             Ok(())
@@ -178,7 +178,7 @@ impl<A: Clone> DoubleEndedIterator for RepeatN<A> {
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         self.advance_by(n)
     }
 
diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs
index 4c8af4eba7889..eb830256962e1 100644
--- a/library/core/src/iter/traits/double_ended.rs
+++ b/library/core/src/iter/traits/double_ended.rs
@@ -1,4 +1,4 @@
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ops::{ControlFlow, Try};
 
 /// An iterator able to yield elements from both ends.
@@ -119,8 +119,8 @@ pub trait DoubleEndedIterator: Iterator {
     ///
     /// ```
     /// #![feature(iter_advance_by)]
-    ///
     /// use std::num::NonZeroUsize;
+    ///
     /// let a = [3, 4, 5, 6];
     /// let mut iter = a.iter();
     ///
@@ -134,11 +134,11 @@ pub trait DoubleEndedIterator: Iterator {
     /// [`Err(k)`]: Err
     #[inline]
     #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         for i in 0..n {
             if self.next_back().is_none() {
                 // SAFETY: `i` is always less than `n`.
-                return Err(unsafe { NonZeroUsize::new_unchecked(n - i) });
+                return Err(unsafe { NonZero::<usize>::new_unchecked(n - i) });
             }
         }
         Ok(())
@@ -373,7 +373,7 @@ impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I {
     fn next_back(&mut self) -> Option<I::Item> {
         (**self).next_back()
     }
-    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         (**self).advance_back_by(n)
     }
     fn nth_back(&mut self, n: usize) -> Option<I::Item> {
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index 20dd95a3a4623..6df66e779c425 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -1,6 +1,6 @@
 use crate::array;
 use crate::cmp::{self, Ordering};
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try};
 
 use super::super::try_process;
@@ -320,8 +320,8 @@ pub trait Iterator {
     ///
     /// ```
     /// #![feature(iter_advance_by)]
-    ///
     /// use std::num::NonZeroUsize;
+    ///
     /// let a = [1, 2, 3, 4];
     /// let mut iter = a.iter();
     ///
@@ -333,11 +333,11 @@ pub trait Iterator {
     #[inline]
     #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")]
     #[rustc_do_not_const_check]
-    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         for i in 0..n {
             if self.next().is_none() {
                 // SAFETY: `i` is always less than `n`.
-                return Err(unsafe { NonZeroUsize::new_unchecked(n - i) });
+                return Err(unsafe { NonZero::<usize>::new_unchecked(n - i) });
             }
         }
         Ok(())
@@ -4138,7 +4138,7 @@ impl<I: Iterator + ?Sized> Iterator for &mut I {
     fn size_hint(&self) -> (usize, Option<usize>) {
         (**self).size_hint()
     }
-    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         (**self).advance_by(n)
     }
     fn nth(&mut self, n: usize) -> Option<Self::Item> {
diff --git a/library/core/src/iter/traits/marker.rs b/library/core/src/iter/traits/marker.rs
index e7c1f195aacc6..8bdbca120d7f9 100644
--- a/library/core/src/iter/traits/marker.rs
+++ b/library/core/src/iter/traits/marker.rs
@@ -1,5 +1,5 @@
 use crate::iter::Step;
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 
 /// Same as FusedIterator
 ///
@@ -91,12 +91,12 @@ pub unsafe trait InPlaceIterable {
     /// E.g. [[u8; 4]; 4].iter().flatten().flatten() would have a `EXPAND_BY` of 16.
     /// This is an upper bound, i.e. the transformations will produce at most this many items per
     /// input. It's meant for layout calculations.
-    const EXPAND_BY: Option<NonZeroUsize>;
+    const EXPAND_BY: Option<NonZero<usize>>;
     /// The product of many-to-one item reductions that happen throughout the iterator pipeline.
     /// E.g. [u8].iter().array_chunks::<4>().array_chunks::<4>() would have a `MERGE_BY` of 16.
     /// This is a lower bound, i.e. the transformations will consume at least this many items per
     /// output.
-    const MERGE_BY: Option<NonZeroUsize>;
+    const MERGE_BY: Option<NonZero<usize>>;
 }
 
 /// A type that upholds all invariants of [`Step`].
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 288ad8e8d8784..ddaffadf4bf7b 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -312,10 +312,10 @@ macro_rules! nonzero_integer {
             /// #![feature(non_zero_count_ones)]
             /// # fn main() { test().unwrap(); }
             /// # fn test() -> Option<()> {
-            #[doc = concat!("# use std::num::{self, ", stringify!($Ty), "};")]
-            ///
-            /// let one = num::NonZeroU32::new(1)?;
-            /// let three = num::NonZeroU32::new(3)?;
+            /// # use std::num::*;
+            /// #
+            /// let one = NonZeroU32::new(1)?;
+            /// let three = NonZeroU32::new(3)?;
             #[doc = concat!("let a = ", stringify!($Ty), "::new(0b100_0000)?;")]
             #[doc = concat!("let b = ", stringify!($Ty), "::new(0b100_0011)?;")]
             ///
@@ -336,7 +336,7 @@ macro_rules! nonzero_integer {
                 // SAFETY:
                 // `self` is non-zero, which means it has at least one bit set, which means
                 // that the result of `count_ones` is non-zero.
-                unsafe { NonZeroU32::new_unchecked(self.get().count_ones()) }
+                unsafe { NonZero::<u32>::new_unchecked(self.get().count_ones()) }
             }
 
             nonzero_integer_signedness_dependent_methods! {
diff --git a/library/core/src/ops/index_range.rs b/library/core/src/ops/index_range.rs
index 743799c4b3edf..2ba0bd158f74b 100644
--- a/library/core/src/ops/index_range.rs
+++ b/library/core/src/ops/index_range.rs
@@ -1,6 +1,6 @@
 use crate::intrinsics::{unchecked_add, unchecked_sub};
 use crate::iter::{FusedIterator, TrustedLen};
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 
 /// Like a `Range<usize>`, but with a safety invariant that `start <= end`.
 ///
@@ -130,9 +130,9 @@ impl Iterator for IndexRange {
     }
 
     #[inline]
-    fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         let taken = self.take_prefix(n);
-        NonZeroUsize::new(n - taken.len()).map_or(Ok(()), Err)
+        NonZero::<usize>::new(n - taken.len()).map_or(Ok(()), Err)
     }
 }
 
@@ -148,9 +148,9 @@ impl DoubleEndedIterator for IndexRange {
     }
 
     #[inline]
-    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         let taken = self.take_suffix(n);
-        NonZeroUsize::new(n - taken.len()).map_or(Ok(()), Err)
+        NonZero::<usize>::new(n - taken.len()).map_or(Ok(()), Err)
     }
 }
 
diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs
index ce176e6fc18f3..ad22ee5a0271b 100644
--- a/library/core/src/ptr/alignment.rs
+++ b/library/core/src/ptr/alignment.rs
@@ -1,5 +1,5 @@
 use crate::convert::{TryFrom, TryInto};
-use crate::num::NonZeroUsize;
+use crate::num::{NonZero, NonZeroUsize};
 use crate::{cmp, fmt, hash, mem, num};
 
 /// A type storing a `usize` which is a power of two, and thus
@@ -100,7 +100,7 @@ impl Alignment {
     #[inline]
     pub const fn as_nonzero(self) -> NonZeroUsize {
         // SAFETY: All the discriminants are non-zero.
-        unsafe { NonZeroUsize::new_unchecked(self.as_usize()) }
+        unsafe { NonZero::<usize>::new_unchecked(self.as_usize()) }
     }
 
     /// Returns the base-2 logarithm of the alignment.
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 320cd5eb3b2ae..2246596a8832c 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -6,7 +6,7 @@ use crate::intrinsics::assert_unsafe_precondition;
 use crate::marker::Unsize;
 use crate::mem::SizedTypeProperties;
 use crate::mem::{self, MaybeUninit};
-use crate::num::NonZeroUsize;
+use crate::num::{NonZero, NonZeroUsize};
 use crate::ops::{CoerceUnsized, DispatchFromDyn};
 use crate::ptr;
 use crate::ptr::Unique;
@@ -295,7 +295,7 @@ impl<T: ?Sized> NonNull<T> {
     pub fn addr(self) -> NonZeroUsize {
         // SAFETY: The pointer is guaranteed by the type to be non-null,
         // meaning that the address will be non-zero.
-        unsafe { NonZeroUsize::new_unchecked(self.pointer.addr()) }
+        unsafe { NonZero::<usize>::new_unchecked(self.pointer.addr()) }
     }
 
     /// Creates a new pointer with the given address.
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs
index 1429313c89064..617b385a960c4 100644
--- a/library/core/src/slice/iter.rs
+++ b/library/core/src/slice/iter.rs
@@ -11,7 +11,7 @@ use crate::iter::{
 };
 use crate::marker::PhantomData;
 use crate::mem::{self, SizedTypeProperties};
-use crate::num::{NonZero, NonZeroUsize};
+use crate::num::NonZero;
 use crate::ptr::{self, invalid, invalid_mut, NonNull};
 
 use super::{from_raw_parts, from_raw_parts_mut};
diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs
index fc6af45fb9077..53218391dcffd 100644
--- a/library/core/src/slice/iter/macros.rs
+++ b/library/core/src/slice/iter/macros.rs
@@ -196,11 +196,11 @@ macro_rules! iterator {
             }
 
             #[inline]
-            fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+            fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
                 let advance = cmp::min(len!(self), n);
                 // SAFETY: By construction, `advance` does not exceed `self.len()`.
                 unsafe { self.post_inc_start(advance) };
-                NonZeroUsize::new(n - advance).map_or(Ok(()), Err)
+                NonZero::<usize>::new(n - advance).map_or(Ok(()), Err)
             }
 
             #[inline]
@@ -421,11 +421,11 @@ macro_rules! iterator {
             }
 
             #[inline]
-            fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
+            fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
                 let advance = cmp::min(len!(self), n);
                 // SAFETY: By construction, `advance` does not exceed `self.len()`.
                 unsafe { self.pre_dec_end(advance) };
-                NonZeroUsize::new(n - advance).map_or(Ok(()), Err)
+                NonZero::<usize>::new(n - advance).map_or(Ok(()), Err)
             }
         }
 
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 73e92ed1dad63..c70a3d3224d04 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -11,7 +11,7 @@ use crate::fmt;
 use crate::hint;
 use crate::intrinsics::exact_div;
 use crate::mem::{self, SizedTypeProperties};
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ops::{Bound, OneSidedRange, Range, RangeBounds};
 use crate::panic::debug_assert_nounwind;
 use crate::ptr;
@@ -1086,7 +1086,7 @@ impl<T> [T] {
     #[inline]
     #[track_caller]
     pub fn windows(&self, size: usize) -> Windows<'_, T> {
-        let size = NonZeroUsize::new(size).expect("window size must be non-zero");
+        let size = NonZero::<usize>::new(size).expect("window size must be non-zero");
         Windows::new(self, size)
     }
 
diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs
index 4d6239e11a399..d2180fa83fb1e 100644
--- a/library/core/src/str/iter.rs
+++ b/library/core/src/str/iter.rs
@@ -8,7 +8,7 @@ use crate::iter::{TrustedRandomAccess, TrustedRandomAccessNoCoerce};
 use crate::ops::Try;
 use crate::option;
 use crate::slice::{self, Split as SliceSplit};
-use core::num::NonZeroUsize;
+use core::num::{NonZero, NonZeroUsize};
 
 use super::from_utf8_unchecked;
 use super::pattern::Pattern;
@@ -96,7 +96,7 @@ impl<'a> Iterator for Chars<'a> {
             unsafe { self.iter.advance_by(slurp).unwrap_unchecked() };
         }
 
-        NonZeroUsize::new(remainder).map_or(Ok(()), Err)
+        NonZero::<usize>::new(remainder).map_or(Ok(()), Err)
     }
 
     #[inline]
diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs
index ed52de3cbec16..579c140c198c4 100644
--- a/library/core/tests/array.rs
+++ b/library/core/tests/array.rs
@@ -1,4 +1,4 @@
-use core::num::NonZeroUsize;
+use core::num::NonZero;
 use core::sync::atomic::{AtomicUsize, Ordering};
 use core::{array, assert_eq};
 
@@ -548,7 +548,7 @@ fn array_intoiter_advance_by() {
     assert_eq!(counter.get(), 13);
 
     let r = it.advance_by(123456);
-    assert_eq!(r, Err(NonZeroUsize::new(123456 - 87).unwrap()));
+    assert_eq!(r, Err(NonZero::<usize>::new(123456 - 87).unwrap()));
     assert_eq!(it.len(), 0);
     assert_eq!(counter.get(), 100);
 
@@ -558,7 +558,7 @@ fn array_intoiter_advance_by() {
     assert_eq!(counter.get(), 100);
 
     let r = it.advance_by(10);
-    assert_eq!(r, Err(NonZeroUsize::new(10).unwrap()));
+    assert_eq!(r, Err(NonZero::<usize>::new(10).unwrap()));
     assert_eq!(it.len(), 0);
     assert_eq!(counter.get(), 100);
 }
@@ -601,7 +601,7 @@ fn array_intoiter_advance_back_by() {
     assert_eq!(counter.get(), 13);
 
     let r = it.advance_back_by(123456);
-    assert_eq!(r, Err(NonZeroUsize::new(123456 - 87).unwrap()));
+    assert_eq!(r, Err(NonZero::<usize>::new(123456 - 87).unwrap()));
     assert_eq!(it.len(), 0);
     assert_eq!(counter.get(), 100);
 
@@ -611,7 +611,7 @@ fn array_intoiter_advance_back_by() {
     assert_eq!(counter.get(), 100);
 
     let r = it.advance_back_by(10);
-    assert_eq!(r, Err(NonZeroUsize::new(10).unwrap()));
+    assert_eq!(r, Err(NonZero::<usize>::new(10).unwrap()));
     assert_eq!(it.len(), 0);
     assert_eq!(counter.get(), 100);
 }
diff --git a/library/core/tests/iter/adapters/chain.rs b/library/core/tests/iter/adapters/chain.rs
index ad78a85a88dcb..9e098d5bee442 100644
--- a/library/core/tests/iter/adapters/chain.rs
+++ b/library/core/tests/iter/adapters/chain.rs
@@ -1,6 +1,6 @@
 use super::*;
 use core::iter::*;
-use core::num::NonZeroUsize;
+use core::num::NonZero;
 
 #[test]
 fn test_iterator_chain() {
@@ -34,7 +34,10 @@ fn test_iterator_chain_advance_by() {
             let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys));
             assert_eq!(iter.advance_by(i), Ok(()));
             assert_eq!(iter.next(), Some(&xs[i]));
-            assert_eq!(iter.advance_by(100), Err(NonZeroUsize::new(100 - (len - i - 1)).unwrap()));
+            assert_eq!(
+                iter.advance_by(100),
+                Err(NonZero::<usize>::new(100 - (len - i - 1)).unwrap())
+            );
             assert_eq!(iter.advance_by(0), Ok(()));
         }
 
@@ -44,7 +47,7 @@ fn test_iterator_chain_advance_by() {
             assert_eq!(iter.next(), Some(&ys[i]));
             assert_eq!(
                 iter.advance_by(100),
-                Err(NonZeroUsize::new(100 - (ys.len() - i - 1)).unwrap())
+                Err(NonZero::<usize>::new(100 - (ys.len() - i - 1)).unwrap())
             );
             assert_eq!(iter.advance_by(0), Ok(()));
         }
@@ -55,7 +58,7 @@ fn test_iterator_chain_advance_by() {
         assert_eq!(iter.advance_by(0), Ok(()));
 
         let mut iter = xs.iter().chain(ys);
-        assert_eq!(iter.advance_by(len + 1), Err(NonZeroUsize::new(1).unwrap()));
+        assert_eq!(iter.advance_by(len + 1), Err(NonZero::<usize>::new(1).unwrap()));
         assert_eq!(iter.advance_by(0), Ok(()));
     }
 
@@ -76,7 +79,7 @@ fn test_iterator_chain_advance_back_by() {
             assert_eq!(iter.next_back(), Some(&ys[ys.len() - i - 1]));
             assert_eq!(
                 iter.advance_back_by(100),
-                Err(NonZeroUsize::new(100 - (len - i - 1)).unwrap())
+                Err(NonZero::<usize>::new(100 - (len - i - 1)).unwrap())
             );
             assert_eq!(iter.advance_back_by(0), Ok(()));
         }
@@ -87,7 +90,7 @@ fn test_iterator_chain_advance_back_by() {
             assert_eq!(iter.next_back(), Some(&xs[xs.len() - i - 1]));
             assert_eq!(
                 iter.advance_back_by(100),
-                Err(NonZeroUsize::new(100 - (xs.len() - i - 1)).unwrap())
+                Err(NonZero::<usize>::new(100 - (xs.len() - i - 1)).unwrap())
             );
             assert_eq!(iter.advance_back_by(0), Ok(()));
         }
@@ -98,7 +101,7 @@ fn test_iterator_chain_advance_back_by() {
         assert_eq!(iter.advance_back_by(0), Ok(()));
 
         let mut iter = xs.iter().chain(ys);
-        assert_eq!(iter.advance_back_by(len + 1), Err(NonZeroUsize::new(1).unwrap()));
+        assert_eq!(iter.advance_back_by(len + 1), Err(NonZero::<usize>::new(1).unwrap()));
         assert_eq!(iter.advance_back_by(0), Ok(()));
     }
 
diff --git a/library/core/tests/iter/adapters/enumerate.rs b/library/core/tests/iter/adapters/enumerate.rs
index ff57973a62a4b..5aa7532c10cb2 100644
--- a/library/core/tests/iter/adapters/enumerate.rs
+++ b/library/core/tests/iter/adapters/enumerate.rs
@@ -1,5 +1,5 @@
 use core::iter::*;
-use core::num::NonZeroUsize;
+use core::num::NonZero;
 
 #[test]
 fn test_iterator_enumerate() {
@@ -66,7 +66,7 @@ fn test_iterator_enumerate_advance_by() {
     assert_eq!(it.next(), Some((2, &2)));
     assert_eq!(it.advance_by(2), Ok(()));
     assert_eq!(it.next(), Some((5, &5)));
-    assert_eq!(it.advance_by(1), Err(NonZeroUsize::new(1).unwrap()));
+    assert_eq!(it.advance_by(1), Err(NonZero::<usize>::new(1).unwrap()));
     assert_eq!(it.next(), None);
 }
 
diff --git a/library/core/tests/iter/adapters/flatten.rs b/library/core/tests/iter/adapters/flatten.rs
index f429d90cd7ddd..fb6383b3289bb 100644
--- a/library/core/tests/iter/adapters/flatten.rs
+++ b/library/core/tests/iter/adapters/flatten.rs
@@ -1,7 +1,7 @@
 use super::*;
 use core::assert_eq;
 use core::iter::*;
-use core::num::NonZeroUsize;
+use core::num::NonZero;
 
 #[test]
 fn test_iterator_flatten() {
@@ -72,8 +72,8 @@ fn test_flatten_advance_by() {
     assert_eq!(it.advance_back_by(9), Ok(()));
     assert_eq!(it.next_back(), Some(25));
 
-    assert_eq!(it.advance_by(usize::MAX), Err(NonZeroUsize::new(usize::MAX - 9).unwrap()));
-    assert_eq!(it.advance_back_by(usize::MAX), Err(NonZeroUsize::new(usize::MAX).unwrap()));
+    assert_eq!(it.advance_by(usize::MAX), Err(NonZero::<usize>::new(usize::MAX - 9).unwrap()));
+    assert_eq!(it.advance_back_by(usize::MAX), Err(NonZero::<usize>::new(usize::MAX).unwrap()));
     assert_eq!(it.advance_by(0), Ok(()));
     assert_eq!(it.advance_back_by(0), Ok(()));
     assert_eq!(it.size_hint(), (0, Some(0)));
diff --git a/library/core/tests/iter/adapters/skip.rs b/library/core/tests/iter/adapters/skip.rs
index e3e88a84fadf6..45726d158b608 100644
--- a/library/core/tests/iter/adapters/skip.rs
+++ b/library/core/tests/iter/adapters/skip.rs
@@ -1,5 +1,5 @@
 use core::iter::*;
-use core::num::NonZeroUsize;
+use core::num::NonZero;
 
 use super::Unfuse;
 
@@ -75,14 +75,14 @@ fn test_iterator_skip_nth() {
 #[test]
 fn test_skip_advance_by() {
     assert_eq!((0..0).skip(10).advance_by(0), Ok(()));
-    assert_eq!((0..0).skip(10).advance_by(1), Err(NonZeroUsize::new(1).unwrap()));
+    assert_eq!((0..0).skip(10).advance_by(1), Err(NonZero::<usize>::new(1).unwrap()));
     assert_eq!(
         (0u128..(usize::MAX as u128) + 1).skip(usize::MAX - 10).advance_by(usize::MAX - 5),
-        Err(NonZeroUsize::new(usize::MAX - 16).unwrap())
+        Err(NonZero::<usize>::new(usize::MAX - 16).unwrap())
     );
     assert_eq!((0u128..u128::MAX).skip(usize::MAX - 10).advance_by(20), Ok(()));
 
-    assert_eq!((0..2).skip(1).advance_back_by(10), Err(NonZeroUsize::new(9).unwrap()));
+    assert_eq!((0..2).skip(1).advance_back_by(10), Err(NonZero::<usize>::new(9).unwrap()));
     assert_eq!((0..0).skip(1).advance_back_by(0), Ok(()));
 }
 
diff --git a/library/core/tests/iter/adapters/take.rs b/library/core/tests/iter/adapters/take.rs
index ff6e362b065c6..6aa1b92954691 100644
--- a/library/core/tests/iter/adapters/take.rs
+++ b/library/core/tests/iter/adapters/take.rs
@@ -1,5 +1,5 @@
 use core::iter::*;
-use core::num::NonZeroUsize;
+use core::num::NonZero;
 
 #[test]
 fn test_iterator_take() {
@@ -79,23 +79,23 @@ fn test_take_advance_by() {
     let mut take = (0..10).take(3);
     assert_eq!(take.advance_by(2), Ok(()));
     assert_eq!(take.next(), Some(2));
-    assert_eq!(take.advance_by(1), Err(NonZeroUsize::new(1).unwrap()));
+    assert_eq!(take.advance_by(1), Err(NonZero::<usize>::new(1).unwrap()));
 
     assert_eq!((0..0).take(10).advance_by(0), Ok(()));
-    assert_eq!((0..0).take(10).advance_by(1), Err(NonZeroUsize::new(1).unwrap()));
-    assert_eq!((0..10).take(4).advance_by(5), Err(NonZeroUsize::new(1).unwrap()));
+    assert_eq!((0..0).take(10).advance_by(1), Err(NonZero::<usize>::new(1).unwrap()));
+    assert_eq!((0..10).take(4).advance_by(5), Err(NonZero::<usize>::new(1).unwrap()));
 
     let mut take = (0..10).take(3);
     assert_eq!(take.advance_back_by(2), Ok(()));
     assert_eq!(take.next(), Some(0));
-    assert_eq!(take.advance_back_by(1), Err(NonZeroUsize::new(1).unwrap()));
+    assert_eq!(take.advance_back_by(1), Err(NonZero::<usize>::new(1).unwrap()));
 
-    assert_eq!((0..2).take(1).advance_back_by(10), Err(NonZeroUsize::new(9).unwrap()));
-    assert_eq!((0..0).take(1).advance_back_by(1), Err(NonZeroUsize::new(1).unwrap()));
+    assert_eq!((0..2).take(1).advance_back_by(10), Err(NonZero::<usize>::new(9).unwrap()));
+    assert_eq!((0..0).take(1).advance_back_by(1), Err(NonZero::<usize>::new(1).unwrap()));
     assert_eq!((0..0).take(1).advance_back_by(0), Ok(()));
     assert_eq!(
         (0..usize::MAX).take(100).advance_back_by(usize::MAX),
-        Err(NonZeroUsize::new(usize::MAX - 100).unwrap())
+        Err(NonZero::<usize>::new(usize::MAX - 100).unwrap())
     );
 }
 
diff --git a/library/core/tests/iter/range.rs b/library/core/tests/iter/range.rs
index a6b9f1cb7c889..f840218382dae 100644
--- a/library/core/tests/iter/range.rs
+++ b/library/core/tests/iter/range.rs
@@ -1,6 +1,6 @@
 use super::*;
 use core::ascii::Char as AsciiChar;
-use core::num::NonZeroUsize;
+use core::num::NonZero;
 
 #[test]
 fn test_range() {
@@ -314,7 +314,7 @@ fn test_range_advance_by() {
 
     assert_eq!((r.start, r.end), (1, usize::MAX - 1));
 
-    assert_eq!(Err(NonZeroUsize::new(2).unwrap()), r.advance_by(usize::MAX));
+    assert_eq!(Err(NonZero::<usize>::new(2).unwrap()), r.advance_by(usize::MAX));
 
     assert_eq!(Ok(()), r.advance_by(0));
     assert_eq!(Ok(()), r.advance_back_by(0));
diff --git a/library/core/tests/iter/traits/iterator.rs b/library/core/tests/iter/traits/iterator.rs
index 4c2d843eaa0dc..507f15c608832 100644
--- a/library/core/tests/iter/traits/iterator.rs
+++ b/library/core/tests/iter/traits/iterator.rs
@@ -1,4 +1,4 @@
-use core::num::NonZeroUsize;
+use core::num::NonZero;
 
 /// A wrapper struct that implements `Eq` and `Ord` based on the wrapped
 /// integer modulo 3. Used to test that `Iterator::max` and `Iterator::min`
@@ -152,11 +152,14 @@ fn test_iterator_advance_by() {
         let mut iter = v.iter();
         assert_eq!(iter.advance_by(i), Ok(()));
         assert_eq!(iter.next().unwrap(), &v[i]);
-        assert_eq!(iter.advance_by(100), Err(NonZeroUsize::new(100 - (v.len() - 1 - i)).unwrap()));
+        assert_eq!(
+            iter.advance_by(100),
+            Err(NonZero::<usize>::new(100 - (v.len() - 1 - i)).unwrap())
+        );
     }
 
     assert_eq!(v.iter().advance_by(v.len()), Ok(()));
-    assert_eq!(v.iter().advance_by(100), Err(NonZeroUsize::new(100 - v.len()).unwrap()));
+    assert_eq!(v.iter().advance_by(100), Err(NonZero::<usize>::new(100 - v.len()).unwrap()));
 }
 
 #[test]
@@ -169,12 +172,12 @@ fn test_iterator_advance_back_by() {
         assert_eq!(iter.next_back().unwrap(), &v[v.len() - 1 - i]);
         assert_eq!(
             iter.advance_back_by(100),
-            Err(NonZeroUsize::new(100 - (v.len() - 1 - i)).unwrap())
+            Err(NonZero::<usize>::new(100 - (v.len() - 1 - i)).unwrap())
         );
     }
 
     assert_eq!(v.iter().advance_back_by(v.len()), Ok(()));
-    assert_eq!(v.iter().advance_back_by(100), Err(NonZeroUsize::new(100 - v.len()).unwrap()));
+    assert_eq!(v.iter().advance_back_by(100), Err(NonZero::<usize>::new(100 - v.len()).unwrap()));
 }
 
 #[test]
@@ -187,12 +190,15 @@ fn test_iterator_rev_advance_back_by() {
         assert_eq!(iter.next_back().unwrap(), &v[i]);
         assert_eq!(
             iter.advance_back_by(100),
-            Err(NonZeroUsize::new(100 - (v.len() - 1 - i)).unwrap())
+            Err(NonZero::<usize>::new(100 - (v.len() - 1 - i)).unwrap())
         );
     }
 
     assert_eq!(v.iter().rev().advance_back_by(v.len()), Ok(()));
-    assert_eq!(v.iter().rev().advance_back_by(100), Err(NonZeroUsize::new(100 - v.len()).unwrap()));
+    assert_eq!(
+        v.iter().rev().advance_back_by(100),
+        Err(NonZero::<usize>::new(100 - v.len()).unwrap())
+    );
 }
 
 #[test]
@@ -460,11 +466,14 @@ fn test_iterator_rev_advance_by() {
         let mut iter = v.iter().rev();
         assert_eq!(iter.advance_by(i), Ok(()));
         assert_eq!(iter.next().unwrap(), &v[v.len() - 1 - i]);
-        assert_eq!(iter.advance_by(100), Err(NonZeroUsize::new(100 - (v.len() - 1 - i)).unwrap()));
+        assert_eq!(
+            iter.advance_by(100),
+            Err(NonZero::<usize>::new(100 - (v.len() - 1 - i)).unwrap())
+        );
     }
 
     assert_eq!(v.iter().rev().advance_by(v.len()), Ok(()));
-    assert_eq!(v.iter().rev().advance_by(100), Err(NonZeroUsize::new(100 - v.len()).unwrap()));
+    assert_eq!(v.iter().rev().advance_by(100), Err(NonZero::<usize>::new(100 - v.len()).unwrap()));
 }
 
 #[test]
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 2fe79650dbfd4..fa0e9a979d060 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -40,6 +40,7 @@
 #![feature(float_minimum_maximum)]
 #![feature(future_join)]
 #![feature(generic_assert_internals)]
+#![feature(generic_nonzero)]
 #![feature(array_try_from_fn)]
 #![feature(hasher_prefixfree_extras)]
 #![feature(hashmap_internals)]
diff --git a/library/core/tests/nonzero.rs b/library/core/tests/nonzero.rs
index 8873d26880ced..69dbe5d7dea23 100644
--- a/library/core/tests/nonzero.rs
+++ b/library/core/tests/nonzero.rs
@@ -1,30 +1,27 @@
-use core::num::{
-    IntErrorKind, NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize,
-    NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize,
-};
+use core::num::{IntErrorKind, NonZero};
 use core::option::Option::None;
 use std::mem::size_of;
 
 #[test]
 fn test_create_nonzero_instance() {
-    let _a = unsafe { NonZeroU32::new_unchecked(21) };
+    let _a = unsafe { NonZero::<u32>::new_unchecked(21) };
 }
 
 #[test]
 fn test_size_nonzero_in_option() {
-    assert_eq!(size_of::<NonZeroU32>(), size_of::<Option<NonZeroU32>>());
-    assert_eq!(size_of::<NonZeroI32>(), size_of::<Option<NonZeroI32>>());
+    assert_eq!(size_of::<NonZero<u32>>(), size_of::<Option<NonZero<u32>>>());
+    assert_eq!(size_of::<NonZero<i32>>(), size_of::<Option<NonZero<i32>>>());
 }
 
 #[test]
 fn test_match_on_nonzero_option() {
-    let a = Some(unsafe { NonZeroU32::new_unchecked(42) });
+    let a = Some(unsafe { NonZero::<u32>::new_unchecked(42) });
     match a {
         Some(val) => assert_eq!(val.get(), 42),
         None => panic!("unexpected None while matching on Some(NonZeroU32(_))"),
     }
 
-    match unsafe { Some(NonZeroU32::new_unchecked(43)) } {
+    match unsafe { Some(NonZero::<u32>::new_unchecked(43)) } {
         Some(val) => assert_eq!(val.get(), 43),
         None => panic!("unexpected None while matching on Some(NonZeroU32(_))"),
     }
@@ -89,13 +86,14 @@ fn test_match_option_string() {
 }
 
 mod atom {
-    use core::num::NonZeroU32;
+    use core::num::NonZero;
 
     #[derive(PartialEq, Eq)]
     pub struct Atom {
-        index: NonZeroU32, // private
+        index: NonZero<u32>, // private
     }
-    pub const FOO_ATOM: Atom = Atom { index: unsafe { NonZeroU32::new_unchecked(7) } };
+
+    pub const FOO_ATOM: Atom = Atom { index: unsafe { NonZero::<u32>::new_unchecked(7) } };
 }
 
 macro_rules! atom {
@@ -115,62 +113,65 @@ fn test_match_nonzero_const_pattern() {
 
 #[test]
 fn test_from_nonzero() {
-    let nz = NonZeroU32::new(1).unwrap();
+    let nz = NonZero::<u32>::new(1).unwrap();
     let num: u32 = nz.into();
     assert_eq!(num, 1u32);
 }
 
 #[test]
 fn test_from_signed_nonzero() {
-    let nz = NonZeroI32::new(1).unwrap();
+    let nz = NonZero::<i32>::new(1).unwrap();
     let num: i32 = nz.into();
     assert_eq!(num, 1i32);
 }
 
 #[test]
 fn test_from_str() {
-    assert_eq!("123".parse::<NonZeroU8>(), Ok(NonZeroU8::new(123).unwrap()));
-    assert_eq!("0".parse::<NonZeroU8>().err().map(|e| e.kind().clone()), Some(IntErrorKind::Zero));
+    assert_eq!("123".parse::<NonZero<u8>>(), Ok(NonZero::<u8>::new(123).unwrap()));
+    assert_eq!(
+        "0".parse::<NonZero<u8>>().err().map(|e| e.kind().clone()),
+        Some(IntErrorKind::Zero)
+    );
     assert_eq!(
-        "-1".parse::<NonZeroU8>().err().map(|e| e.kind().clone()),
+        "-1".parse::<NonZero<u8>>().err().map(|e| e.kind().clone()),
         Some(IntErrorKind::InvalidDigit)
     );
     assert_eq!(
-        "-129".parse::<NonZeroI8>().err().map(|e| e.kind().clone()),
+        "-129".parse::<NonZero<i8>>().err().map(|e| e.kind().clone()),
         Some(IntErrorKind::NegOverflow)
     );
     assert_eq!(
-        "257".parse::<NonZeroU8>().err().map(|e| e.kind().clone()),
+        "257".parse::<NonZero<u8>>().err().map(|e| e.kind().clone()),
         Some(IntErrorKind::PosOverflow)
     );
 }
 
 #[test]
 fn test_nonzero_bitor() {
-    let nz_alt = NonZeroU8::new(0b1010_1010).unwrap();
-    let nz_low = NonZeroU8::new(0b0000_1111).unwrap();
+    let nz_alt = NonZero::<u8>::new(0b1010_1010).unwrap();
+    let nz_low = NonZero::<u8>::new(0b0000_1111).unwrap();
 
-    let both_nz: NonZeroU8 = nz_alt | nz_low;
+    let both_nz: NonZero<u8> = nz_alt | nz_low;
     assert_eq!(both_nz.get(), 0b1010_1111);
 
-    let rhs_int: NonZeroU8 = nz_low | 0b1100_0000u8;
+    let rhs_int: NonZero<u8> = nz_low | 0b1100_0000u8;
     assert_eq!(rhs_int.get(), 0b1100_1111);
 
-    let rhs_zero: NonZeroU8 = nz_alt | 0u8;
+    let rhs_zero: NonZero<u8> = nz_alt | 0u8;
     assert_eq!(rhs_zero.get(), 0b1010_1010);
 
-    let lhs_int: NonZeroU8 = 0b0110_0110u8 | nz_alt;
+    let lhs_int: NonZero<u8> = 0b0110_0110u8 | nz_alt;
     assert_eq!(lhs_int.get(), 0b1110_1110);
 
-    let lhs_zero: NonZeroU8 = 0u8 | nz_low;
+    let lhs_zero: NonZero<u8> = 0u8 | nz_low;
     assert_eq!(lhs_zero.get(), 0b0000_1111);
 }
 
 #[test]
 fn test_nonzero_bitor_assign() {
-    let mut target = NonZeroU8::new(0b1010_1010).unwrap();
+    let mut target = NonZero::<u8>::new(0b1010_1010).unwrap();
 
-    target |= NonZeroU8::new(0b0000_1111).unwrap();
+    target |= NonZero::<u8>::new(0b0000_1111).unwrap();
     assert_eq!(target.get(), 0b1010_1111);
 
     target |= 0b0001_0000;
@@ -182,147 +183,147 @@ fn test_nonzero_bitor_assign() {
 
 #[test]
 fn test_nonzero_from_int_on_success() {
-    assert_eq!(NonZeroU8::try_from(5), Ok(NonZeroU8::new(5).unwrap()));
-    assert_eq!(NonZeroU32::try_from(5), Ok(NonZeroU32::new(5).unwrap()));
+    assert_eq!(NonZero::<u8>::try_from(5), Ok(NonZero::<u8>::new(5).unwrap()));
+    assert_eq!(NonZero::<u32>::try_from(5), Ok(NonZero::<u32>::new(5).unwrap()));
 
-    assert_eq!(NonZeroI8::try_from(-5), Ok(NonZeroI8::new(-5).unwrap()));
-    assert_eq!(NonZeroI32::try_from(-5), Ok(NonZeroI32::new(-5).unwrap()));
+    assert_eq!(NonZero::<i8>::try_from(-5), Ok(NonZero::<i8>::new(-5).unwrap()));
+    assert_eq!(NonZero::<i32>::try_from(-5), Ok(NonZero::<i32>::new(-5).unwrap()));
 }
 
 #[test]
 fn test_nonzero_from_int_on_err() {
-    assert!(NonZeroU8::try_from(0).is_err());
-    assert!(NonZeroU32::try_from(0).is_err());
+    assert!(NonZero::<u8>::try_from(0).is_err());
+    assert!(NonZero::<u32>::try_from(0).is_err());
 
-    assert!(NonZeroI8::try_from(0).is_err());
-    assert!(NonZeroI32::try_from(0).is_err());
+    assert!(NonZero::<i8>::try_from(0).is_err());
+    assert!(NonZero::<i32>::try_from(0).is_err());
 }
 
 #[test]
 fn nonzero_const() {
     // test that the methods of `NonZeroX>` are usable in a const context
-    // Note: only tests NonZero8
+    // Note: only tests NonZero<u8>
 
-    const NONZERO_U8: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(5) };
+    const NONZERO_U8: NonZero<u8> = unsafe { NonZero::<u8>::new_unchecked(5) };
 
     const GET: u8 = NONZERO_U8.get();
     assert_eq!(GET, 5);
 
-    const ZERO: Option<NonZeroU8> = NonZeroU8::new(0);
+    const ZERO: Option<NonZero<u8>> = NonZero::<u8>::new(0);
     assert!(ZERO.is_none());
 
-    const ONE: Option<NonZeroU8> = NonZeroU8::new(1);
+    const ONE: Option<NonZero<u8>> = NonZero::<u8>::new(1);
     assert!(ONE.is_some());
 
     /* FIXME(#110395)
     const FROM_NONZERO_U8: u8 = u8::from(NONZERO_U8);
     assert_eq!(FROM_NONZERO_U8, 5);
 
-    const NONZERO_CONVERT: NonZeroU32 = NonZeroU32::from(NONZERO_U8);
+    const NONZERO_CONVERT: NonZero<u32> = NonZero::<u32>::from(NONZERO_U8);
     assert_eq!(NONZERO_CONVERT.get(), 5);
     */
 }
 
 #[test]
 fn nonzero_leading_zeros() {
-    assert_eq!(NonZeroU8::new(1).unwrap().leading_zeros(), 7);
-    assert_eq!(NonZeroI8::new(1).unwrap().leading_zeros(), 7);
-    assert_eq!(NonZeroU16::new(1).unwrap().leading_zeros(), 15);
-    assert_eq!(NonZeroI16::new(1).unwrap().leading_zeros(), 15);
-    assert_eq!(NonZeroU32::new(1).unwrap().leading_zeros(), 31);
-    assert_eq!(NonZeroI32::new(1).unwrap().leading_zeros(), 31);
-    assert_eq!(NonZeroU64::new(1).unwrap().leading_zeros(), 63);
-    assert_eq!(NonZeroI64::new(1).unwrap().leading_zeros(), 63);
-    assert_eq!(NonZeroU128::new(1).unwrap().leading_zeros(), 127);
-    assert_eq!(NonZeroI128::new(1).unwrap().leading_zeros(), 127);
-    assert_eq!(NonZeroUsize::new(1).unwrap().leading_zeros(), usize::BITS - 1);
-    assert_eq!(NonZeroIsize::new(1).unwrap().leading_zeros(), usize::BITS - 1);
-
-    assert_eq!(NonZeroU8::new(u8::MAX >> 2).unwrap().leading_zeros(), 2);
-    assert_eq!(NonZeroI8::new((u8::MAX >> 2) as i8).unwrap().leading_zeros(), 2);
-    assert_eq!(NonZeroU16::new(u16::MAX >> 2).unwrap().leading_zeros(), 2);
-    assert_eq!(NonZeroI16::new((u16::MAX >> 2) as i16).unwrap().leading_zeros(), 2);
-    assert_eq!(NonZeroU32::new(u32::MAX >> 2).unwrap().leading_zeros(), 2);
-    assert_eq!(NonZeroI32::new((u32::MAX >> 2) as i32).unwrap().leading_zeros(), 2);
-    assert_eq!(NonZeroU64::new(u64::MAX >> 2).unwrap().leading_zeros(), 2);
-    assert_eq!(NonZeroI64::new((u64::MAX >> 2) as i64).unwrap().leading_zeros(), 2);
-    assert_eq!(NonZeroU128::new(u128::MAX >> 2).unwrap().leading_zeros(), 2);
-    assert_eq!(NonZeroI128::new((u128::MAX >> 2) as i128).unwrap().leading_zeros(), 2);
-    assert_eq!(NonZeroUsize::new(usize::MAX >> 2).unwrap().leading_zeros(), 2);
-    assert_eq!(NonZeroIsize::new((usize::MAX >> 2) as isize).unwrap().leading_zeros(), 2);
-
-    assert_eq!(NonZeroU8::new(u8::MAX).unwrap().leading_zeros(), 0);
-    assert_eq!(NonZeroI8::new(-1i8).unwrap().leading_zeros(), 0);
-    assert_eq!(NonZeroU16::new(u16::MAX).unwrap().leading_zeros(), 0);
-    assert_eq!(NonZeroI16::new(-1i16).unwrap().leading_zeros(), 0);
-    assert_eq!(NonZeroU32::new(u32::MAX).unwrap().leading_zeros(), 0);
-    assert_eq!(NonZeroI32::new(-1i32).unwrap().leading_zeros(), 0);
-    assert_eq!(NonZeroU64::new(u64::MAX).unwrap().leading_zeros(), 0);
-    assert_eq!(NonZeroI64::new(-1i64).unwrap().leading_zeros(), 0);
-    assert_eq!(NonZeroU128::new(u128::MAX).unwrap().leading_zeros(), 0);
-    assert_eq!(NonZeroI128::new(-1i128).unwrap().leading_zeros(), 0);
-    assert_eq!(NonZeroUsize::new(usize::MAX).unwrap().leading_zeros(), 0);
-    assert_eq!(NonZeroIsize::new(-1isize).unwrap().leading_zeros(), 0);
-
-    const LEADING_ZEROS: u32 = NonZeroU16::new(1).unwrap().leading_zeros();
+    assert_eq!(NonZero::<u8>::new(1).unwrap().leading_zeros(), 7);
+    assert_eq!(NonZero::<i8>::new(1).unwrap().leading_zeros(), 7);
+    assert_eq!(NonZero::<u16>::new(1).unwrap().leading_zeros(), 15);
+    assert_eq!(NonZero::<i16>::new(1).unwrap().leading_zeros(), 15);
+    assert_eq!(NonZero::<u32>::new(1).unwrap().leading_zeros(), 31);
+    assert_eq!(NonZero::<i32>::new(1).unwrap().leading_zeros(), 31);
+    assert_eq!(NonZero::<u64>::new(1).unwrap().leading_zeros(), 63);
+    assert_eq!(NonZero::<i64>::new(1).unwrap().leading_zeros(), 63);
+    assert_eq!(NonZero::<u128>::new(1).unwrap().leading_zeros(), 127);
+    assert_eq!(NonZero::<i128>::new(1).unwrap().leading_zeros(), 127);
+    assert_eq!(NonZero::<usize>::new(1).unwrap().leading_zeros(), usize::BITS - 1);
+    assert_eq!(NonZero::<isize>::new(1).unwrap().leading_zeros(), usize::BITS - 1);
+
+    assert_eq!(NonZero::<u8>::new(u8::MAX >> 2).unwrap().leading_zeros(), 2);
+    assert_eq!(NonZero::<i8>::new((u8::MAX >> 2) as i8).unwrap().leading_zeros(), 2);
+    assert_eq!(NonZero::<u16>::new(u16::MAX >> 2).unwrap().leading_zeros(), 2);
+    assert_eq!(NonZero::<i16>::new((u16::MAX >> 2) as i16).unwrap().leading_zeros(), 2);
+    assert_eq!(NonZero::<u32>::new(u32::MAX >> 2).unwrap().leading_zeros(), 2);
+    assert_eq!(NonZero::<i32>::new((u32::MAX >> 2) as i32).unwrap().leading_zeros(), 2);
+    assert_eq!(NonZero::<u64>::new(u64::MAX >> 2).unwrap().leading_zeros(), 2);
+    assert_eq!(NonZero::<i64>::new((u64::MAX >> 2) as i64).unwrap().leading_zeros(), 2);
+    assert_eq!(NonZero::<u128>::new(u128::MAX >> 2).unwrap().leading_zeros(), 2);
+    assert_eq!(NonZero::<i128>::new((u128::MAX >> 2) as i128).unwrap().leading_zeros(), 2);
+    assert_eq!(NonZero::<usize>::new(usize::MAX >> 2).unwrap().leading_zeros(), 2);
+    assert_eq!(NonZero::<isize>::new((usize::MAX >> 2) as isize).unwrap().leading_zeros(), 2);
+
+    assert_eq!(NonZero::<u8>::new(u8::MAX).unwrap().leading_zeros(), 0);
+    assert_eq!(NonZero::<i8>::new(-1i8).unwrap().leading_zeros(), 0);
+    assert_eq!(NonZero::<u16>::new(u16::MAX).unwrap().leading_zeros(), 0);
+    assert_eq!(NonZero::<i16>::new(-1i16).unwrap().leading_zeros(), 0);
+    assert_eq!(NonZero::<u32>::new(u32::MAX).unwrap().leading_zeros(), 0);
+    assert_eq!(NonZero::<i32>::new(-1i32).unwrap().leading_zeros(), 0);
+    assert_eq!(NonZero::<u64>::new(u64::MAX).unwrap().leading_zeros(), 0);
+    assert_eq!(NonZero::<i64>::new(-1i64).unwrap().leading_zeros(), 0);
+    assert_eq!(NonZero::<u128>::new(u128::MAX).unwrap().leading_zeros(), 0);
+    assert_eq!(NonZero::<i128>::new(-1i128).unwrap().leading_zeros(), 0);
+    assert_eq!(NonZero::<usize>::new(usize::MAX).unwrap().leading_zeros(), 0);
+    assert_eq!(NonZero::<isize>::new(-1isize).unwrap().leading_zeros(), 0);
+
+    const LEADING_ZEROS: u32 = NonZero::<u16>::new(1).unwrap().leading_zeros();
     assert_eq!(LEADING_ZEROS, 15);
 }
 
 #[test]
 fn nonzero_trailing_zeros() {
-    assert_eq!(NonZeroU8::new(1).unwrap().trailing_zeros(), 0);
-    assert_eq!(NonZeroI8::new(1).unwrap().trailing_zeros(), 0);
-    assert_eq!(NonZeroU16::new(1).unwrap().trailing_zeros(), 0);
-    assert_eq!(NonZeroI16::new(1).unwrap().trailing_zeros(), 0);
-    assert_eq!(NonZeroU32::new(1).unwrap().trailing_zeros(), 0);
-    assert_eq!(NonZeroI32::new(1).unwrap().trailing_zeros(), 0);
-    assert_eq!(NonZeroU64::new(1).unwrap().trailing_zeros(), 0);
-    assert_eq!(NonZeroI64::new(1).unwrap().trailing_zeros(), 0);
-    assert_eq!(NonZeroU128::new(1).unwrap().trailing_zeros(), 0);
-    assert_eq!(NonZeroI128::new(1).unwrap().trailing_zeros(), 0);
-    assert_eq!(NonZeroUsize::new(1).unwrap().trailing_zeros(), 0);
-    assert_eq!(NonZeroIsize::new(1).unwrap().trailing_zeros(), 0);
-
-    assert_eq!(NonZeroU8::new(1 << 2).unwrap().trailing_zeros(), 2);
-    assert_eq!(NonZeroI8::new(1 << 2).unwrap().trailing_zeros(), 2);
-    assert_eq!(NonZeroU16::new(1 << 2).unwrap().trailing_zeros(), 2);
-    assert_eq!(NonZeroI16::new(1 << 2).unwrap().trailing_zeros(), 2);
-    assert_eq!(NonZeroU32::new(1 << 2).unwrap().trailing_zeros(), 2);
-    assert_eq!(NonZeroI32::new(1 << 2).unwrap().trailing_zeros(), 2);
-    assert_eq!(NonZeroU64::new(1 << 2).unwrap().trailing_zeros(), 2);
-    assert_eq!(NonZeroI64::new(1 << 2).unwrap().trailing_zeros(), 2);
-    assert_eq!(NonZeroU128::new(1 << 2).unwrap().trailing_zeros(), 2);
-    assert_eq!(NonZeroI128::new(1 << 2).unwrap().trailing_zeros(), 2);
-    assert_eq!(NonZeroUsize::new(1 << 2).unwrap().trailing_zeros(), 2);
-    assert_eq!(NonZeroIsize::new(1 << 2).unwrap().trailing_zeros(), 2);
-
-    assert_eq!(NonZeroU8::new(1 << 7).unwrap().trailing_zeros(), 7);
-    assert_eq!(NonZeroI8::new(1 << 7).unwrap().trailing_zeros(), 7);
-    assert_eq!(NonZeroU16::new(1 << 15).unwrap().trailing_zeros(), 15);
-    assert_eq!(NonZeroI16::new(1 << 15).unwrap().trailing_zeros(), 15);
-    assert_eq!(NonZeroU32::new(1 << 31).unwrap().trailing_zeros(), 31);
-    assert_eq!(NonZeroI32::new(1 << 31).unwrap().trailing_zeros(), 31);
-    assert_eq!(NonZeroU64::new(1 << 63).unwrap().trailing_zeros(), 63);
-    assert_eq!(NonZeroI64::new(1 << 63).unwrap().trailing_zeros(), 63);
-    assert_eq!(NonZeroU128::new(1 << 127).unwrap().trailing_zeros(), 127);
-    assert_eq!(NonZeroI128::new(1 << 127).unwrap().trailing_zeros(), 127);
+    assert_eq!(NonZero::<u8>::new(1).unwrap().trailing_zeros(), 0);
+    assert_eq!(NonZero::<i8>::new(1).unwrap().trailing_zeros(), 0);
+    assert_eq!(NonZero::<u16>::new(1).unwrap().trailing_zeros(), 0);
+    assert_eq!(NonZero::<i16>::new(1).unwrap().trailing_zeros(), 0);
+    assert_eq!(NonZero::<u32>::new(1).unwrap().trailing_zeros(), 0);
+    assert_eq!(NonZero::<i32>::new(1).unwrap().trailing_zeros(), 0);
+    assert_eq!(NonZero::<u64>::new(1).unwrap().trailing_zeros(), 0);
+    assert_eq!(NonZero::<i64>::new(1).unwrap().trailing_zeros(), 0);
+    assert_eq!(NonZero::<u128>::new(1).unwrap().trailing_zeros(), 0);
+    assert_eq!(NonZero::<i128>::new(1).unwrap().trailing_zeros(), 0);
+    assert_eq!(NonZero::<usize>::new(1).unwrap().trailing_zeros(), 0);
+    assert_eq!(NonZero::<isize>::new(1).unwrap().trailing_zeros(), 0);
+
+    assert_eq!(NonZero::<u8>::new(1 << 2).unwrap().trailing_zeros(), 2);
+    assert_eq!(NonZero::<i8>::new(1 << 2).unwrap().trailing_zeros(), 2);
+    assert_eq!(NonZero::<u16>::new(1 << 2).unwrap().trailing_zeros(), 2);
+    assert_eq!(NonZero::<i16>::new(1 << 2).unwrap().trailing_zeros(), 2);
+    assert_eq!(NonZero::<u32>::new(1 << 2).unwrap().trailing_zeros(), 2);
+    assert_eq!(NonZero::<i32>::new(1 << 2).unwrap().trailing_zeros(), 2);
+    assert_eq!(NonZero::<u64>::new(1 << 2).unwrap().trailing_zeros(), 2);
+    assert_eq!(NonZero::<i64>::new(1 << 2).unwrap().trailing_zeros(), 2);
+    assert_eq!(NonZero::<u128>::new(1 << 2).unwrap().trailing_zeros(), 2);
+    assert_eq!(NonZero::<i128>::new(1 << 2).unwrap().trailing_zeros(), 2);
+    assert_eq!(NonZero::<usize>::new(1 << 2).unwrap().trailing_zeros(), 2);
+    assert_eq!(NonZero::<isize>::new(1 << 2).unwrap().trailing_zeros(), 2);
+
+    assert_eq!(NonZero::<u8>::new(1 << 7).unwrap().trailing_zeros(), 7);
+    assert_eq!(NonZero::<i8>::new(1 << 7).unwrap().trailing_zeros(), 7);
+    assert_eq!(NonZero::<u16>::new(1 << 15).unwrap().trailing_zeros(), 15);
+    assert_eq!(NonZero::<i16>::new(1 << 15).unwrap().trailing_zeros(), 15);
+    assert_eq!(NonZero::<u32>::new(1 << 31).unwrap().trailing_zeros(), 31);
+    assert_eq!(NonZero::<i32>::new(1 << 31).unwrap().trailing_zeros(), 31);
+    assert_eq!(NonZero::<u64>::new(1 << 63).unwrap().trailing_zeros(), 63);
+    assert_eq!(NonZero::<i64>::new(1 << 63).unwrap().trailing_zeros(), 63);
+    assert_eq!(NonZero::<u128>::new(1 << 127).unwrap().trailing_zeros(), 127);
+    assert_eq!(NonZero::<i128>::new(1 << 127).unwrap().trailing_zeros(), 127);
 
     assert_eq!(
-        NonZeroUsize::new(1 << (usize::BITS - 1)).unwrap().trailing_zeros(),
+        NonZero::<usize>::new(1 << (usize::BITS - 1)).unwrap().trailing_zeros(),
         usize::BITS - 1
     );
     assert_eq!(
-        NonZeroIsize::new(1 << (usize::BITS - 1)).unwrap().trailing_zeros(),
+        NonZero::<isize>::new(1 << (usize::BITS - 1)).unwrap().trailing_zeros(),
         usize::BITS - 1
     );
 
-    const TRAILING_ZEROS: u32 = NonZeroU16::new(1 << 2).unwrap().trailing_zeros();
+    const TRAILING_ZEROS: u32 = NonZero::<u16>::new(1 << 2).unwrap().trailing_zeros();
     assert_eq!(TRAILING_ZEROS, 2);
 }
 
 #[test]
 fn test_nonzero_uint_div() {
-    let nz = NonZeroU32::new(1).unwrap();
+    let nz = NonZero::<u32>::new(1).unwrap();
 
     let x: u32 = 42u32 / nz;
     assert_eq!(x, 42u32);
@@ -330,7 +331,7 @@ fn test_nonzero_uint_div() {
 
 #[test]
 fn test_nonzero_uint_rem() {
-    let nz = NonZeroU32::new(10).unwrap();
+    let nz = NonZero::<u32>::new(10).unwrap();
 
     let x: u32 = 42u32 % nz;
     assert_eq!(x, 2u32);
@@ -338,18 +339,18 @@ fn test_nonzero_uint_rem() {
 
 #[test]
 fn test_signed_nonzero_neg() {
-    assert_eq!((-NonZeroI8::new(1).unwrap()).get(), -1);
-    assert_eq!((-NonZeroI8::new(-1).unwrap()).get(), 1);
+    assert_eq!((-NonZero::<i8>::new(1).unwrap()).get(), -1);
+    assert_eq!((-NonZero::<i8>::new(-1).unwrap()).get(), 1);
 
-    assert_eq!((-NonZeroI16::new(1).unwrap()).get(), -1);
-    assert_eq!((-NonZeroI16::new(-1).unwrap()).get(), 1);
+    assert_eq!((-NonZero::<i16>::new(1).unwrap()).get(), -1);
+    assert_eq!((-NonZero::<i16>::new(-1).unwrap()).get(), 1);
 
-    assert_eq!((-NonZeroI32::new(1).unwrap()).get(), -1);
-    assert_eq!((-NonZeroI32::new(-1).unwrap()).get(), 1);
+    assert_eq!((-NonZero::<i32>::new(1).unwrap()).get(), -1);
+    assert_eq!((-NonZero::<i32>::new(-1).unwrap()).get(), 1);
 
-    assert_eq!((-NonZeroI64::new(1).unwrap()).get(), -1);
-    assert_eq!((-NonZeroI64::new(-1).unwrap()).get(), 1);
+    assert_eq!((-NonZero::<i64>::new(1).unwrap()).get(), -1);
+    assert_eq!((-NonZero::<i64>::new(-1).unwrap()).get(), 1);
 
-    assert_eq!((-NonZeroI128::new(1).unwrap()).get(), -1);
-    assert_eq!((-NonZeroI128::new(-1).unwrap()).get(), 1);
+    assert_eq!((-NonZero::<i128>::new(1).unwrap()).get(), -1);
+    assert_eq!((-NonZero::<i128>::new(-1).unwrap()).get(), 1);
 }
diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs
index b68f2a50b3211..8a0cf90d799c0 100644
--- a/library/core/tests/ptr.rs
+++ b/library/core/tests/ptr.rs
@@ -1,6 +1,6 @@
 use core::cell::RefCell;
 use core::mem::{self, MaybeUninit};
-use core::num::NonZeroUsize;
+use core::num::NonZero;
 use core::ptr;
 use core::ptr::*;
 use std::fmt::{Debug, Display};
@@ -1051,7 +1051,7 @@ fn nonnull_tagged_pointer_with_provenance() {
         pub fn pointer(self) -> NonNull<T> {
             // SAFETY: The `addr` guaranteed to have bits set in the Self::ADDRESS_MASK, so the result will be non-null.
             self.0.map_addr(|addr| unsafe {
-                NonZeroUsize::new_unchecked(addr.get() & Self::ADDRESS_MASK)
+                NonZero::<usize>::new_unchecked(addr.get() & Self::ADDRESS_MASK)
             })
         }
 
@@ -1073,7 +1073,7 @@ fn nonnull_tagged_pointer_with_provenance() {
             // ADDRESS_MASK) will always be non-zero. This a property of the type and its
             // construction.
             self.0 = self.0.map_addr(|addr| unsafe {
-                NonZeroUsize::new_unchecked((addr.get() & Self::ADDRESS_MASK) | data)
+                NonZero::<usize>::new_unchecked((addr.get() & Self::ADDRESS_MASK) | data)
             })
         }
     }
diff --git a/library/core/tests/result.rs b/library/core/tests/result.rs
index 50926da3ce799..758203408a86c 100644
--- a/library/core/tests/result.rs
+++ b/library/core/tests/result.rs
@@ -406,13 +406,14 @@ fn result_opt_conversions() {
 
 #[test]
 fn result_try_trait_v2_branch() {
-    use core::num::NonZeroU32;
+    use core::num::NonZero;
     use core::ops::{ControlFlow::*, Try};
+
     assert_eq!(Ok::<i32, i32>(4).branch(), Continue(4));
     assert_eq!(Err::<i32, i32>(4).branch(), Break(Err(4)));
-    let one = NonZeroU32::new(1).unwrap();
-    assert_eq!(Ok::<(), NonZeroU32>(()).branch(), Continue(()));
-    assert_eq!(Err::<(), NonZeroU32>(one).branch(), Break(Err(one)));
-    assert_eq!(Ok::<NonZeroU32, ()>(one).branch(), Continue(one));
-    assert_eq!(Err::<NonZeroU32, ()>(()).branch(), Break(Err(())));
+    let one = NonZero::<u32>::new(1).unwrap();
+    assert_eq!(Ok::<(), NonZero<u32>>(()).branch(), Continue(()));
+    assert_eq!(Err::<(), NonZero<u32>>(one).branch(), Break(Err(one)));
+    assert_eq!(Ok::<NonZero<u32>, ()>(one).branch(), Continue(one));
+    assert_eq!(Err::<NonZero<u32>, ()>(()).branch(), Break(Err(())));
 }
diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
index bcf7b5e59775a..bb2c17a479e22 100644
--- a/library/core/tests/slice.rs
+++ b/library/core/tests/slice.rs
@@ -1,7 +1,7 @@
 use core::cell::Cell;
 use core::cmp::Ordering;
 use core::mem::MaybeUninit;
-use core::num::NonZeroUsize;
+use core::num::NonZero;
 use core::slice;
 
 #[test]
@@ -147,7 +147,7 @@ fn test_iterator_advance_by() {
     }
 
     let mut iter = v.iter();
-    assert_eq!(iter.advance_by(v.len() + 1), Err(NonZeroUsize::new(1).unwrap()));
+    assert_eq!(iter.advance_by(v.len() + 1), Err(NonZero::<usize>::new(1).unwrap()));
     assert_eq!(iter.as_slice(), &[]);
 
     let mut iter = v.iter();
@@ -169,7 +169,7 @@ fn test_iterator_advance_back_by() {
     }
 
     let mut iter = v.iter();
-    assert_eq!(iter.advance_back_by(v.len() + 1), Err(NonZeroUsize::new(1).unwrap()));
+    assert_eq!(iter.advance_back_by(v.len() + 1), Err(NonZero::<usize>::new(1).unwrap()));
     assert_eq!(iter.as_slice(), &[]);
 
     let mut iter = v.iter();
diff --git a/library/proc_macro/src/bridge/handle.rs b/library/proc_macro/src/bridge/handle.rs
index b3a763069974f..894acae217e44 100644
--- a/library/proc_macro/src/bridge/handle.rs
+++ b/library/proc_macro/src/bridge/handle.rs
@@ -2,13 +2,13 @@
 
 use std::collections::BTreeMap;
 use std::hash::Hash;
-use std::num::NonZeroU32;
+use std::num::NonZero;
 use std::ops::{Index, IndexMut};
 use std::sync::atomic::{AtomicU32, Ordering};
 
 use super::fxhash::FxHashMap;
 
-pub(super) type Handle = NonZeroU32;
+pub(super) type Handle = NonZero<u32>;
 
 /// A store that associates values of type `T` with numeric handles. A value can
 /// be looked up using its handle.
@@ -20,7 +20,7 @@ pub(super) struct OwnedStore<T: 'static> {
 impl<T> OwnedStore<T> {
     pub(super) fn new(counter: &'static AtomicU32) -> Self {
         // Ensure the handle counter isn't 0, which would panic later,
-        // when `NonZeroU32::new` (aka `Handle::new`) is called in `alloc`.
+        // when `NonZero::new` (aka `Handle::new`) is called in `alloc`.
         assert_ne!(counter.load(Ordering::SeqCst), 0);
 
         OwnedStore { counter, data: BTreeMap::new() }
diff --git a/library/proc_macro/src/bridge/rpc.rs b/library/proc_macro/src/bridge/rpc.rs
index 5b1bfb30983b2..6d75a5a627c82 100644
--- a/library/proc_macro/src/bridge/rpc.rs
+++ b/library/proc_macro/src/bridge/rpc.rs
@@ -2,7 +2,7 @@
 
 use std::any::Any;
 use std::io::Write;
-use std::num::NonZeroU32;
+use std::num::NonZero;
 use std::str;
 
 pub(super) type Writer = super::buffer::Buffer;
@@ -157,13 +157,13 @@ impl<S> DecodeMut<'_, '_, S> for char {
     }
 }
 
-impl<S> Encode<S> for NonZeroU32 {
+impl<S> Encode<S> for NonZero<u32> {
     fn encode(self, w: &mut Writer, s: &mut S) {
         self.get().encode(w, s);
     }
 }
 
-impl<S> DecodeMut<'_, '_, S> for NonZeroU32 {
+impl<S> DecodeMut<'_, '_, S> for NonZero<u32> {
     fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
         Self::new(u32::decode(r, s)).unwrap()
     }
diff --git a/library/proc_macro/src/bridge/symbol.rs b/library/proc_macro/src/bridge/symbol.rs
index 930c111455df0..ae3c0fe018fb1 100644
--- a/library/proc_macro/src/bridge/symbol.rs
+++ b/library/proc_macro/src/bridge/symbol.rs
@@ -10,14 +10,14 @@
 //! proc_macro, this module should probably be removed or simplified.
 
 use std::cell::RefCell;
-use std::num::NonZeroU32;
+use std::num::NonZero;
 use std::str;
 
 use super::*;
 
 /// Handle for a symbol string stored within the Interner.
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
-pub struct Symbol(NonZeroU32);
+pub struct Symbol(NonZero<u32>);
 
 impl !Send for Symbol {}
 impl !Sync for Symbol {}
@@ -137,7 +137,7 @@ thread_local! {
         names: fxhash::FxHashMap::default(),
         strings: Vec::new(),
         // Start with a base of 1 to make sure that `NonZeroU32` works.
-        sym_base: NonZeroU32::new(1).unwrap(),
+        sym_base: NonZero::<u32>::new(1).unwrap(),
     });
 }
 
@@ -152,7 +152,7 @@ struct Interner {
     // The offset to apply to symbol names stored in the interner. This is used
     // to ensure that symbol names are not re-used after the interner is
     // cleared.
-    sym_base: NonZeroU32,
+    sym_base: NonZero<u32>,
 }
 
 impl Interner {
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index 90b76cbc26ebf..1e6e4a043106b 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -26,6 +26,7 @@
 #![feature(staged_api)]
 #![feature(allow_internal_unstable)]
 #![feature(decl_macro)]
+#![feature(generic_nonzero)]
 #![feature(maybe_uninit_write_slice)]
 #![feature(negative_impls)]
 #![feature(new_uninit)]
diff --git a/library/std/src/sys/pal/hermit/thread.rs b/library/std/src/sys/pal/hermit/thread.rs
index 3384906a15e3b..789de7f41ff9a 100644
--- a/library/std/src/sys/pal/hermit/thread.rs
+++ b/library/std/src/sys/pal/hermit/thread.rs
@@ -5,7 +5,7 @@ use super::thread_local_dtor::run_dtors;
 use crate::ffi::CStr;
 use crate::io;
 use crate::mem;
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ptr;
 use crate::time::Duration;
 
@@ -97,8 +97,8 @@ impl Thread {
     }
 }
 
-pub fn available_parallelism() -> io::Result<NonZeroUsize> {
-    unsafe { Ok(NonZeroUsize::new_unchecked(abi::get_processor_count())) }
+pub fn available_parallelism() -> io::Result<NonZero<usize>> {
+    unsafe { Ok(NonZero::<usize>::new_unchecked(abi::get_processor_count())) }
 }
 
 pub mod guard {
diff --git a/library/std/src/sys/pal/itron/thread.rs b/library/std/src/sys/pal/itron/thread.rs
index ae0f718535b26..9c1387bf4083a 100644
--- a/library/std/src/sys/pal/itron/thread.rs
+++ b/library/std/src/sys/pal/itron/thread.rs
@@ -11,6 +11,7 @@ use crate::{
     ffi::CStr,
     hint, io,
     mem::ManuallyDrop,
+    num::NonZero,
     ptr::NonNull,
     sync::atomic::{AtomicUsize, Ordering},
     sys::thread_local_dtor::run_dtors,
@@ -363,6 +364,6 @@ unsafe fn terminate_and_delete_current_task() -> ! {
     unsafe { crate::hint::unreachable_unchecked() };
 }
 
-pub fn available_parallelism() -> io::Result<crate::num::NonZeroUsize> {
+pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     super::unsupported()
 }
diff --git a/library/std/src/sys/pal/sgx/abi/tls/mod.rs b/library/std/src/sys/pal/sgx/abi/tls/mod.rs
index 09c4ab3d3e901..5ee1621420e3a 100644
--- a/library/std/src/sys/pal/sgx/abi/tls/mod.rs
+++ b/library/std/src/sys/pal/sgx/abi/tls/mod.rs
@@ -3,7 +3,7 @@ mod sync_bitset;
 use self::sync_bitset::*;
 use crate::cell::Cell;
 use crate::mem;
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ptr;
 use crate::sync::atomic::{AtomicUsize, Ordering};
 
@@ -30,7 +30,7 @@ extern "C" {
 
 #[derive(Copy, Clone)]
 #[repr(C)]
-pub struct Key(NonZeroUsize);
+pub struct Key(NonZero<usize>);
 
 impl Key {
     fn to_index(self) -> usize {
@@ -38,7 +38,7 @@ impl Key {
     }
 
     fn from_index(index: usize) -> Self {
-        Key(NonZeroUsize::new(index + 1).unwrap())
+        Key(NonZero::<usize>::new(index + 1).unwrap())
     }
 
     pub fn as_usize(self) -> usize {
@@ -46,7 +46,7 @@ impl Key {
     }
 
     pub fn from_usize(index: usize) -> Self {
-        Key(NonZeroUsize::new(index).unwrap())
+        Key(NonZero::<usize>::new(index).unwrap())
     }
 }
 
diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/raw.rs b/library/std/src/sys/pal/sgx/abi/usercalls/raw.rs
index 10c1456d4fd05..4f52bb474b168 100644
--- a/library/std/src/sys/pal/sgx/abi/usercalls/raw.rs
+++ b/library/std/src/sys/pal/sgx/abi/usercalls/raw.rs
@@ -3,14 +3,15 @@
 #[unstable(feature = "sgx_platform", issue = "56975")]
 pub use fortanix_sgx_abi::*;
 
-use crate::num::NonZeroU64;
+use crate::num::NonZero;
 use crate::ptr::NonNull;
 
 #[repr(C)]
 struct UsercallReturn(u64, u64);
 
 extern "C" {
-    fn usercall(nr: NonZeroU64, p1: u64, p2: u64, abort: u64, p3: u64, p4: u64) -> UsercallReturn;
+    fn usercall(nr: NonZero<u64>, p1: u64, p2: u64, abort: u64, p3: u64, p4: u64)
+    -> UsercallReturn;
 }
 
 /// Performs the raw usercall operation as defined in the ABI calling convention.
@@ -26,7 +27,7 @@ extern "C" {
 #[unstable(feature = "sgx_platform", issue = "56975")]
 #[inline]
 pub unsafe fn do_usercall(
-    nr: NonZeroU64,
+    nr: NonZero<u64>,
     p1: u64,
     p2: u64,
     p3: u64,
@@ -194,7 +195,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
         #[inline(always)]
         pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3, $n4: $t4) -> $r {
             ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
-                    rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
+                    rtunwrap!(Some, NonZero::<u64>::new(Usercalls::$f as Register)),
                     RegisterArgument::into_register($n1),
                     RegisterArgument::into_register($n2),
                     RegisterArgument::into_register($n3),
@@ -210,7 +211,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
         #[inline(always)]
         pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3) -> $r {
             ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
-                    rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
+                    rtunwrap!(Some, NonZero::<u64>::new(Usercalls::$f as Register)),
                     RegisterArgument::into_register($n1),
                     RegisterArgument::into_register($n2),
                     RegisterArgument::into_register($n3),
@@ -226,7 +227,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
         #[inline(always)]
         pub unsafe fn $f($n1: $t1, $n2: $t2) -> $r {
             ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
-                    rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
+                    rtunwrap!(Some, NonZero::<u64>::new(Usercalls::$f as Register)),
                     RegisterArgument::into_register($n1),
                     RegisterArgument::into_register($n2),
                     0,0,
@@ -241,7 +242,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
         #[inline(always)]
         pub unsafe fn $f($n1: $t1) -> $r {
             ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
-                    rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
+                    rtunwrap!(Some, NonZero::<u64>::new(Usercalls::$f as Register)),
                     RegisterArgument::into_register($n1),
                     0,0,0,
                     return_type_is_abort!($r)
@@ -255,7 +256,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
         #[inline(always)]
         pub unsafe fn $f() -> $r {
             ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
-                    rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
+                    rtunwrap!(Some, NonZero::<u64>::new(Usercalls::$f as Register)),
                     0,0,0,0,
                     return_type_is_abort!($r)
             ) })
diff --git a/library/std/src/sys/pal/sgx/rwlock.rs b/library/std/src/sys/pal/sgx/rwlock.rs
index d89de18ca5ff8..87bebac37dac9 100644
--- a/library/std/src/sys/pal/sgx/rwlock.rs
+++ b/library/std/src/sys/pal/sgx/rwlock.rs
@@ -1,7 +1,7 @@
 #[cfg(test)]
 mod tests;
 
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::sys_common::lazy_box::{LazyBox, LazyInit};
 
 use super::waitqueue::{
@@ -10,7 +10,7 @@ use super::waitqueue::{
 use crate::alloc::Layout;
 
 struct AllocatedRwLock {
-    readers: SpinMutex<WaitVariable<Option<NonZeroUsize>>>,
+    readers: SpinMutex<WaitVariable<Option<NonZero<usize>>>>,
     writer: SpinMutex<WaitVariable<bool>>,
 }
 
@@ -54,7 +54,7 @@ impl RwLock {
         } else {
             // No waiting writers, acquire the read lock
             *rguard.lock_var_mut() =
-                NonZeroUsize::new(rguard.lock_var().map_or(0, |n| n.get()) + 1);
+                NonZero::<usize>::new(rguard.lock_var().map_or(0, |n| n.get()) + 1);
         }
     }
 
@@ -69,7 +69,7 @@ impl RwLock {
         } else {
             // No waiting writers, acquire the read lock
             *rguard.lock_var_mut() =
-                NonZeroUsize::new(rguard.lock_var().map_or(0, |n| n.get()) + 1);
+                NonZero::<usize>::new(rguard.lock_var().map_or(0, |n| n.get()) + 1);
             true
         }
     }
@@ -108,10 +108,10 @@ impl RwLock {
     #[inline]
     unsafe fn __read_unlock(
         &self,
-        mut rguard: SpinMutexGuard<'_, WaitVariable<Option<NonZeroUsize>>>,
+        mut rguard: SpinMutexGuard<'_, WaitVariable<Option<NonZero<usize>>>>,
         wguard: SpinMutexGuard<'_, WaitVariable<bool>>,
     ) {
-        *rguard.lock_var_mut() = NonZeroUsize::new(rguard.lock_var().unwrap().get() - 1);
+        *rguard.lock_var_mut() = NonZero::<usize>::new(rguard.lock_var().unwrap().get() - 1);
         if rguard.lock_var().is_some() {
             // There are other active readers
         } else {
@@ -137,7 +137,7 @@ impl RwLock {
     #[inline]
     unsafe fn __write_unlock(
         &self,
-        rguard: SpinMutexGuard<'_, WaitVariable<Option<NonZeroUsize>>>,
+        rguard: SpinMutexGuard<'_, WaitVariable<Option<NonZero<usize>>>>,
         wguard: SpinMutexGuard<'_, WaitVariable<bool>>,
     ) {
         match WaitQueue::notify_one(wguard) {
diff --git a/library/std/src/sys/pal/sgx/thread.rs b/library/std/src/sys/pal/sgx/thread.rs
index 7ac9d1d64b420..c797fde7fbdca 100644
--- a/library/std/src/sys/pal/sgx/thread.rs
+++ b/library/std/src/sys/pal/sgx/thread.rs
@@ -2,7 +2,7 @@
 use super::unsupported;
 use crate::ffi::CStr;
 use crate::io;
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::time::Duration;
 
 use super::abi::usercalls;
@@ -142,7 +142,7 @@ impl Thread {
     }
 }
 
-pub fn available_parallelism() -> io::Result<NonZeroUsize> {
+pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     unsupported()
 }
 
diff --git a/library/std/src/sys/pal/sgx/waitqueue/mod.rs b/library/std/src/sys/pal/sgx/waitqueue/mod.rs
index 25eca61d67b66..92ffec8d0b7d2 100644
--- a/library/std/src/sys/pal/sgx/waitqueue/mod.rs
+++ b/library/std/src/sys/pal/sgx/waitqueue/mod.rs
@@ -16,7 +16,7 @@ mod tests;
 mod spin_mutex;
 mod unsafe_list;
 
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ops::{Deref, DerefMut};
 use crate::panic::{self, AssertUnwindSafe};
 use crate::time::Duration;
@@ -68,7 +68,7 @@ impl<T> WaitVariable<T> {
 #[derive(Copy, Clone)]
 pub enum NotifiedTcs {
     Single(Tcs),
-    All { count: NonZeroUsize },
+    All { count: NonZero<usize> },
 }
 
 /// An RAII guard that will notify a set of target threads as well as unlock
@@ -252,7 +252,7 @@ impl WaitQueue {
                 entry_guard.wake = true;
             }
 
-            if let Some(count) = NonZeroUsize::new(count) {
+            if let Some(count) = NonZero::<usize>::new(count) {
                 Ok(WaitGuard { mutex_guard: Some(guard), notified_tcs: NotifiedTcs::All { count } })
             } else {
                 Err(guard)
diff --git a/library/std/src/sys/pal/teeos/thread.rs b/library/std/src/sys/pal/teeos/thread.rs
index 155f333f90616..77f9040ead540 100644
--- a/library/std/src/sys/pal/teeos/thread.rs
+++ b/library/std/src/sys/pal/teeos/thread.rs
@@ -4,7 +4,7 @@ use crate::cmp;
 use crate::ffi::CStr;
 use crate::io;
 use crate::mem;
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ptr;
 use crate::sys::os;
 use crate::time::Duration;
@@ -140,7 +140,7 @@ impl Drop for Thread {
 
 // Note: Both `sched_getaffinity` and `sysconf` are available but not functional on
 // teeos, so this function always returns an Error!
-pub fn available_parallelism() -> io::Result<NonZeroUsize> {
+pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     Err(io::Error::new(
         io::ErrorKind::NotFound,
         "The number of hardware threads is not known for the target platform",
diff --git a/library/std/src/sys/pal/uefi/thread.rs b/library/std/src/sys/pal/uefi/thread.rs
index ddfc3af2f5011..f6f5b20a42135 100644
--- a/library/std/src/sys/pal/uefi/thread.rs
+++ b/library/std/src/sys/pal/uefi/thread.rs
@@ -1,7 +1,7 @@
 use super::unsupported;
 use crate::ffi::CStr;
 use crate::io;
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ptr::NonNull;
 use crate::time::Duration;
 
@@ -44,9 +44,9 @@ impl Thread {
     }
 }
 
-pub fn available_parallelism() -> io::Result<NonZeroUsize> {
+pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     // UEFI is single threaded
-    Ok(NonZeroUsize::new(1).unwrap())
+    Ok(NonZero::<usize>::new(1).unwrap())
 }
 
 pub mod guard {
diff --git a/library/std/src/sys/pal/unix/process/process_common/tests.rs b/library/std/src/sys/pal/unix/process/process_common/tests.rs
index 4e41efc90962a..823b4a5633629 100644
--- a/library/std/src/sys/pal/unix/process/process_common/tests.rs
+++ b/library/std/src/sys/pal/unix/process/process_common/tests.rs
@@ -170,7 +170,7 @@ fn test_program_kind() {
 )))]
 #[test]
 fn unix_exit_statuses() {
-    use crate::num::NonZeroI32;
+    use crate::num::NonZero;
     use crate::os::unix::process::ExitStatusExt;
     use crate::process::*;
 
@@ -182,7 +182,7 @@ fn unix_exit_statuses() {
 
         assert_eq!(exit_status.code(), Some(exit_code));
 
-        if let Ok(nz) = NonZeroI32::try_from(exit_code) {
+        if let Ok(nz) = NonZero::try_from(exit_code) {
             assert!(!exit_status.success());
             let es_error = exit_status.exit_ok().unwrap_err();
             assert_eq!(es_error.code().unwrap(), i32::from(nz));
diff --git a/library/std/src/sys/pal/unix/process/process_fuchsia.rs b/library/std/src/sys/pal/unix/process/process_fuchsia.rs
index 9931c2af2f1e0..b6a74fb48318c 100644
--- a/library/std/src/sys/pal/unix/process/process_fuchsia.rs
+++ b/library/std/src/sys/pal/unix/process/process_fuchsia.rs
@@ -1,7 +1,7 @@
 use crate::fmt;
 use crate::io;
 use crate::mem;
-use crate::num::{NonZeroI32, NonZeroI64};
+use crate::num::NonZero;
 use crate::ptr;
 
 use crate::sys::process::process_common::*;
@@ -240,7 +240,7 @@ pub struct ExitStatus(i64);
 
 impl ExitStatus {
     pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
-        match NonZeroI64::try_from(self.0) {
+        match NonZero::try_from(self.0) {
             /* was nonzero */ Ok(failure) => Err(ExitStatusError(failure)),
             /* was zero, couldn't convert */ Err(_) => Ok(()),
         }
@@ -314,7 +314,7 @@ impl fmt::Display for ExitStatus {
 }
 
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
-pub struct ExitStatusError(NonZeroI64);
+pub struct ExitStatusError(NonZero<i64>);
 
 impl Into<ExitStatus> for ExitStatusError {
     fn into(self) -> ExitStatus {
@@ -323,7 +323,7 @@ impl Into<ExitStatus> for ExitStatusError {
 }
 
 impl ExitStatusError {
-    pub fn code(self) -> Option<NonZeroI32> {
+    pub fn code(self) -> Option<NonZero<i32>> {
         // fixme: affected by the same bug as ExitStatus::code()
         ExitStatus(self.0.into()).code().map(|st| st.try_into().unwrap())
     }
diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs
index 94c4c56bd51cf..d5a77085725c5 100644
--- a/library/std/src/sys/pal/unix/process/process_unix.rs
+++ b/library/std/src/sys/pal/unix/process/process_unix.rs
@@ -1,7 +1,7 @@
 use crate::fmt;
 use crate::io::{self, Error, ErrorKind};
 use crate::mem;
-use crate::num::{NonZero, NonZeroI32};
+use crate::num::NonZero;
 use crate::sys;
 use crate::sys::cvt;
 use crate::sys::process::process_common::*;
@@ -1106,7 +1106,7 @@ impl fmt::Debug for ExitStatusError {
 }
 
 impl ExitStatusError {
-    pub fn code(self) -> Option<NonZeroI32> {
+    pub fn code(self) -> Option<NonZero<i32>> {
         ExitStatus(self.0.into()).code().map(|st| st.try_into().unwrap())
     }
 }
diff --git a/library/std/src/sys/pal/unix/process/process_unsupported.rs b/library/std/src/sys/pal/unix/process/process_unsupported.rs
index 89a2a0c6e567b..33d359d3f8411 100644
--- a/library/std/src/sys/pal/unix/process/process_unsupported.rs
+++ b/library/std/src/sys/pal/unix/process/process_unsupported.rs
@@ -1,6 +1,6 @@
 use crate::fmt;
 use crate::io;
-use crate::num::{NonZero, NonZeroI32};
+use crate::num::NonZero;
 use crate::sys::pal::unix::unsupported::*;
 use crate::sys::process::process_common::*;
 
@@ -67,7 +67,7 @@ impl Into<ExitStatus> for ExitStatusError {
 }
 
 impl ExitStatusError {
-    pub fn code(self) -> Option<NonZeroI32> {
+    pub fn code(self) -> Option<NonZero<i32>> {
         ExitStatus::from(c_int::from(self.0)).code().map(|st| st.try_into().unwrap())
     }
 }
diff --git a/library/std/src/sys/pal/unix/process/process_vxworks.rs b/library/std/src/sys/pal/unix/process/process_vxworks.rs
index 5b4e94d0f1b97..76179e0910d9e 100644
--- a/library/std/src/sys/pal/unix/process/process_vxworks.rs
+++ b/library/std/src/sys/pal/unix/process/process_vxworks.rs
@@ -1,6 +1,6 @@
 use crate::fmt;
 use crate::io::{self, Error, ErrorKind};
-use crate::num::{NonZero, NonZeroI32};
+use crate::num::NonZero;
 use crate::sys;
 use crate::sys::cvt;
 use crate::sys::process::process_common::*;
@@ -257,7 +257,7 @@ impl Into<ExitStatus> for ExitStatusError {
 }
 
 impl ExitStatusError {
-    pub fn code(self) -> Option<NonZeroI32> {
+    pub fn code(self) -> Option<NonZero<i32>> {
         ExitStatus(self.0.into()).code().map(|st| st.try_into().unwrap())
     }
 }
diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs
index 7e4a01a5ecd33..dd3c370667a1e 100644
--- a/library/std/src/sys/pal/unix/thread.rs
+++ b/library/std/src/sys/pal/unix/thread.rs
@@ -2,7 +2,7 @@ use crate::cmp;
 use crate::ffi::CStr;
 use crate::io;
 use crate::mem;
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::ptr;
 use crate::sys::{os, stack_overflow};
 use crate::time::Duration;
@@ -306,7 +306,7 @@ fn truncate_cstr<const MAX_WITH_NUL: usize>(cstr: &CStr) -> [libc::c_char; MAX_W
     result
 }
 
-pub fn available_parallelism() -> io::Result<NonZeroUsize> {
+pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     cfg_if::cfg_if! {
         if #[cfg(any(
             target_os = "android",
@@ -338,7 +338,7 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
                         // some old MIPS kernels were buggy and zero-initialized the mask if
                         // none was explicitly set.
                         // In that case we use the sysconf fallback.
-                        if let Some(count) = NonZeroUsize::new(count) {
+                        if let Some(count) = NonZero::<usize>::new(count) {
                             return Ok(count)
                         }
                     }
@@ -351,7 +351,7 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
                     let count = cpus as usize;
                     // Cover the unusual situation where we were able to get the quota but not the affinity mask
                     let count = count.min(quota);
-                    Ok(unsafe { NonZeroUsize::new_unchecked(count) })
+                    Ok(unsafe { NonZero::<usize>::new_unchecked(count) })
                 }
             }
         } else if #[cfg(any(
@@ -375,7 +375,7 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
                     ) == 0 {
                         let count = libc::CPU_COUNT(&set) as usize;
                         if count > 0 {
-                            return Ok(NonZeroUsize::new_unchecked(count));
+                            return Ok(NonZero::<usize>::new_unchecked(count));
                         }
                     }
                 }
@@ -397,7 +397,7 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
                             }
                         }
                         libc::_cpuset_destroy(set);
-                        if let Some(count) = NonZeroUsize::new(count) {
+                        if let Some(count) = NonZero::<usize>::new(count) {
                             return Ok(count);
                         }
                     }
@@ -433,7 +433,7 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
                 }
             }
 
-            Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) })
+            Ok(unsafe { NonZero::<usize>::new_unchecked(cpus as usize) })
         } else if #[cfg(target_os = "nto")] {
             unsafe {
                 use libc::_syspage_ptr;
@@ -441,7 +441,7 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
                     Err(io::const_io_error!(io::ErrorKind::NotFound, "No syspage available"))
                 } else {
                     let cpus = (*_syspage_ptr).num_cpu;
-                    NonZeroUsize::new(cpus as usize)
+                    NonZero::<usize>::new(cpus as usize)
                         .ok_or(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"))
                 }
             }
@@ -456,7 +456,7 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
                     return Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"));
                 }
 
-                Ok(NonZeroUsize::new_unchecked(sinfo.cpu_count as usize))
+                Ok(NonZero::<usize>::new_unchecked(sinfo.cpu_count as usize))
             }
         } else {
             // FIXME: implement on vxWorks, Redox, l4re
diff --git a/library/std/src/sys/pal/unsupported/process.rs b/library/std/src/sys/pal/unsupported/process.rs
index a639afcc674ed..6a989dd3e76bb 100644
--- a/library/std/src/sys/pal/unsupported/process.rs
+++ b/library/std/src/sys/pal/unsupported/process.rs
@@ -2,7 +2,7 @@ use crate::ffi::OsStr;
 use crate::fmt;
 use crate::io;
 use crate::marker::PhantomData;
-use crate::num::NonZeroI32;
+use crate::num::NonZero;
 use crate::path::Path;
 use crate::sys::fs::File;
 use crate::sys::pipe::AnonPipe;
@@ -170,7 +170,7 @@ impl Into<ExitStatus> for ExitStatusError {
 }
 
 impl ExitStatusError {
-    pub fn code(self) -> Option<NonZeroI32> {
+    pub fn code(self) -> Option<NonZero<i32>> {
         self.0
     }
 }
diff --git a/library/std/src/sys/pal/unsupported/thread.rs b/library/std/src/sys/pal/unsupported/thread.rs
index a8db251de2017..cd1ae7f7d11cd 100644
--- a/library/std/src/sys/pal/unsupported/thread.rs
+++ b/library/std/src/sys/pal/unsupported/thread.rs
@@ -1,7 +1,7 @@
 use super::unsupported;
 use crate::ffi::CStr;
 use crate::io;
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::time::Duration;
 
 pub struct Thread(!);
@@ -31,7 +31,7 @@ impl Thread {
     }
 }
 
-pub fn available_parallelism() -> io::Result<NonZeroUsize> {
+pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     unsupported()
 }
 
diff --git a/library/std/src/sys/pal/wasi/thread.rs b/library/std/src/sys/pal/wasi/thread.rs
index a0eefa8811a39..77d8b4378e7d5 100644
--- a/library/std/src/sys/pal/wasi/thread.rs
+++ b/library/std/src/sys/pal/wasi/thread.rs
@@ -1,7 +1,7 @@
 use crate::ffi::CStr;
 use crate::io;
 use crate::mem;
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::sys::unsupported;
 use crate::time::Duration;
 
@@ -186,7 +186,7 @@ impl Thread {
     }
 }
 
-pub fn available_parallelism() -> io::Result<NonZeroUsize> {
+pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     unsupported()
 }
 
diff --git a/library/std/src/sys/pal/wasm/atomics/thread.rs b/library/std/src/sys/pal/wasm/atomics/thread.rs
index 714b704922794..49f936f14498c 100644
--- a/library/std/src/sys/pal/wasm/atomics/thread.rs
+++ b/library/std/src/sys/pal/wasm/atomics/thread.rs
@@ -1,6 +1,6 @@
 use crate::ffi::CStr;
 use crate::io;
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::sys::unsupported;
 use crate::time::Duration;
 
@@ -40,7 +40,7 @@ impl Thread {
     pub fn join(self) {}
 }
 
-pub fn available_parallelism() -> io::Result<NonZeroUsize> {
+pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     unsupported()
 }
 
diff --git a/library/std/src/sys/pal/windows/args.rs b/library/std/src/sys/pal/windows/args.rs
index fbbdbc2126595..c3a4d4706996d 100644
--- a/library/std/src/sys/pal/windows/args.rs
+++ b/library/std/src/sys/pal/windows/args.rs
@@ -10,7 +10,7 @@ use super::os::current_exe;
 use crate::ffi::OsString;
 use crate::fmt;
 use crate::io;
-use crate::num::NonZeroU16;
+use crate::num::NonZero;
 use crate::os::windows::prelude::*;
 use crate::path::{Path, PathBuf};
 use crate::sys::path::get_long_path;
@@ -21,12 +21,12 @@ use crate::vec;
 
 use crate::iter;
 
-/// This is the const equivalent to `NonZeroU16::new(n).unwrap()`
+/// This is the const equivalent to `NonZero::<u16>::new(n).unwrap()`
 ///
 /// FIXME: This can be removed once `Option::unwrap` is stably const.
 /// See the `const_option` feature (#67441).
-const fn non_zero_u16(n: u16) -> NonZeroU16 {
-    match NonZeroU16::new(n) {
+const fn non_zero_u16(n: u16) -> NonZero<u16> {
+    match NonZero::<u16>::new(n) {
         Some(n) => n,
         None => panic!("called `unwrap` on a `None` value"),
     }
@@ -69,10 +69,10 @@ fn parse_lp_cmd_line<'a, F: Fn() -> OsString>(
     lp_cmd_line: Option<WStrUnits<'a>>,
     exe_name: F,
 ) -> Vec<OsString> {
-    const BACKSLASH: NonZeroU16 = non_zero_u16(b'\\' as u16);
-    const QUOTE: NonZeroU16 = non_zero_u16(b'"' as u16);
-    const TAB: NonZeroU16 = non_zero_u16(b'\t' as u16);
-    const SPACE: NonZeroU16 = non_zero_u16(b' ' as u16);
+    const BACKSLASH: NonZero<u16> = non_zero_u16(b'\\' as u16);
+    const QUOTE: NonZero<u16> = non_zero_u16(b'"' as u16);
+    const TAB: NonZero<u16> = non_zero_u16(b'\t' as u16);
+    const SPACE: NonZero<u16> = non_zero_u16(b' ' as u16);
 
     let mut ret_val = Vec::new();
     // If the cmd line pointer is null or it points to an empty string then
diff --git a/library/std/src/sys/pal/windows/process.rs b/library/std/src/sys/pal/windows/process.rs
index 9ec775959fd45..6a94d37714038 100644
--- a/library/std/src/sys/pal/windows/process.rs
+++ b/library/std/src/sys/pal/windows/process.rs
@@ -12,7 +12,7 @@ use crate::fmt;
 use crate::io::{self, Error, ErrorKind};
 use crate::mem;
 use crate::mem::MaybeUninit;
-use crate::num::NonZeroI32;
+use crate::num::NonZero;
 use crate::os::windows::ffi::{OsStrExt, OsStringExt};
 use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle};
 use crate::path::{Path, PathBuf};
@@ -747,7 +747,7 @@ impl Into<ExitStatus> for ExitStatusError {
 }
 
 impl ExitStatusError {
-    pub fn code(self) -> Option<NonZeroI32> {
+    pub fn code(self) -> Option<NonZero<i32>> {
         Some((u32::from(self.0) as i32).try_into().unwrap())
     }
 }
diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/pal/windows/thread.rs
index 1fe744935193c..4f189944fb2b8 100644
--- a/library/std/src/sys/pal/windows/thread.rs
+++ b/library/std/src/sys/pal/windows/thread.rs
@@ -1,6 +1,6 @@
 use crate::ffi::CStr;
 use crate::io;
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::os::windows::io::AsRawHandle;
 use crate::os::windows::io::HandleOrNull;
 use crate::ptr;
@@ -110,7 +110,7 @@ impl Thread {
     }
 }
 
-pub fn available_parallelism() -> io::Result<NonZeroUsize> {
+pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     let res = unsafe {
         let mut sysinfo: c::SYSTEM_INFO = crate::mem::zeroed();
         c::GetSystemInfo(&mut sysinfo);
@@ -121,7 +121,7 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
             io::ErrorKind::NotFound,
             "The number of hardware threads is not known for the target platform",
         )),
-        cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus) }),
+        cpus => Ok(unsafe { NonZero::<usize>::new_unchecked(cpus) }),
     }
 }
 
diff --git a/library/std/src/sys/pal/xous/thread.rs b/library/std/src/sys/pal/xous/thread.rs
index 0f452e07a5c58..2cc1585650184 100644
--- a/library/std/src/sys/pal/xous/thread.rs
+++ b/library/std/src/sys/pal/xous/thread.rs
@@ -1,6 +1,6 @@
 use crate::ffi::CStr;
 use crate::io;
-use crate::num::NonZeroUsize;
+use crate::num::NonZero;
 use crate::os::xous::ffi::{
     blocking_scalar, create_thread, do_yield, join_thread, map_memory, update_memory_flags,
     MemoryFlags, Syscall, ThreadId,
@@ -132,9 +132,9 @@ impl Thread {
     }
 }
 
-pub fn available_parallelism() -> io::Result<NonZeroUsize> {
+pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     // We're unicore right now.
-    Ok(unsafe { NonZeroUsize::new_unchecked(1) })
+    Ok(unsafe { NonZero::<usize>::new_unchecked(1) })
 }
 
 pub mod guard {
diff --git a/library/std/src/sys_common/wstr.rs b/library/std/src/sys_common/wstr.rs
index b230fd1a829f7..601ef3dd1505c 100644
--- a/library/std/src/sys_common/wstr.rs
+++ b/library/std/src/sys_common/wstr.rs
@@ -2,7 +2,7 @@
 #![allow(dead_code)]
 
 use crate::marker::PhantomData;
-use crate::num::NonZeroU16;
+use crate::num::NonZero;
 use crate::ptr::NonNull;
 
 /// A safe iterator over a LPWSTR
@@ -23,15 +23,15 @@ impl WStrUnits<'_> {
         Some(Self { lpwstr: NonNull::new(lpwstr as _)?, lifetime: PhantomData })
     }
 
-    pub fn peek(&self) -> Option<NonZeroU16> {
+    pub fn peek(&self) -> Option<NonZero<u16>> {
         // SAFETY: It's always safe to read the current item because we don't
         // ever move out of the array's bounds.
-        unsafe { NonZeroU16::new(*self.lpwstr.as_ptr()) }
+        unsafe { NonZero::<u16>::new(*self.lpwstr.as_ptr()) }
     }
 
     /// Advance the iterator while `predicate` returns true.
     /// Returns the number of items it advanced by.
-    pub fn advance_while<P: FnMut(NonZeroU16) -> bool>(&mut self, mut predicate: P) -> usize {
+    pub fn advance_while<P: FnMut(NonZero<u16>) -> bool>(&mut self, mut predicate: P) -> usize {
         let mut counter = 0;
         while let Some(w) = self.peek() {
             if !predicate(w) {
@@ -46,8 +46,9 @@ impl WStrUnits<'_> {
 
 impl Iterator for WStrUnits<'_> {
     // This can never return zero as that marks the end of the string.
-    type Item = NonZeroU16;
-    fn next(&mut self) -> Option<NonZeroU16> {
+    type Item = NonZero<u16>;
+
+    fn next(&mut self) -> Option<Self::Item> {
         // SAFETY: If NULL is reached we immediately return.
         // Therefore it's safe to advance the pointer after that.
         unsafe {
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index eb837c8f6c63f..0da3da23568ec 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -165,8 +165,7 @@ use crate::fmt;
 use crate::io;
 use crate::marker::PhantomData;
 use crate::mem::{self, forget};
-use crate::num::NonZeroU64;
-use crate::num::NonZeroUsize;
+use crate::num::{NonZero, NonZeroU64, NonZeroUsize};
 use crate::panic;
 use crate::panicking;
 use crate::pin::Pin;
@@ -1166,7 +1165,7 @@ pub fn park_timeout(dur: Duration) {
 /// [`id`]: Thread::id
 #[stable(feature = "thread_id", since = "1.19.0")]
 #[derive(Eq, PartialEq, Clone, Copy, Hash, Debug)]
-pub struct ThreadId(NonZeroU64);
+pub struct ThreadId(NonZero<u64>);
 
 impl ThreadId {
     // Generate a new unique thread ID.
@@ -1189,7 +1188,7 @@ impl ThreadId {
                     };
 
                     match COUNTER.compare_exchange_weak(last, id, Relaxed, Relaxed) {
-                        Ok(_) => return ThreadId(NonZeroU64::new(id).unwrap()),
+                        Ok(_) => return ThreadId(NonZero::<u64>::new(id).unwrap()),
                         Err(id) => last = id,
                     }
                 }
@@ -1208,7 +1207,7 @@ impl ThreadId {
 
                 *counter = id;
                 drop(counter);
-                ThreadId(NonZeroU64::new(id).unwrap())
+                ThreadId(NonZero::<u64>::new(id).unwrap())
             }
         }
     }
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index de7a4b79d26ff..095ba17367135 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -1,3 +1,4 @@
+#![feature(generic_nonzero)]
 #![feature(rustc_private, stmt_expr_attributes)]
 #![allow(
     clippy::manual_range_contains,
@@ -17,7 +18,7 @@ extern crate rustc_middle;
 extern crate rustc_session;
 
 use std::env::{self, VarError};
-use std::num::NonZeroU64;
+use std::num::NonZero;
 use std::path::PathBuf;
 use std::str::FromStr;
 
@@ -528,7 +529,7 @@ fn main() {
                 }
             }
         } else if let Some(param) = arg.strip_prefix("-Zmiri-track-alloc-id=") {
-            let ids: Vec<miri::AllocId> = match parse_comma_list::<NonZeroU64>(param) {
+            let ids: Vec<miri::AllocId> = match parse_comma_list::<NonZero<u64>>(param) {
                 Ok(ids) => ids.into_iter().map(miri::AllocId).collect(),
                 Err(err) =>
                     show_error!(
diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs
index 46f96a715f1c6..4424595ea1cdf 100644
--- a/src/tools/miri/src/borrow_tracker/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/mod.rs
@@ -1,6 +1,6 @@
 use std::cell::RefCell;
 use std::fmt;
-use std::num::NonZeroU64;
+use std::num::NonZero;
 
 use log::trace;
 use smallvec::SmallVec;
@@ -13,22 +13,22 @@ use crate::*;
 pub mod stacked_borrows;
 pub mod tree_borrows;
 
-pub type CallId = NonZeroU64;
+pub type CallId = NonZero<u64>;
 
 /// Tracking pointer provenance
 #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
-pub struct BorTag(NonZeroU64);
+pub struct BorTag(NonZero<u64>);
 
 impl BorTag {
     pub fn new(i: u64) -> Option<Self> {
-        NonZeroU64::new(i).map(BorTag)
+        NonZero::<u64>::new(i).map(BorTag)
     }
 
     pub fn get(&self) -> u64 {
         self.0.get()
     }
 
-    pub fn inner(&self) -> NonZeroU64 {
+    pub fn inner(&self) -> NonZero<u64> {
         self.0
     }
 
@@ -184,7 +184,7 @@ impl GlobalStateInner {
             borrow_tracker_method,
             next_ptr_tag: BorTag::one(),
             base_ptr_tags: FxHashMap::default(),
-            next_call_id: NonZeroU64::new(1).unwrap(),
+            next_call_id: NonZero::<u64>::new(1).unwrap(),
             protected_tags: FxHashMap::default(),
             tracked_pointer_tags,
             tracked_call_ids,
@@ -206,7 +206,7 @@ impl GlobalStateInner {
         if self.tracked_call_ids.contains(&call_id) {
             machine.emit_diagnostic(NonHaltingDiagnostic::CreatedCallId(call_id));
         }
-        self.next_call_id = NonZeroU64::new(call_id.get() + 1).unwrap();
+        self.next_call_id = NonZero::<u64>::new(call_id.get() + 1).unwrap();
         FrameState { call_id, protected_tags: SmallVec::new() }
     }
 
diff --git a/src/tools/miri/src/concurrency/init_once.rs b/src/tools/miri/src/concurrency/init_once.rs
index 9a848d50341a4..35dcfecbbe334 100644
--- a/src/tools/miri/src/concurrency/init_once.rs
+++ b/src/tools/miri/src/concurrency/init_once.rs
@@ -1,5 +1,4 @@
 use std::collections::VecDeque;
-use std::num::NonZeroU32;
 
 use rustc_index::Idx;
 use rustc_middle::ty::layout::TyAndLayout;
diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs
index b288b69e0cef9..c3130c8a8f0b8 100644
--- a/src/tools/miri/src/concurrency/sync.rs
+++ b/src/tools/miri/src/concurrency/sync.rs
@@ -1,5 +1,4 @@
 use std::collections::{hash_map::Entry, VecDeque};
-use std::num::NonZeroU32;
 use std::ops::Not;
 
 use log::trace;
@@ -26,12 +25,12 @@ macro_rules! declare_id {
         /// 0 is used to indicate that the id was not yet assigned and,
         /// therefore, is not a valid identifier.
         #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
-        pub struct $name(NonZeroU32);
+        pub struct $name(std::num::NonZero<u32>);
 
         impl SyncId for $name {
             // Panics if `id == 0`.
             fn from_u32(id: u32) -> Self {
-                Self(NonZeroU32::new(id).unwrap())
+                Self(std::num::NonZero::<u32>::new(id).unwrap())
             }
             fn to_u32(&self) -> u32 {
                 self.0.get()
@@ -44,11 +43,11 @@ macro_rules! declare_id {
                 // therefore, need to shift by one when converting from an index
                 // into a vector.
                 let shifted_idx = u32::try_from(idx).unwrap().checked_add(1).unwrap();
-                $name(NonZeroU32::new(shifted_idx).unwrap())
+                $name(std::num::NonZero::<u32>::new(shifted_idx).unwrap())
             }
             fn index(self) -> usize {
                 // See the comment in `Self::new`.
-                // (This cannot underflow because self is NonZeroU32.)
+                // (This cannot underflow because `self.0` is `NonZero<u32>`.)
                 usize::try_from(self.0.get() - 1).unwrap()
             }
         }
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index 7f91af59d5622..19b29a4181984 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -1,5 +1,5 @@
 use std::fmt::{self, Write};
-use std::num::NonZeroU64;
+use std::num::NonZero;
 
 use log::trace;
 
@@ -115,7 +115,7 @@ pub enum NonHaltingDiagnostic {
     /// (new_tag, new_perm, (alloc_id, base_offset, orig_tag))
     ///
     /// new_perm is `None` for base tags.
-    CreatedPointerTag(NonZeroU64, Option<String>, Option<(AllocId, AllocRange, ProvenanceExtra)>),
+    CreatedPointerTag(NonZero<u64>, Option<String>, Option<(AllocId, AllocRange, ProvenanceExtra)>),
     /// This `Item` was popped from the borrow stack. The string explains the reason.
     PoppedPointerTag(Item, String),
     CreatedCallId(CallId),
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index d6b1e1358086c..3cee4df588542 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -1,6 +1,6 @@
 use std::cmp;
 use std::iter;
-use std::num::NonZeroUsize;
+use std::num::NonZero;
 use std::time::Duration;
 
 use log::trace;
@@ -574,7 +574,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             fn visit_union(
                 &mut self,
                 _v: &MPlaceTy<'tcx, Provenance>,
-                _fields: NonZeroUsize,
+                _fields: NonZero<usize>,
             ) -> InterpResult<'tcx> {
                 bug!("we should have already handled unions in `visit_value`")
             }
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 5a2bb84f3eff0..305c71fb0f945 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -1,6 +1,7 @@
 #![feature(rustc_private)]
 #![feature(cell_update)]
 #![feature(float_gamma)]
+#![feature(generic_nonzero)]
 #![feature(map_try_insert)]
 #![feature(never_type)]
 #![feature(try_blocks)]
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index 25654248db41a..f0e6e0374d287 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -477,7 +477,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 let [id, show_unnamed] = this.check_shim(abi, Abi::Rust, link_name, args)?;
                 let id = this.read_scalar(id)?.to_u64()?;
                 let show_unnamed = this.read_scalar(show_unnamed)?.to_bool()?;
-                if let Some(id) = std::num::NonZeroU64::new(id) {
+                if let Some(id) = std::num::NonZero::<u64>::new(id) {
                     this.print_borrow_state(AllocId(id), show_unnamed)?;
                 }
             }

From a90cc05233858fcd16c3ca0e0b4320fc5ae09af2 Mon Sep 17 00:00:00 2001
From: Markus Reiter <me@reitermark.us>
Date: Thu, 8 Feb 2024 23:03:25 +0100
Subject: [PATCH 41/58] Replace `NonZero::<_>::new` with `NonZero::new`.

---
 .../src/tagged_ptr/copy.rs                    |  5 +--
 compiler/rustc_feature/src/lib.rs             |  2 +-
 compiler/rustc_interface/src/tests.rs         |  2 +-
 compiler/rustc_interface/src/util.rs          |  2 +-
 compiler/rustc_metadata/src/rmeta/decoder.rs  | 10 ++---
 compiler/rustc_metadata/src/rmeta/encoder.rs  |  6 +--
 compiler/rustc_metadata/src/rmeta/mod.rs      |  2 +-
 compiler/rustc_metadata/src/rmeta/table.rs    |  6 +--
 compiler/rustc_middle/src/middle/stability.rs |  2 +-
 .../rustc_middle/src/mir/interpret/mod.rs     |  2 +-
 .../rustc_middle/src/mir/interpret/pointer.rs |  2 +-
 compiler/rustc_middle/src/ty/consts/int.rs    | 23 +++++------
 compiler/rustc_middle/src/ty/generic_args.rs  |  5 +--
 compiler/rustc_middle/src/ty/layout.rs        |  2 +-
 compiler/rustc_middle/src/ty/mod.rs           |  5 +--
 compiler/rustc_passes/src/stability.rs        |  2 +-
 compiler/rustc_query_impl/src/plumbing.rs     |  6 +--
 compiler/rustc_serialize/src/serialize.rs     |  2 +-
 compiler/rustc_session/src/options.rs         |  2 +-
 .../alloc/src/collections/binary_heap/mod.rs  |  6 +--
 .../src/collections/vec_deque/into_iter.rs    |  4 +-
 library/alloc/src/vec/into_iter.rs            |  8 ++--
 library/alloc/tests/vec.rs                    |  6 +--
 library/alloc/tests/vec_deque.rs              |  4 +-
 library/core/src/array/iter.rs                |  4 +-
 .../core/src/iter/adapters/array_chunks.rs    |  2 +-
 library/core/src/iter/adapters/chain.rs       |  4 +-
 library/core/src/iter/adapters/cycle.rs       |  2 +-
 library/core/src/iter/adapters/flatten.rs     | 14 +++----
 library/core/src/iter/adapters/skip.rs        |  4 +-
 library/core/src/iter/adapters/take.rs        |  4 +-
 library/core/src/iter/range.rs                |  8 ++--
 library/core/src/iter/sources/repeat_n.rs     |  2 +-
 library/core/src/iter/traits/double_ended.rs  |  2 +-
 library/core/src/iter/traits/iterator.rs      |  2 +-
 library/core/src/num/nonzero.rs               |  2 +-
 library/core/src/ops/index_range.rs           |  4 +-
 library/core/src/ptr/alignment.rs             |  2 +-
 library/core/src/ptr/non_null.rs              |  2 +-
 library/core/src/slice/iter/macros.rs         |  4 +-
 library/core/src/slice/mod.rs                 |  2 +-
 library/core/src/str/iter.rs                  |  2 +-
 library/core/tests/array.rs                   |  8 ++--
 library/core/tests/iter/adapters/chain.rs     | 21 +++-------
 library/core/tests/iter/adapters/enumerate.rs |  2 +-
 library/core/tests/iter/adapters/flatten.rs   |  4 +-
 library/core/tests/iter/adapters/skip.rs      |  6 +--
 library/core/tests/iter/adapters/take.rs      | 14 +++----
 library/core/tests/iter/range.rs              |  2 +-
 library/core/tests/iter/traits/iterator.rs    | 31 ++++-----------
 library/core/tests/nonzero.rs                 | 38 +++++++++----------
 library/core/tests/ptr.rs                     |  7 ++--
 library/core/tests/result.rs                  |  2 +-
 library/core/tests/slice.rs                   |  4 +-
 library/proc_macro/src/bridge/symbol.rs       |  2 +-
 library/std/src/sys/pal/hermit/thread.rs      |  2 +-
 library/std/src/sys/pal/sgx/abi/tls/mod.rs    |  4 +-
 .../std/src/sys/pal/sgx/abi/usercalls/raw.rs  | 10 ++---
 library/std/src/sys/pal/sgx/rwlock.rs         |  8 ++--
 library/std/src/sys/pal/sgx/waitqueue/mod.rs  |  2 +-
 library/std/src/sys/pal/uefi/thread.rs        |  2 +-
 library/std/src/sys/pal/unix/thread.rs        | 14 +++----
 library/std/src/sys/pal/windows/args.rs       |  4 +-
 library/std/src/sys/pal/windows/thread.rs     |  2 +-
 library/std/src/sys/pal/xous/thread.rs        |  2 +-
 library/std/src/sys_common/wstr.rs            |  2 +-
 library/std/src/thread/mod.rs                 |  4 +-
 src/tools/miri/src/borrow_tracker/mod.rs      |  6 +--
 src/tools/miri/src/concurrency/sync.rs        |  4 +-
 src/tools/miri/src/shims/foreign_items.rs     |  2 +-
 70 files changed, 175 insertions(+), 216 deletions(-)

diff --git a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs
index 8af4042ad875b..ff4208def319d 100644
--- a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs
+++ b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs
@@ -143,15 +143,14 @@ where
             // `{non_zero} | packed_tag` can't make the value zero.
 
             let packed = (addr.get() >> T::BITS) | packed_tag;
-            unsafe { NonZero::<usize>::new_unchecked(packed) }
+            unsafe { NonZero::new_unchecked(packed) }
         })
     }
 
     /// Retrieves the original raw pointer from `self.packed`.
     #[inline]
     pub(super) fn pointer_raw(&self) -> NonNull<P::Target> {
-        self.packed
-            .map_addr(|addr| unsafe { NonZero::<usize>::new_unchecked(addr.get() << T::BITS) })
+        self.packed.map_addr(|addr| unsafe { NonZero::new_unchecked(addr.get() << T::BITS) })
     }
 
     /// This provides a reference to the `P` pointer itself, rather than the
diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs
index 02ce5d3534c43..cbc0ce8c97468 100644
--- a/compiler/rustc_feature/src/lib.rs
+++ b/compiler/rustc_feature/src/lib.rs
@@ -105,7 +105,7 @@ const fn to_nonzero(n: Option<u32>) -> Option<NonZero<u32>> {
     // in const context. Requires https://github.com/rust-lang/rfcs/pull/2632.
     match n {
         None => None,
-        Some(n) => NonZero::<u32>::new(n),
+        Some(n) => NonZero::new(n),
     }
 }
 
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index a9c614df7adef..112553b2f7031 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -827,7 +827,7 @@ fn test_unstable_options_tracking_hash() {
     tracked!(tls_model, Some(TlsModel::GeneralDynamic));
     tracked!(translate_remapped_path_to_local_path, false);
     tracked!(trap_unreachable, Some(false));
-    tracked!(treat_err_as_bug, NonZero::<usize>::new(1));
+    tracked!(treat_err_as_bug, NonZero::new(1));
     tracked!(tune_cpu, Some(String::from("abc")));
     tracked!(uninit_const_chunk_threshold, 123);
     tracked!(unleash_the_miri_inside_of_you, true);
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 00cf84138bac6..087c43075f175 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -107,7 +107,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
     use rustc_query_impl::QueryCtxt;
     use rustc_query_system::query::{deadlock, QueryContext};
 
-    let registry = sync::Registry::new(std::num::NonZero::<usize>::new(threads).unwrap());
+    let registry = sync::Registry::new(std::num::NonZero::new(threads).unwrap());
 
     if !sync::is_dyn_thread_safe() {
         return run_in_thread_with_globals(edition, || {
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 8a031e4f3a301..13d2af7a78e9b 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -338,7 +338,7 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> {
             }
             LazyState::Previous(last_pos) => last_pos.get() + distance,
         };
-        let position = NonZero::<usize>::new(position).unwrap();
+        let position = NonZero::new(position).unwrap();
         self.lazy_state = LazyState::Previous(position);
         f(position)
     }
@@ -685,17 +685,15 @@ impl MetadataBlob {
     }
 
     pub(crate) fn get_rustc_version(&self) -> String {
-        LazyValue::<String>::from_position(
-            NonZero::<usize>::new(METADATA_HEADER.len() + 8).unwrap(),
-        )
-        .decode(self)
+        LazyValue::<String>::from_position(NonZero::new(METADATA_HEADER.len() + 8).unwrap())
+            .decode(self)
     }
 
     fn root_pos(&self) -> NonZero<usize> {
         let offset = METADATA_HEADER.len();
         let pos_bytes = self.blob()[offset..][..8].try_into().unwrap();
         let pos = u64::from_le_bytes(pos_bytes);
-        NonZero::<usize>::new(pos as usize).unwrap()
+        NonZero::new(pos as usize).unwrap()
     }
 
     pub(crate) fn get_header(&self) -> CrateHeader {
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 51d747efdd36b..b25f215c1aaae 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -439,7 +439,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 position.get() - last_pos.get()
             }
         };
-        self.lazy_state = LazyState::Previous(NonZero::<usize>::new(pos).unwrap());
+        self.lazy_state = LazyState::Previous(NonZero::new(pos).unwrap());
         self.emit_usize(distance);
     }
 
@@ -447,7 +447,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     where
         T::Value<'tcx>: Encodable<EncodeContext<'a, 'tcx>>,
     {
-        let pos = NonZero::<usize>::new(self.position()).unwrap();
+        let pos = NonZero::new(self.position()).unwrap();
 
         assert_eq!(self.lazy_state, LazyState::NoNode);
         self.lazy_state = LazyState::NodeStart(pos);
@@ -466,7 +466,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     where
         T::Value<'tcx>: Encodable<EncodeContext<'a, 'tcx>>,
     {
-        let pos = NonZero::<usize>::new(self.position()).unwrap();
+        let pos = NonZero::new(self.position()).unwrap();
 
         assert_eq!(self.lazy_state, LazyState::NoNode);
         self.lazy_state = LazyState::NodeStart(pos);
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 81d834e0456a5..7c145cb5f82ad 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -119,7 +119,7 @@ impl<T: ParameterizedOverTcx> ParameterizedOverTcx for LazyArray<T> {
 
 impl<T> Default for LazyArray<T> {
     fn default() -> LazyArray<T> {
-        LazyArray::from_position_and_num_elems(NonZero::<usize>::new(1).unwrap(), 0)
+        LazyArray::from_position_and_num_elems(NonZero::new(1).unwrap(), 0)
     }
 }
 
diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs
index 00752ad15a33a..c5f281964df02 100644
--- a/compiler/rustc_metadata/src/rmeta/table.rs
+++ b/compiler/rustc_metadata/src/rmeta/table.rs
@@ -339,7 +339,7 @@ impl<T> FixedSizeEncoding for Option<LazyValue<T>> {
 
     #[inline]
     fn from_bytes(b: &[u8; 8]) -> Self {
-        let position = NonZero::<usize>::new(u64::from_bytes(b) as usize)?;
+        let position = NonZero::new(u64::from_bytes(b) as usize)?;
         Some(LazyValue::from_position(position))
     }
 
@@ -366,7 +366,7 @@ impl<T> LazyArray<T> {
     }
 
     fn from_bytes_impl(position: &[u8; 8], meta: &[u8; 8]) -> Option<LazyArray<T>> {
-        let position = NonZero::<usize>::new(u64::from_bytes(position) as usize)?;
+        let position = NonZero::new(u64::from_bytes(position) as usize)?;
         let len = u64::from_bytes(meta) as usize;
         Some(LazyArray::from_position_and_num_elems(position, len))
     }
@@ -497,7 +497,7 @@ impl<I: Idx, const N: usize, T: FixedSizeEncoding<ByteArray = [u8; N]>> TableBui
         }
 
         LazyTable::from_position_and_encoded_size(
-            NonZero::<usize>::new(pos).unwrap(),
+            NonZero::new(pos).unwrap(),
             width,
             self.blocks.len(),
         )
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 15ef00629b986..2f624ab052710 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -433,7 +433,7 @@ impl<'tcx> TyCtxt<'tcx> {
                 // the `-Z force-unstable-if-unmarked` flag present (we're
                 // compiling a compiler crate), then let this missing feature
                 // annotation slide.
-                if feature == sym::rustc_private && issue == NonZero::<u32>::new(27812) {
+                if feature == sym::rustc_private && issue == NonZero::new(27812) {
                     if self.sess.opts.unstable_opts.force_unstable_if_unmarked {
                         return EvalResult::Allow;
                     }
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index 4ef02a86e30e2..903c83cc54e51 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -500,7 +500,7 @@ impl<'tcx> AllocMap<'tcx> {
         AllocMap {
             alloc_map: Default::default(),
             dedup: Default::default(),
-            next_id: AllocId(NonZero::<u64>::new(1).unwrap()),
+            next_id: AllocId(NonZero::new(1).unwrap()),
         }
     }
     fn reserve(&mut self) -> AllocId {
diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs
index 15e12c456793b..e2767ee298958 100644
--- a/compiler/rustc_middle/src/mir/interpret/pointer.rs
+++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs
@@ -155,7 +155,7 @@ impl CtfeProvenance {
     /// Returns the `AllocId` of this provenance.
     #[inline(always)]
     pub fn alloc_id(self) -> AllocId {
-        AllocId(NonZero::<u64>::new(self.0.get() & !IMMUTABLE_MASK).unwrap())
+        AllocId(NonZero::new(self.0.get() & !IMMUTABLE_MASK).unwrap())
     }
 
     /// Returns whether this provenance is immutable.
diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs
index 15f69d2333c73..5d50510338c61 100644
--- a/compiler/rustc_middle/src/ty/consts/int.rs
+++ b/compiler/rustc_middle/src/ty/consts/int.rs
@@ -161,14 +161,14 @@ impl<D: Decoder> Decodable<D> for ScalarInt {
         let mut data = [0u8; 16];
         let size = d.read_u8();
         data[..size as usize].copy_from_slice(d.read_raw_bytes(size as usize));
-        ScalarInt { data: u128::from_le_bytes(data), size: NonZero::<u8>::new(size).unwrap() }
+        ScalarInt { data: u128::from_le_bytes(data), size: NonZero::new(size).unwrap() }
     }
 }
 
 impl ScalarInt {
-    pub const TRUE: ScalarInt = ScalarInt { data: 1_u128, size: NonZero::<u8>::new(1).unwrap() };
+    pub const TRUE: ScalarInt = ScalarInt { data: 1_u128, size: NonZero::new(1).unwrap() };
 
-    pub const FALSE: ScalarInt = ScalarInt { data: 0_u128, size: NonZero::<u8>::new(1).unwrap() };
+    pub const FALSE: ScalarInt = ScalarInt { data: 0_u128, size: NonZero::new(1).unwrap() };
 
     #[inline]
     pub fn size(self) -> Size {
@@ -196,7 +196,7 @@ impl ScalarInt {
 
     #[inline]
     pub fn null(size: Size) -> Self {
-        Self { data: 0, size: NonZero::<u8>::new(size.bytes() as u8).unwrap() }
+        Self { data: 0, size: NonZero::new(size.bytes() as u8).unwrap() }
     }
 
     #[inline]
@@ -208,7 +208,7 @@ impl ScalarInt {
     pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> {
         let data = i.into();
         if size.truncate(data) == data {
-            Some(Self { data, size: NonZero::<u8>::new(size.bytes() as u8).unwrap() })
+            Some(Self { data, size: NonZero::new(size.bytes() as u8).unwrap() })
         } else {
             None
         }
@@ -220,7 +220,7 @@ impl ScalarInt {
         // `into` performed sign extension, we have to truncate
         let truncated = size.truncate(i as u128);
         if size.sign_extend(truncated) as i128 == i {
-            Some(Self { data: truncated, size: NonZero::<u8>::new(size.bytes() as u8).unwrap() })
+            Some(Self { data: truncated, size: NonZero::new(size.bytes() as u8).unwrap() })
         } else {
             None
         }
@@ -388,7 +388,7 @@ macro_rules! from {
                 fn from(u: $ty) -> Self {
                     Self {
                         data: u128::from(u),
-                        size: NonZero::<u8>::new(std::mem::size_of::<$ty>() as u8).unwrap(),
+                        size: NonZero::new(std::mem::size_of::<$ty>() as u8).unwrap(),
                     }
                 }
             }
@@ -427,10 +427,7 @@ impl TryFrom<ScalarInt> for bool {
 impl From<char> for ScalarInt {
     #[inline]
     fn from(c: char) -> Self {
-        Self {
-            data: c as u128,
-            size: NonZero::<u8>::new(std::mem::size_of::<char>() as u8).unwrap(),
-        }
+        Self { data: c as u128, size: NonZero::new(std::mem::size_of::<char>() as u8).unwrap() }
     }
 }
 
@@ -457,7 +454,7 @@ impl From<Single> for ScalarInt {
     #[inline]
     fn from(f: Single) -> Self {
         // We trust apfloat to give us properly truncated data.
-        Self { data: f.to_bits(), size: NonZero::<u8>::new((Single::BITS / 8) as u8).unwrap() }
+        Self { data: f.to_bits(), size: NonZero::new((Single::BITS / 8) as u8).unwrap() }
     }
 }
 
@@ -473,7 +470,7 @@ impl From<Double> for ScalarInt {
     #[inline]
     fn from(f: Double) -> Self {
         // We trust apfloat to give us properly truncated data.
-        Self { data: f.to_bits(), size: NonZero::<u8>::new((Double::BITS / 8) as u8).unwrap() }
+        Self { data: f.to_bits(), size: NonZero::new((Double::BITS / 8) as u8).unwrap() }
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs
index c931c2064b0c5..813a7a64daf00 100644
--- a/compiler/rustc_middle/src/ty/generic_args.rs
+++ b/compiler/rustc_middle/src/ty/generic_args.rs
@@ -143,9 +143,8 @@ impl<'tcx> From<ty::Term<'tcx>> for GenericArg<'tcx> {
 impl<'tcx> GenericArg<'tcx> {
     #[inline]
     pub fn unpack(self) -> GenericArgKind<'tcx> {
-        let ptr = unsafe {
-            self.ptr.map_addr(|addr| NonZero::<usize>::new_unchecked(addr.get() & !TAG_MASK))
-        };
+        let ptr =
+            unsafe { self.ptr.map_addr(|addr| NonZero::new_unchecked(addr.get() & !TAG_MASK)) };
         // SAFETY: use of `Interned::new_unchecked` here is ok because these
         // pointers were originally created from `Interned` types in `pack()`,
         // and this is just going in the other direction.
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index d9fa99535b1b5..2b34f5daaf63f 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -761,7 +761,7 @@ where
                 };
                 tcx.mk_layout(LayoutS {
                     variants: Variants::Single { index: variant_index },
-                    fields: match NonZero::<usize>::new(fields) {
+                    fields: match NonZero::new(fields) {
                         Some(fields) => FieldsShape::Union(fields),
                         None => FieldsShape::Arbitrary { offsets: IndexVec::new(), memory_index: IndexVec::new() },
                     },
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 3eea0d428eeb9..eea3624898c8c 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -617,9 +617,8 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for Term<'tcx> {
 impl<'tcx> Term<'tcx> {
     #[inline]
     pub fn unpack(self) -> TermKind<'tcx> {
-        let ptr = unsafe {
-            self.ptr.map_addr(|addr| NonZero::<usize>::new_unchecked(addr.get() & !TAG_MASK))
-        };
+        let ptr =
+            unsafe { self.ptr.map_addr(|addr| NonZero::new_unchecked(addr.get() & !TAG_MASK)) };
         // SAFETY: use of `Interned::new_unchecked` here is ok because these
         // pointers were originally created from `Interned` types in `pack()`,
         // and this is just going in the other direction.
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 312a136c897c6..19272b52b32e6 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -645,7 +645,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
             let stability = Stability {
                 level: attr::StabilityLevel::Unstable {
                     reason: UnstableReason::Default,
-                    issue: NonZero::<u32>::new(27812),
+                    issue: NonZero::new(27812),
                     is_soft: false,
                     implied_by: None,
                 },
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index 8cbcce986a1a3..5917d79983d02 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -68,10 +68,8 @@ impl QueryContext for QueryCtxt<'_> {
     #[inline]
     fn next_job_id(self) -> QueryJobId {
         QueryJobId(
-            NonZero::<u64>::new(
-                self.query_system.jobs.fetch_add(1, std::sync::atomic::Ordering::Relaxed),
-            )
-            .unwrap(),
+            NonZero::new(self.query_system.jobs.fetch_add(1, std::sync::atomic::Ordering::Relaxed))
+                .unwrap(),
         )
     }
 
diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs
index a38a4a916fb82..412f7eced433c 100644
--- a/compiler/rustc_serialize/src/serialize.rs
+++ b/compiler/rustc_serialize/src/serialize.rs
@@ -225,7 +225,7 @@ impl<S: Encoder> Encodable<S> for NonZero<u32> {
 
 impl<D: Decoder> Decodable<D> for NonZero<u32> {
     fn decode(d: &mut D) -> Self {
-        NonZero::<u32>::new(d.read_u32()).unwrap()
+        NonZero::new(d.read_u32()).unwrap()
     }
 }
 
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 1a046667bd718..743f476033935 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1007,7 +1007,7 @@ mod parse {
                 }
             },
             None => {
-                *slot = NonZero::<usize>::new(1);
+                *slot = NonZero::new(1);
                 true
             }
         }
diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs
index 3a82fb0df8833..c89a380628020 100644
--- a/library/alloc/src/collections/binary_heap/mod.rs
+++ b/library/alloc/src/collections/binary_heap/mod.rs
@@ -350,7 +350,7 @@ impl<T: Ord, A: Allocator> DerefMut for PeekMut<'_, T, A> {
             // the standard library as "leak amplification".
             unsafe {
                 // SAFETY: len > 1 so len != 0.
-                self.original_len = Some(NonZero::<usize>::new_unchecked(len));
+                self.original_len = Some(NonZero::new_unchecked(len));
                 // SAFETY: len > 1 so all this does for now is leak elements,
                 // which is safe.
                 self.heap.data.set_len(1);
@@ -1576,8 +1576,8 @@ unsafe impl<T, A: Allocator> SourceIter for IntoIter<T, A> {
 #[unstable(issue = "none", feature = "inplace_iteration")]
 #[doc(hidden)]
 unsafe impl<I, A: Allocator> InPlaceIterable for IntoIter<I, A> {
-    const EXPAND_BY: Option<NonZero<usize>> = NonZero::<usize>::new(1);
-    const MERGE_BY: Option<NonZero<usize>> = NonZero::<usize>::new(1);
+    const EXPAND_BY: Option<NonZero<usize>> = NonZero::new(1);
+    const MERGE_BY: Option<NonZero<usize>> = NonZero::new(1);
 }
 
 unsafe impl<I> AsVecIntoIter for IntoIter<I> {
diff --git a/library/alloc/src/collections/vec_deque/into_iter.rs b/library/alloc/src/collections/vec_deque/into_iter.rs
index 02ab3f79b0641..692af7c197a30 100644
--- a/library/alloc/src/collections/vec_deque/into_iter.rs
+++ b/library/alloc/src/collections/vec_deque/into_iter.rs
@@ -63,7 +63,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
             self.inner.drain(..n);
             0
         };
-        NonZero::<usize>::new(rem).map_or(Ok(()), Err)
+        NonZero::new(rem).map_or(Ok(()), Err)
     }
 
     #[inline]
@@ -192,7 +192,7 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
             self.inner.truncate(len - n);
             0
         };
-        NonZero::<usize>::new(rem).map_or(Ok(()), Err)
+        NonZero::new(rem).map_or(Ok(()), Err)
     }
 
     fn try_rfold<B, F, R>(&mut self, mut init: B, mut f: F) -> R
diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs
index 76d1b7b72a12f..63d8fe19ac35c 100644
--- a/library/alloc/src/vec/into_iter.rs
+++ b/library/alloc/src/vec/into_iter.rs
@@ -248,7 +248,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
         unsafe {
             ptr::drop_in_place(to_drop);
         }
-        NonZero::<usize>::new(n - step_size).map_or(Ok(()), Err)
+        NonZero::new(n - step_size).map_or(Ok(()), Err)
     }
 
     #[inline]
@@ -350,7 +350,7 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
         unsafe {
             ptr::drop_in_place(to_drop);
         }
-        NonZero::<usize>::new(n - step_size).map_or(Ok(()), Err)
+        NonZero::new(n - step_size).map_or(Ok(()), Err)
     }
 }
 
@@ -457,8 +457,8 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for IntoIter<T, A> {
 #[unstable(issue = "none", feature = "inplace_iteration")]
 #[doc(hidden)]
 unsafe impl<T, A: Allocator> InPlaceIterable for IntoIter<T, A> {
-    const EXPAND_BY: Option<NonZero<usize>> = NonZero::<usize>::new(1);
-    const MERGE_BY: Option<NonZero<usize>> = NonZero::<usize>::new(1);
+    const EXPAND_BY: Option<NonZero<usize>> = NonZero::new(1);
+    const MERGE_BY: Option<NonZero<usize>> = NonZero::new(1);
 }
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs
index e872ace883c03..04bb20e96b792 100644
--- a/library/alloc/tests/vec.rs
+++ b/library/alloc/tests/vec.rs
@@ -1089,9 +1089,9 @@ fn test_into_iter_advance_by() {
     assert_eq!(i.advance_back_by(1), Ok(()));
     assert_eq!(i.as_slice(), [2, 3, 4]);
 
-    assert_eq!(i.advance_back_by(usize::MAX), Err(NonZero::<usize>::new(usize::MAX - 3).unwrap()));
+    assert_eq!(i.advance_back_by(usize::MAX), Err(NonZero::new(usize::MAX - 3).unwrap()));
 
-    assert_eq!(i.advance_by(usize::MAX), Err(NonZero::<usize>::new(usize::MAX).unwrap()));
+    assert_eq!(i.advance_by(usize::MAX), Err(NonZero::new(usize::MAX).unwrap()));
 
     assert_eq!(i.advance_by(0), Ok(()));
     assert_eq!(i.advance_back_by(0), Ok(()));
@@ -1192,7 +1192,7 @@ fn test_from_iter_specialization_with_iterator_adapters() {
         .map(|(a, b)| a + b)
         .map_while(Option::Some)
         .skip(1)
-        .map(|e| if e != usize::MAX { Ok(NonZero::<usize>::new(e)) } else { Err(()) });
+        .map(|e| if e != usize::MAX { Ok(NonZero::new(e)) } else { Err(()) });
     assert_in_place_trait(&iter);
     let sink = iter.collect::<Result<Vec<_>, _>>().unwrap();
     let sinkptr = sink.as_ptr();
diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs
index 079750abd69fb..eda2f8bb812b5 100644
--- a/library/alloc/tests/vec_deque.rs
+++ b/library/alloc/tests/vec_deque.rs
@@ -445,9 +445,9 @@ fn test_into_iter() {
         assert_eq!(it.next_back(), Some(3));
 
         let mut it = VecDeque::from(vec![1, 2, 3, 4, 5]).into_iter();
-        assert_eq!(it.advance_by(10), Err(NonZero::<usize>::new(5).unwrap()));
+        assert_eq!(it.advance_by(10), Err(NonZero::new(5).unwrap()));
         let mut it = VecDeque::from(vec![1, 2, 3, 4, 5]).into_iter();
-        assert_eq!(it.advance_back_by(10), Err(NonZero::<usize>::new(5).unwrap()));
+        assert_eq!(it.advance_back_by(10), Err(NonZero::new(5).unwrap()));
     }
 }
 
diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs
index e50ae1b0d70af..e3d2cd2a31fbc 100644
--- a/library/core/src/array/iter.rs
+++ b/library/core/src/array/iter.rs
@@ -292,7 +292,7 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> {
             ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(slice));
         }
 
-        NonZero::<usize>::new(remaining).map_or(Ok(()), Err)
+        NonZero::new(remaining).map_or(Ok(()), Err)
     }
 
     #[inline]
@@ -347,7 +347,7 @@ impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
             ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(slice));
         }
 
-        NonZero::<usize>::new(remaining).map_or(Ok(()), Err)
+        NonZero::new(remaining).map_or(Ok(()), Err)
     }
 }
 
diff --git a/library/core/src/iter/adapters/array_chunks.rs b/library/core/src/iter/adapters/array_chunks.rs
index 2e437b41dcebc..8c68ea114dbd2 100644
--- a/library/core/src/iter/adapters/array_chunks.rs
+++ b/library/core/src/iter/adapters/array_chunks.rs
@@ -255,7 +255,7 @@ where
 unsafe impl<I: InPlaceIterable + Iterator, const N: usize> InPlaceIterable for ArrayChunks<I, N> {
     const EXPAND_BY: Option<NonZero<usize>> = I::EXPAND_BY;
     const MERGE_BY: Option<NonZero<usize>> = const {
-        match (I::MERGE_BY, NonZero::<usize>::new(N)) {
+        match (I::MERGE_BY, NonZero::new(N)) {
             (Some(m), Some(n)) => m.checked_mul(n),
             _ => None,
         }
diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs
index 7edfee7bf6c5f..bcaac2f42cf04 100644
--- a/library/core/src/iter/adapters/chain.rs
+++ b/library/core/src/iter/adapters/chain.rs
@@ -110,7 +110,7 @@ where
             // we don't fuse the second iterator
         }
 
-        NonZero::<usize>::new(n).map_or(Ok(()), Err)
+        NonZero::new(n).map_or(Ok(()), Err)
     }
 
     #[inline]
@@ -196,7 +196,7 @@ where
             // we don't fuse the second iterator
         }
 
-        NonZero::<usize>::new(n).map_or(Ok(()), Err)
+        NonZero::new(n).map_or(Ok(()), Err)
     }
 
     #[inline]
diff --git a/library/core/src/iter/adapters/cycle.rs b/library/core/src/iter/adapters/cycle.rs
index 7919c040dba9b..b35ed8442032d 100644
--- a/library/core/src/iter/adapters/cycle.rs
+++ b/library/core/src/iter/adapters/cycle.rs
@@ -97,7 +97,7 @@ where
             };
         }
 
-        NonZero::<usize>::new(n).map_or(Ok(()), Err)
+        NonZero::new(n).map_or(Ok(()), Err)
     }
 
     // No `fold` override, because `fold` doesn't make much sense for `Cycle`,
diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs
index 42396157d863d..99344a88efc3f 100644
--- a/library/core/src/iter/adapters/flatten.rs
+++ b/library/core/src/iter/adapters/flatten.rs
@@ -200,7 +200,7 @@ where
 #[rustc_specialization_trait]
 #[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe trait BoundedSize {
-    const UPPER_BOUND: Option<NonZero<usize>> = NonZero::<usize>::new(1);
+    const UPPER_BOUND: Option<NonZero<usize>> = NonZero::new(1);
 }
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
@@ -217,11 +217,11 @@ unsafe impl<T> BoundedSize for Once<T> {}
 unsafe impl<T> BoundedSize for OnceWith<T> {}
 #[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe impl<T, const N: usize> BoundedSize for [T; N] {
-    const UPPER_BOUND: Option<NonZero<usize>> = NonZero::<usize>::new(N);
+    const UPPER_BOUND: Option<NonZero<usize>> = NonZero::new(N);
 }
 #[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe impl<T, const N: usize> BoundedSize for array::IntoIter<T, N> {
-    const UPPER_BOUND: Option<NonZero<usize>> = NonZero::<usize>::new(N);
+    const UPPER_BOUND: Option<NonZero<usize>> = NonZero::new(N);
 }
 #[unstable(issue = "none", feature = "inplace_iteration")]
 unsafe impl<I: BoundedSize, P> BoundedSize for Filter<I, P> {
@@ -680,9 +680,7 @@ where
         }
 
         match self.iter_try_fold(n, advance) {
-            ControlFlow::Continue(remaining) => {
-                NonZero::<usize>::new(remaining).map_or(Ok(()), Err)
-            }
+            ControlFlow::Continue(remaining) => NonZero::new(remaining).map_or(Ok(()), Err),
             _ => Ok(()),
         }
     }
@@ -772,9 +770,7 @@ where
         }
 
         match self.iter_try_rfold(n, advance) {
-            ControlFlow::Continue(remaining) => {
-                NonZero::<usize>::new(remaining).map_or(Ok(()), Err)
-            }
+            ControlFlow::Continue(remaining) => NonZero::new(remaining).map_or(Ok(()), Err),
             _ => Ok(()),
         }
     }
diff --git a/library/core/src/iter/adapters/skip.rs b/library/core/src/iter/adapters/skip.rs
index 20a3b616f81e5..f51a2c39b8e28 100644
--- a/library/core/src/iter/adapters/skip.rs
+++ b/library/core/src/iter/adapters/skip.rs
@@ -154,7 +154,7 @@ where
             }
         }
 
-        NonZero::<usize>::new(n).map_or(Ok(()), Err)
+        NonZero::new(n).map_or(Ok(()), Err)
     }
 
     #[doc(hidden)]
@@ -238,7 +238,7 @@ where
         let min = crate::cmp::min(self.len(), n);
         let rem = self.iter.advance_back_by(min);
         assert!(rem.is_ok(), "ExactSizeIterator contract violation");
-        NonZero::<usize>::new(n - min).map_or(Ok(()), Err)
+        NonZero::new(n - min).map_or(Ok(()), Err)
     }
 }
 
diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs
index e668e66253607..6870c677b1e07 100644
--- a/library/core/src/iter/adapters/take.rs
+++ b/library/core/src/iter/adapters/take.rs
@@ -125,7 +125,7 @@ where
         };
         let advanced = min - rem;
         self.n -= advanced;
-        NonZero::<usize>::new(n - advanced).map_or(Ok(()), Err)
+        NonZero::new(n - advanced).map_or(Ok(()), Err)
     }
 }
 
@@ -235,7 +235,7 @@ where
         let advanced_by_inner = advance_by - remainder;
         let advanced_by = advanced_by_inner - trim_inner;
         self.n -= advanced_by;
-        NonZero::<usize>::new(n - advanced_by).map_or(Ok(()), Err)
+        NonZero::new(n - advanced_by).map_or(Ok(()), Err)
     }
 }
 
diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs
index 7a4748dcc0d8c..68937161e046a 100644
--- a/library/core/src/iter/range.rs
+++ b/library/core/src/iter/range.rs
@@ -678,7 +678,7 @@ impl<A: Step> RangeIteratorImpl for ops::Range<A> {
         self.start =
             Step::forward_checked(self.start.clone(), taken).expect("`Step` invariants not upheld");
 
-        NonZero::<usize>::new(n - taken).map_or(Ok(()), Err)
+        NonZero::new(n - taken).map_or(Ok(()), Err)
     }
 
     #[inline]
@@ -719,7 +719,7 @@ impl<A: Step> RangeIteratorImpl for ops::Range<A> {
         self.end =
             Step::backward_checked(self.end.clone(), taken).expect("`Step` invariants not upheld");
 
-        NonZero::<usize>::new(n - taken).map_or(Ok(()), Err)
+        NonZero::new(n - taken).map_or(Ok(()), Err)
     }
 }
 
@@ -766,7 +766,7 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> {
         // Otherwise 0 is returned which always safe to use.
         self.start = unsafe { Step::forward_unchecked(self.start, taken) };
 
-        NonZero::<usize>::new(n - taken).map_or(Ok(()), Err)
+        NonZero::new(n - taken).map_or(Ok(()), Err)
     }
 
     #[inline]
@@ -807,7 +807,7 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> {
         // SAFETY: same as the spec_advance_by() implementation
         self.end = unsafe { Step::backward_unchecked(self.end, taken) };
 
-        NonZero::<usize>::new(n - taken).map_or(Ok(()), Err)
+        NonZero::new(n - taken).map_or(Ok(()), Err)
     }
 }
 
diff --git a/library/core/src/iter/sources/repeat_n.rs b/library/core/src/iter/sources/repeat_n.rs
index 77bb8372a446a..8224e4b12a0eb 100644
--- a/library/core/src/iter/sources/repeat_n.rs
+++ b/library/core/src/iter/sources/repeat_n.rs
@@ -145,7 +145,7 @@ impl<A: Clone> Iterator for RepeatN<A> {
 
         if skip > len {
             // SAFETY: we just checked that the difference is positive
-            Err(unsafe { NonZero::<usize>::new_unchecked(skip - len) })
+            Err(unsafe { NonZero::new_unchecked(skip - len) })
         } else {
             self.count = len - skip;
             Ok(())
diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs
index eb830256962e1..48aae73d928a0 100644
--- a/library/core/src/iter/traits/double_ended.rs
+++ b/library/core/src/iter/traits/double_ended.rs
@@ -138,7 +138,7 @@ pub trait DoubleEndedIterator: Iterator {
         for i in 0..n {
             if self.next_back().is_none() {
                 // SAFETY: `i` is always less than `n`.
-                return Err(unsafe { NonZero::<usize>::new_unchecked(n - i) });
+                return Err(unsafe { NonZero::new_unchecked(n - i) });
             }
         }
         Ok(())
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index 6df66e779c425..522e75a5683b2 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -337,7 +337,7 @@ pub trait Iterator {
         for i in 0..n {
             if self.next().is_none() {
                 // SAFETY: `i` is always less than `n`.
-                return Err(unsafe { NonZero::<usize>::new_unchecked(n - i) });
+                return Err(unsafe { NonZero::new_unchecked(n - i) });
             }
         }
         Ok(())
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index ddaffadf4bf7b..6410ff5f828b8 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -336,7 +336,7 @@ macro_rules! nonzero_integer {
                 // SAFETY:
                 // `self` is non-zero, which means it has at least one bit set, which means
                 // that the result of `count_ones` is non-zero.
-                unsafe { NonZero::<u32>::new_unchecked(self.get().count_ones()) }
+                unsafe { NonZero::new_unchecked(self.get().count_ones()) }
             }
 
             nonzero_integer_signedness_dependent_methods! {
diff --git a/library/core/src/ops/index_range.rs b/library/core/src/ops/index_range.rs
index 2ba0bd158f74b..07ea2e930d57a 100644
--- a/library/core/src/ops/index_range.rs
+++ b/library/core/src/ops/index_range.rs
@@ -132,7 +132,7 @@ impl Iterator for IndexRange {
     #[inline]
     fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         let taken = self.take_prefix(n);
-        NonZero::<usize>::new(n - taken.len()).map_or(Ok(()), Err)
+        NonZero::new(n - taken.len()).map_or(Ok(()), Err)
     }
 }
 
@@ -150,7 +150,7 @@ impl DoubleEndedIterator for IndexRange {
     #[inline]
     fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
         let taken = self.take_suffix(n);
-        NonZero::<usize>::new(n - taken.len()).map_or(Ok(()), Err)
+        NonZero::new(n - taken.len()).map_or(Ok(()), Err)
     }
 }
 
diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs
index ad22ee5a0271b..d2422bb80ae58 100644
--- a/library/core/src/ptr/alignment.rs
+++ b/library/core/src/ptr/alignment.rs
@@ -100,7 +100,7 @@ impl Alignment {
     #[inline]
     pub const fn as_nonzero(self) -> NonZeroUsize {
         // SAFETY: All the discriminants are non-zero.
-        unsafe { NonZero::<usize>::new_unchecked(self.as_usize()) }
+        unsafe { NonZero::new_unchecked(self.as_usize()) }
     }
 
     /// Returns the base-2 logarithm of the alignment.
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 2246596a8832c..16e903439936d 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -295,7 +295,7 @@ impl<T: ?Sized> NonNull<T> {
     pub fn addr(self) -> NonZeroUsize {
         // SAFETY: The pointer is guaranteed by the type to be non-null,
         // meaning that the address will be non-zero.
-        unsafe { NonZero::<usize>::new_unchecked(self.pointer.addr()) }
+        unsafe { NonZero::new_unchecked(self.pointer.addr()) }
     }
 
     /// Creates a new pointer with the given address.
diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs
index 53218391dcffd..7910981d0f5ee 100644
--- a/library/core/src/slice/iter/macros.rs
+++ b/library/core/src/slice/iter/macros.rs
@@ -200,7 +200,7 @@ macro_rules! iterator {
                 let advance = cmp::min(len!(self), n);
                 // SAFETY: By construction, `advance` does not exceed `self.len()`.
                 unsafe { self.post_inc_start(advance) };
-                NonZero::<usize>::new(n - advance).map_or(Ok(()), Err)
+                NonZero::new(n - advance).map_or(Ok(()), Err)
             }
 
             #[inline]
@@ -425,7 +425,7 @@ macro_rules! iterator {
                 let advance = cmp::min(len!(self), n);
                 // SAFETY: By construction, `advance` does not exceed `self.len()`.
                 unsafe { self.pre_dec_end(advance) };
-                NonZero::<usize>::new(n - advance).map_or(Ok(()), Err)
+                NonZero::new(n - advance).map_or(Ok(()), Err)
             }
         }
 
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index c70a3d3224d04..1d8ac6aa04394 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -1086,7 +1086,7 @@ impl<T> [T] {
     #[inline]
     #[track_caller]
     pub fn windows(&self, size: usize) -> Windows<'_, T> {
-        let size = NonZero::<usize>::new(size).expect("window size must be non-zero");
+        let size = NonZero::new(size).expect("window size must be non-zero");
         Windows::new(self, size)
     }
 
diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs
index d2180fa83fb1e..00b4405faaefb 100644
--- a/library/core/src/str/iter.rs
+++ b/library/core/src/str/iter.rs
@@ -96,7 +96,7 @@ impl<'a> Iterator for Chars<'a> {
             unsafe { self.iter.advance_by(slurp).unwrap_unchecked() };
         }
 
-        NonZero::<usize>::new(remainder).map_or(Ok(()), Err)
+        NonZero::new(remainder).map_or(Ok(()), Err)
     }
 
     #[inline]
diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs
index 579c140c198c4..e7773d138c255 100644
--- a/library/core/tests/array.rs
+++ b/library/core/tests/array.rs
@@ -548,7 +548,7 @@ fn array_intoiter_advance_by() {
     assert_eq!(counter.get(), 13);
 
     let r = it.advance_by(123456);
-    assert_eq!(r, Err(NonZero::<usize>::new(123456 - 87).unwrap()));
+    assert_eq!(r, Err(NonZero::new(123456 - 87).unwrap()));
     assert_eq!(it.len(), 0);
     assert_eq!(counter.get(), 100);
 
@@ -558,7 +558,7 @@ fn array_intoiter_advance_by() {
     assert_eq!(counter.get(), 100);
 
     let r = it.advance_by(10);
-    assert_eq!(r, Err(NonZero::<usize>::new(10).unwrap()));
+    assert_eq!(r, Err(NonZero::new(10).unwrap()));
     assert_eq!(it.len(), 0);
     assert_eq!(counter.get(), 100);
 }
@@ -601,7 +601,7 @@ fn array_intoiter_advance_back_by() {
     assert_eq!(counter.get(), 13);
 
     let r = it.advance_back_by(123456);
-    assert_eq!(r, Err(NonZero::<usize>::new(123456 - 87).unwrap()));
+    assert_eq!(r, Err(NonZero::new(123456 - 87).unwrap()));
     assert_eq!(it.len(), 0);
     assert_eq!(counter.get(), 100);
 
@@ -611,7 +611,7 @@ fn array_intoiter_advance_back_by() {
     assert_eq!(counter.get(), 100);
 
     let r = it.advance_back_by(10);
-    assert_eq!(r, Err(NonZero::<usize>::new(10).unwrap()));
+    assert_eq!(r, Err(NonZero::new(10).unwrap()));
     assert_eq!(it.len(), 0);
     assert_eq!(counter.get(), 100);
 }
diff --git a/library/core/tests/iter/adapters/chain.rs b/library/core/tests/iter/adapters/chain.rs
index 9e098d5bee442..b2429588de12b 100644
--- a/library/core/tests/iter/adapters/chain.rs
+++ b/library/core/tests/iter/adapters/chain.rs
@@ -34,10 +34,7 @@ fn test_iterator_chain_advance_by() {
             let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys));
             assert_eq!(iter.advance_by(i), Ok(()));
             assert_eq!(iter.next(), Some(&xs[i]));
-            assert_eq!(
-                iter.advance_by(100),
-                Err(NonZero::<usize>::new(100 - (len - i - 1)).unwrap())
-            );
+            assert_eq!(iter.advance_by(100), Err(NonZero::new(100 - (len - i - 1)).unwrap()));
             assert_eq!(iter.advance_by(0), Ok(()));
         }
 
@@ -45,10 +42,7 @@ fn test_iterator_chain_advance_by() {
             let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys));
             assert_eq!(iter.advance_by(xs.len() + i), Ok(()));
             assert_eq!(iter.next(), Some(&ys[i]));
-            assert_eq!(
-                iter.advance_by(100),
-                Err(NonZero::<usize>::new(100 - (ys.len() - i - 1)).unwrap())
-            );
+            assert_eq!(iter.advance_by(100), Err(NonZero::new(100 - (ys.len() - i - 1)).unwrap()));
             assert_eq!(iter.advance_by(0), Ok(()));
         }
 
@@ -58,7 +52,7 @@ fn test_iterator_chain_advance_by() {
         assert_eq!(iter.advance_by(0), Ok(()));
 
         let mut iter = xs.iter().chain(ys);
-        assert_eq!(iter.advance_by(len + 1), Err(NonZero::<usize>::new(1).unwrap()));
+        assert_eq!(iter.advance_by(len + 1), Err(NonZero::new(1).unwrap()));
         assert_eq!(iter.advance_by(0), Ok(()));
     }
 
@@ -77,10 +71,7 @@ fn test_iterator_chain_advance_back_by() {
             let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys));
             assert_eq!(iter.advance_back_by(i), Ok(()));
             assert_eq!(iter.next_back(), Some(&ys[ys.len() - i - 1]));
-            assert_eq!(
-                iter.advance_back_by(100),
-                Err(NonZero::<usize>::new(100 - (len - i - 1)).unwrap())
-            );
+            assert_eq!(iter.advance_back_by(100), Err(NonZero::new(100 - (len - i - 1)).unwrap()));
             assert_eq!(iter.advance_back_by(0), Ok(()));
         }
 
@@ -90,7 +81,7 @@ fn test_iterator_chain_advance_back_by() {
             assert_eq!(iter.next_back(), Some(&xs[xs.len() - i - 1]));
             assert_eq!(
                 iter.advance_back_by(100),
-                Err(NonZero::<usize>::new(100 - (xs.len() - i - 1)).unwrap())
+                Err(NonZero::new(100 - (xs.len() - i - 1)).unwrap())
             );
             assert_eq!(iter.advance_back_by(0), Ok(()));
         }
@@ -101,7 +92,7 @@ fn test_iterator_chain_advance_back_by() {
         assert_eq!(iter.advance_back_by(0), Ok(()));
 
         let mut iter = xs.iter().chain(ys);
-        assert_eq!(iter.advance_back_by(len + 1), Err(NonZero::<usize>::new(1).unwrap()));
+        assert_eq!(iter.advance_back_by(len + 1), Err(NonZero::new(1).unwrap()));
         assert_eq!(iter.advance_back_by(0), Ok(()));
     }
 
diff --git a/library/core/tests/iter/adapters/enumerate.rs b/library/core/tests/iter/adapters/enumerate.rs
index 5aa7532c10cb2..b57d51c077e9b 100644
--- a/library/core/tests/iter/adapters/enumerate.rs
+++ b/library/core/tests/iter/adapters/enumerate.rs
@@ -66,7 +66,7 @@ fn test_iterator_enumerate_advance_by() {
     assert_eq!(it.next(), Some((2, &2)));
     assert_eq!(it.advance_by(2), Ok(()));
     assert_eq!(it.next(), Some((5, &5)));
-    assert_eq!(it.advance_by(1), Err(NonZero::<usize>::new(1).unwrap()));
+    assert_eq!(it.advance_by(1), Err(NonZero::new(1).unwrap()));
     assert_eq!(it.next(), None);
 }
 
diff --git a/library/core/tests/iter/adapters/flatten.rs b/library/core/tests/iter/adapters/flatten.rs
index fb6383b3289bb..2af7e0c388a3b 100644
--- a/library/core/tests/iter/adapters/flatten.rs
+++ b/library/core/tests/iter/adapters/flatten.rs
@@ -72,8 +72,8 @@ fn test_flatten_advance_by() {
     assert_eq!(it.advance_back_by(9), Ok(()));
     assert_eq!(it.next_back(), Some(25));
 
-    assert_eq!(it.advance_by(usize::MAX), Err(NonZero::<usize>::new(usize::MAX - 9).unwrap()));
-    assert_eq!(it.advance_back_by(usize::MAX), Err(NonZero::<usize>::new(usize::MAX).unwrap()));
+    assert_eq!(it.advance_by(usize::MAX), Err(NonZero::new(usize::MAX - 9).unwrap()));
+    assert_eq!(it.advance_back_by(usize::MAX), Err(NonZero::new(usize::MAX).unwrap()));
     assert_eq!(it.advance_by(0), Ok(()));
     assert_eq!(it.advance_back_by(0), Ok(()));
     assert_eq!(it.size_hint(), (0, Some(0)));
diff --git a/library/core/tests/iter/adapters/skip.rs b/library/core/tests/iter/adapters/skip.rs
index 45726d158b608..8d5d06ad9fb3a 100644
--- a/library/core/tests/iter/adapters/skip.rs
+++ b/library/core/tests/iter/adapters/skip.rs
@@ -75,14 +75,14 @@ fn test_iterator_skip_nth() {
 #[test]
 fn test_skip_advance_by() {
     assert_eq!((0..0).skip(10).advance_by(0), Ok(()));
-    assert_eq!((0..0).skip(10).advance_by(1), Err(NonZero::<usize>::new(1).unwrap()));
+    assert_eq!((0..0).skip(10).advance_by(1), Err(NonZero::new(1).unwrap()));
     assert_eq!(
         (0u128..(usize::MAX as u128) + 1).skip(usize::MAX - 10).advance_by(usize::MAX - 5),
-        Err(NonZero::<usize>::new(usize::MAX - 16).unwrap())
+        Err(NonZero::new(usize::MAX - 16).unwrap())
     );
     assert_eq!((0u128..u128::MAX).skip(usize::MAX - 10).advance_by(20), Ok(()));
 
-    assert_eq!((0..2).skip(1).advance_back_by(10), Err(NonZero::<usize>::new(9).unwrap()));
+    assert_eq!((0..2).skip(1).advance_back_by(10), Err(NonZero::new(9).unwrap()));
     assert_eq!((0..0).skip(1).advance_back_by(0), Ok(()));
 }
 
diff --git a/library/core/tests/iter/adapters/take.rs b/library/core/tests/iter/adapters/take.rs
index 6aa1b92954691..39afa2cbfcaf2 100644
--- a/library/core/tests/iter/adapters/take.rs
+++ b/library/core/tests/iter/adapters/take.rs
@@ -79,23 +79,23 @@ fn test_take_advance_by() {
     let mut take = (0..10).take(3);
     assert_eq!(take.advance_by(2), Ok(()));
     assert_eq!(take.next(), Some(2));
-    assert_eq!(take.advance_by(1), Err(NonZero::<usize>::new(1).unwrap()));
+    assert_eq!(take.advance_by(1), Err(NonZero::new(1).unwrap()));
 
     assert_eq!((0..0).take(10).advance_by(0), Ok(()));
-    assert_eq!((0..0).take(10).advance_by(1), Err(NonZero::<usize>::new(1).unwrap()));
-    assert_eq!((0..10).take(4).advance_by(5), Err(NonZero::<usize>::new(1).unwrap()));
+    assert_eq!((0..0).take(10).advance_by(1), Err(NonZero::new(1).unwrap()));
+    assert_eq!((0..10).take(4).advance_by(5), Err(NonZero::new(1).unwrap()));
 
     let mut take = (0..10).take(3);
     assert_eq!(take.advance_back_by(2), Ok(()));
     assert_eq!(take.next(), Some(0));
-    assert_eq!(take.advance_back_by(1), Err(NonZero::<usize>::new(1).unwrap()));
+    assert_eq!(take.advance_back_by(1), Err(NonZero::new(1).unwrap()));
 
-    assert_eq!((0..2).take(1).advance_back_by(10), Err(NonZero::<usize>::new(9).unwrap()));
-    assert_eq!((0..0).take(1).advance_back_by(1), Err(NonZero::<usize>::new(1).unwrap()));
+    assert_eq!((0..2).take(1).advance_back_by(10), Err(NonZero::new(9).unwrap()));
+    assert_eq!((0..0).take(1).advance_back_by(1), Err(NonZero::new(1).unwrap()));
     assert_eq!((0..0).take(1).advance_back_by(0), Ok(()));
     assert_eq!(
         (0..usize::MAX).take(100).advance_back_by(usize::MAX),
-        Err(NonZero::<usize>::new(usize::MAX - 100).unwrap())
+        Err(NonZero::new(usize::MAX - 100).unwrap())
     );
 }
 
diff --git a/library/core/tests/iter/range.rs b/library/core/tests/iter/range.rs
index f840218382dae..9af07119a89a2 100644
--- a/library/core/tests/iter/range.rs
+++ b/library/core/tests/iter/range.rs
@@ -314,7 +314,7 @@ fn test_range_advance_by() {
 
     assert_eq!((r.start, r.end), (1, usize::MAX - 1));
 
-    assert_eq!(Err(NonZero::<usize>::new(2).unwrap()), r.advance_by(usize::MAX));
+    assert_eq!(Err(NonZero::new(2).unwrap()), r.advance_by(usize::MAX));
 
     assert_eq!(Ok(()), r.advance_by(0));
     assert_eq!(Ok(()), r.advance_back_by(0));
diff --git a/library/core/tests/iter/traits/iterator.rs b/library/core/tests/iter/traits/iterator.rs
index 507f15c608832..93ef9c0812b16 100644
--- a/library/core/tests/iter/traits/iterator.rs
+++ b/library/core/tests/iter/traits/iterator.rs
@@ -152,14 +152,11 @@ fn test_iterator_advance_by() {
         let mut iter = v.iter();
         assert_eq!(iter.advance_by(i), Ok(()));
         assert_eq!(iter.next().unwrap(), &v[i]);
-        assert_eq!(
-            iter.advance_by(100),
-            Err(NonZero::<usize>::new(100 - (v.len() - 1 - i)).unwrap())
-        );
+        assert_eq!(iter.advance_by(100), Err(NonZero::new(100 - (v.len() - 1 - i)).unwrap()));
     }
 
     assert_eq!(v.iter().advance_by(v.len()), Ok(()));
-    assert_eq!(v.iter().advance_by(100), Err(NonZero::<usize>::new(100 - v.len()).unwrap()));
+    assert_eq!(v.iter().advance_by(100), Err(NonZero::new(100 - v.len()).unwrap()));
 }
 
 #[test]
@@ -170,14 +167,11 @@ fn test_iterator_advance_back_by() {
         let mut iter = v.iter();
         assert_eq!(iter.advance_back_by(i), Ok(()));
         assert_eq!(iter.next_back().unwrap(), &v[v.len() - 1 - i]);
-        assert_eq!(
-            iter.advance_back_by(100),
-            Err(NonZero::<usize>::new(100 - (v.len() - 1 - i)).unwrap())
-        );
+        assert_eq!(iter.advance_back_by(100), Err(NonZero::new(100 - (v.len() - 1 - i)).unwrap()));
     }
 
     assert_eq!(v.iter().advance_back_by(v.len()), Ok(()));
-    assert_eq!(v.iter().advance_back_by(100), Err(NonZero::<usize>::new(100 - v.len()).unwrap()));
+    assert_eq!(v.iter().advance_back_by(100), Err(NonZero::new(100 - v.len()).unwrap()));
 }
 
 #[test]
@@ -188,17 +182,11 @@ fn test_iterator_rev_advance_back_by() {
         let mut iter = v.iter().rev();
         assert_eq!(iter.advance_back_by(i), Ok(()));
         assert_eq!(iter.next_back().unwrap(), &v[i]);
-        assert_eq!(
-            iter.advance_back_by(100),
-            Err(NonZero::<usize>::new(100 - (v.len() - 1 - i)).unwrap())
-        );
+        assert_eq!(iter.advance_back_by(100), Err(NonZero::new(100 - (v.len() - 1 - i)).unwrap()));
     }
 
     assert_eq!(v.iter().rev().advance_back_by(v.len()), Ok(()));
-    assert_eq!(
-        v.iter().rev().advance_back_by(100),
-        Err(NonZero::<usize>::new(100 - v.len()).unwrap())
-    );
+    assert_eq!(v.iter().rev().advance_back_by(100), Err(NonZero::new(100 - v.len()).unwrap()));
 }
 
 #[test]
@@ -466,14 +454,11 @@ fn test_iterator_rev_advance_by() {
         let mut iter = v.iter().rev();
         assert_eq!(iter.advance_by(i), Ok(()));
         assert_eq!(iter.next().unwrap(), &v[v.len() - 1 - i]);
-        assert_eq!(
-            iter.advance_by(100),
-            Err(NonZero::<usize>::new(100 - (v.len() - 1 - i)).unwrap())
-        );
+        assert_eq!(iter.advance_by(100), Err(NonZero::new(100 - (v.len() - 1 - i)).unwrap()));
     }
 
     assert_eq!(v.iter().rev().advance_by(v.len()), Ok(()));
-    assert_eq!(v.iter().rev().advance_by(100), Err(NonZero::<usize>::new(100 - v.len()).unwrap()));
+    assert_eq!(v.iter().rev().advance_by(100), Err(NonZero::new(100 - v.len()).unwrap()));
 }
 
 #[test]
diff --git a/library/core/tests/nonzero.rs b/library/core/tests/nonzero.rs
index 69dbe5d7dea23..d728513a4e297 100644
--- a/library/core/tests/nonzero.rs
+++ b/library/core/tests/nonzero.rs
@@ -4,7 +4,7 @@ use std::mem::size_of;
 
 #[test]
 fn test_create_nonzero_instance() {
-    let _a = unsafe { NonZero::<u32>::new_unchecked(21) };
+    let _a = unsafe { NonZero::new_unchecked(21) };
 }
 
 #[test]
@@ -18,12 +18,12 @@ fn test_match_on_nonzero_option() {
     let a = Some(unsafe { NonZero::<u32>::new_unchecked(42) });
     match a {
         Some(val) => assert_eq!(val.get(), 42),
-        None => panic!("unexpected None while matching on Some(NonZeroU32(_))"),
+        None => panic!("unexpected None while matching on Some(NonZero(_))"),
     }
 
     match unsafe { Some(NonZero::<u32>::new_unchecked(43)) } {
         Some(val) => assert_eq!(val.get(), 43),
-        None => panic!("unexpected None while matching on Some(NonZeroU32(_))"),
+        None => panic!("unexpected None while matching on Some(NonZero(_))"),
     }
 }
 
@@ -93,7 +93,7 @@ mod atom {
         index: NonZero<u32>, // private
     }
 
-    pub const FOO_ATOM: Atom = Atom { index: unsafe { NonZero::<u32>::new_unchecked(7) } };
+    pub const FOO_ATOM: Atom = Atom { index: unsafe { NonZero::new_unchecked(7) } };
 }
 
 macro_rules! atom {
@@ -113,21 +113,21 @@ fn test_match_nonzero_const_pattern() {
 
 #[test]
 fn test_from_nonzero() {
-    let nz = NonZero::<u32>::new(1).unwrap();
+    let nz = NonZero::new(1).unwrap();
     let num: u32 = nz.into();
     assert_eq!(num, 1u32);
 }
 
 #[test]
 fn test_from_signed_nonzero() {
-    let nz = NonZero::<i32>::new(1).unwrap();
+    let nz = NonZero::new(1).unwrap();
     let num: i32 = nz.into();
     assert_eq!(num, 1i32);
 }
 
 #[test]
 fn test_from_str() {
-    assert_eq!("123".parse::<NonZero<u8>>(), Ok(NonZero::<u8>::new(123).unwrap()));
+    assert_eq!("123".parse::<NonZero<u8>>(), Ok(NonZero::new(123).unwrap()));
     assert_eq!(
         "0".parse::<NonZero<u8>>().err().map(|e| e.kind().clone()),
         Some(IntErrorKind::Zero)
@@ -148,8 +148,8 @@ fn test_from_str() {
 
 #[test]
 fn test_nonzero_bitor() {
-    let nz_alt = NonZero::<u8>::new(0b1010_1010).unwrap();
-    let nz_low = NonZero::<u8>::new(0b0000_1111).unwrap();
+    let nz_alt = NonZero::new(0b1010_1010).unwrap();
+    let nz_low = NonZero::new(0b0000_1111).unwrap();
 
     let both_nz: NonZero<u8> = nz_alt | nz_low;
     assert_eq!(both_nz.get(), 0b1010_1111);
@@ -171,7 +171,7 @@ fn test_nonzero_bitor() {
 fn test_nonzero_bitor_assign() {
     let mut target = NonZero::<u8>::new(0b1010_1010).unwrap();
 
-    target |= NonZero::<u8>::new(0b0000_1111).unwrap();
+    target |= NonZero::new(0b0000_1111).unwrap();
     assert_eq!(target.get(), 0b1010_1111);
 
     target |= 0b0001_0000;
@@ -183,11 +183,11 @@ fn test_nonzero_bitor_assign() {
 
 #[test]
 fn test_nonzero_from_int_on_success() {
-    assert_eq!(NonZero::<u8>::try_from(5), Ok(NonZero::<u8>::new(5).unwrap()));
-    assert_eq!(NonZero::<u32>::try_from(5), Ok(NonZero::<u32>::new(5).unwrap()));
+    assert_eq!(NonZero::<u8>::try_from(5), Ok(NonZero::new(5).unwrap()));
+    assert_eq!(NonZero::<u32>::try_from(5), Ok(NonZero::new(5).unwrap()));
 
-    assert_eq!(NonZero::<i8>::try_from(-5), Ok(NonZero::<i8>::new(-5).unwrap()));
-    assert_eq!(NonZero::<i32>::try_from(-5), Ok(NonZero::<i32>::new(-5).unwrap()));
+    assert_eq!(NonZero::<i8>::try_from(-5), Ok(NonZero::new(-5).unwrap()));
+    assert_eq!(NonZero::<i32>::try_from(-5), Ok(NonZero::new(-5).unwrap()));
 }
 
 #[test]
@@ -204,15 +204,15 @@ fn nonzero_const() {
     // test that the methods of `NonZeroX>` are usable in a const context
     // Note: only tests NonZero<u8>
 
-    const NONZERO_U8: NonZero<u8> = unsafe { NonZero::<u8>::new_unchecked(5) };
+    const NONZERO_U8: NonZero<u8> = unsafe { NonZero::new_unchecked(5) };
 
     const GET: u8 = NONZERO_U8.get();
     assert_eq!(GET, 5);
 
-    const ZERO: Option<NonZero<u8>> = NonZero::<u8>::new(0);
+    const ZERO: Option<NonZero<u8>> = NonZero::new(0);
     assert!(ZERO.is_none());
 
-    const ONE: Option<NonZero<u8>> = NonZero::<u8>::new(1);
+    const ONE: Option<NonZero<u8>> = NonZero::new(1);
     assert!(ONE.is_some());
 
     /* FIXME(#110395)
@@ -323,7 +323,7 @@ fn nonzero_trailing_zeros() {
 
 #[test]
 fn test_nonzero_uint_div() {
-    let nz = NonZero::<u32>::new(1).unwrap();
+    let nz = NonZero::new(1).unwrap();
 
     let x: u32 = 42u32 / nz;
     assert_eq!(x, 42u32);
@@ -331,7 +331,7 @@ fn test_nonzero_uint_div() {
 
 #[test]
 fn test_nonzero_uint_rem() {
-    let nz = NonZero::<u32>::new(10).unwrap();
+    let nz = NonZero::new(10).unwrap();
 
     let x: u32 = 42u32 % nz;
     assert_eq!(x, 2u32);
diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs
index 8a0cf90d799c0..b3f7dfa1fb9c7 100644
--- a/library/core/tests/ptr.rs
+++ b/library/core/tests/ptr.rs
@@ -1050,9 +1050,8 @@ fn nonnull_tagged_pointer_with_provenance() {
         /// memory location.
         pub fn pointer(self) -> NonNull<T> {
             // SAFETY: The `addr` guaranteed to have bits set in the Self::ADDRESS_MASK, so the result will be non-null.
-            self.0.map_addr(|addr| unsafe {
-                NonZero::<usize>::new_unchecked(addr.get() & Self::ADDRESS_MASK)
-            })
+            self.0
+                .map_addr(|addr| unsafe { NonZero::new_unchecked(addr.get() & Self::ADDRESS_MASK) })
         }
 
         /// Consume this tagged pointer and produce the data it carries.
@@ -1073,7 +1072,7 @@ fn nonnull_tagged_pointer_with_provenance() {
             // ADDRESS_MASK) will always be non-zero. This a property of the type and its
             // construction.
             self.0 = self.0.map_addr(|addr| unsafe {
-                NonZero::<usize>::new_unchecked((addr.get() & Self::ADDRESS_MASK) | data)
+                NonZero::new_unchecked((addr.get() & Self::ADDRESS_MASK) | data)
             })
         }
     }
diff --git a/library/core/tests/result.rs b/library/core/tests/result.rs
index 758203408a86c..6c008ab2cb196 100644
--- a/library/core/tests/result.rs
+++ b/library/core/tests/result.rs
@@ -411,7 +411,7 @@ fn result_try_trait_v2_branch() {
 
     assert_eq!(Ok::<i32, i32>(4).branch(), Continue(4));
     assert_eq!(Err::<i32, i32>(4).branch(), Break(Err(4)));
-    let one = NonZero::<u32>::new(1).unwrap();
+    let one = NonZero::new(1).unwrap();
     assert_eq!(Ok::<(), NonZero<u32>>(()).branch(), Continue(()));
     assert_eq!(Err::<(), NonZero<u32>>(one).branch(), Break(Err(one)));
     assert_eq!(Ok::<NonZero<u32>, ()>(one).branch(), Continue(one));
diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
index bb2c17a479e22..c5743eda3e802 100644
--- a/library/core/tests/slice.rs
+++ b/library/core/tests/slice.rs
@@ -147,7 +147,7 @@ fn test_iterator_advance_by() {
     }
 
     let mut iter = v.iter();
-    assert_eq!(iter.advance_by(v.len() + 1), Err(NonZero::<usize>::new(1).unwrap()));
+    assert_eq!(iter.advance_by(v.len() + 1), Err(NonZero::new(1).unwrap()));
     assert_eq!(iter.as_slice(), &[]);
 
     let mut iter = v.iter();
@@ -169,7 +169,7 @@ fn test_iterator_advance_back_by() {
     }
 
     let mut iter = v.iter();
-    assert_eq!(iter.advance_back_by(v.len() + 1), Err(NonZero::<usize>::new(1).unwrap()));
+    assert_eq!(iter.advance_back_by(v.len() + 1), Err(NonZero::new(1).unwrap()));
     assert_eq!(iter.as_slice(), &[]);
 
     let mut iter = v.iter();
diff --git a/library/proc_macro/src/bridge/symbol.rs b/library/proc_macro/src/bridge/symbol.rs
index ae3c0fe018fb1..712f6b4545828 100644
--- a/library/proc_macro/src/bridge/symbol.rs
+++ b/library/proc_macro/src/bridge/symbol.rs
@@ -137,7 +137,7 @@ thread_local! {
         names: fxhash::FxHashMap::default(),
         strings: Vec::new(),
         // Start with a base of 1 to make sure that `NonZeroU32` works.
-        sym_base: NonZero::<u32>::new(1).unwrap(),
+        sym_base: NonZero::new(1).unwrap(),
     });
 }
 
diff --git a/library/std/src/sys/pal/hermit/thread.rs b/library/std/src/sys/pal/hermit/thread.rs
index 789de7f41ff9a..fee80c02d4a6f 100644
--- a/library/std/src/sys/pal/hermit/thread.rs
+++ b/library/std/src/sys/pal/hermit/thread.rs
@@ -98,7 +98,7 @@ impl Thread {
 }
 
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
-    unsafe { Ok(NonZero::<usize>::new_unchecked(abi::get_processor_count())) }
+    unsafe { Ok(NonZero::new_unchecked(abi::get_processor_count())) }
 }
 
 pub mod guard {
diff --git a/library/std/src/sys/pal/sgx/abi/tls/mod.rs b/library/std/src/sys/pal/sgx/abi/tls/mod.rs
index 5ee1621420e3a..6762a43b483a4 100644
--- a/library/std/src/sys/pal/sgx/abi/tls/mod.rs
+++ b/library/std/src/sys/pal/sgx/abi/tls/mod.rs
@@ -38,7 +38,7 @@ impl Key {
     }
 
     fn from_index(index: usize) -> Self {
-        Key(NonZero::<usize>::new(index + 1).unwrap())
+        Key(NonZero::new(index + 1).unwrap())
     }
 
     pub fn as_usize(self) -> usize {
@@ -46,7 +46,7 @@ impl Key {
     }
 
     pub fn from_usize(index: usize) -> Self {
-        Key(NonZero::<usize>::new(index).unwrap())
+        Key(NonZero::new(index).unwrap())
     }
 }
 
diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/raw.rs b/library/std/src/sys/pal/sgx/abi/usercalls/raw.rs
index 4f52bb474b168..943b771498f8f 100644
--- a/library/std/src/sys/pal/sgx/abi/usercalls/raw.rs
+++ b/library/std/src/sys/pal/sgx/abi/usercalls/raw.rs
@@ -195,7 +195,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
         #[inline(always)]
         pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3, $n4: $t4) -> $r {
             ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
-                    rtunwrap!(Some, NonZero::<u64>::new(Usercalls::$f as Register)),
+                    rtunwrap!(Some, NonZero::new(Usercalls::$f as Register)),
                     RegisterArgument::into_register($n1),
                     RegisterArgument::into_register($n2),
                     RegisterArgument::into_register($n3),
@@ -211,7 +211,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
         #[inline(always)]
         pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3) -> $r {
             ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
-                    rtunwrap!(Some, NonZero::<u64>::new(Usercalls::$f as Register)),
+                    rtunwrap!(Some, NonZero::new(Usercalls::$f as Register)),
                     RegisterArgument::into_register($n1),
                     RegisterArgument::into_register($n2),
                     RegisterArgument::into_register($n3),
@@ -227,7 +227,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
         #[inline(always)]
         pub unsafe fn $f($n1: $t1, $n2: $t2) -> $r {
             ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
-                    rtunwrap!(Some, NonZero::<u64>::new(Usercalls::$f as Register)),
+                    rtunwrap!(Some, NonZero::new(Usercalls::$f as Register)),
                     RegisterArgument::into_register($n1),
                     RegisterArgument::into_register($n2),
                     0,0,
@@ -242,7 +242,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
         #[inline(always)]
         pub unsafe fn $f($n1: $t1) -> $r {
             ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
-                    rtunwrap!(Some, NonZero::<u64>::new(Usercalls::$f as Register)),
+                    rtunwrap!(Some, NonZero::new(Usercalls::$f as Register)),
                     RegisterArgument::into_register($n1),
                     0,0,0,
                     return_type_is_abort!($r)
@@ -256,7 +256,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
         #[inline(always)]
         pub unsafe fn $f() -> $r {
             ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
-                    rtunwrap!(Some, NonZero::<u64>::new(Usercalls::$f as Register)),
+                    rtunwrap!(Some, NonZero::new(Usercalls::$f as Register)),
                     0,0,0,0,
                     return_type_is_abort!($r)
             ) })
diff --git a/library/std/src/sys/pal/sgx/rwlock.rs b/library/std/src/sys/pal/sgx/rwlock.rs
index 87bebac37dac9..ebae1cff0ee17 100644
--- a/library/std/src/sys/pal/sgx/rwlock.rs
+++ b/library/std/src/sys/pal/sgx/rwlock.rs
@@ -53,8 +53,7 @@ impl RwLock {
         // Another thread has passed the lock to us
         } else {
             // No waiting writers, acquire the read lock
-            *rguard.lock_var_mut() =
-                NonZero::<usize>::new(rguard.lock_var().map_or(0, |n| n.get()) + 1);
+            *rguard.lock_var_mut() = NonZero::new(rguard.lock_var().map_or(0, |n| n.get()) + 1);
         }
     }
 
@@ -68,8 +67,7 @@ impl RwLock {
             false
         } else {
             // No waiting writers, acquire the read lock
-            *rguard.lock_var_mut() =
-                NonZero::<usize>::new(rguard.lock_var().map_or(0, |n| n.get()) + 1);
+            *rguard.lock_var_mut() = NonZero::new(rguard.lock_var().map_or(0, |n| n.get()) + 1);
             true
         }
     }
@@ -111,7 +109,7 @@ impl RwLock {
         mut rguard: SpinMutexGuard<'_, WaitVariable<Option<NonZero<usize>>>>,
         wguard: SpinMutexGuard<'_, WaitVariable<bool>>,
     ) {
-        *rguard.lock_var_mut() = NonZero::<usize>::new(rguard.lock_var().unwrap().get() - 1);
+        *rguard.lock_var_mut() = NonZero::new(rguard.lock_var().unwrap().get() - 1);
         if rguard.lock_var().is_some() {
             // There are other active readers
         } else {
diff --git a/library/std/src/sys/pal/sgx/waitqueue/mod.rs b/library/std/src/sys/pal/sgx/waitqueue/mod.rs
index 92ffec8d0b7d2..2d952b7ebbca3 100644
--- a/library/std/src/sys/pal/sgx/waitqueue/mod.rs
+++ b/library/std/src/sys/pal/sgx/waitqueue/mod.rs
@@ -252,7 +252,7 @@ impl WaitQueue {
                 entry_guard.wake = true;
             }
 
-            if let Some(count) = NonZero::<usize>::new(count) {
+            if let Some(count) = NonZero::new(count) {
                 Ok(WaitGuard { mutex_guard: Some(guard), notified_tcs: NotifiedTcs::All { count } })
             } else {
                 Err(guard)
diff --git a/library/std/src/sys/pal/uefi/thread.rs b/library/std/src/sys/pal/uefi/thread.rs
index f6f5b20a42135..3d8fa27251f01 100644
--- a/library/std/src/sys/pal/uefi/thread.rs
+++ b/library/std/src/sys/pal/uefi/thread.rs
@@ -46,7 +46,7 @@ impl Thread {
 
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     // UEFI is single threaded
-    Ok(NonZero::<usize>::new(1).unwrap())
+    Ok(NonZero::new(1).unwrap())
 }
 
 pub mod guard {
diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs
index dd3c370667a1e..767f269dbea3d 100644
--- a/library/std/src/sys/pal/unix/thread.rs
+++ b/library/std/src/sys/pal/unix/thread.rs
@@ -338,7 +338,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
                         // some old MIPS kernels were buggy and zero-initialized the mask if
                         // none was explicitly set.
                         // In that case we use the sysconf fallback.
-                        if let Some(count) = NonZero::<usize>::new(count) {
+                        if let Some(count) = NonZero::new(count) {
                             return Ok(count)
                         }
                     }
@@ -351,7 +351,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
                     let count = cpus as usize;
                     // Cover the unusual situation where we were able to get the quota but not the affinity mask
                     let count = count.min(quota);
-                    Ok(unsafe { NonZero::<usize>::new_unchecked(count) })
+                    Ok(unsafe { NonZero::new_unchecked(count) })
                 }
             }
         } else if #[cfg(any(
@@ -375,7 +375,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
                     ) == 0 {
                         let count = libc::CPU_COUNT(&set) as usize;
                         if count > 0 {
-                            return Ok(NonZero::<usize>::new_unchecked(count));
+                            return Ok(NonZero::new_unchecked(count));
                         }
                     }
                 }
@@ -397,7 +397,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
                             }
                         }
                         libc::_cpuset_destroy(set);
-                        if let Some(count) = NonZero::<usize>::new(count) {
+                        if let Some(count) = NonZero::new(count) {
                             return Ok(count);
                         }
                     }
@@ -433,7 +433,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
                 }
             }
 
-            Ok(unsafe { NonZero::<usize>::new_unchecked(cpus as usize) })
+            Ok(unsafe { NonZero::new_unchecked(cpus as usize) })
         } else if #[cfg(target_os = "nto")] {
             unsafe {
                 use libc::_syspage_ptr;
@@ -441,7 +441,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
                     Err(io::const_io_error!(io::ErrorKind::NotFound, "No syspage available"))
                 } else {
                     let cpus = (*_syspage_ptr).num_cpu;
-                    NonZero::<usize>::new(cpus as usize)
+                    NonZero::new(cpus as usize)
                         .ok_or(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"))
                 }
             }
@@ -456,7 +456,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
                     return Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"));
                 }
 
-                Ok(NonZero::<usize>::new_unchecked(sinfo.cpu_count as usize))
+                Ok(NonZero::new_unchecked(sinfo.cpu_count as usize))
             }
         } else {
             // FIXME: implement on vxWorks, Redox, l4re
diff --git a/library/std/src/sys/pal/windows/args.rs b/library/std/src/sys/pal/windows/args.rs
index c3a4d4706996d..2ecfe088d107b 100644
--- a/library/std/src/sys/pal/windows/args.rs
+++ b/library/std/src/sys/pal/windows/args.rs
@@ -21,12 +21,12 @@ use crate::vec;
 
 use crate::iter;
 
-/// This is the const equivalent to `NonZero::<u16>::new(n).unwrap()`
+/// This is the const equivalent to `NonZero::new(n).unwrap()`
 ///
 /// FIXME: This can be removed once `Option::unwrap` is stably const.
 /// See the `const_option` feature (#67441).
 const fn non_zero_u16(n: u16) -> NonZero<u16> {
-    match NonZero::<u16>::new(n) {
+    match NonZero::new(n) {
         Some(n) => n,
         None => panic!("called `unwrap` on a `None` value"),
     }
diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/pal/windows/thread.rs
index 4f189944fb2b8..0f709e2ec7ba7 100644
--- a/library/std/src/sys/pal/windows/thread.rs
+++ b/library/std/src/sys/pal/windows/thread.rs
@@ -121,7 +121,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
             io::ErrorKind::NotFound,
             "The number of hardware threads is not known for the target platform",
         )),
-        cpus => Ok(unsafe { NonZero::<usize>::new_unchecked(cpus) }),
+        cpus => Ok(unsafe { NonZero::new_unchecked(cpus) }),
     }
 }
 
diff --git a/library/std/src/sys/pal/xous/thread.rs b/library/std/src/sys/pal/xous/thread.rs
index 2cc1585650184..21f5954d6e2d2 100644
--- a/library/std/src/sys/pal/xous/thread.rs
+++ b/library/std/src/sys/pal/xous/thread.rs
@@ -134,7 +134,7 @@ impl Thread {
 
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     // We're unicore right now.
-    Ok(unsafe { NonZero::<usize>::new_unchecked(1) })
+    Ok(unsafe { NonZero::new_unchecked(1) })
 }
 
 pub mod guard {
diff --git a/library/std/src/sys_common/wstr.rs b/library/std/src/sys_common/wstr.rs
index 601ef3dd1505c..8eae160648502 100644
--- a/library/std/src/sys_common/wstr.rs
+++ b/library/std/src/sys_common/wstr.rs
@@ -26,7 +26,7 @@ impl WStrUnits<'_> {
     pub fn peek(&self) -> Option<NonZero<u16>> {
         // SAFETY: It's always safe to read the current item because we don't
         // ever move out of the array's bounds.
-        unsafe { NonZero::<u16>::new(*self.lpwstr.as_ptr()) }
+        unsafe { NonZero::new(*self.lpwstr.as_ptr()) }
     }
 
     /// Advance the iterator while `predicate` returns true.
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 0da3da23568ec..4f0f010984ab9 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -1188,7 +1188,7 @@ impl ThreadId {
                     };
 
                     match COUNTER.compare_exchange_weak(last, id, Relaxed, Relaxed) {
-                        Ok(_) => return ThreadId(NonZero::<u64>::new(id).unwrap()),
+                        Ok(_) => return ThreadId(NonZero::new(id).unwrap()),
                         Err(id) => last = id,
                     }
                 }
@@ -1207,7 +1207,7 @@ impl ThreadId {
 
                 *counter = id;
                 drop(counter);
-                ThreadId(NonZero::<u64>::new(id).unwrap())
+                ThreadId(NonZero::new(id).unwrap())
             }
         }
     }
diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs
index 4424595ea1cdf..45240edea455d 100644
--- a/src/tools/miri/src/borrow_tracker/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/mod.rs
@@ -21,7 +21,7 @@ pub struct BorTag(NonZero<u64>);
 
 impl BorTag {
     pub fn new(i: u64) -> Option<Self> {
-        NonZero::<u64>::new(i).map(BorTag)
+        NonZero::new(i).map(BorTag)
     }
 
     pub fn get(&self) -> u64 {
@@ -184,7 +184,7 @@ impl GlobalStateInner {
             borrow_tracker_method,
             next_ptr_tag: BorTag::one(),
             base_ptr_tags: FxHashMap::default(),
-            next_call_id: NonZero::<u64>::new(1).unwrap(),
+            next_call_id: NonZero::new(1).unwrap(),
             protected_tags: FxHashMap::default(),
             tracked_pointer_tags,
             tracked_call_ids,
@@ -206,7 +206,7 @@ impl GlobalStateInner {
         if self.tracked_call_ids.contains(&call_id) {
             machine.emit_diagnostic(NonHaltingDiagnostic::CreatedCallId(call_id));
         }
-        self.next_call_id = NonZero::<u64>::new(call_id.get() + 1).unwrap();
+        self.next_call_id = NonZero::new(call_id.get() + 1).unwrap();
         FrameState { call_id, protected_tags: SmallVec::new() }
     }
 
diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs
index c3130c8a8f0b8..b948ecb834539 100644
--- a/src/tools/miri/src/concurrency/sync.rs
+++ b/src/tools/miri/src/concurrency/sync.rs
@@ -30,7 +30,7 @@ macro_rules! declare_id {
         impl SyncId for $name {
             // Panics if `id == 0`.
             fn from_u32(id: u32) -> Self {
-                Self(std::num::NonZero::<u32>::new(id).unwrap())
+                Self(std::num::NonZero::new(id).unwrap())
             }
             fn to_u32(&self) -> u32 {
                 self.0.get()
@@ -43,7 +43,7 @@ macro_rules! declare_id {
                 // therefore, need to shift by one when converting from an index
                 // into a vector.
                 let shifted_idx = u32::try_from(idx).unwrap().checked_add(1).unwrap();
-                $name(std::num::NonZero::<u32>::new(shifted_idx).unwrap())
+                $name(std::num::NonZero::new(shifted_idx).unwrap())
             }
             fn index(self) -> usize {
                 // See the comment in `Self::new`.
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index f0e6e0374d287..bf90d1468bb0e 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -477,7 +477,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 let [id, show_unnamed] = this.check_shim(abi, Abi::Rust, link_name, args)?;
                 let id = this.read_scalar(id)?.to_u64()?;
                 let show_unnamed = this.read_scalar(show_unnamed)?.to_bool()?;
-                if let Some(id) = std::num::NonZero::<u64>::new(id) {
+                if let Some(id) = std::num::NonZero::new(id) {
                     this.print_borrow_state(AllocId(id), show_unnamed)?;
                 }
             }

From b80fc5d4e8ce95a00b14a50e8ee0561b64736480 Mon Sep 17 00:00:00 2001
From: David Wood <david.wood@huawei.com>
Date: Wed, 14 Feb 2024 14:17:27 +0000
Subject: [PATCH 42/58] errors: only eagerly translate subdiagnostics

Subdiagnostics don't need to be lazily translated, they can always be
eagerly translated. Eager translation is slightly more complex as we need
to have a `DiagCtxt` available to perform the translation, which involves
slightly more threading of that context.

This slight increase in complexity should enable later simplifications -
like passing `DiagCtxt` into `AddToDiagnostic` and moving Fluent messages
into the diagnostic structs rather than having them in separate files
(working on that was what led to this change).

Signed-off-by: David Wood <david@davidtw.co>
---
 .../src/diagnostics/conflict_errors.rs        |  89 +++++---
 .../rustc_borrowck/src/diagnostics/mod.rs     | 202 +++++++++++-------
 .../src/diagnostics/move_errors.rs            |  47 ++--
 .../src/diagnostics/mutability_errors.rs      |   2 +-
 .../src/diagnostics/region_errors.rs          |  10 +-
 compiler/rustc_codegen_gcc/src/errors.rs      |   2 +-
 compiler/rustc_codegen_llvm/src/errors.rs     |   2 +-
 .../src/transform/check_consts/ops.rs         |   2 +-
 compiler/rustc_error_messages/src/lib.rs      |  36 ++--
 compiler/rustc_errors/src/diagnostic.rs       |  11 +-
 .../rustc_errors/src/diagnostic_builder.rs    |   3 -
 compiler/rustc_errors/src/emitter.rs          |  23 ++
 compiler/rustc_errors/src/lib.rs              |  71 ++++--
 compiler/rustc_errors/src/translation.rs      |   4 +-
 compiler/rustc_expand/src/mbe/diagnostics.rs  |  15 +-
 compiler/rustc_expand/src/mbe/macro_rules.rs  |   2 +-
 compiler/rustc_hir_typeck/src/_match.rs       |   2 +-
 compiler/rustc_hir_typeck/src/cast.rs         |  24 ++-
 compiler/rustc_hir_typeck/src/expr.rs         |   7 +-
 .../rustc_hir_typeck/src/fn_ctxt/checks.rs    |   2 +-
 .../src/fn_ctxt/suggestions.rs                |  96 +++++----
 .../rustc_hir_typeck/src/method/suggest.rs    |  27 +--
 compiler/rustc_hir_typeck/src/op.rs           |   2 +-
 .../src/infer/error_reporting/mod.rs          |   4 +-
 .../src/infer/error_reporting/note.rs         |   2 +-
 .../src/infer/error_reporting/suggest.rs      |  33 +--
 compiler/rustc_lint/src/lints.rs              |   2 +-
 .../src/diagnostics/diagnostic_builder.rs     |  39 +---
 .../src/thir/pattern/check_match.rs           |   2 +-
 compiler/rustc_mir_transform/src/errors.rs    |   2 +-
 .../rustc_parse/src/parser/diagnostics.rs     |   2 +-
 compiler/rustc_parse/src/parser/expr.rs       |   2 +-
 compiler/rustc_parse/src/parser/item.rs       |  13 +-
 compiler/rustc_parse/src/parser/pat.rs        |   2 +-
 compiler/rustc_resolve/src/diagnostics.rs     |  24 ++-
 compiler/rustc_resolve/src/imports.rs         |   4 +-
 .../rustc_resolve/src/late/diagnostics.rs     |  24 ++-
 compiler/rustc_session/src/parse.rs           |  10 +-
 .../src/traits/error_reporting/suggestions.rs |   7 +-
 src/tools/miri/src/diagnostics.rs             |   2 +-
 src/tools/rustfmt/src/parse/session.rs        |  11 +
 .../session-diagnostic/diagnostic-derive.rs   |  10 +-
 .../diagnostic-derive.stderr                  |  44 ++--
 43 files changed, 532 insertions(+), 388 deletions(-)

diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 18cf6f64fbc03..2b0c0e939f59b 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -229,7 +229,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 seen_spans.insert(move_span);
             }
 
-            use_spans.var_path_only_subdiag(&mut err, desired_action);
+            use_spans.var_path_only_subdiag(self.dcx(), &mut err, desired_action);
 
             if !is_loop_move {
                 err.span_label(
@@ -291,18 +291,24 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             if needs_note {
                 if let Some(local) = place.as_local() {
                     let span = self.body.local_decls[local].source_info.span;
-                    err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
-                        is_partial_move,
-                        ty,
-                        place: &note_msg,
-                        span,
-                    });
+                    err.subdiagnostic(
+                        self.dcx(),
+                        crate::session_diagnostics::TypeNoCopy::Label {
+                            is_partial_move,
+                            ty,
+                            place: &note_msg,
+                            span,
+                        },
+                    );
                 } else {
-                    err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Note {
-                        is_partial_move,
-                        ty,
-                        place: &note_msg,
-                    });
+                    err.subdiagnostic(
+                        self.dcx(),
+                        crate::session_diagnostics::TypeNoCopy::Note {
+                            is_partial_move,
+                            ty,
+                            place: &note_msg,
+                        },
+                    );
                 };
             }
 
@@ -557,7 +563,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             E0381,
             "{used} binding {desc}{isnt_initialized}"
         );
-        use_spans.var_path_only_subdiag(&mut err, desired_action);
+        use_spans.var_path_only_subdiag(self.dcx(), &mut err, desired_action);
 
         if let InitializationRequiringAction::PartialAssignment
         | InitializationRequiringAction::Assignment = desired_action
@@ -848,9 +854,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             &value_msg,
         );
 
-        borrow_spans.var_path_only_subdiag(&mut err, crate::InitializationRequiringAction::Borrow);
+        borrow_spans.var_path_only_subdiag(
+            self.dcx(),
+            &mut err,
+            crate::InitializationRequiringAction::Borrow,
+        );
 
-        move_spans.var_subdiag(None, &mut err, None, |kind, var_span| {
+        move_spans.var_subdiag(self.dcx(), &mut err, None, |kind, var_span| {
             use crate::session_diagnostics::CaptureVarCause::*;
             match kind {
                 hir::ClosureKind::Coroutine(_) => MoveUseInCoroutine { var_span },
@@ -895,7 +905,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             borrow_span,
             &self.describe_any_place(borrow.borrowed_place.as_ref()),
         );
-        borrow_spans.var_subdiag(None, &mut err, Some(borrow.kind), |kind, var_span| {
+        borrow_spans.var_subdiag(self.dcx(), &mut err, Some(borrow.kind), |kind, var_span| {
             use crate::session_diagnostics::CaptureVarCause::*;
             let place = &borrow.borrowed_place;
             let desc_place = self.describe_any_place(place.as_ref());
@@ -1043,7 +1053,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         "mutably borrow",
                     );
                     borrow_spans.var_subdiag(
-                        None,
+                        self.dcx(),
                         &mut err,
                         Some(BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }),
                         |kind, var_span| {
@@ -1131,22 +1141,31 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         };
 
         if issued_spans == borrow_spans {
-            borrow_spans.var_subdiag(None, &mut err, Some(gen_borrow_kind), |kind, var_span| {
-                use crate::session_diagnostics::CaptureVarCause::*;
-                match kind {
-                    hir::ClosureKind::Coroutine(_) => BorrowUsePlaceCoroutine {
-                        place: desc_place,
-                        var_span,
-                        is_single_var: false,
-                    },
-                    hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
-                        BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: false }
+            borrow_spans.var_subdiag(
+                self.dcx(),
+                &mut err,
+                Some(gen_borrow_kind),
+                |kind, var_span| {
+                    use crate::session_diagnostics::CaptureVarCause::*;
+                    match kind {
+                        hir::ClosureKind::Coroutine(_) => BorrowUsePlaceCoroutine {
+                            place: desc_place,
+                            var_span,
+                            is_single_var: false,
+                        },
+                        hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
+                            BorrowUsePlaceClosure {
+                                place: desc_place,
+                                var_span,
+                                is_single_var: false,
+                            }
+                        }
                     }
-                }
-            });
+                },
+            );
         } else {
             issued_spans.var_subdiag(
-                Some(self.dcx()),
+                self.dcx(),
                 &mut err,
                 Some(issued_borrow.kind),
                 |kind, var_span| {
@@ -1165,7 +1184,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             );
 
             borrow_spans.var_subdiag(
-                Some(self.dcx()),
+                self.dcx(),
                 &mut err,
                 Some(gen_borrow_kind),
                 |kind, var_span| {
@@ -2217,7 +2236,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             err.span_label(borrow_span, "borrowed value does not live long enough");
             err.span_label(drop_span, format!("`{name}` dropped here while still borrowed"));
 
-            borrow_spans.args_subdiag(&mut err, |args_span| {
+            borrow_spans.args_subdiag(self.dcx(), &mut err, |args_span| {
                 crate::session_diagnostics::CaptureArgLabel::Capture {
                     is_within: borrow_spans.for_coroutine(),
                     args_span,
@@ -2476,7 +2495,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             None,
         );
 
-        borrow_spans.args_subdiag(&mut err, |args_span| {
+        borrow_spans.args_subdiag(self.dcx(), &mut err, |args_span| {
             crate::session_diagnostics::CaptureArgLabel::Capture {
                 is_within: borrow_spans.for_coroutine(),
                 args_span,
@@ -2935,7 +2954,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     "assign",
                 );
 
-                loan_spans.var_subdiag(None, &mut err, Some(loan.kind), |kind, var_span| {
+                loan_spans.var_subdiag(self.dcx(), &mut err, Some(loan.kind), |kind, var_span| {
                     use crate::session_diagnostics::CaptureVarCause::*;
                     match kind {
                         hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span },
@@ -2953,7 +2972,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
         let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place);
 
-        loan_spans.var_subdiag(None, &mut err, Some(loan.kind), |kind, var_span| {
+        loan_spans.var_subdiag(self.dcx(), &mut err, Some(loan.kind), |kind, var_span| {
             use crate::session_diagnostics::CaptureVarCause::*;
             match kind {
                 hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span },
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 59f3aa706edea..4ca854c857de9 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -124,7 +124,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() {
                         let did = did.expect_local();
                         if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
-                            diag.eager_subdiagnostic(
+                            diag.subdiagnostic(
                                 self.dcx(),
                                 OnClosureNote::InvokedTwice {
                                     place_name: &ty::place_to_string_for_capture(
@@ -146,7 +146,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() {
                 let did = did.expect_local();
                 if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
-                    diag.eager_subdiagnostic(
+                    diag.subdiagnostic(
                         self.dcx(),
                         OnClosureNote::MovedTwice {
                             place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place),
@@ -587,11 +587,12 @@ impl UseSpans<'_> {
     /// Add a span label to the arguments of the closure, if it exists.
     pub(super) fn args_subdiag(
         self,
+        dcx: &rustc_errors::DiagCtxt,
         err: &mut Diagnostic,
         f: impl FnOnce(Span) -> CaptureArgLabel,
     ) {
         if let UseSpans::ClosureUse { args_span, .. } = self {
-            err.subdiagnostic(f(args_span));
+            err.subdiagnostic(dcx, f(args_span));
         }
     }
 
@@ -599,6 +600,7 @@ impl UseSpans<'_> {
     /// only adds label to the `path_span`
     pub(super) fn var_path_only_subdiag(
         self,
+        dcx: &rustc_errors::DiagCtxt,
         err: &mut Diagnostic,
         action: crate::InitializationRequiringAction,
     ) {
@@ -607,20 +609,26 @@ impl UseSpans<'_> {
         if let UseSpans::ClosureUse { closure_kind, path_span, .. } = self {
             match closure_kind {
                 hir::ClosureKind::Coroutine(_) => {
-                    err.subdiagnostic(match action {
-                        Borrow => BorrowInCoroutine { path_span },
-                        MatchOn | Use => UseInCoroutine { path_span },
-                        Assignment => AssignInCoroutine { path_span },
-                        PartialAssignment => AssignPartInCoroutine { path_span },
-                    });
+                    err.subdiagnostic(
+                        dcx,
+                        match action {
+                            Borrow => BorrowInCoroutine { path_span },
+                            MatchOn | Use => UseInCoroutine { path_span },
+                            Assignment => AssignInCoroutine { path_span },
+                            PartialAssignment => AssignPartInCoroutine { path_span },
+                        },
+                    );
                 }
                 hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
-                    err.subdiagnostic(match action {
-                        Borrow => BorrowInClosure { path_span },
-                        MatchOn | Use => UseInClosure { path_span },
-                        Assignment => AssignInClosure { path_span },
-                        PartialAssignment => AssignPartInClosure { path_span },
-                    });
+                    err.subdiagnostic(
+                        dcx,
+                        match action {
+                            Borrow => BorrowInClosure { path_span },
+                            MatchOn | Use => UseInClosure { path_span },
+                            Assignment => AssignInClosure { path_span },
+                            PartialAssignment => AssignPartInClosure { path_span },
+                        },
+                    );
                 }
             }
         }
@@ -629,32 +637,32 @@ impl UseSpans<'_> {
     /// Add a subdiagnostic to the use of the captured variable, if it exists.
     pub(super) fn var_subdiag(
         self,
-        dcx: Option<&rustc_errors::DiagCtxt>,
+        dcx: &rustc_errors::DiagCtxt,
         err: &mut Diagnostic,
         kind: Option<rustc_middle::mir::BorrowKind>,
         f: impl FnOnce(hir::ClosureKind, Span) -> CaptureVarCause,
     ) {
         if let UseSpans::ClosureUse { closure_kind, capture_kind_span, path_span, .. } = self {
             if capture_kind_span != path_span {
-                err.subdiagnostic(match kind {
-                    Some(kd) => match kd {
-                        rustc_middle::mir::BorrowKind::Shared
-                        | rustc_middle::mir::BorrowKind::Fake => {
-                            CaptureVarKind::Immut { kind_span: capture_kind_span }
-                        }
+                err.subdiagnostic(
+                    dcx,
+                    match kind {
+                        Some(kd) => match kd {
+                            rustc_middle::mir::BorrowKind::Shared
+                            | rustc_middle::mir::BorrowKind::Fake => {
+                                CaptureVarKind::Immut { kind_span: capture_kind_span }
+                            }
 
-                        rustc_middle::mir::BorrowKind::Mut { .. } => {
-                            CaptureVarKind::Mut { kind_span: capture_kind_span }
-                        }
+                            rustc_middle::mir::BorrowKind::Mut { .. } => {
+                                CaptureVarKind::Mut { kind_span: capture_kind_span }
+                            }
+                        },
+                        None => CaptureVarKind::Move { kind_span: capture_kind_span },
                     },
-                    None => CaptureVarKind::Move { kind_span: capture_kind_span },
-                });
+                );
             };
             let diag = f(closure_kind, path_span);
-            match dcx {
-                Some(hd) => err.eager_subdiagnostic(hd, diag),
-                None => err.subdiagnostic(diag),
-            };
+            err.subdiagnostic(dcx, diag);
         }
     }
 
@@ -1025,26 +1033,33 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 CallKind::FnCall { fn_trait_id, .. }
                     if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() =>
                 {
-                    err.subdiagnostic(CaptureReasonLabel::Call {
-                        fn_call_span,
-                        place_name: &place_name,
-                        is_partial,
-                        is_loop_message,
-                    });
-                    err.subdiagnostic(CaptureReasonNote::FnOnceMoveInCall { var_span });
+                    err.subdiagnostic(
+                        self.dcx(),
+                        CaptureReasonLabel::Call {
+                            fn_call_span,
+                            place_name: &place_name,
+                            is_partial,
+                            is_loop_message,
+                        },
+                    );
+                    err.subdiagnostic(self.dcx(), CaptureReasonNote::FnOnceMoveInCall { var_span });
                 }
                 CallKind::Operator { self_arg, .. } => {
                     let self_arg = self_arg.unwrap();
-                    err.subdiagnostic(CaptureReasonLabel::OperatorUse {
-                        fn_call_span,
-                        place_name: &place_name,
-                        is_partial,
-                        is_loop_message,
-                    });
+                    err.subdiagnostic(
+                        self.dcx(),
+                        CaptureReasonLabel::OperatorUse {
+                            fn_call_span,
+                            place_name: &place_name,
+                            is_partial,
+                            is_loop_message,
+                        },
+                    );
                     if self.fn_self_span_reported.insert(fn_span) {
-                        err.subdiagnostic(CaptureReasonNote::LhsMoveByOperator {
-                            span: self_arg.span,
-                        });
+                        err.subdiagnostic(
+                            self.dcx(),
+                            CaptureReasonNote::LhsMoveByOperator { span: self_arg.span },
+                        );
                     }
                 }
                 CallKind::Normal { self_arg, desugaring, method_did, method_args } => {
@@ -1061,11 +1076,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         );
 
                         let func = tcx.def_path_str(method_did);
-                        err.subdiagnostic(CaptureReasonNote::FuncTakeSelf {
-                            func,
-                            place_name: place_name.clone(),
-                            span: self_arg.span,
-                        });
+                        err.subdiagnostic(
+                            self.dcx(),
+                            CaptureReasonNote::FuncTakeSelf {
+                                func,
+                                place_name: place_name.clone(),
+                                span: self_arg.span,
+                            },
+                        );
                     }
                     let parent_did = tcx.parent(method_did);
                     let parent_self_ty =
@@ -1079,7 +1097,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
                     });
                     if is_option_or_result && maybe_reinitialized_locations_is_empty {
-                        err.subdiagnostic(CaptureReasonLabel::BorrowContent { var_span });
+                        err.subdiagnostic(
+                            self.dcx(),
+                            CaptureReasonLabel::BorrowContent { var_span },
+                        );
                     }
                     if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
                         let ty = moved_place.ty(self.body, tcx).ty;
@@ -1093,18 +1114,24 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             _ => false,
                         };
                         if suggest {
-                            err.subdiagnostic(CaptureReasonSuggest::IterateSlice {
-                                ty,
-                                span: move_span.shrink_to_lo(),
-                            });
+                            err.subdiagnostic(
+                                self.dcx(),
+                                CaptureReasonSuggest::IterateSlice {
+                                    ty,
+                                    span: move_span.shrink_to_lo(),
+                                },
+                            );
                         }
 
-                        err.subdiagnostic(CaptureReasonLabel::ImplicitCall {
-                            fn_call_span,
-                            place_name: &place_name,
-                            is_partial,
-                            is_loop_message,
-                        });
+                        err.subdiagnostic(
+                            self.dcx(),
+                            CaptureReasonLabel::ImplicitCall {
+                                fn_call_span,
+                                place_name: &place_name,
+                                is_partial,
+                                is_loop_message,
+                            },
+                        );
                         // If the moved place was a `&mut` ref, then we can
                         // suggest to reborrow it where it was moved, so it
                         // will still be valid by the time we get to the usage.
@@ -1128,19 +1155,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         }
                     } else {
                         if let Some((CallDesugaringKind::Await, _)) = desugaring {
-                            err.subdiagnostic(CaptureReasonLabel::Await {
-                                fn_call_span,
-                                place_name: &place_name,
-                                is_partial,
-                                is_loop_message,
-                            });
+                            err.subdiagnostic(
+                                self.dcx(),
+                                CaptureReasonLabel::Await {
+                                    fn_call_span,
+                                    place_name: &place_name,
+                                    is_partial,
+                                    is_loop_message,
+                                },
+                            );
                         } else {
-                            err.subdiagnostic(CaptureReasonLabel::MethodCall {
-                                fn_call_span,
-                                place_name: &place_name,
-                                is_partial,
-                                is_loop_message,
-                            });
+                            err.subdiagnostic(
+                                self.dcx(),
+                                CaptureReasonLabel::MethodCall {
+                                    fn_call_span,
+                                    place_name: &place_name,
+                                    is_partial,
+                                    is_loop_message,
+                                },
+                            );
                         }
                         // Erase and shadow everything that could be passed to the new infcx.
                         let ty = moved_place.ty(self.body, tcx).ty;
@@ -1155,7 +1188,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             )
                             && self.infcx.can_eq(self.param_env, ty, self_ty)
                         {
-                            err.eager_subdiagnostic(
+                            err.subdiagnostic(
                                 self.dcx(),
                                 CaptureReasonSuggest::FreshReborrow {
                                     span: move_span.shrink_to_hi(),
@@ -1239,17 +1272,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             }
         } else {
             if move_span != span || is_loop_message {
-                err.subdiagnostic(CaptureReasonLabel::MovedHere {
-                    move_span,
-                    is_partial,
-                    is_move_msg,
-                    is_loop_message,
-                });
+                err.subdiagnostic(
+                    self.dcx(),
+                    CaptureReasonLabel::MovedHere {
+                        move_span,
+                        is_partial,
+                        is_move_msg,
+                        is_loop_message,
+                    },
+                );
             }
             // If the move error occurs due to a loop, don't show
             // another message for the same span
             if !is_loop_message {
-                move_spans.var_subdiag(None, err, None, |kind, var_span| match kind {
+                move_spans.var_subdiag(self.dcx(), err, None, |kind, var_span| match kind {
                     hir::ClosureKind::Coroutine(_) => {
                         CaptureVarCause::PartialMoveUseInCoroutine { var_span, is_partial }
                     }
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index 126a50c91b494..dad20690d02cc 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -448,12 +448,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                         None => "value".to_string(),
                     };
 
-                    err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
-                        is_partial_move: false,
-                        ty: place_ty,
-                        place: &place_desc,
-                        span,
-                    });
+                    err.subdiagnostic(
+                        self.dcx(),
+                        crate::session_diagnostics::TypeNoCopy::Label {
+                            is_partial_move: false,
+                            ty: place_ty,
+                            place: &place_desc,
+                            span,
+                        },
+                    );
                 } else {
                     binds_to.sort();
                     binds_to.dedup();
@@ -475,14 +478,17 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     Some(desc) => format!("`{desc}`"),
                     None => "value".to_string(),
                 };
-                err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
-                    is_partial_move: false,
-                    ty: place_ty,
-                    place: &place_desc,
-                    span,
-                });
+                err.subdiagnostic(
+                    self.dcx(),
+                    crate::session_diagnostics::TypeNoCopy::Label {
+                        is_partial_move: false,
+                        ty: place_ty,
+                        place: &place_desc,
+                        span,
+                    },
+                );
 
-                use_spans.args_subdiag(err, |args_span| {
+                use_spans.args_subdiag(self.dcx(), err, |args_span| {
                     crate::session_diagnostics::CaptureArgLabel::MoveOutPlace {
                         place: place_desc,
                         args_span,
@@ -580,12 +586,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
             if binds_to.len() == 1 {
                 let place_desc = &format!("`{}`", self.local_names[*local].unwrap());
-                err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
-                    is_partial_move: false,
-                    ty: bind_to.ty,
-                    place: place_desc,
-                    span: binding_span,
-                });
+                err.subdiagnostic(
+                    self.dcx(),
+                    crate::session_diagnostics::TypeNoCopy::Label {
+                        is_partial_move: false,
+                        ty: bind_to.ty,
+                        place: place_desc,
+                        span: binding_span,
+                    },
+                );
             }
         }
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index b3d684086c286..5e659a5f3c239 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -229,7 +229,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 }
                 if suggest {
                     borrow_spans.var_subdiag(
-                        None,
+                        self.dcx(),
                         &mut err,
                         Some(mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }),
                         |_kind, var_span| {
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 7529ec53a9869..e8effd5c1633a 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -616,13 +616,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 let upvars_map = self.infcx.tcx.upvars_mentioned(def_id).unwrap();
                 let upvar_def_span = self.infcx.tcx.hir().span(def_hir);
                 let upvar_span = upvars_map.get(&def_hir).unwrap().span;
-                diag.subdiagnostic(VarHereDenote::Defined { span: upvar_def_span });
-                diag.subdiagnostic(VarHereDenote::Captured { span: upvar_span });
+                diag.subdiagnostic(self.dcx(), VarHereDenote::Defined { span: upvar_def_span });
+                diag.subdiagnostic(self.dcx(), VarHereDenote::Captured { span: upvar_span });
             }
         }
 
         if let Some(fr_span) = self.give_region_a_name(*outlived_fr).unwrap().span() {
-            diag.subdiagnostic(VarHereDenote::FnMutInferred { span: fr_span });
+            diag.subdiagnostic(self.dcx(), VarHereDenote::FnMutInferred { span: fr_span });
         }
 
         self.suggest_move_on_borrowing_closure(&mut diag);
@@ -788,7 +788,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             },
         };
 
-        diag.subdiagnostic(err_category);
+        diag.subdiagnostic(self.dcx(), err_category);
 
         self.add_static_impl_trait_suggestion(&mut diag, *fr, fr_name, *outlived_fr);
         self.suggest_adding_lifetime_params(&mut diag, *fr, *outlived_fr);
@@ -979,7 +979,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     ident.span,
                     "calling this method introduces the `impl`'s `'static` requirement",
                 );
-                err.subdiagnostic(RequireStaticErr::UsedImpl { multi_span });
+                err.subdiagnostic(self.dcx(), RequireStaticErr::UsedImpl { multi_span });
                 err.span_suggestion_verbose(
                     span.shrink_to_hi(),
                     "consider relaxing the implicit `'static` requirement",
diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs
index cc0fbe46dcc11..79eb4406b8a33 100644
--- a/compiler/rustc_codegen_gcc/src/errors.rs
+++ b/compiler/rustc_codegen_gcc/src/errors.rs
@@ -122,7 +122,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for TargetFeatureDisableOrEnabl
             diag.span(span);
         };
         if let Some(missing_features) = self.missing_features {
-            diag.subdiagnostic(missing_features);
+            diag.subdiagnostic(dcx, missing_features);
         }
         diag.arg("features", self.features.join(", "));
         diag
diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs
index 587c5e9e8d235..87e3774068bcd 100644
--- a/compiler/rustc_codegen_llvm/src/errors.rs
+++ b/compiler/rustc_codegen_llvm/src/errors.rs
@@ -131,7 +131,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for TargetFeatureDisableOrEnabl
             diag.span(span);
         };
         if let Some(missing_features) = self.missing_features {
-            diag.subdiagnostic(missing_features);
+            diag.subdiagnostic(dcx, missing_features);
         }
         diag.arg("features", self.features.join(", "));
         diag
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
index 0c93cfaa54647..25ddd5e85f9f3 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -131,7 +131,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
                         // FIXME(effects) revisit this
                         if !tcx.is_const_trait_impl_raw(data.impl_def_id) {
                             let span = tcx.def_span(data.impl_def_id);
-                            err.subdiagnostic(errors::NonConstImplNote { span });
+                            err.subdiagnostic(tcx.dcx(), errors::NonConstImplNote { span });
                         }
                     }
                 }
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index a1abe8fd4f306..f91b6655f6399 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -263,14 +263,10 @@ pub enum SubdiagnosticMessage {
     /// Translatable message which has already been translated eagerly.
     ///
     /// Some diagnostics have repeated subdiagnostics where the same interpolated variables would
-    /// be instantiated multiple times with different values. As translation normally happens
-    /// immediately prior to emission, after the diagnostic and subdiagnostic derive logic has run,
-    /// the setting of diagnostic arguments in the derived code will overwrite previous variable
-    /// values and only the final value will be set when translation occurs - resulting in
-    /// incorrect diagnostics. Eager translation results in translation for a subdiagnostic
-    /// happening immediately after the subdiagnostic derive's logic has been run. This variant
-    /// stores messages which have been translated eagerly.
-    Eager(Cow<'static, str>),
+    /// be instantiated multiple times with different values. These subdiagnostics' messages
+    /// are translated when they are added to the parent diagnostic, producing this variant of
+    /// `DiagnosticMessage`.
+    Translated(Cow<'static, str>),
     /// Identifier of a Fluent message. Instances of this variant are generated by the
     /// `Subdiagnostic` derive.
     FluentIdentifier(FluentId),
@@ -307,19 +303,15 @@ impl From<Cow<'static, str>> for SubdiagnosticMessage {
 pub enum DiagnosticMessage {
     /// Non-translatable diagnostic message.
     Str(Cow<'static, str>),
-    /// Translatable message which has already been translated eagerly.
+    /// Translatable message which has been already translated.
     ///
     /// Some diagnostics have repeated subdiagnostics where the same interpolated variables would
-    /// be instantiated multiple times with different values. As translation normally happens
-    /// immediately prior to emission, after the diagnostic and subdiagnostic derive logic has run,
-    /// the setting of diagnostic arguments in the derived code will overwrite previous variable
-    /// values and only the final value will be set when translation occurs - resulting in
-    /// incorrect diagnostics. Eager translation results in translation for a subdiagnostic
-    /// happening immediately after the subdiagnostic derive's logic has been run. This variant
-    /// stores messages which have been translated eagerly.
-    Eager(Cow<'static, str>),
+    /// be instantiated multiple times with different values. These subdiagnostics' messages
+    /// are translated when they are added to the parent diagnostic, producing this variant of
+    /// `DiagnosticMessage`.
+    Translated(Cow<'static, str>),
     /// Identifier for a Fluent message (with optional attribute) corresponding to the diagnostic
-    /// message.
+    /// message. Yet to be translated.
     ///
     /// <https://projectfluent.org/fluent/guide/hello.html>
     /// <https://projectfluent.org/fluent/guide/attributes.html>
@@ -336,7 +328,7 @@ impl DiagnosticMessage {
     pub fn with_subdiagnostic_message(&self, sub: SubdiagnosticMessage) -> Self {
         let attr = match sub {
             SubdiagnosticMessage::Str(s) => return DiagnosticMessage::Str(s),
-            SubdiagnosticMessage::Eager(s) => return DiagnosticMessage::Eager(s),
+            SubdiagnosticMessage::Translated(s) => return DiagnosticMessage::Translated(s),
             SubdiagnosticMessage::FluentIdentifier(id) => {
                 return DiagnosticMessage::FluentIdentifier(id, None);
             }
@@ -345,7 +337,7 @@ impl DiagnosticMessage {
 
         match self {
             DiagnosticMessage::Str(s) => DiagnosticMessage::Str(s.clone()),
-            DiagnosticMessage::Eager(s) => DiagnosticMessage::Eager(s.clone()),
+            DiagnosticMessage::Translated(s) => DiagnosticMessage::Translated(s.clone()),
             DiagnosticMessage::FluentIdentifier(id, _) => {
                 DiagnosticMessage::FluentIdentifier(id.clone(), Some(attr))
             }
@@ -354,7 +346,7 @@ impl DiagnosticMessage {
 
     pub fn as_str(&self) -> Option<&str> {
         match self {
-            DiagnosticMessage::Eager(s) | DiagnosticMessage::Str(s) => Some(s),
+            DiagnosticMessage::Translated(s) | DiagnosticMessage::Str(s) => Some(s),
             DiagnosticMessage::FluentIdentifier(_, _) => None,
         }
     }
@@ -396,7 +388,7 @@ impl Into<SubdiagnosticMessage> for DiagnosticMessage {
     fn into(self) -> SubdiagnosticMessage {
         match self {
             DiagnosticMessage::Str(s) => SubdiagnosticMessage::Str(s),
-            DiagnosticMessage::Eager(s) => SubdiagnosticMessage::Eager(s),
+            DiagnosticMessage::Translated(s) => SubdiagnosticMessage::Translated(s),
             DiagnosticMessage::FluentIdentifier(id, None) => {
                 SubdiagnosticMessage::FluentIdentifier(id)
             }
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index b14a12175c79b..d31321b48d007 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -851,18 +851,11 @@ impl Diagnostic {
         self
     }
 
-    /// Add a subdiagnostic from a type that implements `Subdiagnostic` (see
-    /// [rustc_macros::Subdiagnostic]).
-    pub fn subdiagnostic(&mut self, subdiagnostic: impl AddToDiagnostic) -> &mut Self {
-        subdiagnostic.add_to_diagnostic(self);
-        self
-    }
-
     /// Add a subdiagnostic from a type that implements `Subdiagnostic` (see
     /// [rustc_macros::Subdiagnostic]). Performs eager translation of any translatable messages
     /// used in the subdiagnostic, so suitable for use with repeated messages (i.e. re-use of
     /// interpolated variables).
-    pub fn eager_subdiagnostic(
+    pub fn subdiagnostic(
         &mut self,
         dcx: &crate::DiagCtxt,
         subdiagnostic: impl AddToDiagnostic,
@@ -921,7 +914,7 @@ impl Diagnostic {
     /// Helper function that takes a `SubdiagnosticMessage` and returns a `DiagnosticMessage` by
     /// combining it with the primary message of the diagnostic (if translatable, otherwise it just
     /// passes the user's string along).
-    fn subdiagnostic_message_to_diagnostic_message(
+    pub(crate) fn subdiagnostic_message_to_diagnostic_message(
         &self,
         attr: impl Into<SubdiagnosticMessage>,
     ) -> DiagnosticMessage {
diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs
index e484bef0e0bc9..0572df69ca947 100644
--- a/compiler/rustc_errors/src/diagnostic_builder.rs
+++ b/compiler/rustc_errors/src/diagnostic_builder.rs
@@ -404,9 +404,6 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
         name: impl Into<Cow<'static, str>>, arg: impl IntoDiagnosticArg,
     ));
     forward!((subdiagnostic, with_subdiagnostic)(
-        subdiagnostic: impl crate::AddToDiagnostic,
-    ));
-    forward!((eager_subdiagnostic, with_eager_subdiagnostic)(
         dcx: &DiagCtxt,
         subdiagnostic: impl crate::AddToDiagnostic,
     ));
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 38c6661377b19..00b7c50ad17d3 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -10,6 +10,7 @@
 use rustc_span::source_map::SourceMap;
 use rustc_span::{FileLines, FileName, SourceFile, Span};
 
+use crate::error::TranslateError;
 use crate::snippet::{
     Annotation, AnnotationColumn, AnnotationType, Line, MultilineAnnotation, Style, StyledString,
 };
@@ -559,6 +560,18 @@ pub struct SilentEmitter {
     pub fatal_note: String,
 }
 
+pub fn silent_translate<'a>(
+    message: &'a DiagnosticMessage,
+) -> Result<Cow<'_, str>, TranslateError<'_>> {
+    match message {
+        DiagnosticMessage::Str(msg) | DiagnosticMessage::Translated(msg) => Ok(Cow::Borrowed(msg)),
+        DiagnosticMessage::FluentIdentifier(identifier, _) => {
+            // Any value works here.
+            Ok(identifier.clone())
+        }
+    }
+}
+
 impl Translate for SilentEmitter {
     fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
         None
@@ -567,6 +580,16 @@ impl Translate for SilentEmitter {
     fn fallback_fluent_bundle(&self) -> &FluentBundle {
         panic!("silent emitter attempted to translate message")
     }
+
+    // Override `translate_message` for the silent emitter because eager translation of
+    // subdiagnostics result in a call to this.
+    fn translate_message<'a>(
+        &'a self,
+        message: &'a DiagnosticMessage,
+        _: &'a FluentArgs<'_>,
+    ) -> Result<Cow<'_, str>, TranslateError<'_>> {
+        silent_translate(message)
+    }
 }
 
 impl Emitter for SilentEmitter {
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index b738ecb54ffc1..986e87cd2e2ce 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -640,7 +640,8 @@ impl DiagCtxt {
         message: DiagnosticMessage,
         args: impl Iterator<Item = DiagnosticArg<'a>>,
     ) -> SubdiagnosticMessage {
-        SubdiagnosticMessage::Eager(Cow::from(self.eagerly_translate_to_string(message, args)))
+        let inner = self.inner.borrow();
+        inner.eagerly_translate(message, args)
     }
 
     /// Translate `message` eagerly with `args` to `String`.
@@ -650,8 +651,7 @@ impl DiagCtxt {
         args: impl Iterator<Item = DiagnosticArg<'a>>,
     ) -> String {
         let inner = self.inner.borrow();
-        let args = crate::translation::to_fluent_args(args);
-        inner.emitter.translate_message(&message, &args).map_err(Report::new).unwrap().to_string()
+        inner.eagerly_translate_to_string(message, args)
     }
 
     // This is here to not allow mutation of flags;
@@ -1446,6 +1446,25 @@ impl DiagCtxtInner {
             .or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied())
     }
 
+    /// Translate `message` eagerly with `args` to `SubdiagnosticMessage::Eager`.
+    pub fn eagerly_translate<'a>(
+        &self,
+        message: DiagnosticMessage,
+        args: impl Iterator<Item = DiagnosticArg<'a>>,
+    ) -> SubdiagnosticMessage {
+        SubdiagnosticMessage::Translated(Cow::from(self.eagerly_translate_to_string(message, args)))
+    }
+
+    /// Translate `message` eagerly with `args` to `String`.
+    pub fn eagerly_translate_to_string<'a>(
+        &self,
+        message: DiagnosticMessage,
+        args: impl Iterator<Item = DiagnosticArg<'a>>,
+    ) -> String {
+        let args = crate::translation::to_fluent_args(args);
+        self.emitter.translate_message(&message, &args).map_err(Report::new).unwrap().to_string()
+    }
+
     fn flush_delayed(&mut self) {
         if self.delayed_bugs.is_empty() {
             return;
@@ -1484,15 +1503,22 @@ impl DiagCtxtInner {
             }
 
             let mut bug =
-                if backtrace || self.ice_file.is_none() { bug.decorate() } else { bug.inner };
+                if backtrace || self.ice_file.is_none() { bug.decorate(self) } else { bug.inner };
 
             // "Undelay" the delayed bugs (into plain `Bug`s).
             if bug.level != DelayedBug {
                 // NOTE(eddyb) not panicking here because we're already producing
                 // an ICE, and the more information the merrier.
-                bug.subdiagnostic(InvalidFlushedDelayedDiagnosticLevel {
+                let subdiag = InvalidFlushedDelayedDiagnosticLevel {
                     span: bug.span.primary_span().unwrap(),
                     level: bug.level,
+                };
+                // FIXME: Cannot use `Diagnostic::subdiagnostic` which takes `DiagCtxt`, but it
+                // just uses `DiagCtxtInner` functions.
+                subdiag.add_to_diagnostic_with(&mut bug, |diag, msg| {
+                    let args = diag.args();
+                    let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
+                    self.eagerly_translate(msg, args)
                 });
             }
             bug.level = Bug;
@@ -1527,25 +1553,35 @@ impl DelayedDiagnostic {
         DelayedDiagnostic { inner: diagnostic, note: backtrace }
     }
 
-    fn decorate(mut self) -> Diagnostic {
+    fn decorate(mut self, dcx: &DiagCtxtInner) -> Diagnostic {
+        // FIXME: Cannot use `Diagnostic::subdiagnostic` which takes `DiagCtxt`, but it
+        // just uses `DiagCtxtInner` functions.
+        let subdiag_with = |diag: &mut Diagnostic, msg| {
+            let args = diag.args();
+            let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
+            dcx.eagerly_translate(msg, args)
+        };
+
         match self.note.status() {
             BacktraceStatus::Captured => {
                 let inner = &self.inner;
-                self.inner.subdiagnostic(DelayedAtWithNewline {
+                let subdiag = DelayedAtWithNewline {
                     span: inner.span.primary_span().unwrap_or(DUMMY_SP),
                     emitted_at: inner.emitted_at.clone(),
                     note: self.note,
-                });
+                };
+                subdiag.add_to_diagnostic_with(&mut self.inner, subdiag_with);
             }
             // Avoid the needless newline when no backtrace has been captured,
             // the display impl should just be a single line.
             _ => {
                 let inner = &self.inner;
-                self.inner.subdiagnostic(DelayedAtWithoutNewline {
+                let subdiag = DelayedAtWithoutNewline {
                     span: inner.span.primary_span().unwrap_or(DUMMY_SP),
                     emitted_at: inner.emitted_at.clone(),
                     note: self.note,
-                });
+                };
+                subdiag.add_to_diagnostic_with(&mut self.inner, subdiag_with);
             }
         }
 
@@ -1691,15 +1727,15 @@ impl Level {
 }
 
 // FIXME(eddyb) this doesn't belong here AFAICT, should be moved to callsite.
-pub fn add_elided_lifetime_in_path_suggestion(
+pub fn add_elided_lifetime_in_path_suggestion<E: EmissionGuarantee>(
     source_map: &SourceMap,
-    diag: &mut Diagnostic,
+    diag: &mut DiagnosticBuilder<'_, E>,
     n: usize,
     path_span: Span,
     incl_angl_brckt: bool,
     insertion_span: Span,
 ) {
-    diag.subdiagnostic(ExpectedLifetimeParameter { span: path_span, count: n });
+    diag.subdiagnostic(diag.dcx, ExpectedLifetimeParameter { span: path_span, count: n });
     if !source_map.is_span_accessible(insertion_span) {
         // Do not try to suggest anything if generated by a proc-macro.
         return;
@@ -1708,11 +1744,10 @@ pub fn add_elided_lifetime_in_path_suggestion(
     let suggestion =
         if incl_angl_brckt { format!("<{anon_lts}>") } else { format!("{anon_lts}, ") };
 
-    diag.subdiagnostic(IndicateAnonymousLifetime {
-        span: insertion_span.shrink_to_hi(),
-        count: n,
-        suggestion,
-    });
+    diag.subdiagnostic(
+        diag.dcx,
+        IndicateAnonymousLifetime { span: insertion_span.shrink_to_hi(), count: n, suggestion },
+    );
 }
 
 pub fn report_ambiguity_error<'a, G: EmissionGuarantee>(
diff --git a/compiler/rustc_errors/src/translation.rs b/compiler/rustc_errors/src/translation.rs
index 5bdac367d55e7..5f074dbbbad30 100644
--- a/compiler/rustc_errors/src/translation.rs
+++ b/compiler/rustc_errors/src/translation.rs
@@ -2,7 +2,7 @@ use crate::error::{TranslateError, TranslateErrorKind};
 use crate::snippet::Style;
 use crate::{DiagnosticArg, DiagnosticMessage, FluentBundle};
 use rustc_data_structures::sync::Lrc;
-use rustc_error_messages::FluentArgs;
+pub use rustc_error_messages::FluentArgs;
 use std::borrow::Cow;
 use std::env;
 use std::error::Report;
@@ -61,7 +61,7 @@ pub trait Translate {
     ) -> Result<Cow<'_, str>, TranslateError<'_>> {
         trace!(?message, ?args);
         let (identifier, attr) = match message {
-            DiagnosticMessage::Str(msg) | DiagnosticMessage::Eager(msg) => {
+            DiagnosticMessage::Str(msg) | DiagnosticMessage::Translated(msg) => {
                 return Ok(Cow::Borrowed(msg));
             }
             DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr),
diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs
index eec86c36aedae..b3d370a9c8dec 100644
--- a/compiler/rustc_expand/src/mbe/diagnostics.rs
+++ b/compiler/rustc_expand/src/mbe/diagnostics.rs
@@ -7,7 +7,7 @@ use crate::mbe::{
 use rustc_ast::token::{self, Token, TokenKind};
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast_pretty::pprust;
-use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage};
+use rustc_errors::{Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, DiagnosticMessage};
 use rustc_parse::parser::{Parser, Recovery};
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::Ident;
@@ -58,7 +58,7 @@ pub(super) fn failed_to_match_macro<'cx>(
         err.span_label(cx.source_map().guess_head_span(def_span), "when calling this macro");
     }
 
-    annotate_doc_comment(&mut err, sess.source_map(), span);
+    annotate_doc_comment(cx.sess.dcx(), &mut err, sess.source_map(), span);
 
     if let Some(span) = remaining_matcher.span() {
         err.span_note(span, format!("while trying to match {remaining_matcher}"));
@@ -311,12 +311,17 @@ enum ExplainDocComment {
     },
 }
 
-pub(super) fn annotate_doc_comment(err: &mut Diagnostic, sm: &SourceMap, span: Span) {
+pub(super) fn annotate_doc_comment(
+    dcx: &DiagCtxt,
+    err: &mut Diagnostic,
+    sm: &SourceMap,
+    span: Span,
+) {
     if let Ok(src) = sm.span_to_snippet(span) {
         if src.starts_with("///") || src.starts_with("/**") {
-            err.subdiagnostic(ExplainDocComment::Outer { span });
+            err.subdiagnostic(dcx, ExplainDocComment::Outer { span });
         } else if src.starts_with("//!") || src.starts_with("/*!") {
-            err.subdiagnostic(ExplainDocComment::Inner { span });
+            err.subdiagnostic(dcx, ExplainDocComment::Inner { span });
         }
     }
 }
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 83e0f870c8a25..c82609503c18a 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -454,7 +454,7 @@ pub fn compile_declarative_macro(
                 let sp = token.span.substitute_dummy(def.span);
                 let mut err = sess.dcx().struct_span_err(sp, s);
                 err.span_label(sp, msg);
-                annotate_doc_comment(&mut err, sess.source_map(), sp);
+                annotate_doc_comment(sess.dcx(), &mut err, sess.source_map(), sp);
                 err.emit();
                 return dummy_syn_ext();
             }
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index 0311aa94cd485..f4ac010691cd4 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -261,7 +261,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let semi = expr.span.shrink_to_hi().with_hi(semi_span.hi());
         let sugg = crate::errors::RemoveSemiForCoerce { expr: expr.span, ret, semi };
-        diag.subdiagnostic(sugg);
+        diag.subdiagnostic(self.dcx(), sugg);
     }
 
     /// When the previously checked expression (the scrutinee) diverges,
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index f21de1609cb7f..2142bb914209a 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -993,19 +993,25 @@ impl<'a, 'tcx> CastCheck<'tcx> {
             if let Some((deref_ty, _)) = derefed {
                 // Give a note about what the expr derefs to.
                 if deref_ty != self.expr_ty.peel_refs() {
-                    err.subdiagnostic(errors::DerefImplsIsEmpty {
-                        span: self.expr_span,
-                        deref_ty: fcx.ty_to_string(deref_ty),
-                    });
+                    err.subdiagnostic(
+                        fcx.dcx(),
+                        errors::DerefImplsIsEmpty {
+                            span: self.expr_span,
+                            deref_ty: fcx.ty_to_string(deref_ty),
+                        },
+                    );
                 }
 
                 // Create a multipart suggestion: add `!` and `.is_empty()` in
                 // place of the cast.
-                err.subdiagnostic(errors::UseIsEmpty {
-                    lo: self.expr_span.shrink_to_lo(),
-                    hi: self.span.with_lo(self.expr_span.hi()),
-                    expr_ty: fcx.ty_to_string(self.expr_ty),
-                });
+                err.subdiagnostic(
+                    fcx.dcx(),
+                    errors::UseIsEmpty {
+                        lo: self.expr_span.shrink_to_lo(),
+                        hi: self.span.with_lo(self.expr_span.hi()),
+                        expr_ty: fcx.ty_to_string(self.expr_ty),
+                    },
+                );
             }
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 19bdeab409bb7..7f30b36a1f94a 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -395,7 +395,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         if let Some(sp) =
                             tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp)
                         {
-                            err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
+                            err.subdiagnostic(self.dcx(), ExprParenthesesNeeded::surrounding(*sp));
                         }
                         oprnd_t = Ty::new_error(tcx, err.emit());
                     }
@@ -2050,7 +2050,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .shrink_to_hi()
                 .to(range_end.span);
 
-            err.subdiagnostic(TypeMismatchFruTypo { expr_span: range_start.span, fru_span, expr });
+            err.subdiagnostic(
+                self.dcx(),
+                TypeMismatchFruTypo { expr_span: range_start.span, fru_span, expr },
+            );
         }
     }
 
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 65b8505c09098..339bc9f0f7a99 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1269,7 +1269,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         {
             // The user provided `ptr::null()`, but the function expects
             // `ptr::null_mut()`.
-            err.subdiagnostic(SuggestPtrNullMut { span: arg.span });
+            err.subdiagnostic(self.dcx(), SuggestPtrNullMut { span: arg.span });
         }
     }
 
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 8b6f263b1a746..c1a32a1afa3cf 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -458,13 +458,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // but those checks need to be a bit more delicate and the benefit is diminishing.
             if self.can_eq(self.param_env, found_ty_inner, peeled) && error_tys_equate_as_ref {
                 let sugg = prefix_wrap(".as_ref()");
-                err.subdiagnostic(errors::SuggestConvertViaMethod {
-                    span: expr.span.shrink_to_hi(),
-                    sugg,
-                    expected,
-                    found,
-                    borrow_removal_span,
-                });
+                err.subdiagnostic(
+                    self.dcx(),
+                    errors::SuggestConvertViaMethod {
+                        span: expr.span.shrink_to_hi(),
+                        sugg,
+                        expected,
+                        found,
+                        borrow_removal_span,
+                    },
+                );
                 return true;
             } else if let Some((deref_ty, _)) =
                 self.autoderef(expr.span, found_ty_inner).silence_errors().nth(1)
@@ -472,13 +475,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 && error_tys_equate_as_ref
             {
                 let sugg = prefix_wrap(".as_deref()");
-                err.subdiagnostic(errors::SuggestConvertViaMethod {
-                    span: expr.span.shrink_to_hi(),
-                    sugg,
-                    expected,
-                    found,
-                    borrow_removal_span,
-                });
+                err.subdiagnostic(
+                    self.dcx(),
+                    errors::SuggestConvertViaMethod {
+                        span: expr.span.shrink_to_hi(),
+                        sugg,
+                        expected,
+                        found,
+                        borrow_removal_span,
+                    },
+                );
                 return true;
             } else if let ty::Adt(adt, _) = found_ty_inner.peel_refs().kind()
                 && Some(adt.did()) == self.tcx.lang_items().string()
@@ -565,7 +571,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     end: span.shrink_to_hi(),
                 },
             };
-            err.subdiagnostic(suggest_boxing);
+            err.subdiagnostic(self.dcx(), suggest_boxing);
 
             true
         } else {
@@ -799,29 +805,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         match &fn_decl.output {
             &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() && !can_suggest => {
                 // `fn main()` must return `()`, do not suggest changing return type
-                err.subdiagnostic(errors::ExpectedReturnTypeLabel::Unit { span });
+                err.subdiagnostic(self.dcx(), errors::ExpectedReturnTypeLabel::Unit { span });
                 return true;
             }
             &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => {
                 if let Some(found) = found.make_suggestable(self.tcx, false) {
-                    err.subdiagnostic(errors::AddReturnTypeSuggestion::Add {
-                        span,
-                        found: found.to_string(),
-                    });
+                    err.subdiagnostic(
+                        self.dcx(),
+                        errors::AddReturnTypeSuggestion::Add { span, found: found.to_string() },
+                    );
                     return true;
                 } else if let ty::Closure(_, args) = found.kind()
                     // FIXME(compiler-errors): Get better at printing binders...
                     && let closure = args.as_closure()
                     && closure.sig().is_suggestable(self.tcx, false)
                 {
-                    err.subdiagnostic(errors::AddReturnTypeSuggestion::Add {
-                        span,
-                        found: closure.print_as_impl_trait().to_string(),
-                    });
+                    err.subdiagnostic(
+                        self.dcx(),
+                        errors::AddReturnTypeSuggestion::Add {
+                            span,
+                            found: closure.print_as_impl_trait().to_string(),
+                        },
+                    );
                     return true;
                 } else {
                     // FIXME: if `found` could be `impl Iterator` we should suggest that.
-                    err.subdiagnostic(errors::AddReturnTypeSuggestion::MissingHere { span });
+                    err.subdiagnostic(
+                        self.dcx(),
+                        errors::AddReturnTypeSuggestion::MissingHere { span },
+                    );
                     return true;
                 }
             }
@@ -843,16 +855,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     debug!(?found);
                     if found.is_suggestable(self.tcx, false) {
                         if term.span.is_empty() {
-                            err.subdiagnostic(errors::AddReturnTypeSuggestion::Add {
-                                span: term.span,
-                                found: found.to_string(),
-                            });
+                            err.subdiagnostic(
+                                self.dcx(),
+                                errors::AddReturnTypeSuggestion::Add {
+                                    span: term.span,
+                                    found: found.to_string(),
+                                },
+                            );
                             return true;
                         } else {
-                            err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other {
-                                span: term.span,
-                                expected,
-                            });
+                            err.subdiagnostic(
+                                self.dcx(),
+                                errors::ExpectedReturnTypeLabel::Other {
+                                    span: term.span,
+                                    expected,
+                                },
+                            );
                         }
                     }
                 } else {
@@ -867,10 +885,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     let ty = self.normalize(hir_ty.span, ty);
                     let ty = self.tcx.instantiate_bound_regions_with_erased(ty);
                     if self.can_coerce(expected, ty) {
-                        err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other {
-                            span: hir_ty.span,
-                            expected,
-                        });
+                        err.subdiagnostic(
+                            self.dcx(),
+                            errors::ExpectedReturnTypeLabel::Other { span: hir_ty.span, expected },
+                        );
                         self.try_suggest_return_impl_trait(err, expected, ty, fn_id);
                         return true;
                     }
@@ -1106,7 +1124,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let sp = self.tcx.sess.source_map().start_point(expr.span).with_parent(None);
         if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) {
             // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
-            err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
+            err.subdiagnostic(self.dcx(), ExprParenthesesNeeded::surrounding(*sp));
             true
         } else {
             false
@@ -1220,7 +1238,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 } else {
                     return false;
                 };
-                diag.subdiagnostic(subdiag);
+                diag.subdiagnostic(self.dcx(), subdiag);
                 return true;
             }
         }
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 729ce1f00cd8b..2269e9f7d4c3d 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -3173,19 +3173,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     if impls_trait(trait_info.def_id) {
                         self.suggest_valid_traits(err, vec![trait_info.def_id], false);
                     } else {
-                        err.subdiagnostic(CandidateTraitNote {
-                            span: self.tcx.def_span(trait_info.def_id),
-                            trait_name: self.tcx.def_path_str(trait_info.def_id),
-                            item_name,
-                            action_or_ty: if trait_missing_method {
-                                "NONE".to_string()
-                            } else {
-                                param_type.map_or_else(
-                                    || "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented.
-                                    ToString::to_string,
-                                )
+                        err.subdiagnostic(
+                            self.dcx(),
+                            CandidateTraitNote {
+                                span: self.tcx.def_span(trait_info.def_id),
+                                trait_name: self.tcx.def_path_str(trait_info.def_id),
+                                item_name,
+                                action_or_ty: if trait_missing_method {
+                                    "NONE".to_string()
+                                } else {
+                                    param_type.map_or_else(
+                                        || "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented.
+                                        ToString::to_string,
+                                    )
+                                },
                             },
-                        });
+                        );
                     }
                 }
                 trait_infos => {
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index 9a8444e6a2bcd..929b3557f5242 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -824,7 +824,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         // If the previous expression was a block expression, suggest parentheses
                         // (turning this into a binary subtraction operation instead.)
                         // for example, `{2} - 2` -> `({2}) - 2` (see src\test\ui\parser\expr-as-stmt.rs)
-                        err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
+                        err.subdiagnostic(self.dcx(), ExprParenthesesNeeded::surrounding(*sp));
                     } else {
                         match actual.kind() {
                             Uint(_) if op == hir::UnOp::Neg => {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index b953b25d6c4cf..280701b8ec6d5 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -846,7 +846,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         arm_ty,
                         arm_span,
                     ) {
-                        err.subdiagnostic(subdiag);
+                        err.subdiagnostic(self.dcx(), subdiag);
                     }
                     if let hir::Node::Expr(m) = self.tcx.parent_hir_node(scrut_hir_id)
                         && let hir::Node::Stmt(stmt) = self.tcx.parent_hir_node(m.hir_id)
@@ -892,7 +892,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     else_ty,
                     else_span,
                 ) {
-                    err.subdiagnostic(subdiag);
+                    err.subdiagnostic(self.dcx(), subdiag);
                 }
                 // don't suggest wrapping either blocks in `if .. {} else {}`
                 let is_empty_arm = |id| {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index 02200d6a4aaf5..50ac6235debc0 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -342,7 +342,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 trait_predicates: trait_predicates.join(", "),
             }
         };
-        err.subdiagnostic(suggestion);
+        err.subdiagnostic(self.dcx(), suggestion);
     }
 
     pub(super) fn report_placeholder_failure(
diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
index 248e1c0fcc878..31e980fdfabe3 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
@@ -84,7 +84,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             start_sp: return_sp.with_hi(return_sp.lo() + BytePos(4)),
             end_sp: return_sp.shrink_to_hi(),
         };
-        err.subdiagnostic(sugg);
+        err.subdiagnostic(self.dcx(), sugg);
 
         let mut starts = Vec::new();
         let mut ends = Vec::new();
@@ -93,7 +93,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             ends.push(span.shrink_to_hi());
         }
         let sugg = SuggestBoxingForReturnImplTrait::BoxReturnExpr { starts, ends };
-        err.subdiagnostic(sugg);
+        err.subdiagnostic(self.dcx(), sugg);
     }
 
     pub(super) fn suggest_tuple_pattern(
@@ -138,7 +138,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                             span_low: cause.span.shrink_to_lo(),
                             span_high: cause.span.shrink_to_hi(),
                         };
-                        diag.subdiagnostic(sugg);
+                        diag.subdiagnostic(self.dcx(), sugg);
                     }
                     _ => {
                         // More than one matching variant.
@@ -147,7 +147,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                             cause_span: cause.span,
                             compatible_variants,
                         };
-                        diag.subdiagnostic(sugg);
+                        diag.subdiagnostic(self.dcx(), sugg);
                     }
                 }
             }
@@ -219,9 +219,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             },
             (_, Some(ty)) if self.same_type_modulo_infer(exp_found.expected, ty) => {
                 // FIXME: Seems like we can't have a suggestion and a note with different spans in a single subdiagnostic
-                diag.subdiagnostic(ConsiderAddingAwait::FutureSugg {
-                    span: exp_span.shrink_to_hi(),
-                });
+                diag.subdiagnostic(
+                    self.dcx(),
+                    ConsiderAddingAwait::FutureSugg { span: exp_span.shrink_to_hi() },
+                );
                 Some(ConsiderAddingAwait::FutureSuggNote { span: exp_span })
             }
             (Some(ty), _) if self.same_type_modulo_infer(ty, exp_found.found) => match cause.code()
@@ -246,7 +247,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             _ => None,
         };
         if let Some(subdiag) = subdiag {
-            diag.subdiagnostic(subdiag);
+            diag.subdiagnostic(self.dcx(), subdiag);
         }
     }
 
@@ -282,7 +283,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         } else {
                             return;
                         };
-                        diag.subdiagnostic(suggestion);
+                        diag.subdiagnostic(self.dcx(), suggestion);
                     }
                 }
             }
@@ -322,15 +323,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     (true, false) => FunctionPointerSuggestion::UseRef { span, fn_name },
                     (false, true) => FunctionPointerSuggestion::RemoveRef { span, fn_name },
                     (true, true) => {
-                        diag.subdiagnostic(FnItemsAreDistinct);
+                        diag.subdiagnostic(self.dcx(), FnItemsAreDistinct);
                         FunctionPointerSuggestion::CastRef { span, fn_name, sig: *sig }
                     }
                     (false, false) => {
-                        diag.subdiagnostic(FnItemsAreDistinct);
+                        diag.subdiagnostic(self.dcx(), FnItemsAreDistinct);
                         FunctionPointerSuggestion::Cast { span, fn_name, sig: *sig }
                     }
                 };
-                diag.subdiagnostic(sugg);
+                diag.subdiagnostic(self.dcx(), sugg);
             }
             (ty::FnDef(did1, args1), ty::FnDef(did2, args2)) => {
                 let expected_sig =
@@ -339,7 +340,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     &(self.normalize_fn_sig)(self.tcx.fn_sig(*did2).instantiate(self.tcx, args2));
 
                 if self.same_type_modulo_infer(*expected_sig, *found_sig) {
-                    diag.subdiagnostic(FnUniqTypes);
+                    diag.subdiagnostic(self.dcx(), FnUniqTypes);
                 }
 
                 if !self.same_type_modulo_infer(*found_sig, *expected_sig)
@@ -368,7 +369,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     }
                 };
 
-                diag.subdiagnostic(sug);
+                diag.subdiagnostic(self.dcx(), sug);
             }
             (ty::FnDef(did, args), ty::FnPtr(sig)) => {
                 let expected_sig =
@@ -387,7 +388,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     format!("{fn_name} as {found_sig}")
                 };
 
-                diag.subdiagnostic(FnConsiderCasting { casting });
+                diag.subdiagnostic(self.dcx(), FnConsiderCasting { casting });
             }
             _ => {
                 return;
@@ -819,7 +820,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         let diag = self.consider_returning_binding_diag(blk, expected_ty);
         match diag {
             Some(diag) => {
-                err.subdiagnostic(diag);
+                err.subdiagnostic(self.dcx(), diag);
                 true
             }
             None => false,
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 7445e2e80b407..2987d8a5ed0b2 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -1758,7 +1758,7 @@ impl<'a> DecorateLint<'a, ()> for UnusedDef<'_, '_> {
             diag.note(note.to_string());
         }
         if let Some(sugg) = self.suggestion {
-            diag.subdiagnostic(sugg);
+            diag.subdiagnostic(diag.dcx, sugg);
         }
     }
 
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
index 85bb9584a0575..ae481efb263df 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
@@ -331,44 +331,7 @@ impl DiagnosticDeriveVariantBuilder {
                 }
             }
             (Meta::Path(_), "subdiagnostic") => {
-                if FieldInnerTy::from_type(&info.binding.ast().ty).will_iterate() {
-                    let DiagnosticDeriveKind::Diagnostic = self.kind else {
-                        // No eager translation for lints.
-                        return Ok(quote! { diag.subdiagnostic(#binding); });
-                    };
-                    return Ok(quote! { diag.eager_subdiagnostic(dcx, #binding); });
-                } else {
-                    return Ok(quote! { diag.subdiagnostic(#binding); });
-                }
-            }
-            (Meta::List(meta_list), "subdiagnostic") => {
-                let err = || {
-                    span_err(
-                        meta_list.span().unwrap(),
-                        "`eager` is the only supported nested attribute for `subdiagnostic`",
-                    )
-                    .emit();
-                };
-
-                let Ok(p): Result<Path, _> = meta_list.parse_args() else {
-                    err();
-                    return Ok(quote! {});
-                };
-
-                if !p.is_ident("eager") {
-                    err();
-                    return Ok(quote! {});
-                }
-
-                match &self.kind {
-                    DiagnosticDeriveKind::Diagnostic => {}
-                    DiagnosticDeriveKind::LintDiagnostic => {
-                        throw_invalid_attr!(attr, |diag| {
-                            diag.help("eager subdiagnostics are not supported on lints")
-                        })
-                    }
-                };
-                return Ok(quote! { diag.eager_subdiagnostic(dcx, #binding); });
+                return Ok(quote! { diag.subdiagnostic(diag.dcx, #binding); });
             }
             _ => (),
         }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 692f4511bb807..a0235f20a0570 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -1109,7 +1109,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
 
     let all_arms_have_guards = arms.iter().all(|arm_id| thir[*arm_id].guard.is_some());
     if !is_empty_match && all_arms_have_guards {
-        err.subdiagnostic(NonExhaustiveMatchAllArmsGuarded);
+        err.subdiagnostic(cx.tcx.dcx(), NonExhaustiveMatchAllArmsGuarded);
     }
     if let Some((span, sugg)) = suggestion {
         err.span_suggestion_verbose(span, msg, sugg, Applicability::HasPlaceholders);
diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs
index 30de40e226c33..ff4918df9a262 100644
--- a/compiler/rustc_mir_transform/src/errors.rs
+++ b/compiler/rustc_mir_transform/src/errors.rs
@@ -270,7 +270,7 @@ impl<'a> DecorateLint<'a, ()> for MustNotSupend<'_, '_> {
     fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) {
         diag.span_label(self.yield_sp, fluent::_subdiag::label);
         if let Some(reason) = self.reason {
-            diag.subdiagnostic(reason);
+            diag.subdiagnostic(diag.dcx, reason);
         }
         diag.span_help(self.src_sp, fluent::_subdiag::help);
         diag.arg("pre", self.pre);
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 445d5b2ce790c..e44c63f1ed760 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -2350,7 +2350,7 @@ impl<'a> Parser<'a> {
         let mut err = self.dcx().struct_span_err(span, msg);
         let sp = self.sess.source_map().start_point(self.token.span);
         if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) {
-            err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
+            err.subdiagnostic(self.dcx(), ExprParenthesesNeeded::surrounding(*sp));
         }
         err.span_label(span, "expected expression");
 
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 1a57474bac289..06134818435ca 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1433,7 +1433,7 @@ impl<'a> Parser<'a> {
                     // If the input is something like `if a { 1 } else { 2 } | if a { 3 } else { 4 }`
                     // then suggest parens around the lhs.
                     if let Some(sp) = this.sess.ambiguous_block_expr_parse.borrow().get(&lo) {
-                        err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
+                        err.subdiagnostic(this.dcx(), ExprParenthesesNeeded::surrounding(*sp));
                     }
                     err
                 })
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 8050b34956ce9..a34adbe7f674d 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1917,7 +1917,7 @@ impl<'a> Parser<'a> {
         if self.token.kind == token::Not {
             if let Err(mut err) = self.unexpected::<FieldDef>() {
                 // Encounter the macro invocation
-                err.subdiagnostic(MacroExpandsToAdtField { adt_ty });
+                err.subdiagnostic(self.dcx(), MacroExpandsToAdtField { adt_ty });
                 return Err(err);
             }
         }
@@ -2336,10 +2336,13 @@ impl<'a> Parser<'a> {
                             .into_iter()
                             .any(|s| self.prev_token.is_ident_named(s));
 
-                        err.subdiagnostic(errors::FnTraitMissingParen {
-                            span: self.prev_token.span,
-                            machine_applicable,
-                        });
+                        err.subdiagnostic(
+                            self.dcx(),
+                            errors::FnTraitMissingParen {
+                                span: self.prev_token.span,
+                                machine_applicable,
+                            },
+                        );
                     }
                     return Err(err);
                 }
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 12260ec95a5b9..75fc013d3e6fe 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -843,7 +843,7 @@ impl<'a> Parser<'a> {
 
         let sp = self.sess.source_map().start_point(self.token.span);
         if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) {
-            err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
+            err.subdiagnostic(self.dcx(), ExprParenthesesNeeded::surrounding(*sp));
         }
 
         Err(err)
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index d91a865e38aba..737481c78db68 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -403,9 +403,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         }
 
         if let Some(suggestion) = suggestion {
-            err.subdiagnostic(ChangeImportBindingSuggestion { span: binding_span, suggestion });
+            err.subdiagnostic(
+                self.dcx(),
+                ChangeImportBindingSuggestion { span: binding_span, suggestion },
+            );
         } else {
-            err.subdiagnostic(ChangeImportBinding { span: binding_span });
+            err.subdiagnostic(self.dcx(), ChangeImportBinding { span: binding_span });
         }
     }
 
@@ -1430,17 +1433,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         );
 
         if macro_kind == MacroKind::Bang && ident.name == sym::macro_rules {
-            err.subdiagnostic(MaybeMissingMacroRulesName { span: ident.span });
+            err.subdiagnostic(self.dcx(), MaybeMissingMacroRulesName { span: ident.span });
             return;
         }
 
         if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
-            err.subdiagnostic(ExplicitUnsafeTraits { span: ident.span, ident });
+            err.subdiagnostic(self.dcx(), ExplicitUnsafeTraits { span: ident.span, ident });
             return;
         }
 
         if self.macro_names.contains(&ident.normalize_to_macros_2_0()) {
-            err.subdiagnostic(AddedMacroUse);
+            err.subdiagnostic(self.dcx(), AddedMacroUse);
             return;
         }
 
@@ -1450,10 +1453,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             let span = self.def_span(def_id);
             let source_map = self.tcx.sess.source_map();
             let head_span = source_map.guess_head_span(span);
-            err.subdiagnostic(ConsiderAddingADerive {
-                span: head_span.shrink_to_lo(),
-                suggestion: "#[derive(Default)]\n".to_string(),
-            });
+            err.subdiagnostic(
+                self.dcx(),
+                ConsiderAddingADerive {
+                    span: head_span.shrink_to_lo(),
+                    suggestion: "#[derive(Default)]\n".to_string(),
+                },
+            );
         }
         for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] {
             if let Ok(binding) = self.early_resolve_ident_in_lexical_scope(
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 30fb35238c3c7..dcd01b9b33417 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -1262,12 +1262,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                             // exclude decl_macro
                             if self.get_macro_by_def_id(def_id).macro_rules =>
                         {
-                            err.subdiagnostic(ConsiderAddingMacroExport {
+                            err.subdiagnostic(self.dcx(), ConsiderAddingMacroExport {
                                 span: binding.span,
                             });
                         }
                         _ => {
-                            err.subdiagnostic(ConsiderMarkingAsPub {
+                            err.subdiagnostic(self.dcx(), ConsiderMarkingAsPub {
                                 span: import.span,
                                 ident,
                             });
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 5d712461993d8..7f0d8374b3abc 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1095,11 +1095,14 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 Side::Start => (segment.ident.span.between(range.span), " @ ".into()),
                 Side::End => (range.span.to(segment.ident.span), format!("{} @ ..", segment.ident)),
             };
-            err.subdiagnostic(errors::UnexpectedResUseAtOpInSlicePatWithRangeSugg {
-                span,
-                ident: segment.ident,
-                snippet,
-            });
+            err.subdiagnostic(
+                self.r.dcx(),
+                errors::UnexpectedResUseAtOpInSlicePatWithRangeSugg {
+                    span,
+                    ident: segment.ident,
+                    snippet,
+                },
+            );
         }
 
         enum Side {
@@ -1191,10 +1194,13 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
         });
 
         if let Some(param) = param {
-            err.subdiagnostic(errors::UnexpectedResChangeTyToConstParamSugg {
-                span: param.shrink_to_lo(),
-                applicability,
-            });
+            err.subdiagnostic(
+                self.r.dcx(),
+                errors::UnexpectedResChangeTyToConstParamSugg {
+                    span: param.shrink_to_lo(),
+                    applicability,
+                },
+            );
         }
     }
 
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index 8adb0cbcc9d76..a906d5532b5a0 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -173,21 +173,21 @@ pub fn add_feature_diagnostics_for_issue(
     feature_from_cli: bool,
 ) {
     if let Some(n) = find_feature_issue(feature, issue) {
-        err.subdiagnostic(FeatureDiagnosticForIssue { n });
+        err.subdiagnostic(sess.dcx(), FeatureDiagnosticForIssue { n });
     }
 
     // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
     if sess.parse_sess.unstable_features.is_nightly_build() {
         if feature_from_cli {
-            err.subdiagnostic(CliFeatureDiagnosticHelp { feature });
+            err.subdiagnostic(sess.dcx(), CliFeatureDiagnosticHelp { feature });
         } else {
-            err.subdiagnostic(FeatureDiagnosticHelp { feature });
+            err.subdiagnostic(sess.dcx(), FeatureDiagnosticHelp { feature });
         }
 
         if sess.opts.unstable_opts.ui_testing {
-            err.subdiagnostic(SuggestUpgradeCompiler::ui_testing());
+            err.subdiagnostic(sess.dcx(), SuggestUpgradeCompiler::ui_testing());
         } else if let Some(suggestion) = SuggestUpgradeCompiler::new() {
-            err.subdiagnostic(suggestion);
+            err.subdiagnostic(sess.dcx(), suggestion);
         }
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index c7b56aac7e55b..a8b6fc1f12c26 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -4830,11 +4830,14 @@ fn hint_missing_borrow<'tcx>(
     }
 
     if !to_borrow.is_empty() {
-        err.subdiagnostic(errors::AdjustSignatureBorrow::Borrow { to_borrow });
+        err.subdiagnostic(infcx.dcx(), errors::AdjustSignatureBorrow::Borrow { to_borrow });
     }
 
     if !remove_borrow.is_empty() {
-        err.subdiagnostic(errors::AdjustSignatureBorrow::RemoveBorrow { remove_borrow });
+        err.subdiagnostic(
+            infcx.dcx(),
+            errors::AdjustSignatureBorrow::RemoveBorrow { remove_borrow },
+        );
     }
 }
 
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index 7f91af59d5622..ed401d5751b69 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -504,7 +504,7 @@ pub fn report_msg<'tcx>(
         let is_local = machine.is_local(frame_info);
         // No span for non-local frames and the first frame (which is the error site).
         if is_local && idx > 0 {
-            err.eager_subdiagnostic(err.dcx, frame_info.as_note(machine.tcx));
+            err.subdiagnostic(err.dcx, frame_info.as_note(machine.tcx));
         } else {
             let sm = sess.source_map();
             let span = sm.span_to_embeddable_string(frame_info.span);
diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs
index f0af401d3da4b..cff025cf2ab3a 100644
--- a/src/tools/rustfmt/src/parse/session.rs
+++ b/src/tools/rustfmt/src/parse/session.rs
@@ -1,3 +1,4 @@
+use std::borrow::Cow;
 use std::path::Path;
 use std::sync::atomic::{AtomicBool, Ordering};
 
@@ -40,6 +41,16 @@ impl Translate for SilentEmitter {
     fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle {
         panic!("silent emitter attempted to translate a diagnostic");
     }
+
+    // Override `translate_message` for the silent emitter because eager translation of
+    // subdiagnostics result in a call to this.
+    fn translate_message<'a>(
+        &'a self,
+        message: &'a rustc_errors::DiagnosticMessage,
+        _: &'a rustc_errors::translation::FluentArgs<'_>,
+    ) -> Result<Cow<'_, str>, rustc_errors::error::TranslateError<'_>> {
+        rustc_errors::emitter::silent_translate(message)
+    }
 }
 
 impl Emitter for SilentEmitter {
diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
index d3cfd28082d61..6cc6fdfc0eb2b 100644
--- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
+++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
@@ -701,7 +701,7 @@ struct RawIdentDiagnosticArg {
 #[diag(no_crate_example)]
 struct SubdiagnosticBad {
     #[subdiagnostic(bad)]
-    //~^ ERROR `eager` is the only supported nested attribute for `subdiagnostic`
+    //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
     note: Note,
 }
 
@@ -717,7 +717,7 @@ struct SubdiagnosticBadStr {
 #[diag(no_crate_example)]
 struct SubdiagnosticBadTwice {
     #[subdiagnostic(bad, bad)]
-    //~^ ERROR `eager` is the only supported nested attribute for `subdiagnostic`
+    //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
     note: Note,
 }
 
@@ -725,7 +725,7 @@ struct SubdiagnosticBadTwice {
 #[diag(no_crate_example)]
 struct SubdiagnosticBadLitStr {
     #[subdiagnostic("bad")]
-    //~^ ERROR `eager` is the only supported nested attribute for `subdiagnostic`
+    //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
     note: Note,
 }
 
@@ -739,8 +739,9 @@ struct SubdiagnosticEagerLint {
 
 #[derive(Diagnostic)]
 #[diag(no_crate_example)]
-struct SubdiagnosticEagerCorrect {
+struct SubdiagnosticEagerFormerlyCorrect {
     #[subdiagnostic(eager)]
+    //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
     note: Note,
 }
 
@@ -761,6 +762,7 @@ pub(crate) struct SubdiagnosticWithSuggestion {
 #[diag(no_crate_example)]
 struct SubdiagnosticEagerSuggestion {
     #[subdiagnostic(eager)]
+    //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
     sub: SubdiagnosticWithSuggestion,
 }
 
diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
index 2032b8a972a3b..f2dbc718c7627 100644
--- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
+++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
@@ -468,11 +468,11 @@ LL | #[label]
    |
    = help: `#[label]` and `#[suggestion]` can only be applied to fields
 
-error: `eager` is the only supported nested attribute for `subdiagnostic`
-  --> $DIR/diagnostic-derive.rs:703:7
+error: `#[subdiagnostic(...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:703:5
    |
 LL |     #[subdiagnostic(bad)]
-   |       ^^^^^^^^^^^^^
+   |     ^
 
 error: `#[subdiagnostic = ...]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:711:5
@@ -480,40 +480,50 @@ error: `#[subdiagnostic = ...]` is not a valid attribute
 LL |     #[subdiagnostic = "bad"]
    |     ^
 
-error: `eager` is the only supported nested attribute for `subdiagnostic`
-  --> $DIR/diagnostic-derive.rs:719:7
+error: `#[subdiagnostic(...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:719:5
    |
 LL |     #[subdiagnostic(bad, bad)]
-   |       ^^^^^^^^^^^^^
+   |     ^
 
-error: `eager` is the only supported nested attribute for `subdiagnostic`
-  --> $DIR/diagnostic-derive.rs:727:7
+error: `#[subdiagnostic(...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:727:5
    |
 LL |     #[subdiagnostic("bad")]
-   |       ^^^^^^^^^^^^^
+   |     ^
 
 error: `#[subdiagnostic(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:735:5
    |
 LL |     #[subdiagnostic(eager)]
    |     ^
+
+error: `#[subdiagnostic(...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:743:5
    |
-   = help: eager subdiagnostics are not supported on lints
+LL |     #[subdiagnostic(eager)]
+   |     ^
+
+error: `#[subdiagnostic(...)]` is not a valid attribute
+  --> $DIR/diagnostic-derive.rs:764:5
+   |
+LL |     #[subdiagnostic(eager)]
+   |     ^
 
 error: expected at least one string literal for `code(...)`
-  --> $DIR/diagnostic-derive.rs:793:23
+  --> $DIR/diagnostic-derive.rs:795:23
    |
 LL |     #[suggestion(code())]
    |                       ^
 
 error: `code(...)` must contain only string literals
-  --> $DIR/diagnostic-derive.rs:801:23
+  --> $DIR/diagnostic-derive.rs:803:23
    |
 LL |     #[suggestion(code(foo))]
    |                       ^^^
 
 error: `#[suggestion(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:825:5
+  --> $DIR/diagnostic-derive.rs:827:5
    |
 LL |     #[suggestion(no_crate_suggestion, code = "")]
    |     ^
@@ -529,13 +539,13 @@ LL | #[diag = "E0123"]
    |        ^ maybe a missing crate `core`?
 
 error[E0433]: failed to resolve: maybe a missing crate `core`?
-  --> $DIR/diagnostic-derive.rs:801:23
+  --> $DIR/diagnostic-derive.rs:803:23
    |
 LL |     #[suggestion(code(foo))]
    |                       ^^^ maybe a missing crate `core`?
 
 error[E0433]: failed to resolve: maybe a missing crate `core`?
-  --> $DIR/diagnostic-derive.rs:810:25
+  --> $DIR/diagnostic-derive.rs:812:25
    |
 LL |     #[suggestion(code = 3)]
    |                         ^ maybe a missing crate `core`?
@@ -601,7 +611,7 @@ LL | #[diag(nonsense, code = E0123)]
    |        ^^^^^^^^ not found in `crate::fluent_generated`
 
 error[E0425]: cannot find value `__code_34` in this scope
-  --> $DIR/diagnostic-derive.rs:807:10
+  --> $DIR/diagnostic-derive.rs:809:10
    |
 LL | #[derive(Diagnostic)]
    |          ^^^^^^^^^^ not found in this scope
@@ -622,7 +632,7 @@ note: required by a bound in `DiagnosticBuilder::<'a, G>::arg`
   --> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:LL:CC
    = note: this error originates in the macro `forward` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 84 previous errors
+error: aborting due to 86 previous errors
 
 Some errors have detailed explanations: E0277, E0425, E0433.
 For more information about an error, try `rustc --explain E0277`.

From bd546fb20a2d299a0a2e9c2062df9227e82bdb65 Mon Sep 17 00:00:00 2001
From: yukang <moorekang@gmail.com>
Date: Thu, 15 Feb 2024 01:06:27 +0800
Subject: [PATCH 43/58] add extra indent spaces for rust-playground link

---
 src/librustdoc/doctest.rs       | 18 ++++++++++++--
 src/librustdoc/doctest/tests.rs | 44 ++++++++++++++++++++++++++++++++-
 src/librustdoc/html/markdown.rs |  7 ++++--
 tests/rustdoc/playground-arg.rs |  2 +-
 tests/rustdoc/playground.rs     |  2 +-
 5 files changed, 66 insertions(+), 7 deletions(-)

diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index f2e083de0ec74..f9d4d1af1140f 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -40,6 +40,9 @@ use crate::lint::init_lints;
 pub(crate) struct GlobalTestOptions {
     /// Whether to disable the default `extern crate my_crate;` when creating doctests.
     pub(crate) no_crate_inject: bool,
+    /// Whether inserting extra indent spaces in code block,
+    /// default is `false`, only `true` for generating code link of Rust playground
+    pub(crate) insert_indent_space: bool,
     /// Additional crate-level attributes to add to doctests.
     pub(crate) attrs: Vec<String>,
 }
@@ -221,7 +224,8 @@ pub(crate) fn run_tests(
 fn scrape_test_config(attrs: &[ast::Attribute]) -> GlobalTestOptions {
     use rustc_ast_pretty::pprust;
 
-    let mut opts = GlobalTestOptions { no_crate_inject: false, attrs: Vec::new() };
+    let mut opts =
+        GlobalTestOptions { no_crate_inject: false, attrs: Vec::new(), insert_indent_space: false };
 
     let test_attrs: Vec<_> = attrs
         .iter()
@@ -725,7 +729,17 @@ pub(crate) fn make_test(
         // /// ``` <- end of the inner main
         line_offset += 1;
 
-        prog.extend([&main_pre, everything_else, &main_post].iter().cloned());
+        // add extra 4 spaces for each line to offset the code block
+        let content = if opts.insert_indent_space {
+            everything_else
+                .lines()
+                .map(|line| format!("    {}", line))
+                .collect::<Vec<String>>()
+                .join("\n")
+        } else {
+            everything_else.to_string()
+        };
+        prog.extend([&main_pre, content.as_str(), &main_post].iter().cloned());
     }
 
     debug!("final doctest:\n{prog}");
diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs
index a30fe28f94f99..9629acb31eb68 100644
--- a/src/librustdoc/doctest/tests.rs
+++ b/src/librustdoc/doctest/tests.rs
@@ -53,7 +53,8 @@ assert_eq!(2+2, 4);
 fn make_test_no_crate_inject() {
     // Even if you do use the crate within the test, setting `opts.no_crate_inject` will skip
     // adding it anyway.
-    let opts = GlobalTestOptions { no_crate_inject: true, attrs: vec![] };
+    let opts =
+        GlobalTestOptions { no_crate_inject: true, attrs: vec![], insert_indent_space: false };
     let input = "use asdf::qwop;
 assert_eq!(2+2, 4);";
     let expected = "#![allow(unused)]
@@ -302,3 +303,44 @@ assert_eq!(2+2, 4);
         make_test(input, None, false, &opts, DEFAULT_EDITION, Some("_some_unique_name"));
     assert_eq!((output, len), (expected, 2));
 }
+
+#[test]
+fn make_test_insert_extra_space() {
+    // will insert indent spaces in the code block if `insert_indent_space` is true
+    let opts =
+        GlobalTestOptions { no_crate_inject: false, attrs: vec![], insert_indent_space: true };
+    let input = "use std::*;
+assert_eq!(2+2, 4);
+eprintln!(\"hello anan\");
+";
+    let expected = "#![allow(unused)]
+fn main() {
+    use std::*;
+    assert_eq!(2+2, 4);
+    eprintln!(\"hello anan\");
+}"
+    .to_string();
+    let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None);
+    assert_eq!((output, len), (expected, 2));
+}
+
+#[test]
+fn make_test_insert_extra_space_fn_main() {
+    // if input already has a fn main, it should insert a space before it
+    let opts =
+        GlobalTestOptions { no_crate_inject: false, attrs: vec![], insert_indent_space: true };
+    let input = "use std::*;
+fn main() {
+    assert_eq!(2+2, 4);
+    eprintln!(\"hello anan\");
+}";
+    let expected = "#![allow(unused)]
+use std::*;
+fn main() {
+    assert_eq!(2+2, 4);
+    eprintln!(\"hello anan\");
+}"
+    .to_string();
+    let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None);
+    assert_eq!((output, len), (expected, 1));
+}
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index ee5891c12fc5a..21f682d15b97d 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -45,6 +45,7 @@ use std::str::{self, CharIndices};
 
 use crate::clean::RenderedLink;
 use crate::doctest;
+use crate::doctest::GlobalTestOptions;
 use crate::html::escape::Escape;
 use crate::html::format::Buffer;
 use crate::html::highlight;
@@ -302,8 +303,10 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
                 .intersperse("\n".into())
                 .collect::<String>();
             let krate = krate.as_ref().map(|s| s.as_str());
-            let (test, _, _) =
-                doctest::make_test(&test, krate, false, &Default::default(), edition, None);
+
+            let mut opts: GlobalTestOptions = Default::default();
+            opts.insert_indent_space = true;
+            let (test, _, _) = doctest::make_test(&test, krate, false, &opts, edition, None);
             let channel = if test.contains("#![feature(") { "&amp;version=nightly" } else { "" };
 
             let test_escaped = small_url_encode(test);
diff --git a/tests/rustdoc/playground-arg.rs b/tests/rustdoc/playground-arg.rs
index 2542ed657c1a7..1d7085064e5ac 100644
--- a/tests/rustdoc/playground-arg.rs
+++ b/tests/rustdoc/playground-arg.rs
@@ -10,4 +10,4 @@
 pub fn dummy() {}
 
 // ensure that `extern crate foo;` was inserted into code snips automatically:
-// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0A%23%5Ballow(unused_extern_crates)%5D%0Aextern+crate+r%23foo;%0Afn+main()+%7B%0Ause+foo::dummy;%0Adummy();%0A%7D&edition=2015"]' "Run"
+// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0A%23%5Ballow(unused_extern_crates)%5D%0Aextern+crate+r%23foo;%0Afn+main()+%7B%0A++++use+foo::dummy;%0A++++dummy();%0A%7D&edition=2015"]' "Run"
diff --git a/tests/rustdoc/playground.rs b/tests/rustdoc/playground.rs
index 5c7fa33efc5e5..a2fc9eb7387aa 100644
--- a/tests/rustdoc/playground.rs
+++ b/tests/rustdoc/playground.rs
@@ -22,6 +22,6 @@
 //! }
 //! ```
 
-// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0Aprintln!(%22Hello,+world!%22);%0A%7D&edition=2015"]' "Run"
+// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&edition=2015"]' "Run"
 // @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&edition=2015"]' "Run"
 // @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&version=nightly&edition=2015"]' "Run"

From b277772451805f35c02500b020eedf49742eae08 Mon Sep 17 00:00:00 2001
From: Obei Sideg <obei.sideg@gmail.com>
Date: Thu, 15 Feb 2024 14:29:13 +0300
Subject: [PATCH 44/58] Improve wording of static_mut_ref

Rename `static_mut_ref` lint to `static_mut_refs`.
---
 .../example/mini_core_hello_world.rs          |  4 +-
 .../example/mini_core_hello_world.rs          |  4 +-
 .../src/error_codes/E0796.md                  | 26 +++---
 compiler/rustc_hir_analysis/messages.ftl      | 31 ++++---
 compiler/rustc_hir_analysis/src/check/errs.rs | 28 ++----
 compiler/rustc_hir_analysis/src/errors.rs     | 28 ++----
 compiler/rustc_lint/src/lib.rs                |  1 +
 compiler/rustc_lint_defs/src/builtin.rs       |  8 +-
 library/panic_unwind/src/seh.rs               |  8 +-
 library/std/src/panicking.rs                  |  5 +-
 .../sys/pal/common/thread_local/fast_local.rs |  5 +-
 .../pal/common/thread_local/static_local.rs   |  4 +-
 library/std/src/thread/local.rs               |  4 +-
 .../miri/tests/fail/tls/tls_static_dealloc.rs |  4 +-
 src/tools/miri/tests/pass/static_mut.rs       |  4 +-
 src/tools/miri/tests/pass/tls/tls_static.rs   |  4 +-
 tests/ui/abi/statics/static-mut-foreign.rs    |  4 +-
 .../ui/abi/statics/static-mut-foreign.stderr  | 22 ++---
 .../borrowck/borrowck-access-permissions.rs   |  2 +-
 .../borrowck-access-permissions.stderr        | 12 +--
 .../borrowck-unsafe-static-mutable-borrows.rs |  2 +-
 ...rowck-unsafe-static-mutable-borrows.stderr | 12 +--
 tests/ui/borrowck/issue-20801.rs              |  2 +-
 tests/ui/borrowck/issue-20801.stderr          | 12 +--
 ...ue-55492-borrowck-migrate-scans-parents.rs |  6 +-
 ...5492-borrowck-migrate-scans-parents.stderr | 32 +++----
 tests/ui/consts/const_let_assign2.rs          |  2 +-
 tests/ui/consts/const_let_assign2.stderr      | 12 +--
 .../const_refs_to_static_fail_invalid.rs      |  6 +-
 .../const_refs_to_static_fail_invalid.stderr  |  2 +-
 .../ui/consts/issue-17718-const-bad-values.rs |  2 +-
 .../const_refers_to_static_cross_crate.rs     |  2 +-
 .../ui/consts/miri_unleashed/extern-static.rs |  2 +-
 .../miri_unleashed/mutable_references_err.rs  |  2 +-
 .../static-promoted-to-mutable-static.rs      |  2 +-
 .../consts/static_mut_containing_mut_ref.rs   |  2 +-
 .../consts/static_mut_containing_mut_ref2.rs  |  2 +-
 .../issue-23338-ensure-param-drop-order.rs    |  2 +-
 ...issue-23338-ensure-param-drop-order.stderr | 12 +--
 tests/ui/error-codes/E0017.rs                 |  2 +-
 tests/ui/error-codes/E0017.stderr             | 12 +--
 .../issues/issue-23611-enum-swap-in-drop.rs   |  2 +-
 .../issue-23611-enum-swap-in-drop.stderr      | 12 +--
 tests/ui/issues/issue-54410.rs                |  2 +-
 tests/ui/issues/issue-54410.stderr            | 12 +--
 ...ead-local-static-mut-borrow-outlives-fn.rs |  2 +-
 ...local-static-mut-borrow-outlives-fn.stderr | 12 +--
 .../reference-of-mut-static-safe.e2021.stderr | 26 ------
 .../reference-of-mut-static-safe.e2024.stderr | 15 ---
 .../reference-of-mut-static-unsafe-fn.rs      | 23 -----
 .../reference-of-mut-static-unsafe-fn.stderr  | 63 -------------
 .../reference-of-mut-static.e2021.stderr      | 91 -------------------
 .../reference-of-mut-static.e2024.stderr      | 75 ---------------
 tests/ui/static/reference-of-mut-static.rs    | 50 ----------
 .../reference-to-mut-static-safe.e2021.stderr | 26 ++++++
 .../reference-to-mut-static-safe.e2024.stderr | 15 +++
 ...afe.rs => reference-to-mut-static-safe.rs} |  4 +-
 .../reference-to-mut-static-unsafe-fn.rs      | 26 ++++++
 .../reference-to-mut-static-unsafe-fn.stderr  | 75 +++++++++++++++
 .../reference-to-mut-static.e2021.stderr      | 91 +++++++++++++++++++
 .../reference-to-mut-static.e2024.stderr      | 75 +++++++++++++++
 tests/ui/static/reference-to-mut-static.rs    | 50 ++++++++++
 tests/ui/static/safe-extern-statics-mut.rs    |  4 +-
 .../ui/static/safe-extern-statics-mut.stderr  | 22 ++---
 tests/ui/statics/issue-15261.rs               |  2 +-
 tests/ui/statics/issue-15261.stderr           | 12 +--
 tests/ui/statics/static-mut-xc.rs             |  4 +-
 tests/ui/statics/static-mut-xc.stderr         | 22 ++---
 tests/ui/statics/static-recursive.rs          |  2 +-
 tests/ui/statics/static-recursive.stderr      | 12 +--
 tests/ui/thread-local/thread-local-static.rs  |  2 +-
 71 files changed, 586 insertions(+), 581 deletions(-)
 delete mode 100644 tests/ui/static/reference-of-mut-static-safe.e2021.stderr
 delete mode 100644 tests/ui/static/reference-of-mut-static-safe.e2024.stderr
 delete mode 100644 tests/ui/static/reference-of-mut-static-unsafe-fn.rs
 delete mode 100644 tests/ui/static/reference-of-mut-static-unsafe-fn.stderr
 delete mode 100644 tests/ui/static/reference-of-mut-static.e2021.stderr
 delete mode 100644 tests/ui/static/reference-of-mut-static.e2024.stderr
 delete mode 100644 tests/ui/static/reference-of-mut-static.rs
 create mode 100644 tests/ui/static/reference-to-mut-static-safe.e2021.stderr
 create mode 100644 tests/ui/static/reference-to-mut-static-safe.e2024.stderr
 rename tests/ui/static/{reference-of-mut-static-safe.rs => reference-to-mut-static-safe.rs} (62%)
 create mode 100644 tests/ui/static/reference-to-mut-static-unsafe-fn.rs
 create mode 100644 tests/ui/static/reference-to-mut-static-unsafe-fn.stderr
 create mode 100644 tests/ui/static/reference-to-mut-static.e2021.stderr
 create mode 100644 tests/ui/static/reference-to-mut-static.e2024.stderr
 create mode 100644 tests/ui/static/reference-to-mut-static.rs

diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
index 2a7b1107ffcaa..8b0b9123ac7df 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
@@ -112,8 +112,8 @@ fn start<T: Termination + 'static>(
 
 static mut NUM: u8 = 6 * 7;
 
-// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint
-#[allow(static_mut_ref)]
+// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
+#[allow(static_mut_refs)]
 static NUM_REF: &'static u8 = unsafe { &NUM };
 
 unsafe fn zeroed<T>() -> T {
diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
index 9827e299f2a31..add77880716c8 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
@@ -99,8 +99,8 @@ fn start<T: Termination + 'static>(
 
 static mut NUM: u8 = 6 * 7;
 
-// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint
-#[allow(static_mut_ref)]
+// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
+#[allow(static_mut_refs)]
 static NUM_REF: &'static u8 = unsafe { &NUM };
 
 macro_rules! assert {
diff --git a/compiler/rustc_error_codes/src/error_codes/E0796.md b/compiler/rustc_error_codes/src/error_codes/E0796.md
index cea18f8db851f..7ac429e521581 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0796.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0796.md
@@ -1,22 +1,26 @@
-Reference of mutable static.
+You have created a reference to a mutable static.
 
 Erroneous code example:
 
 ```compile_fail,edition2024,E0796
 static mut X: i32 = 23;
-static mut Y: i32 = 24;
 
-unsafe {
-  let y = &X;
-  let ref x = X;
-  let (x, y) = (&X, &Y);
-  foo(&X);
+fn work() {
+  let _val = unsafe { X };
 }
 
-fn foo<'a>(_x: &'a i32) {}
+let x_ref = unsafe { &mut X };
+work();
+// The next line has Undefined Behavior!
+// `x_ref` is a mutable reference and allows no aliases,
+// but `work` has been reading the reference between
+// the moment `x_ref` was created and when it was used.
+// This violates the uniqueness of `x_ref`.
+*x_ref = 42;
 ```
 
-Mutable statics can be written to by multiple threads: aliasing violations or
-data races will cause undefined behavior.
+A reference to a mutable static has lifetime `'static`. This is very dangerous
+as it is easy to accidentally overlap the lifetime of that reference with
+other, conflicting accesses to the same static.
 
-Reference of mutable static is a hard error from 2024 edition.
+References to mutable statics are a hard error in the 2024 edition.
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index a61cfd0e4ce9a..99f7ab2fa4d9c 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -373,19 +373,24 @@ hir_analysis_start_not_target_feature = `#[start]` function is not allowed to ha
 hir_analysis_start_not_track_caller = `#[start]` function is not allowed to be `#[track_caller]`
     .label = `#[start]` function is not allowed to be `#[track_caller]`
 
-hir_analysis_static_mut_ref = reference of mutable static is disallowed
-    .label = reference of mutable static
-    .note = mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-    .suggestion = shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
-    .suggestion_mut = mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
-
-hir_analysis_static_mut_ref_lint = {$shared}reference of mutable static is discouraged
-    .label = shared reference of mutable static
-    .label_mut = mutable reference of mutable static
-    .suggestion = shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
-    .suggestion_mut = mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
-    .note = reference of mutable static is a hard error from 2024 edition
-    .why_note = mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
+hir_analysis_static_mut_ref = creating a {$shared} reference to a mutable static
+    .label = {$shared}reference to mutable static
+    .note = {$shared ->
+        [shared] this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+        *[mutable] this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+    }
+    .suggestion = use `addr_of!` instead to create a raw pointer
+    .suggestion_mut = use `addr_of_mut!` instead to create a raw pointer
+
+hir_analysis_static_mut_refs_lint = creating a {$shared} reference to mutable static is discouraged
+    .label = {$shared} reference to mutable static
+    .suggestion = use `addr_of!` instead to create a raw pointer
+    .suggestion_mut = use `addr_of_mut!` instead to create a raw pointer
+    .note = this will be a hard error in the 2024 edition
+    .why_note = {$shared ->
+        [shared] this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+        *[mutable] this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+    }
 
 hir_analysis_static_specialize = cannot specialize on `'static` lifetime
 
diff --git a/compiler/rustc_hir_analysis/src/check/errs.rs b/compiler/rustc_hir_analysis/src/check/errs.rs
index 87a1f3d342580..4a7ace274c5bb 100644
--- a/compiler/rustc_hir_analysis/src/check/errs.rs
+++ b/compiler/rustc_hir_analysis/src/check/errs.rs
@@ -1,6 +1,6 @@
 use rustc_hir as hir;
 use rustc_hir_pretty::qpath_to_string;
-use rustc_lint_defs::builtin::STATIC_MUT_REF;
+use rustc_lint_defs::builtin::STATIC_MUT_REFS;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::Span;
 use rustc_type_ir::Mutability;
@@ -66,32 +66,24 @@ fn handle_static_mut_ref(
     hir_id: hir::HirId,
 ) {
     if e2024 {
-        let sugg = if mutable {
-            errors::StaticMutRefSugg::Mut { span, var }
+        let (sugg, shared) = if mutable {
+            (errors::StaticMutRefSugg::Mut { span, var }, "mutable")
         } else {
-            errors::StaticMutRefSugg::Shared { span, var }
+            (errors::StaticMutRefSugg::Shared { span, var }, "shared")
         };
-        tcx.sess.parse_sess.dcx.emit_err(errors::StaticMutRef { span, sugg });
+        tcx.sess.parse_sess.dcx.emit_err(errors::StaticMutRef { span, sugg, shared });
         return;
     }
 
-    let (label, sugg, shared) = if mutable {
-        (
-            errors::RefOfMutStaticLabel::Mut { span },
-            errors::RefOfMutStaticSugg::Mut { span, var },
-            "mutable ",
-        )
+    let (sugg, shared) = if mutable {
+        (errors::RefOfMutStaticSugg::Mut { span, var }, "mutable")
     } else {
-        (
-            errors::RefOfMutStaticLabel::Shared { span },
-            errors::RefOfMutStaticSugg::Shared { span, var },
-            "shared ",
-        )
+        (errors::RefOfMutStaticSugg::Shared { span, var }, "shared")
     };
     tcx.emit_node_span_lint(
-        STATIC_MUT_REF,
+        STATIC_MUT_REFS,
         hir_id,
         span,
-        errors::RefOfMutStatic { shared, why_note: (), label, sugg },
+        errors::RefOfMutStatic { span, sugg, shared },
     );
 }
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 6a505b961974f..a8fd311df4321 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1455,12 +1455,13 @@ pub struct OnlyCurrentTraitsPointerSugg<'a> {
 #[derive(Diagnostic)]
 #[diag(hir_analysis_static_mut_ref, code = E0796)]
 #[note]
-pub struct StaticMutRef {
+pub struct StaticMutRef<'a> {
     #[primary_span]
     #[label]
     pub span: Span,
     #[subdiagnostic]
     pub sugg: StaticMutRefSugg,
+    pub shared: &'a str,
 }
 
 #[derive(Subdiagnostic)]
@@ -1491,30 +1492,15 @@ pub enum StaticMutRefSugg {
 
 // STATIC_MUT_REF lint
 #[derive(LintDiagnostic)]
-#[diag(hir_analysis_static_mut_ref_lint)]
+#[diag(hir_analysis_static_mut_refs_lint)]
 #[note]
+#[note(hir_analysis_why_note)]
 pub struct RefOfMutStatic<'a> {
-    pub shared: &'a str,
-    #[note(hir_analysis_why_note)]
-    pub why_note: (),
-    #[subdiagnostic]
-    pub label: RefOfMutStaticLabel,
+    #[label]
+    pub span: Span,
     #[subdiagnostic]
     pub sugg: RefOfMutStaticSugg,
-}
-
-#[derive(Subdiagnostic)]
-pub enum RefOfMutStaticLabel {
-    #[label(hir_analysis_label)]
-    Shared {
-        #[primary_span]
-        span: Span,
-    },
-    #[label(hir_analysis_label_mut)]
-    Mut {
-        #[primary_span]
-        span: Span,
-    },
+    pub shared: &'a str,
 }
 
 #[derive(Subdiagnostic)]
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 5f769e9ad8a5b..0598a5de06342 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -324,6 +324,7 @@ fn register_builtins(store: &mut LintStore) {
     store.register_renamed("or_patterns_back_compat", "rust_2021_incompatible_or_patterns");
     store.register_renamed("non_fmt_panic", "non_fmt_panics");
     store.register_renamed("unused_tuple_struct_fields", "dead_code");
+    store.register_renamed("static_mut_ref", "static_mut_refs");
 
     // These were moved to tool lints, but rustc still sees them when compiling normally, before
     // tool lints are registered, so `check_tool_name_for_backwards_compat` doesn't work. Use
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 6a2a2c1e48e2a..3f5d3c2597151 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -89,7 +89,7 @@ declare_lint_pass! {
         SINGLE_USE_LIFETIMES,
         SOFT_UNSTABLE,
         STABLE_FEATURES,
-        STATIC_MUT_REF,
+        STATIC_MUT_REFS,
         SUSPICIOUS_AUTO_TRAIT_IMPLS,
         TEST_UNSTABLE_LINT,
         TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
@@ -1769,7 +1769,7 @@ declare_lint! {
 }
 
 declare_lint! {
-    /// The `static_mut_ref` lint checks for shared or mutable references
+    /// The `static_mut_refs` lint checks for shared or mutable references
     /// of mutable static inside `unsafe` blocks and `unsafe` functions.
     ///
     /// ### Example
@@ -1807,9 +1807,9 @@ declare_lint! {
     /// Shared or mutable references of mutable static are almost always a mistake and
     /// can lead to undefined behavior and various other problems in your code.
     ///
-    /// This lint is "warn" by default on editions up to 2021, from 2024 there is
+    /// This lint is "warn" by default on editions up to 2021, in 2024 there is
     /// a hard error instead.
-    pub STATIC_MUT_REF,
+    pub STATIC_MUT_REFS,
     Warn,
     "shared references or mutable references of mutable static is discouraged",
     @future_incompatible = FutureIncompatibleInfo {
diff --git a/library/panic_unwind/src/seh.rs b/library/panic_unwind/src/seh.rs
index d3ba546d730d4..876954ab87e85 100644
--- a/library/panic_unwind/src/seh.rs
+++ b/library/panic_unwind/src/seh.rs
@@ -261,8 +261,8 @@ cfg_if::cfg_if! {
    }
 }
 
-// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint
-#[allow(static_mut_ref)]
+// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
+#[allow(static_mut_refs)]
 pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
     use core::intrinsics::atomic_store_seqcst;
 
@@ -324,8 +324,8 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
     _CxxThrowException(throw_ptr, &mut THROW_INFO as *mut _ as *mut _);
 }
 
-// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint
-#[allow(static_mut_ref)]
+// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
+#[allow(static_mut_refs)]
 pub unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send> {
     // A null payload here means that we got here from the catch (...) of
     // __rust_try. This happens when a non-Rust foreign exception is caught.
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index 8294160b72ca7..c8306c1b597a3 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -337,8 +337,9 @@ pub mod panic_count {
 #[doc(hidden)]
 #[cfg(not(feature = "panic_immediate_abort"))]
 #[unstable(feature = "update_panic_count", issue = "none")]
-// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint
-#[allow(static_mut_ref)]
+// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
+#[cfg_attr(bootstrap, allow(static_mut_ref))]
+#[cfg_attr(not(bootstrap), allow(static_mut_refs))]
 pub mod panic_count {
     use crate::cell::Cell;
     use crate::sync::atomic::{AtomicUsize, Ordering};
diff --git a/library/std/src/sys/pal/common/thread_local/fast_local.rs b/library/std/src/sys/pal/common/thread_local/fast_local.rs
index 04c0dd6f75090..646dcd7f3a3e8 100644
--- a/library/std/src/sys/pal/common/thread_local/fast_local.rs
+++ b/library/std/src/sys/pal/common/thread_local/fast_local.rs
@@ -13,8 +13,9 @@ pub macro thread_local_inner {
     (@key $t:ty, const $init:expr) => {{
         #[inline]
         #[deny(unsafe_op_in_unsafe_fn)]
-        // FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint
-        #[allow(static_mut_ref)]
+        // FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
+        #[cfg_attr(bootstrap, allow(static_mut_ref))]
+        #[cfg_attr(not(bootstrap), allow(static_mut_refs))]
         unsafe fn __getit(
             _init: $crate::option::Option<&mut $crate::option::Option<$t>>,
         ) -> $crate::option::Option<&'static $t> {
diff --git a/library/std/src/sys/pal/common/thread_local/static_local.rs b/library/std/src/sys/pal/common/thread_local/static_local.rs
index 0dde78b14dbb8..206e62bb5e2c8 100644
--- a/library/std/src/sys/pal/common/thread_local/static_local.rs
+++ b/library/std/src/sys/pal/common/thread_local/static_local.rs
@@ -11,8 +11,8 @@ pub macro thread_local_inner {
     (@key $t:ty, const $init:expr) => {{
         #[inline] // see comments below
         #[deny(unsafe_op_in_unsafe_fn)]
-        // FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint
-        #[allow(static_mut_ref)]
+        // FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
+        #[allow(static_mut_refs)]
         unsafe fn __getit(
             _init: $crate::option::Option<&mut $crate::option::Option<$t>>,
         ) -> $crate::option::Option<&'static $t> {
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index 83d5d63556fc3..d1213e2f16686 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -180,8 +180,8 @@ impl<T: 'static> fmt::Debug for LocalKey<T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "thread_local_macro")]
 #[allow_internal_unstable(thread_local_internals)]
-// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint
-#[allow(static_mut_ref)]
+// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
+#[cfg_attr(not(bootstrap), allow(static_mut_refs))]
 macro_rules! thread_local {
     // empty (base case for the recursion)
     () => {};
diff --git a/src/tools/miri/tests/fail/tls/tls_static_dealloc.rs b/src/tools/miri/tests/fail/tls/tls_static_dealloc.rs
index 762a8d85314f2..d47a05d8475cf 100644
--- a/src/tools/miri/tests/fail/tls/tls_static_dealloc.rs
+++ b/src/tools/miri/tests/fail/tls/tls_static_dealloc.rs
@@ -1,8 +1,8 @@
 //! Ensure that thread-local statics get deallocated when the thread dies.
 
 #![feature(thread_local)]
-// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint
-#![allow(static_mut_ref)]
+// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
+#![allow(static_mut_refs)]
 
 #[thread_local]
 static mut TLS: u8 = 0;
diff --git a/src/tools/miri/tests/pass/static_mut.rs b/src/tools/miri/tests/pass/static_mut.rs
index c1e58b70adb0b..6b0c0297726f3 100644
--- a/src/tools/miri/tests/pass/static_mut.rs
+++ b/src/tools/miri/tests/pass/static_mut.rs
@@ -1,7 +1,7 @@
 static mut FOO: i32 = 42;
 
-// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint
-#[allow(static_mut_ref)]
+// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
+#[allow(static_mut_refs)]
 static BAR: Foo = Foo(unsafe { &FOO as *const _ });
 
 #[allow(dead_code)]
diff --git a/src/tools/miri/tests/pass/tls/tls_static.rs b/src/tools/miri/tests/pass/tls/tls_static.rs
index 9be00af47aa35..fea5bb1db5e6b 100644
--- a/src/tools/miri/tests/pass/tls/tls_static.rs
+++ b/src/tools/miri/tests/pass/tls/tls_static.rs
@@ -8,8 +8,8 @@
 //! test, we also check that thread-locals act as per-thread statics.
 
 #![feature(thread_local)]
-// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint
-#![allow(static_mut_ref)]
+// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
+#![allow(static_mut_refs)]
 
 use std::thread;
 
diff --git a/tests/ui/abi/statics/static-mut-foreign.rs b/tests/ui/abi/statics/static-mut-foreign.rs
index eb732e7c2c31f..5d7cf1477c1c1 100644
--- a/tests/ui/abi/statics/static-mut-foreign.rs
+++ b/tests/ui/abi/statics/static-mut-foreign.rs
@@ -33,9 +33,9 @@ unsafe fn run() {
     rust_dbg_static_mut = -3;
     assert_eq!(rust_dbg_static_mut, -3);
     static_bound(&rust_dbg_static_mut);
-    //~^ WARN shared reference of mutable static is discouraged [static_mut_ref]
+    //~^ WARN shared reference to mutable static is discouraged [static_mut_refs]
     static_bound_set(&mut rust_dbg_static_mut);
-    //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref]
+    //~^ WARN mutable reference to mutable static is discouraged [static_mut_refs]
 }
 
 pub fn main() {
diff --git a/tests/ui/abi/statics/static-mut-foreign.stderr b/tests/ui/abi/statics/static-mut-foreign.stderr
index 144ac056f87e4..f393088ff9f33 100644
--- a/tests/ui/abi/statics/static-mut-foreign.stderr
+++ b/tests/ui/abi/statics/static-mut-foreign.stderr
@@ -1,28 +1,28 @@
-warning: shared reference of mutable static is discouraged
+warning: creating a shared reference to mutable static is discouraged
   --> $DIR/static-mut-foreign.rs:35:18
    |
 LL |     static_bound(&rust_dbg_static_mut);
-   |                  ^^^^^^^^^^^^^^^^^^^^ shared reference of mutable static
+   |                  ^^^^^^^^^^^^^^^^^^^^ shared reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of!` instead to create a raw pointer
    |
 LL |     static_bound(addr_of!(rust_dbg_static_mut));
    |                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-warning: mutable reference of mutable static is discouraged
+warning: creating a mutable reference to mutable static is discouraged
   --> $DIR/static-mut-foreign.rs:37:22
    |
 LL |     static_bound_set(&mut rust_dbg_static_mut);
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^ mutable reference of mutable static
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^ mutable reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+help: use `addr_of_mut!` instead to create a raw pointer
    |
 LL |     static_bound_set(addr_of_mut!(rust_dbg_static_mut));
    |                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tests/ui/borrowck/borrowck-access-permissions.rs b/tests/ui/borrowck/borrowck-access-permissions.rs
index 1638644103ba4..be11286a523df 100644
--- a/tests/ui/borrowck/borrowck-access-permissions.rs
+++ b/tests/ui/borrowck/borrowck-access-permissions.rs
@@ -16,7 +16,7 @@ fn main() {
         let _y1 = &mut static_x; //~ ERROR [E0596]
         unsafe {
             let _y2 = &mut static_x_mut;
-            //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref]
+            //~^ WARN mutable reference to mutable static is discouraged [static_mut_refs]
         }
     }
 
diff --git a/tests/ui/borrowck/borrowck-access-permissions.stderr b/tests/ui/borrowck/borrowck-access-permissions.stderr
index 93d92295dd9b6..11e2b63bd6cd7 100644
--- a/tests/ui/borrowck/borrowck-access-permissions.stderr
+++ b/tests/ui/borrowck/borrowck-access-permissions.stderr
@@ -1,14 +1,14 @@
-warning: mutable reference of mutable static is discouraged
+warning: creating a mutable reference to mutable static is discouraged
   --> $DIR/borrowck-access-permissions.rs:18:23
    |
 LL |             let _y2 = &mut static_x_mut;
-   |                       ^^^^^^^^^^^^^^^^^ mutable reference of mutable static
+   |                       ^^^^^^^^^^^^^^^^^ mutable reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of_mut!` instead to create a raw pointer
    |
 LL |             let _y2 = addr_of_mut!(static_x_mut);
    |                       ~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.rs b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.rs
index 1bf079e24cae4..76a28f928e3c0 100644
--- a/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.rs
+++ b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.rs
@@ -17,7 +17,7 @@ impl Foo {
 fn main() {
     unsafe {
         let sfoo: *mut Foo = &mut SFOO;
-        //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref]
+        //~^ WARN mutable reference to mutable static is discouraged [static_mut_refs]
         let x = (*sfoo).x();
         (*sfoo).x[1] += 1;
         *x += 1;
diff --git a/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr
index 7a3824f79a4c2..354d70eb1ad49 100644
--- a/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr
+++ b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr
@@ -1,14 +1,14 @@
-warning: mutable reference of mutable static is discouraged
+warning: creating a mutable reference to mutable static is discouraged
   --> $DIR/borrowck-unsafe-static-mutable-borrows.rs:19:30
    |
 LL |         let sfoo: *mut Foo = &mut SFOO;
-   |                              ^^^^^^^^^ mutable reference of mutable static
+   |                              ^^^^^^^^^ mutable reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of_mut!` instead to create a raw pointer
    |
 LL |         let sfoo: *mut Foo = addr_of_mut!(SFOO);
    |                              ~~~~~~~~~~~~~~~~~~
diff --git a/tests/ui/borrowck/issue-20801.rs b/tests/ui/borrowck/issue-20801.rs
index ec83af5d5dfc6..7e3d3703dc765 100644
--- a/tests/ui/borrowck/issue-20801.rs
+++ b/tests/ui/borrowck/issue-20801.rs
@@ -12,7 +12,7 @@ fn imm_ref() -> &'static T {
 
 fn mut_ref() -> &'static mut T {
     unsafe { &mut GLOBAL_MUT_T }
-    //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref]
+    //~^ WARN mutable reference to mutable static is discouraged [static_mut_refs]
 }
 
 fn mut_ptr() -> *mut T {
diff --git a/tests/ui/borrowck/issue-20801.stderr b/tests/ui/borrowck/issue-20801.stderr
index b2bee2d880394..97294afd3df9e 100644
--- a/tests/ui/borrowck/issue-20801.stderr
+++ b/tests/ui/borrowck/issue-20801.stderr
@@ -1,14 +1,14 @@
-warning: mutable reference of mutable static is discouraged
+warning: creating a mutable reference to mutable static is discouraged
   --> $DIR/issue-20801.rs:14:14
    |
 LL |     unsafe { &mut GLOBAL_MUT_T }
-   |              ^^^^^^^^^^^^^^^^^ mutable reference of mutable static
+   |              ^^^^^^^^^^^^^^^^^ mutable reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of_mut!` instead to create a raw pointer
    |
 LL |     unsafe { addr_of_mut!(GLOBAL_MUT_T) }
    |              ~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs
index 9b172b4131911..c3909d0596339 100644
--- a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs
+++ b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs
@@ -10,7 +10,7 @@ mod borrowck_closures_unique {
         //~^ ERROR is not declared as mutable
         unsafe {
             c1(&mut Y);
-            //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref]
+            //~^ WARN mutable reference to mutable static is discouraged [static_mut_refs]
         }
     }
 }
@@ -25,7 +25,7 @@ mod borrowck_closures_unique_grandparent {
         };
         unsafe {
             c1(&mut Z);
-            //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref]
+            //~^ WARN mutable reference to mutable static is discouraged [static_mut_refs]
         }
     }
 }
@@ -62,7 +62,7 @@ fn main() {
     static mut X: isize = 2;
     unsafe {
         borrowck_closures_unique::e(&mut X);
-        //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref]
+        //~^ WARN mutable reference to mutable static is discouraged [static_mut_refs]
     }
 
     mutability_errors::capture_assign_whole((1000,));
diff --git a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr
index e4e4947fce1c1..098a2964e9fc7 100644
--- a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr
+++ b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr
@@ -1,42 +1,42 @@
-warning: mutable reference of mutable static is discouraged
+warning: creating a mutable reference to mutable static is discouraged
   --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:12:16
    |
 LL |             c1(&mut Y);
-   |                ^^^^^^ mutable reference of mutable static
+   |                ^^^^^^ mutable reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of_mut!` instead to create a raw pointer
    |
 LL |             c1(addr_of_mut!(Y));
    |                ~~~~~~~~~~~~~~~
 
-warning: mutable reference of mutable static is discouraged
+warning: creating a mutable reference to mutable static is discouraged
   --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:27:16
    |
 LL |             c1(&mut Z);
-   |                ^^^^^^ mutable reference of mutable static
+   |                ^^^^^^ mutable reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+help: use `addr_of_mut!` instead to create a raw pointer
    |
 LL |             c1(addr_of_mut!(Z));
    |                ~~~~~~~~~~~~~~~
 
-warning: mutable reference of mutable static is discouraged
+warning: creating a mutable reference to mutable static is discouraged
   --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:64:37
    |
 LL |         borrowck_closures_unique::e(&mut X);
-   |                                     ^^^^^^ mutable reference of mutable static
+   |                                     ^^^^^^ mutable reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+help: use `addr_of_mut!` instead to create a raw pointer
    |
 LL |         borrowck_closures_unique::e(addr_of_mut!(X));
    |                                     ~~~~~~~~~~~~~~~
diff --git a/tests/ui/consts/const_let_assign2.rs b/tests/ui/consts/const_let_assign2.rs
index 1c7afe0e3d6cb..f375f0f603df5 100644
--- a/tests/ui/consts/const_let_assign2.rs
+++ b/tests/ui/consts/const_let_assign2.rs
@@ -16,7 +16,7 @@ static mut BB: AA = AA::new();
 
 fn main() {
     let ptr = unsafe { &mut BB };
-    //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref]
+    //~^ WARN mutable reference to mutable static is discouraged [static_mut_refs]
     for a in ptr.data.iter() {
         println!("{}", a);
     }
diff --git a/tests/ui/consts/const_let_assign2.stderr b/tests/ui/consts/const_let_assign2.stderr
index 2764153a8a590..5ae8fd353dd78 100644
--- a/tests/ui/consts/const_let_assign2.stderr
+++ b/tests/ui/consts/const_let_assign2.stderr
@@ -1,14 +1,14 @@
-warning: mutable reference of mutable static is discouraged
+warning: creating a mutable reference to mutable static is discouraged
   --> $DIR/const_let_assign2.rs:18:24
    |
 LL |     let ptr = unsafe { &mut BB };
-   |                        ^^^^^^^ mutable reference of mutable static
+   |                        ^^^^^^^ mutable reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of_mut!` instead to create a raw pointer
    |
 LL |     let ptr = unsafe { addr_of_mut!(BB) };
    |                        ~~~~~~~~~~~~~~~~
diff --git a/tests/ui/consts/const_refs_to_static_fail_invalid.rs b/tests/ui/consts/const_refs_to_static_fail_invalid.rs
index 665b876c43e2c..bd841c175bf81 100644
--- a/tests/ui/consts/const_refs_to_static_fail_invalid.rs
+++ b/tests/ui/consts/const_refs_to_static_fail_invalid.rs
@@ -1,7 +1,7 @@
 // normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
 // normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
 #![feature(const_refs_to_static)]
-#![allow(static_mut_ref)]
+#![allow(static_mut_refs)]
 
 fn invalid() {
     static S: i8 = 10;
@@ -43,8 +43,8 @@ fn mutable() {
     // This *must not build*, the constant we are matching against
     // could change its value!
     match &42 {
-        C => {}, //~ERROR: could not evaluate constant pattern
-        _ => {},
+        C => {} //~ERROR: could not evaluate constant pattern
+        _ => {}
     }
 }
 
diff --git a/tests/ui/consts/const_refs_to_static_fail_invalid.stderr b/tests/ui/consts/const_refs_to_static_fail_invalid.stderr
index 082f8532444ad..4ff15f0c28b8f 100644
--- a/tests/ui/consts/const_refs_to_static_fail_invalid.stderr
+++ b/tests/ui/consts/const_refs_to_static_fail_invalid.stderr
@@ -46,7 +46,7 @@ LL |     const C: &i32 = unsafe { &S_MUT };
 error: could not evaluate constant pattern
   --> $DIR/const_refs_to_static_fail_invalid.rs:46:9
    |
-LL |         C => {},
+LL |         C => {}
    |         ^
 
 error: aborting due to 6 previous errors
diff --git a/tests/ui/consts/issue-17718-const-bad-values.rs b/tests/ui/consts/issue-17718-const-bad-values.rs
index 0299bfef1b49a..52f8c9bf149a6 100644
--- a/tests/ui/consts/issue-17718-const-bad-values.rs
+++ b/tests/ui/consts/issue-17718-const-bad-values.rs
@@ -1,4 +1,4 @@
-#![allow(static_mut_ref)]
+#![allow(static_mut_refs)]
 
 const C1: &'static mut [usize] = &mut [];
 //~^ ERROR: mutable references are not allowed
diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs
index bcd29f8b03441..bcece4ccb34b5 100644
--- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs
+++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs
@@ -2,7 +2,7 @@
 // aux-build:static_cross_crate.rs
 // stderr-per-bitwidth
 #![feature(exclusive_range_pattern, half_open_range_patterns_in_slices)]
-#![allow(static_mut_ref)]
+#![allow(static_mut_refs)]
 
 extern crate static_cross_crate;
 
diff --git a/tests/ui/consts/miri_unleashed/extern-static.rs b/tests/ui/consts/miri_unleashed/extern-static.rs
index 81176b3d4e997..686aa90f55e81 100644
--- a/tests/ui/consts/miri_unleashed/extern-static.rs
+++ b/tests/ui/consts/miri_unleashed/extern-static.rs
@@ -1,6 +1,6 @@
 // compile-flags: -Zunleash-the-miri-inside-of-you
 #![feature(thread_local)]
-#![allow(static_mut_ref)]
+#![allow(static_mut_refs)]
 
 extern "C" {
     static mut DATA: u8;
diff --git a/tests/ui/consts/miri_unleashed/mutable_references_err.rs b/tests/ui/consts/miri_unleashed/mutable_references_err.rs
index 43b65f459a1eb..aabcf6d7bee3e 100644
--- a/tests/ui/consts/miri_unleashed/mutable_references_err.rs
+++ b/tests/ui/consts/miri_unleashed/mutable_references_err.rs
@@ -1,6 +1,6 @@
 // stderr-per-bitwidth
 // compile-flags: -Zunleash-the-miri-inside-of-you
-#![allow(invalid_reference_casting, static_mut_ref)]
+#![allow(invalid_reference_casting, static_mut_refs)]
 
 use std::sync::atomic::*;
 use std::cell::UnsafeCell;
diff --git a/tests/ui/consts/static-promoted-to-mutable-static.rs b/tests/ui/consts/static-promoted-to-mutable-static.rs
index d49ba478dbc82..9150867d42330 100644
--- a/tests/ui/consts/static-promoted-to-mutable-static.rs
+++ b/tests/ui/consts/static-promoted-to-mutable-static.rs
@@ -1,5 +1,5 @@
 // check-pass
-#![allow(non_camel_case_types, non_upper_case_globals, static_mut_ref)]
+#![allow(non_camel_case_types, non_upper_case_globals, static_mut_refs)]
 
 pub struct wl_interface {
     pub version: i32
diff --git a/tests/ui/consts/static_mut_containing_mut_ref.rs b/tests/ui/consts/static_mut_containing_mut_ref.rs
index 495804649b14b..3f5bd8007adca 100644
--- a/tests/ui/consts/static_mut_containing_mut_ref.rs
+++ b/tests/ui/consts/static_mut_containing_mut_ref.rs
@@ -1,5 +1,5 @@
 // build-pass (FIXME(62277): could be check-pass?)
-#![allow(static_mut_ref)]
+#![allow(static_mut_refs)]
 
 static mut STDERR_BUFFER_SPACE: [u8; 42] = [0u8; 42];
 
diff --git a/tests/ui/consts/static_mut_containing_mut_ref2.rs b/tests/ui/consts/static_mut_containing_mut_ref2.rs
index e60a17922fd0c..c2e75c1ba9f0e 100644
--- a/tests/ui/consts/static_mut_containing_mut_ref2.rs
+++ b/tests/ui/consts/static_mut_containing_mut_ref2.rs
@@ -1,5 +1,5 @@
 // revisions: stock mut_refs
-#![allow(static_mut_ref)]
+#![allow(static_mut_refs)]
 #![cfg_attr(mut_refs, feature(const_mut_refs))]
 
 static mut STDERR_BUFFER_SPACE: u8 = 0;
diff --git a/tests/ui/drop/issue-23338-ensure-param-drop-order.rs b/tests/ui/drop/issue-23338-ensure-param-drop-order.rs
index 52603744c45fc..a6796bd17df17 100644
--- a/tests/ui/drop/issue-23338-ensure-param-drop-order.rs
+++ b/tests/ui/drop/issue-23338-ensure-param-drop-order.rs
@@ -91,7 +91,7 @@ pub mod d {
     pub fn max_width() -> u32 {
         unsafe {
             (mem::size_of_val(&trails) * 8) as u32
-            //~^ WARN shared reference of mutable static is discouraged [static_mut_ref]
+            //~^ WARN shared reference to mutable static is discouraged [static_mut_refs]
         }
     }
 
diff --git a/tests/ui/drop/issue-23338-ensure-param-drop-order.stderr b/tests/ui/drop/issue-23338-ensure-param-drop-order.stderr
index fd36ccbcbee47..de1194e74b40d 100644
--- a/tests/ui/drop/issue-23338-ensure-param-drop-order.stderr
+++ b/tests/ui/drop/issue-23338-ensure-param-drop-order.stderr
@@ -1,14 +1,14 @@
-warning: shared reference of mutable static is discouraged
+warning: creating a shared reference to mutable static is discouraged
   --> $DIR/issue-23338-ensure-param-drop-order.rs:93:31
    |
 LL |             (mem::size_of_val(&trails) * 8) as u32
-   |                               ^^^^^^^ shared reference of mutable static
+   |                               ^^^^^^^ shared reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of!` instead to create a raw pointer
    |
 LL |             (mem::size_of_val(addr_of!(trails)) * 8) as u32
    |                               ~~~~~~~~~~~~~~~~
diff --git a/tests/ui/error-codes/E0017.rs b/tests/ui/error-codes/E0017.rs
index 9d3433fa543fd..4637fc75b48c7 100644
--- a/tests/ui/error-codes/E0017.rs
+++ b/tests/ui/error-codes/E0017.rs
@@ -13,6 +13,6 @@ static CONST_REF: &'static mut i32 = &mut C; //~ ERROR mutable references are no
 //~| WARN taking a mutable
 
 static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR mutable references are not
-//~^ WARN mutable reference of mutable static is discouraged [static_mut_ref]
+//~^ WARN mutable reference to mutable static is discouraged [static_mut_refs]
 
 fn main() {}
diff --git a/tests/ui/error-codes/E0017.stderr b/tests/ui/error-codes/E0017.stderr
index 2a70f2ee0ae82..f4a51dca207d9 100644
--- a/tests/ui/error-codes/E0017.stderr
+++ b/tests/ui/error-codes/E0017.stderr
@@ -1,14 +1,14 @@
-warning: mutable reference of mutable static is discouraged
+warning: creating a mutable reference to mutable static is discouraged
   --> $DIR/E0017.rs:15:52
    |
 LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M };
-   |                                                    ^^^^^^ mutable reference of mutable static
+   |                                                    ^^^^^^ mutable reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of_mut!` instead to create a raw pointer
    |
 LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { addr_of_mut!(M) };
    |                                                    ~~~~~~~~~~~~~~~
diff --git a/tests/ui/issues/issue-23611-enum-swap-in-drop.rs b/tests/ui/issues/issue-23611-enum-swap-in-drop.rs
index b967e6aecdd43..0582ff5e80ad9 100644
--- a/tests/ui/issues/issue-23611-enum-swap-in-drop.rs
+++ b/tests/ui/issues/issue-23611-enum-swap-in-drop.rs
@@ -187,7 +187,7 @@ pub mod d {
     pub fn max_width() -> u32 {
         unsafe {
             (mem::size_of_val(&trails) * 8) as u32
-            //~^ WARN shared reference of mutable static is discouraged [static_mut_ref]
+            //~^ WARN shared reference to mutable static is discouraged [static_mut_refs]
         }
     }
 
diff --git a/tests/ui/issues/issue-23611-enum-swap-in-drop.stderr b/tests/ui/issues/issue-23611-enum-swap-in-drop.stderr
index 14a986a333264..bdf46abea8a1f 100644
--- a/tests/ui/issues/issue-23611-enum-swap-in-drop.stderr
+++ b/tests/ui/issues/issue-23611-enum-swap-in-drop.stderr
@@ -1,14 +1,14 @@
-warning: shared reference of mutable static is discouraged
+warning: creating a shared reference to mutable static is discouraged
   --> $DIR/issue-23611-enum-swap-in-drop.rs:189:31
    |
 LL |             (mem::size_of_val(&trails) * 8) as u32
-   |                               ^^^^^^^ shared reference of mutable static
+   |                               ^^^^^^^ shared reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of!` instead to create a raw pointer
    |
 LL |             (mem::size_of_val(addr_of!(trails)) * 8) as u32
    |                               ~~~~~~~~~~~~~~~~
diff --git a/tests/ui/issues/issue-54410.rs b/tests/ui/issues/issue-54410.rs
index 51eea3ad9ac43..208be6f221c25 100644
--- a/tests/ui/issues/issue-54410.rs
+++ b/tests/ui/issues/issue-54410.rs
@@ -5,5 +5,5 @@ extern "C" {
 
 fn main() {
     println!("{:p}", unsafe { &symbol });
-    //~^ WARN: shared reference of mutable static is discouraged
+    //~^ WARN creating a shared reference to mutable static is discouraged [static_mut_refs]
 }
diff --git a/tests/ui/issues/issue-54410.stderr b/tests/ui/issues/issue-54410.stderr
index 941c1be3eab5f..7cc67ab72c396 100644
--- a/tests/ui/issues/issue-54410.stderr
+++ b/tests/ui/issues/issue-54410.stderr
@@ -6,17 +6,17 @@ LL |     pub static mut symbol: [i8];
    |
    = help: the trait `Sized` is not implemented for `[i8]`
 
-warning: shared reference of mutable static is discouraged
+warning: creating a shared reference to mutable static is discouraged
   --> $DIR/issue-54410.rs:7:31
    |
 LL |     println!("{:p}", unsafe { &symbol });
-   |                               ^^^^^^^ shared reference of mutable static
+   |                               ^^^^^^^ shared reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of!` instead to create a raw pointer
    |
 LL |     println!("{:p}", unsafe { addr_of!(symbol) });
    |                               ~~~~~~~~~~~~~~~~
diff --git a/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs
index 8eb544e8ab9d2..39d594b0e3227 100644
--- a/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs
+++ b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs
@@ -15,7 +15,7 @@ struct S1 {
 impl S1 {
     fn new(_x: u64) -> S1 {
         S1 { a: unsafe { &mut X1 } }
-        //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref]
+        //~^ WARN mutable reference to mutable static is discouraged [static_mut_refs]
     }
 }
 
diff --git a/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr
index 17217cd5859d0..82065cc06ea1d 100644
--- a/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr
+++ b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr
@@ -1,14 +1,14 @@
-warning: mutable reference of mutable static is discouraged
+warning: creating a mutable reference to mutable static is discouraged
   --> $DIR/borrowck-thread-local-static-mut-borrow-outlives-fn.rs:17:26
    |
 LL |         S1 { a: unsafe { &mut X1 } }
-   |                          ^^^^^^^ mutable reference of mutable static
+   |                          ^^^^^^^ mutable reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of_mut!` instead to create a raw pointer
    |
 LL |         S1 { a: unsafe { addr_of_mut!(X1) } }
    |                          ~~~~~~~~~~~~~~~~
diff --git a/tests/ui/static/reference-of-mut-static-safe.e2021.stderr b/tests/ui/static/reference-of-mut-static-safe.e2021.stderr
deleted file mode 100644
index 16f47ace3a930..0000000000000
--- a/tests/ui/static/reference-of-mut-static-safe.e2021.stderr
+++ /dev/null
@@ -1,26 +0,0 @@
-warning: shared reference of mutable static is discouraged
-  --> $DIR/reference-of-mut-static-safe.rs:9:14
-   |
-LL |     let _x = &X;
-   |              ^^ shared reference of mutable static
-   |
-   = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
-   |
-LL |     let _x = addr_of!(X);
-   |              ~~~~~~~~~~~
-
-error[E0133]: use of mutable static is unsafe and requires unsafe function or block
-  --> $DIR/reference-of-mut-static-safe.rs:9:15
-   |
-LL |     let _x = &X;
-   |               ^ use of mutable static
-   |
-   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
-
-error: aborting due to 1 previous error; 1 warning emitted
-
-For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/static/reference-of-mut-static-safe.e2024.stderr b/tests/ui/static/reference-of-mut-static-safe.e2024.stderr
deleted file mode 100644
index 53f81179de55a..0000000000000
--- a/tests/ui/static/reference-of-mut-static-safe.e2024.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0796]: reference of mutable static is disallowed
-  --> $DIR/reference-of-mut-static-safe.rs:9:14
-   |
-LL |     let _x = &X;
-   |              ^^ reference of mutable static
-   |
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
-   |
-LL |     let _x = addr_of!(X);
-   |              ~~~~~~~~~~~
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0796`.
diff --git a/tests/ui/static/reference-of-mut-static-unsafe-fn.rs b/tests/ui/static/reference-of-mut-static-unsafe-fn.rs
deleted file mode 100644
index 6b1e77850e50d..0000000000000
--- a/tests/ui/static/reference-of-mut-static-unsafe-fn.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-// compile-flags: --edition 2024 -Z unstable-options
-
-fn main() {}
-
-unsafe fn _foo() {
-    static mut X: i32 = 1;
-    static mut Y: i32 = 1;
-
-    let _y = &X;
-    //~^ ERROR reference of mutable static is disallowed
-
-    let ref _a = X;
-    //~^ ERROR reference of mutable static is disallowed
-
-    let (_b, _c) = (&X, &Y);
-    //~^ ERROR reference of mutable static is disallowed
-    //~^^ ERROR reference of mutable static is disallowed
-
-    foo(&X);
-    //~^ ERROR reference of mutable static is disallowed
-}
-
-fn foo<'a>(_x: &'a i32) {}
diff --git a/tests/ui/static/reference-of-mut-static-unsafe-fn.stderr b/tests/ui/static/reference-of-mut-static-unsafe-fn.stderr
deleted file mode 100644
index 5c6fdedfa96f7..0000000000000
--- a/tests/ui/static/reference-of-mut-static-unsafe-fn.stderr
+++ /dev/null
@@ -1,63 +0,0 @@
-error[E0796]: reference of mutable static is disallowed
-  --> $DIR/reference-of-mut-static-unsafe-fn.rs:9:14
-   |
-LL |     let _y = &X;
-   |              ^^ reference of mutable static
-   |
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
-   |
-LL |     let _y = addr_of!(X);
-   |              ~~~~~~~~~~~
-
-error[E0796]: reference of mutable static is disallowed
-  --> $DIR/reference-of-mut-static-unsafe-fn.rs:12:18
-   |
-LL |     let ref _a = X;
-   |                  ^ reference of mutable static
-   |
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
-   |
-LL |     let ref _a = addr_of!(X);
-   |                  ~~~~~~~~~~~
-
-error[E0796]: reference of mutable static is disallowed
-  --> $DIR/reference-of-mut-static-unsafe-fn.rs:15:21
-   |
-LL |     let (_b, _c) = (&X, &Y);
-   |                     ^^ reference of mutable static
-   |
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
-   |
-LL |     let (_b, _c) = (addr_of!(X), &Y);
-   |                     ~~~~~~~~~~~
-
-error[E0796]: reference of mutable static is disallowed
-  --> $DIR/reference-of-mut-static-unsafe-fn.rs:15:25
-   |
-LL |     let (_b, _c) = (&X, &Y);
-   |                         ^^ reference of mutable static
-   |
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
-   |
-LL |     let (_b, _c) = (&X, addr_of!(Y));
-   |                         ~~~~~~~~~~~
-
-error[E0796]: reference of mutable static is disallowed
-  --> $DIR/reference-of-mut-static-unsafe-fn.rs:19:9
-   |
-LL |     foo(&X);
-   |         ^^ reference of mutable static
-   |
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
-   |
-LL |     foo(addr_of!(X));
-   |         ~~~~~~~~~~~
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0796`.
diff --git a/tests/ui/static/reference-of-mut-static.e2021.stderr b/tests/ui/static/reference-of-mut-static.e2021.stderr
deleted file mode 100644
index 77a6b3d304bdb..0000000000000
--- a/tests/ui/static/reference-of-mut-static.e2021.stderr
+++ /dev/null
@@ -1,91 +0,0 @@
-error: shared reference of mutable static is discouraged
-  --> $DIR/reference-of-mut-static.rs:16:18
-   |
-LL |         let _y = &X;
-   |                  ^^ shared reference of mutable static
-   |
-   = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-note: the lint level is defined here
-  --> $DIR/reference-of-mut-static.rs:6:9
-   |
-LL | #![deny(static_mut_ref)]
-   |         ^^^^^^^^^^^^^^
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
-   |
-LL |         let _y = addr_of!(X);
-   |                  ~~~~~~~~~~~
-
-error: mutable reference of mutable static is discouraged
-  --> $DIR/reference-of-mut-static.rs:20:18
-   |
-LL |         let _y = &mut X;
-   |                  ^^^^^^ mutable reference of mutable static
-   |
-   = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
-   |
-LL |         let _y = addr_of_mut!(X);
-   |                  ~~~~~~~~~~~~~~~
-
-error: shared reference of mutable static is discouraged
-  --> $DIR/reference-of-mut-static.rs:28:22
-   |
-LL |         let ref _a = X;
-   |                      ^ shared reference of mutable static
-   |
-   = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
-   |
-LL |         let ref _a = addr_of!(X);
-   |                      ~~~~~~~~~~~
-
-error: shared reference of mutable static is discouraged
-  --> $DIR/reference-of-mut-static.rs:32:25
-   |
-LL |         let (_b, _c) = (&X, &Y);
-   |                         ^^ shared reference of mutable static
-   |
-   = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
-   |
-LL |         let (_b, _c) = (addr_of!(X), &Y);
-   |                         ~~~~~~~~~~~
-
-error: shared reference of mutable static is discouraged
-  --> $DIR/reference-of-mut-static.rs:32:29
-   |
-LL |         let (_b, _c) = (&X, &Y);
-   |                             ^^ shared reference of mutable static
-   |
-   = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
-   |
-LL |         let (_b, _c) = (&X, addr_of!(Y));
-   |                             ~~~~~~~~~~~
-
-error: shared reference of mutable static is discouraged
-  --> $DIR/reference-of-mut-static.rs:38:13
-   |
-LL |         foo(&X);
-   |             ^^ shared reference of mutable static
-   |
-   = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
-   |
-LL |         foo(addr_of!(X));
-   |             ~~~~~~~~~~~
-
-error: aborting due to 6 previous errors
-
diff --git a/tests/ui/static/reference-of-mut-static.e2024.stderr b/tests/ui/static/reference-of-mut-static.e2024.stderr
deleted file mode 100644
index f445ec65a5d24..0000000000000
--- a/tests/ui/static/reference-of-mut-static.e2024.stderr
+++ /dev/null
@@ -1,75 +0,0 @@
-error[E0796]: reference of mutable static is disallowed
-  --> $DIR/reference-of-mut-static.rs:16:18
-   |
-LL |         let _y = &X;
-   |                  ^^ reference of mutable static
-   |
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
-   |
-LL |         let _y = addr_of!(X);
-   |                  ~~~~~~~~~~~
-
-error[E0796]: reference of mutable static is disallowed
-  --> $DIR/reference-of-mut-static.rs:20:18
-   |
-LL |         let _y = &mut X;
-   |                  ^^^^^^ reference of mutable static
-   |
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
-   |
-LL |         let _y = addr_of_mut!(X);
-   |                  ~~~~~~~~~~~~~~~
-
-error[E0796]: reference of mutable static is disallowed
-  --> $DIR/reference-of-mut-static.rs:28:22
-   |
-LL |         let ref _a = X;
-   |                      ^ reference of mutable static
-   |
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
-   |
-LL |         let ref _a = addr_of!(X);
-   |                      ~~~~~~~~~~~
-
-error[E0796]: reference of mutable static is disallowed
-  --> $DIR/reference-of-mut-static.rs:32:25
-   |
-LL |         let (_b, _c) = (&X, &Y);
-   |                         ^^ reference of mutable static
-   |
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
-   |
-LL |         let (_b, _c) = (addr_of!(X), &Y);
-   |                         ~~~~~~~~~~~
-
-error[E0796]: reference of mutable static is disallowed
-  --> $DIR/reference-of-mut-static.rs:32:29
-   |
-LL |         let (_b, _c) = (&X, &Y);
-   |                             ^^ reference of mutable static
-   |
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
-   |
-LL |         let (_b, _c) = (&X, addr_of!(Y));
-   |                             ~~~~~~~~~~~
-
-error[E0796]: reference of mutable static is disallowed
-  --> $DIR/reference-of-mut-static.rs:38:13
-   |
-LL |         foo(&X);
-   |             ^^ reference of mutable static
-   |
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
-   |
-LL |         foo(addr_of!(X));
-   |             ~~~~~~~~~~~
-
-error: aborting due to 6 previous errors
-
-For more information about this error, try `rustc --explain E0796`.
diff --git a/tests/ui/static/reference-of-mut-static.rs b/tests/ui/static/reference-of-mut-static.rs
deleted file mode 100644
index 01a3b1fbd9b51..0000000000000
--- a/tests/ui/static/reference-of-mut-static.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-// revisions: e2021 e2024
-
-// [e2021] edition:2021
-// [e2024] compile-flags: --edition 2024 -Z unstable-options
-
-#![deny(static_mut_ref)]
-
-use std::ptr::{addr_of, addr_of_mut};
-
-fn main() {
-    static mut X: i32 = 1;
-
-    static mut Y: i32 = 1;
-
-    unsafe {
-        let _y = &X;
-        //[e2024]~^ ERROR reference of mutable static is disallowed
-        //[e2021]~^^ ERROR shared reference of mutable static is discouraged [static_mut_ref]
-
-        let _y = &mut X;
-        //[e2024]~^ ERROR reference of mutable static is disallowed
-        //[e2021]~^^ ERROR mutable reference of mutable static is discouraged [static_mut_ref]
-
-        let _z = addr_of_mut!(X);
-
-        let _p = addr_of!(X);
-
-        let ref _a = X;
-        //[e2024]~^ ERROR reference of mutable static is disallowed
-        //[e2021]~^^ ERROR shared reference of mutable static is discouraged [static_mut_ref]
-
-        let (_b, _c) = (&X, &Y);
-        //[e2024]~^ ERROR reference of mutable static is disallowed
-        //[e2021]~^^ ERROR shared reference of mutable static is discouraged [static_mut_ref]
-        //[e2024]~^^^ ERROR reference of mutable static is disallowed
-        //[e2021]~^^^^ ERROR shared reference of mutable static is discouraged [static_mut_ref]
-
-        foo(&X);
-        //[e2024]~^ ERROR reference of mutable static is disallowed
-        //[e2021]~^^ ERROR shared reference of mutable static is discouraged [static_mut_ref]
-
-        static mut Z: &[i32; 3] = &[0, 1, 2];
-
-        let _ = Z.len();
-        let _ = Z[0];
-        let _ = format!("{:?}", Z);
-    }
-}
-
-fn foo<'a>(_x: &'a i32) {}
diff --git a/tests/ui/static/reference-to-mut-static-safe.e2021.stderr b/tests/ui/static/reference-to-mut-static-safe.e2021.stderr
new file mode 100644
index 0000000000000..9ea34290e36d6
--- /dev/null
+++ b/tests/ui/static/reference-to-mut-static-safe.e2021.stderr
@@ -0,0 +1,26 @@
+warning: creating a shared reference to mutable static is discouraged
+  --> $DIR/reference-to-mut-static-safe.rs:9:14
+   |
+LL |     let _x = &X;
+   |              ^^ shared reference to mutable static
+   |
+   = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |     let _x = addr_of!(X);
+   |              ~~~~~~~~~~~
+
+error[E0133]: use of mutable static is unsafe and requires unsafe function or block
+  --> $DIR/reference-to-mut-static-safe.rs:9:15
+   |
+LL |     let _x = &X;
+   |               ^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/static/reference-to-mut-static-safe.e2024.stderr b/tests/ui/static/reference-to-mut-static-safe.e2024.stderr
new file mode 100644
index 0000000000000..39575441422d4
--- /dev/null
+++ b/tests/ui/static/reference-to-mut-static-safe.e2024.stderr
@@ -0,0 +1,15 @@
+error[E0796]: creating a shared reference to a mutable static
+  --> $DIR/reference-to-mut-static-safe.rs:9:14
+   |
+LL |     let _x = &X;
+   |              ^^ sharedreference to mutable static
+   |
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |     let _x = addr_of!(X);
+   |              ~~~~~~~~~~~
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0796`.
diff --git a/tests/ui/static/reference-of-mut-static-safe.rs b/tests/ui/static/reference-to-mut-static-safe.rs
similarity index 62%
rename from tests/ui/static/reference-of-mut-static-safe.rs
rename to tests/ui/static/reference-to-mut-static-safe.rs
index 5cb1a03bef512..cc3ef63a2ace3 100644
--- a/tests/ui/static/reference-of-mut-static-safe.rs
+++ b/tests/ui/static/reference-to-mut-static-safe.rs
@@ -7,7 +7,7 @@ fn main() {
     static mut X: i32 = 1;
 
     let _x = &X;
-    //[e2024]~^ reference of mutable static is disallowed [E0796]
+    //[e2024]~^ creating a shared reference to a mutable static [E0796]
     //[e2021]~^^ use of mutable static is unsafe and requires unsafe function or block [E0133]
-    //[e2021]~^^^ shared reference of mutable static is discouraged [static_mut_ref]
+    //[e2021]~^^^ shared reference to mutable static is discouraged [static_mut_refs]
 }
diff --git a/tests/ui/static/reference-to-mut-static-unsafe-fn.rs b/tests/ui/static/reference-to-mut-static-unsafe-fn.rs
new file mode 100644
index 0000000000000..737fcb996af18
--- /dev/null
+++ b/tests/ui/static/reference-to-mut-static-unsafe-fn.rs
@@ -0,0 +1,26 @@
+// compile-flags: --edition 2024 -Z unstable-options
+
+fn main() {}
+
+unsafe fn _foo() {
+    static mut X: i32 = 1;
+    static mut Y: i32 = 1;
+
+    let _y = &X;
+    //~^ ERROR creating a shared reference to a mutable static [E0796]
+
+    let ref _a = X;
+    //~^ ERROR creating a shared reference to a mutable static [E0796]
+
+    let ref mut _a = X;
+    //~^ ERROR creating a mutable reference to a mutable static [E0796]
+
+    let (_b, _c) = (&X, &mut Y);
+    //~^ ERROR creating a shared reference to a mutable static [E0796]
+    //~^^ ERROR creating a mutable reference to a mutable static [E0796]
+
+    foo(&X);
+    //~^ ERROR creating a shared reference to a mutable static [E0796]
+}
+
+fn foo<'a>(_x: &'a i32) {}
diff --git a/tests/ui/static/reference-to-mut-static-unsafe-fn.stderr b/tests/ui/static/reference-to-mut-static-unsafe-fn.stderr
new file mode 100644
index 0000000000000..439a205a5f415
--- /dev/null
+++ b/tests/ui/static/reference-to-mut-static-unsafe-fn.stderr
@@ -0,0 +1,75 @@
+error[E0796]: creating a shared reference to a mutable static
+  --> $DIR/reference-to-mut-static-unsafe-fn.rs:9:14
+   |
+LL |     let _y = &X;
+   |              ^^ sharedreference to mutable static
+   |
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |     let _y = addr_of!(X);
+   |              ~~~~~~~~~~~
+
+error[E0796]: creating a shared reference to a mutable static
+  --> $DIR/reference-to-mut-static-unsafe-fn.rs:12:18
+   |
+LL |     let ref _a = X;
+   |                  ^ sharedreference to mutable static
+   |
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |     let ref _a = addr_of!(X);
+   |                  ~~~~~~~~~~~
+
+error[E0796]: creating a mutable reference to a mutable static
+  --> $DIR/reference-to-mut-static-unsafe-fn.rs:15:22
+   |
+LL |     let ref mut _a = X;
+   |                      ^ mutablereference to mutable static
+   |
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+help: use `addr_of_mut!` instead to create a raw pointer
+   |
+LL |     let ref mut _a = addr_of_mut!(X);
+   |                      ~~~~~~~~~~~~~~~
+
+error[E0796]: creating a shared reference to a mutable static
+  --> $DIR/reference-to-mut-static-unsafe-fn.rs:18:21
+   |
+LL |     let (_b, _c) = (&X, &mut Y);
+   |                     ^^ sharedreference to mutable static
+   |
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |     let (_b, _c) = (addr_of!(X), &mut Y);
+   |                     ~~~~~~~~~~~
+
+error[E0796]: creating a mutable reference to a mutable static
+  --> $DIR/reference-to-mut-static-unsafe-fn.rs:18:25
+   |
+LL |     let (_b, _c) = (&X, &mut Y);
+   |                         ^^^^^^ mutablereference to mutable static
+   |
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+help: use `addr_of_mut!` instead to create a raw pointer
+   |
+LL |     let (_b, _c) = (&X, addr_of_mut!(Y));
+   |                         ~~~~~~~~~~~~~~~
+
+error[E0796]: creating a shared reference to a mutable static
+  --> $DIR/reference-to-mut-static-unsafe-fn.rs:22:9
+   |
+LL |     foo(&X);
+   |         ^^ sharedreference to mutable static
+   |
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |     foo(addr_of!(X));
+   |         ~~~~~~~~~~~
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0796`.
diff --git a/tests/ui/static/reference-to-mut-static.e2021.stderr b/tests/ui/static/reference-to-mut-static.e2021.stderr
new file mode 100644
index 0000000000000..f477e5ac6c5c2
--- /dev/null
+++ b/tests/ui/static/reference-to-mut-static.e2021.stderr
@@ -0,0 +1,91 @@
+error: creating a shared reference to mutable static is discouraged
+  --> $DIR/reference-to-mut-static.rs:16:18
+   |
+LL |         let _y = &X;
+   |                  ^^ shared reference to mutable static
+   |
+   = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+note: the lint level is defined here
+  --> $DIR/reference-to-mut-static.rs:6:9
+   |
+LL | #![deny(static_mut_refs)]
+   |         ^^^^^^^^^^^^^^^
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |         let _y = addr_of!(X);
+   |                  ~~~~~~~~~~~
+
+error: creating a mutable reference to mutable static is discouraged
+  --> $DIR/reference-to-mut-static.rs:20:18
+   |
+LL |         let _y = &mut X;
+   |                  ^^^^^^ mutable reference to mutable static
+   |
+   = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
+   = note: this will be a hard error in the 2024 edition
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+help: use `addr_of_mut!` instead to create a raw pointer
+   |
+LL |         let _y = addr_of_mut!(X);
+   |                  ~~~~~~~~~~~~~~~
+
+error: creating a shared reference to mutable static is discouraged
+  --> $DIR/reference-to-mut-static.rs:28:22
+   |
+LL |         let ref _a = X;
+   |                      ^ shared reference to mutable static
+   |
+   = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |         let ref _a = addr_of!(X);
+   |                      ~~~~~~~~~~~
+
+error: creating a shared reference to mutable static is discouraged
+  --> $DIR/reference-to-mut-static.rs:32:25
+   |
+LL |         let (_b, _c) = (&X, &Y);
+   |                         ^^ shared reference to mutable static
+   |
+   = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |         let (_b, _c) = (addr_of!(X), &Y);
+   |                         ~~~~~~~~~~~
+
+error: creating a shared reference to mutable static is discouraged
+  --> $DIR/reference-to-mut-static.rs:32:29
+   |
+LL |         let (_b, _c) = (&X, &Y);
+   |                             ^^ shared reference to mutable static
+   |
+   = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |         let (_b, _c) = (&X, addr_of!(Y));
+   |                             ~~~~~~~~~~~
+
+error: creating a shared reference to mutable static is discouraged
+  --> $DIR/reference-to-mut-static.rs:38:13
+   |
+LL |         foo(&X);
+   |             ^^ shared reference to mutable static
+   |
+   = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |         foo(addr_of!(X));
+   |             ~~~~~~~~~~~
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/static/reference-to-mut-static.e2024.stderr b/tests/ui/static/reference-to-mut-static.e2024.stderr
new file mode 100644
index 0000000000000..12af318572d91
--- /dev/null
+++ b/tests/ui/static/reference-to-mut-static.e2024.stderr
@@ -0,0 +1,75 @@
+error[E0796]: creating a shared reference to a mutable static
+  --> $DIR/reference-to-mut-static.rs:16:18
+   |
+LL |         let _y = &X;
+   |                  ^^ sharedreference to mutable static
+   |
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |         let _y = addr_of!(X);
+   |                  ~~~~~~~~~~~
+
+error[E0796]: creating a mutable reference to a mutable static
+  --> $DIR/reference-to-mut-static.rs:20:18
+   |
+LL |         let _y = &mut X;
+   |                  ^^^^^^ mutablereference to mutable static
+   |
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+help: use `addr_of_mut!` instead to create a raw pointer
+   |
+LL |         let _y = addr_of_mut!(X);
+   |                  ~~~~~~~~~~~~~~~
+
+error[E0796]: creating a shared reference to a mutable static
+  --> $DIR/reference-to-mut-static.rs:28:22
+   |
+LL |         let ref _a = X;
+   |                      ^ sharedreference to mutable static
+   |
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |         let ref _a = addr_of!(X);
+   |                      ~~~~~~~~~~~
+
+error[E0796]: creating a shared reference to a mutable static
+  --> $DIR/reference-to-mut-static.rs:32:25
+   |
+LL |         let (_b, _c) = (&X, &Y);
+   |                         ^^ sharedreference to mutable static
+   |
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |         let (_b, _c) = (addr_of!(X), &Y);
+   |                         ~~~~~~~~~~~
+
+error[E0796]: creating a shared reference to a mutable static
+  --> $DIR/reference-to-mut-static.rs:32:29
+   |
+LL |         let (_b, _c) = (&X, &Y);
+   |                             ^^ sharedreference to mutable static
+   |
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |         let (_b, _c) = (&X, addr_of!(Y));
+   |                             ~~~~~~~~~~~
+
+error[E0796]: creating a shared reference to a mutable static
+  --> $DIR/reference-to-mut-static.rs:38:13
+   |
+LL |         foo(&X);
+   |             ^^ sharedreference to mutable static
+   |
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
+   |
+LL |         foo(addr_of!(X));
+   |             ~~~~~~~~~~~
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0796`.
diff --git a/tests/ui/static/reference-to-mut-static.rs b/tests/ui/static/reference-to-mut-static.rs
new file mode 100644
index 0000000000000..b9aecd5185a09
--- /dev/null
+++ b/tests/ui/static/reference-to-mut-static.rs
@@ -0,0 +1,50 @@
+// revisions: e2021 e2024
+
+// [e2021] edition:2021
+// [e2024] compile-flags: --edition 2024 -Z unstable-options
+
+#![deny(static_mut_refs)]
+
+use std::ptr::{addr_of, addr_of_mut};
+
+fn main() {
+    static mut X: i32 = 1;
+
+    static mut Y: i32 = 1;
+
+    unsafe {
+        let _y = &X;
+        //[e2024]~^ ERROR creating a shared reference to a mutable static [E0796]
+        //[e2021]~^^ ERROR shared reference to mutable static is discouraged [static_mut_refs]
+
+        let _y = &mut X;
+        //[e2024]~^ ERROR creating a mutable reference to a mutable static [E0796]
+        //[e2021]~^^ ERROR mutable reference to mutable static is discouraged [static_mut_refs]
+
+        let _z = addr_of_mut!(X);
+
+        let _p = addr_of!(X);
+
+        let ref _a = X;
+        //[e2024]~^ ERROR creating a shared reference to a mutable static [E0796]
+        //[e2021]~^^ ERROR shared reference to mutable static is discouraged [static_mut_refs]
+
+        let (_b, _c) = (&X, &Y);
+        //[e2024]~^ ERROR creating a shared reference to a mutable static [E0796]
+        //[e2021]~^^ ERROR shared reference to mutable static is discouraged [static_mut_refs]
+        //[e2024]~^^^ ERROR creating a shared reference to a mutable static [E0796]
+        //[e2021]~^^^^ ERROR shared reference to mutable static is discouraged [static_mut_refs]
+
+        foo(&X);
+        //[e2024]~^ ERROR creating a shared reference to a mutable static [E0796]
+        //[e2021]~^^ ERROR shared reference to mutable static is discouraged [static_mut_refs]
+
+        static mut Z: &[i32; 3] = &[0, 1, 2];
+
+        let _ = Z.len();
+        let _ = Z[0];
+        let _ = format!("{:?}", Z);
+    }
+}
+
+fn foo<'a>(_x: &'a i32) {}
diff --git a/tests/ui/static/safe-extern-statics-mut.rs b/tests/ui/static/safe-extern-statics-mut.rs
index 1c0662e0a6cec..05cc6dd01917c 100644
--- a/tests/ui/static/safe-extern-statics-mut.rs
+++ b/tests/ui/static/safe-extern-statics-mut.rs
@@ -10,8 +10,8 @@ extern "C" {
 fn main() {
     let b = B; //~ ERROR use of mutable static is unsafe
     let rb = &B; //~ ERROR use of mutable static is unsafe
-    //~^ WARN shared reference of mutable static is discouraged [static_mut_ref]
+    //~^ WARN shared reference to mutable static is discouraged [static_mut_refs]
     let xb = XB; //~ ERROR use of mutable static is unsafe
     let xrb = &XB; //~ ERROR use of mutable static is unsafe
-    //~^ WARN shared reference of mutable static is discouraged [static_mut_ref]
+    //~^ WARN shared reference to mutable static is discouraged [static_mut_refs]
 }
diff --git a/tests/ui/static/safe-extern-statics-mut.stderr b/tests/ui/static/safe-extern-statics-mut.stderr
index eda353ce6736f..9a4b651405f23 100644
--- a/tests/ui/static/safe-extern-statics-mut.stderr
+++ b/tests/ui/static/safe-extern-statics-mut.stderr
@@ -1,28 +1,28 @@
-warning: shared reference of mutable static is discouraged
+warning: creating a shared reference to mutable static is discouraged
   --> $DIR/safe-extern-statics-mut.rs:12:14
    |
 LL |     let rb = &B;
-   |              ^^ shared reference of mutable static
+   |              ^^ shared reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of!` instead to create a raw pointer
    |
 LL |     let rb = addr_of!(B);
    |              ~~~~~~~~~~~
 
-warning: shared reference of mutable static is discouraged
+warning: creating a shared reference to mutable static is discouraged
   --> $DIR/safe-extern-statics-mut.rs:15:15
    |
 LL |     let xrb = &XB;
-   |               ^^^ shared reference of mutable static
+   |               ^^^ shared reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+help: use `addr_of!` instead to create a raw pointer
    |
 LL |     let xrb = addr_of!(XB);
    |               ~~~~~~~~~~~~
diff --git a/tests/ui/statics/issue-15261.rs b/tests/ui/statics/issue-15261.rs
index 14422329b7dc8..a6f99bd13c605 100644
--- a/tests/ui/statics/issue-15261.rs
+++ b/tests/ui/statics/issue-15261.rs
@@ -7,6 +7,6 @@
 static mut n_mut: usize = 0;
 
 static n: &'static usize = unsafe { &n_mut };
-//~^ WARN shared reference of mutable static is discouraged [static_mut_ref]
+//~^ WARN shared reference to mutable static is discouraged [static_mut_refs]
 
 fn main() {}
diff --git a/tests/ui/statics/issue-15261.stderr b/tests/ui/statics/issue-15261.stderr
index 72d88ce1b3832..c31793f3d8f15 100644
--- a/tests/ui/statics/issue-15261.stderr
+++ b/tests/ui/statics/issue-15261.stderr
@@ -1,14 +1,14 @@
-warning: shared reference of mutable static is discouraged
+warning: creating a shared reference to mutable static is discouraged
   --> $DIR/issue-15261.rs:9:37
    |
 LL | static n: &'static usize = unsafe { &n_mut };
-   |                                     ^^^^^^ shared reference of mutable static
+   |                                     ^^^^^^ shared reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of!` instead to create a raw pointer
    |
 LL | static n: &'static usize = unsafe { addr_of!(n_mut) };
    |                                     ~~~~~~~~~~~~~~~
diff --git a/tests/ui/statics/static-mut-xc.rs b/tests/ui/statics/static-mut-xc.rs
index 2fc265e02eaa3..f242836eccfbc 100644
--- a/tests/ui/statics/static-mut-xc.rs
+++ b/tests/ui/statics/static-mut-xc.rs
@@ -26,9 +26,9 @@ unsafe fn run() {
     static_mut_xc::a = -3;
     assert_eq!(static_mut_xc::a, -3);
     static_bound(&static_mut_xc::a);
-    //~^ WARN shared reference of mutable static is discouraged [static_mut_ref]
+    //~^ WARN shared reference to mutable static is discouraged [static_mut_refs]
     static_bound_set(&mut static_mut_xc::a);
-    //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref]
+    //~^ WARN mutable reference to mutable static is discouraged [static_mut_refs]
 }
 
 pub fn main() {
diff --git a/tests/ui/statics/static-mut-xc.stderr b/tests/ui/statics/static-mut-xc.stderr
index 37aa336bc50f7..d381328c07178 100644
--- a/tests/ui/statics/static-mut-xc.stderr
+++ b/tests/ui/statics/static-mut-xc.stderr
@@ -1,28 +1,28 @@
-warning: shared reference of mutable static is discouraged
+warning: creating a shared reference to mutable static is discouraged
   --> $DIR/static-mut-xc.rs:28:18
    |
 LL |     static_bound(&static_mut_xc::a);
-   |                  ^^^^^^^^^^^^^^^^^ shared reference of mutable static
+   |                  ^^^^^^^^^^^^^^^^^ shared reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of!` instead to create a raw pointer
    |
 LL |     static_bound(addr_of!(static_mut_xc::a));
    |                  ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-warning: mutable reference of mutable static is discouraged
+warning: creating a mutable reference to mutable static is discouraged
   --> $DIR/static-mut-xc.rs:30:22
    |
 LL |     static_bound_set(&mut static_mut_xc::a);
-   |                      ^^^^^^^^^^^^^^^^^^^^^ mutable reference of mutable static
+   |                      ^^^^^^^^^^^^^^^^^^^^^ mutable reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
+help: use `addr_of_mut!` instead to create a raw pointer
    |
 LL |     static_bound_set(addr_of_mut!(static_mut_xc::a));
    |                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tests/ui/statics/static-recursive.rs b/tests/ui/statics/static-recursive.rs
index 216beb0206d9c..52660888986da 100644
--- a/tests/ui/statics/static-recursive.rs
+++ b/tests/ui/statics/static-recursive.rs
@@ -1,7 +1,7 @@
 // run-pass
 
 static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 };
-//~^ WARN shared reference of mutable static is discouraged [static_mut_ref]
+//~^ WARN shared reference to mutable static is discouraged [static_mut_refs]
 
 struct StaticDoubleLinked {
     prev: &'static StaticDoubleLinked,
diff --git a/tests/ui/statics/static-recursive.stderr b/tests/ui/statics/static-recursive.stderr
index 15888e5c68d84..cd285c6c2a463 100644
--- a/tests/ui/statics/static-recursive.stderr
+++ b/tests/ui/statics/static-recursive.stderr
@@ -1,14 +1,14 @@
-warning: shared reference of mutable static is discouraged
+warning: creating a shared reference to mutable static is discouraged
   --> $DIR/static-recursive.rs:3:36
    |
 LL | static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 };
-   |                                    ^^ shared reference of mutable static
+   |                                    ^^ shared reference to mutable static
    |
    = note: for more information, see issue #114447 <https://github.com/rust-lang/rust/issues/114447>
-   = note: reference of mutable static is a hard error from 2024 edition
-   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
-   = note: `#[warn(static_mut_ref)]` on by default
-help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer
+   = note: this will be a hard error in the 2024 edition
+   = note: this shared reference has lifetime `'static`, but if the static ever gets mutated, or a mutable reference is created, then any further use of this shared reference is Undefined Behavior
+   = note: `#[warn(static_mut_refs)]` on by default
+help: use `addr_of!` instead to create a raw pointer
    |
 LL | static mut S: *const u8 = unsafe { addr_of!(S) as *const *const u8 as *const u8 };
    |                                    ~~~~~~~~~~~
diff --git a/tests/ui/thread-local/thread-local-static.rs b/tests/ui/thread-local/thread-local-static.rs
index a2c1954881f89..3da1b80a5dd5b 100644
--- a/tests/ui/thread-local/thread-local-static.rs
+++ b/tests/ui/thread-local/thread-local-static.rs
@@ -2,7 +2,7 @@
 
 #![feature(thread_local)]
 #![feature(const_swap)]
-#![allow(static_mut_ref)]
+#![allow(static_mut_refs)]
 
 #[thread_local]
 static mut STATIC_VAR_2: [u32; 8] = [4; 8];

From 3b791a41f99f52d02fc1ebbd5ccd6a95ca52cd5a Mon Sep 17 00:00:00 2001
From: Lukas Markeffsky <@>
Date: Thu, 23 Nov 2023 10:25:25 +0000
Subject: [PATCH 45/58] simplify codegen for trivially droppable types

---
 library/alloc/src/collections/vec_deque/drain.rs | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/library/alloc/src/collections/vec_deque/drain.rs b/library/alloc/src/collections/vec_deque/drain.rs
index 0be274a3822d3..7d40ce65ad75b 100644
--- a/library/alloc/src/collections/vec_deque/drain.rs
+++ b/library/alloc/src/collections/vec_deque/drain.rs
@@ -96,8 +96,9 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
         struct DropGuard<'r, 'a, T, A: Allocator>(&'r mut Drain<'a, T, A>);
 
         impl<'r, 'a, T, A: Allocator> Drop for DropGuard<'r, 'a, T, A> {
+            #[inline]
             fn drop(&mut self) {
-                if self.0.remaining != 0 {
+                if mem::needs_drop::<T>() && self.0.remaining != 0 {
                     unsafe {
                         // SAFETY: We just checked that `self.remaining != 0`.
                         let (front, back) = self.0.as_slices();
@@ -158,7 +159,7 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
         }
 
         let guard = DropGuard(self);
-        if guard.0.remaining != 0 {
+        if mem::needs_drop::<T>() && guard.0.remaining != 0 {
             unsafe {
                 // SAFETY: We just checked that `self.remaining != 0`.
                 let (front, back) = guard.0.as_slices();

From fe9bc1be27aa6d8feeab8f87e5c56d45e352f496 Mon Sep 17 00:00:00 2001
From: Lukas Markeffsky <@>
Date: Thu, 23 Nov 2023 10:41:35 +0000
Subject: [PATCH 46/58] reduce amount of math

---
 .../alloc/src/collections/vec_deque/drain.rs  | 26 +++++++++----------
 1 file changed, 12 insertions(+), 14 deletions(-)

diff --git a/library/alloc/src/collections/vec_deque/drain.rs b/library/alloc/src/collections/vec_deque/drain.rs
index 7d40ce65ad75b..aa5cc0fb1ce2b 100644
--- a/library/alloc/src/collections/vec_deque/drain.rs
+++ b/library/alloc/src/collections/vec_deque/drain.rs
@@ -27,8 +27,8 @@ pub struct Drain<
     drain_len: usize,
     // index into the logical array, not the physical one (always lies in [0..deque.len))
     idx: usize,
-    // number of elements after the drain range
-    tail_len: usize,
+    // number of elements remaining after dropping the drain
+    new_len: usize,
     remaining: usize,
     // Needed to make Drain covariant over T
     _marker: PhantomData<&'a T>,
@@ -41,12 +41,12 @@ impl<'a, T, A: Allocator> Drain<'a, T, A> {
         drain_len: usize,
     ) -> Self {
         let orig_len = mem::replace(&mut deque.len, drain_start);
-        let tail_len = orig_len - drain_start - drain_len;
+        let new_len = orig_len - drain_len;
         Drain {
             deque: NonNull::from(deque),
             drain_len,
             idx: drain_start,
-            tail_len,
+            new_len,
             remaining: drain_len,
             _marker: PhantomData,
         }
@@ -79,7 +79,7 @@ impl<T: fmt::Debug, A: Allocator> fmt::Debug for Drain<'_, T, A> {
         f.debug_tuple("Drain")
             .field(&self.drain_len)
             .field(&self.idx)
-            .field(&self.tail_len)
+            .field(&self.new_len)
             .field(&self.remaining)
             .finish()
     }
@@ -111,18 +111,16 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
 
                 let drain_start = source_deque.len();
                 let drain_len = self.0.drain_len;
-                let drain_end = drain_start + drain_len;
-
-                let orig_len = self.0.tail_len + drain_end;
+                let new_len = self.0.new_len;
 
                 if T::IS_ZST {
                     // no need to copy around any memory if T is a ZST
-                    source_deque.len = orig_len - drain_len;
+                    source_deque.len = new_len;
                     return;
                 }
 
                 let head_len = drain_start;
-                let tail_len = self.0.tail_len;
+                let tail_len = new_len - head_len;
 
                 match (head_len, tail_len) {
                     (0, 0) => {
@@ -131,10 +129,10 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
                     }
                     (0, _) => {
                         source_deque.head = source_deque.to_physical_idx(drain_len);
-                        source_deque.len = orig_len - drain_len;
+                        source_deque.len = new_len;
                     }
                     (_, 0) => {
-                        source_deque.len = orig_len - drain_len;
+                        source_deque.len = new_len;
                     }
                     _ => unsafe {
                         if head_len <= tail_len {
@@ -144,14 +142,14 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
                                 head_len,
                             );
                             source_deque.head = source_deque.to_physical_idx(drain_len);
-                            source_deque.len = orig_len - drain_len;
+                            source_deque.len = new_len;
                         } else {
                             source_deque.wrap_copy(
                                 source_deque.to_physical_idx(head_len + drain_len),
                                 source_deque.to_physical_idx(head_len),
                                 tail_len,
                             );
-                            source_deque.len = orig_len - drain_len;
+                            source_deque.len = new_len;
                         }
                     },
                 }

From b13c926ea644bfa7a21353630e6d552836a61b00 Mon Sep 17 00:00:00 2001
From: Lukas Markeffsky <@>
Date: Thu, 23 Nov 2023 16:03:21 +0000
Subject: [PATCH 47/58] reduce branchiness

---
 .../alloc/src/collections/vec_deque/drain.rs  | 53 ++++++++-----------
 1 file changed, 22 insertions(+), 31 deletions(-)

diff --git a/library/alloc/src/collections/vec_deque/drain.rs b/library/alloc/src/collections/vec_deque/drain.rs
index aa5cc0fb1ce2b..7a413ddf971d7 100644
--- a/library/alloc/src/collections/vec_deque/drain.rs
+++ b/library/alloc/src/collections/vec_deque/drain.rs
@@ -109,7 +109,6 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
 
                 let source_deque = unsafe { self.0.deque.as_mut() };
 
-                let drain_start = source_deque.len();
                 let drain_len = self.0.drain_len;
                 let new_len = self.0.new_len;
 
@@ -119,40 +118,32 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
                     return;
                 }
 
-                let head_len = drain_start;
+                let head_len = source_deque.len();
                 let tail_len = new_len - head_len;
 
-                match (head_len, tail_len) {
-                    (0, 0) => {
-                        source_deque.head = 0;
-                        source_deque.len = 0;
-                    }
-                    (0, _) => {
-                        source_deque.head = source_deque.to_physical_idx(drain_len);
-                        source_deque.len = new_len;
-                    }
-                    (_, 0) => {
-                        source_deque.len = new_len;
+                if head_len != 0 && tail_len != 0 {
+                    let (src, dst, len);
+                    if head_len < tail_len {
+                        src = source_deque.head;
+                        dst = source_deque.to_physical_idx(drain_len);
+                        len = head_len;
+                    } else {
+                        src = source_deque.to_physical_idx(head_len + drain_len);
+                        dst = source_deque.to_physical_idx(head_len);
+                        len = tail_len;
+                    };
+
+                    unsafe {
+                        source_deque.wrap_copy(src, dst, len);
                     }
-                    _ => unsafe {
-                        if head_len <= tail_len {
-                            source_deque.wrap_copy(
-                                source_deque.head,
-                                source_deque.to_physical_idx(drain_len),
-                                head_len,
-                            );
-                            source_deque.head = source_deque.to_physical_idx(drain_len);
-                            source_deque.len = new_len;
-                        } else {
-                            source_deque.wrap_copy(
-                                source_deque.to_physical_idx(head_len + drain_len),
-                                source_deque.to_physical_idx(head_len),
-                                tail_len,
-                            );
-                            source_deque.len = new_len;
-                        }
-                    },
                 }
+
+                if new_len == 0 {
+                    source_deque.head = 0;
+                } else if head_len < tail_len {
+                    source_deque.head = source_deque.to_physical_idx(drain_len);
+                }
+                source_deque.len = new_len;
             }
         }
 

From 064f97260cb205bbf6657f9a54b5f4a112ca0ab0 Mon Sep 17 00:00:00 2001
From: Lukas Markeffsky <@>
Date: Thu, 23 Nov 2023 23:31:19 +0100
Subject: [PATCH 48/58] outline large copies

---
 .../alloc/src/collections/vec_deque/drain.rs  | 27 ++++++++++++++-----
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/library/alloc/src/collections/vec_deque/drain.rs b/library/alloc/src/collections/vec_deque/drain.rs
index 7a413ddf971d7..bf8c9b2d47aed 100644
--- a/library/alloc/src/collections/vec_deque/drain.rs
+++ b/library/alloc/src/collections/vec_deque/drain.rs
@@ -121,7 +121,27 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
                 let head_len = source_deque.len();
                 let tail_len = new_len - head_len;
 
+                // When draining at the front (`.drain(..n)`) or at the back (`.drain(n..)`),
+                // we don't need to copy any data.
+                // Outlining this function helps LLVM to eliminate the copies in these cases.
                 if head_len != 0 && tail_len != 0 {
+                    copy_data(source_deque, drain_len, head_len, tail_len);
+                }
+
+                if new_len == 0 {
+                    source_deque.head = 0;
+                } else if head_len < tail_len {
+                    source_deque.head = source_deque.to_physical_idx(drain_len);
+                }
+                source_deque.len = new_len;
+
+                #[cold]
+                fn copy_data<T, A: Allocator>(
+                    source_deque: &mut VecDeque<T, A>,
+                    drain_len: usize,
+                    head_len: usize,
+                    tail_len: usize,
+                ) {
                     let (src, dst, len);
                     if head_len < tail_len {
                         src = source_deque.head;
@@ -137,13 +157,6 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
                         source_deque.wrap_copy(src, dst, len);
                     }
                 }
-
-                if new_len == 0 {
-                    source_deque.head = 0;
-                } else if head_len < tail_len {
-                    source_deque.head = source_deque.to_physical_idx(drain_len);
-                }
-                source_deque.len = new_len;
             }
         }
 

From a77d6b983d2e96d8405b1fe84128e72384d41df2 Mon Sep 17 00:00:00 2001
From: Lukas Markeffsky <@>
Date: Thu, 23 Nov 2023 23:11:22 +0100
Subject: [PATCH 49/58] add codegen test

---
 tests/codegen/vecdeque-drain.rs | 68 +++++++++++++++++++++++++++++++++
 1 file changed, 68 insertions(+)
 create mode 100644 tests/codegen/vecdeque-drain.rs

diff --git a/tests/codegen/vecdeque-drain.rs b/tests/codegen/vecdeque-drain.rs
new file mode 100644
index 0000000000000..4a25a1c40f9a7
--- /dev/null
+++ b/tests/codegen/vecdeque-drain.rs
@@ -0,0 +1,68 @@
+// Check that draining at the front or back doesn't copy memory.
+
+// compile-flags: -O
+// ignore-debug: the debug assertions get in the way
+
+#![crate_type = "lib"]
+
+use std::collections::VecDeque;
+
+// CHECK-LABEL: @clear
+// CHECK-NOT: call
+// CHECK-NOT: br
+// CHECK: getelementptr inbounds
+// CHECK-NEXT: call void @llvm.memset
+// CHECK-NEXT: ret void
+#[no_mangle]
+pub fn clear(v: &mut VecDeque<i32>) {
+    v.drain(..);
+}
+
+// CHECK-LABEL: @truncate
+// CHECK-NOT: call
+// CHECK: br
+// CHECK-NOT: call
+// CHECK: br
+// CHECK-NOT: call
+// CHECK: br
+// CHECK-NOT: call
+// CHECK: br
+// CHECK-NOT: call
+// CHECK-NOT: br
+// CHECK: ret void
+#[no_mangle]
+pub fn truncate(v: &mut VecDeque<i32>, n: usize) {
+    if n < v.len() {
+        v.drain(n..);
+    }
+}
+
+// CHECK-LABEL: @advance
+// CHECK-NOT: call
+// CHECK: br
+// CHECK-NOT: call
+// CHECK: br
+// CHECK-NOT: call
+// CHECK: br
+// CHECK-NOT: call
+// CHECK: br
+// CHECK-NOT: call
+// CHECK: br
+// CHECK-NOT: call
+// CHECK-NOT: br
+// CHECK: ret void
+#[no_mangle]
+pub fn advance(v: &mut VecDeque<i32>, n: usize) {
+    if n < v.len() {
+        v.drain(..n);
+    } else {
+        v.clear();
+    }
+}
+
+// CHECK-LABEL: @remove
+// CHECK: call
+#[no_mangle]
+pub fn remove(v: &mut VecDeque<i32>, a: usize, b: usize) {
+    v.drain(a..b);
+}

From da1c7f639d3d443cba4c05e18e7c58daa87fd572 Mon Sep 17 00:00:00 2001
From: Lukas Markeffsky <@>
Date: Sun, 11 Feb 2024 17:13:23 +0100
Subject: [PATCH 50/58] address review comments

---
 .../alloc/src/collections/vec_deque/drain.rs  | 143 ++++++++++++------
 1 file changed, 99 insertions(+), 44 deletions(-)

diff --git a/library/alloc/src/collections/vec_deque/drain.rs b/library/alloc/src/collections/vec_deque/drain.rs
index bf8c9b2d47aed..1373e60149274 100644
--- a/library/alloc/src/collections/vec_deque/drain.rs
+++ b/library/alloc/src/collections/vec_deque/drain.rs
@@ -95,6 +95,22 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
     fn drop(&mut self) {
         struct DropGuard<'r, 'a, T, A: Allocator>(&'r mut Drain<'a, T, A>);
 
+        let guard = DropGuard(self);
+
+        if mem::needs_drop::<T>() && guard.0.remaining != 0 {
+            unsafe {
+                // SAFETY: We just checked that `self.remaining != 0`.
+                let (front, back) = guard.0.as_slices();
+                // since idx is a logical index, we don't need to worry about wrapping.
+                guard.0.idx += front.len();
+                guard.0.remaining -= front.len();
+                ptr::drop_in_place(front);
+                guard.0.remaining = 0;
+                ptr::drop_in_place(back);
+            }
+        }
+
+        // Dropping `guard` handles moving the remaining elements into place.
         impl<'r, 'a, T, A: Allocator> Drop for DropGuard<'r, 'a, T, A> {
             #[inline]
             fn drop(&mut self) {
@@ -118,63 +134,102 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
                     return;
                 }
 
-                let head_len = source_deque.len();
-                let tail_len = new_len - head_len;
+                let head_len = source_deque.len; // #elements in front of the drain
+                let tail_len = new_len - head_len; // #elements behind the drain
+
+                // Next, we will fill the hole left by the drain with as few writes as possible.
+                // The code below handles the following control flow and reduces the amount of
+                // branches under the assumption that `head_len == 0 || tail_len == 0`, i.e.
+                // draining at the front or at the back of the dequeue is especially common.
+                //
+                // H = "head index" = `deque.head`
+                // h = elements in front of the drain
+                // d = elements in the drain
+                // t = elements behind the drain
+                //
+                // Note that the buffer may wrap at any point and the wrapping is handled by
+                // `wrap_copy` and `to_physical_idx`.
+                //
+                // Case 1: if `head_len == 0 && tail_len == 0`
+                // Everything was drained, reset the head index back to 0.
+                //             H
+                // [ . . . . . d d d d . . . . . ]
+                //   H
+                // [ . . . . . . . . . . . . . . ]
+                //
+                // Case 2: else if `tail_len == 0`
+                // Don't move data or the head index.
+                //         H
+                // [ . . . h h h h d d d d . . . ]
+                //         H
+                // [ . . . h h h h . . . . . . . ]
+                //
+                // Case 3: else if `head_len == 0`
+                // Don't move data, but move the head index.
+                //         H
+                // [ . . . d d d d t t t t . . . ]
+                //                 H
+                // [ . . . . . . . t t t t . . . ]
+                //
+                // Case 4: else if `tail_len <= head_len`
+                // Move data, but not the head index.
+                //       H
+                // [ . . h h h h d d d d t t . . ]
+                //       H
+                // [ . . h h h h t t . . . . . . ]
+                //
+                // Case 5: else
+                // Move data and the head index.
+                //       H
+                // [ . . h h d d d d t t t t . . ]
+                //               H
+                // [ . . . . . . h h t t t t . . ]
 
                 // When draining at the front (`.drain(..n)`) or at the back (`.drain(n..)`),
-                // we don't need to copy any data.
-                // Outlining this function helps LLVM to eliminate the copies in these cases.
+                // we don't need to copy any data. The number of elements copied would be 0.
                 if head_len != 0 && tail_len != 0 {
-                    copy_data(source_deque, drain_len, head_len, tail_len);
+                    join_head_and_tail_wrapping(source_deque, drain_len, head_len, tail_len);
+                    // Marking this function as cold helps LLVM to eliminate it entirely if
+                    // this branch is never taken.
+                    // We use `#[cold]` instead of `#[inline(never)]`, because inlining this
+                    // function into the general case (`.drain(n..m)`) is fine.
+                    // See `tests/codegen/vecdeque-drain.rs` for a test.
+                    #[cold]
+                    fn join_head_and_tail_wrapping<T, A: Allocator>(
+                        source_deque: &mut VecDeque<T, A>,
+                        drain_len: usize,
+                        head_len: usize,
+                        tail_len: usize,
+                    ) {
+                        // Pick whether to move the head or the tail here.
+                        let (src, dst, len);
+                        if head_len < tail_len {
+                            src = source_deque.head;
+                            dst = source_deque.to_physical_idx(drain_len);
+                            len = head_len;
+                        } else {
+                            src = source_deque.to_physical_idx(head_len + drain_len);
+                            dst = source_deque.to_physical_idx(head_len);
+                            len = tail_len;
+                        };
+
+                        unsafe {
+                            source_deque.wrap_copy(src, dst, len);
+                        }
+                    }
                 }
 
                 if new_len == 0 {
+                    // Special case: If the entire dequeue was drained, reset the head back to 0,
+                    // like `.clear()` does.
                     source_deque.head = 0;
                 } else if head_len < tail_len {
+                    // If we moved the head above, then we need to adjust the head index here.
                     source_deque.head = source_deque.to_physical_idx(drain_len);
                 }
                 source_deque.len = new_len;
-
-                #[cold]
-                fn copy_data<T, A: Allocator>(
-                    source_deque: &mut VecDeque<T, A>,
-                    drain_len: usize,
-                    head_len: usize,
-                    tail_len: usize,
-                ) {
-                    let (src, dst, len);
-                    if head_len < tail_len {
-                        src = source_deque.head;
-                        dst = source_deque.to_physical_idx(drain_len);
-                        len = head_len;
-                    } else {
-                        src = source_deque.to_physical_idx(head_len + drain_len);
-                        dst = source_deque.to_physical_idx(head_len);
-                        len = tail_len;
-                    };
-
-                    unsafe {
-                        source_deque.wrap_copy(src, dst, len);
-                    }
-                }
-            }
-        }
-
-        let guard = DropGuard(self);
-        if mem::needs_drop::<T>() && guard.0.remaining != 0 {
-            unsafe {
-                // SAFETY: We just checked that `self.remaining != 0`.
-                let (front, back) = guard.0.as_slices();
-                // since idx is a logical index, we don't need to worry about wrapping.
-                guard.0.idx += front.len();
-                guard.0.remaining -= front.len();
-                ptr::drop_in_place(front);
-                guard.0.remaining = 0;
-                ptr::drop_in_place(back);
             }
         }
-
-        // Dropping `guard` handles moving the remaining elements into place.
     }
 }
 

From cc7b4e02beecdb75b3b5ee348840b50d06ad67c1 Mon Sep 17 00:00:00 2001
From: Adam Gemmell <adam.gemmell@arm.com>
Date: Thu, 25 Jan 2024 15:28:23 +0000
Subject: [PATCH 51/58] Update aarch64 target feature docs to match LLVM

---
 compiler/rustc_target/src/target_features.rs | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index 04943fa3879fb..2b7ac68c21dfb 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -86,7 +86,7 @@ const ARM_ALLOWED_FEATURES: &[(&str, Stability)] = &[
 
 const AARCH64_ALLOWED_FEATURES: &[(&str, Stability)] = &[
     // tidy-alphabetical-start
-    // FEAT_AES
+    // FEAT_AES & FEAT_PMULL
     ("aes", Stable),
     // FEAT_BF16
     ("bf16", Stable),
@@ -124,7 +124,7 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability)] = &[
     ("lor", Stable),
     // FEAT_LSE
     ("lse", Stable),
-    // FEAT_MTE
+    // FEAT_MTE & FEAT_MTE2
     ("mte", Stable),
     // FEAT_AdvSimd & FEAT_FP
     ("neon", Stable),
@@ -138,7 +138,7 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability)] = &[
     ("pmuv3", Stable),
     // FEAT_RAND
     ("rand", Stable),
-    // FEAT_RAS
+    // FEAT_RAS & FEAT_RASv1p1
     ("ras", Stable),
     // FEAT_RCPC
     ("rcpc", Stable),
@@ -156,7 +156,7 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability)] = &[
     ("sm4", Stable),
     // FEAT_SPE
     ("spe", Stable),
-    // FEAT_SSBS
+    // FEAT_SSBS & FEAT_SSBS2
     ("ssbs", Stable),
     // FEAT_SVE
     ("sve", Stable),

From 5d65b1954ef4dc6ea3a1260e1bce31524fc286f4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= <tomasz.miasko@gmail.com>
Date: Thu, 15 Feb 2024 00:00:00 +0000
Subject: [PATCH 52/58] Avoid debug logging entire MIR body

If there is a need to examine the MIR body there is -Zmir-dump.
---
 compiler/rustc_mir_transform/src/lib.rs                      | 1 -
 compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs | 5 ++---
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index b4fa7f3bea6a0..fb174192b8492 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -653,7 +653,6 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
     debug!("about to call mir_drops_elaborated...");
     let body = tcx.mir_drops_elaborated_and_const_checked(did).steal();
     let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::NotConst);
-    debug!("body: {:#?}", body);
 
     if body.tainted_by_errors.is_some() {
         return body;
diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
index 095119e2e3ff8..fb52bfa468a01 100644
--- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
+++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
@@ -15,7 +15,8 @@ impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads {
     }
 
     fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        debug!("remove_noop_landing_pads({:?})", body);
+        let def_id = body.source.def_id();
+        debug!(?def_id);
         self.remove_nop_landing_pads(body)
     }
 }
@@ -81,8 +82,6 @@ impl RemoveNoopLandingPads {
     }
 
     fn remove_nop_landing_pads(&self, body: &mut Body<'_>) {
-        debug!("body: {:#?}", body);
-
         // Skip the pass if there are no blocks with a resume terminator.
         let has_resume = body
             .basic_blocks

From c763f833d14d31fbe63e0b26370a23a51b4f11c5 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Thu, 15 Feb 2024 14:34:42 +0000
Subject: [PATCH 53/58] Only point out non-diverging arms for match suggestions

---
 compiler/rustc_hir_typeck/src/_match.rs       | 14 +++++------
 .../src/infer/error_reporting/mod.rs          | 13 ++++++----
 .../src/infer/error_reporting/suggest.rs      | 11 +++++---
 compiler/rustc_middle/src/traits/mod.rs       |  2 +-
 .../ui/match/dont-highlight-diverging-arms.rs | 17 +++++++++++++
 .../dont-highlight-diverging-arms.stderr      | 25 +++++++++++++++++++
 .../match/match-arm-resolving-to-never.stderr |  5 +++-
 7 files changed, 69 insertions(+), 18 deletions(-)
 create mode 100644 tests/ui/match/dont-highlight-diverging-arms.rs
 create mode 100644 tests/ui/match/dont-highlight-diverging-arms.stderr

diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index 0311aa94cd485..214066814221b 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -79,7 +79,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             CoerceMany::with_coercion_sites(coerce_first, arms)
         };
 
-        let mut other_arms = vec![]; // Used only for diagnostics.
+        let mut prior_non_diverging_arms = vec![]; // Used only for diagnostics.
         let mut prior_arm = None;
         for arm in arms {
             if let Some(e) = &arm.guard {
@@ -120,7 +120,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         scrut_span: scrut.span,
                         scrut_hir_id: scrut.hir_id,
                         source: match_src,
-                        prior_arms: other_arms.clone(),
+                        prior_non_diverging_arms: prior_non_diverging_arms.clone(),
                         opt_suggest_box_span,
                     })),
                 ),
@@ -142,16 +142,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 false,
             );
 
-            other_arms.push(arm_span);
-            if other_arms.len() > 5 {
-                other_arms.remove(0);
-            }
-
             if !arm_ty.is_never() {
                 // When a match arm has type `!`, then it doesn't influence the expected type for
                 // the following arm. If all of the prior arms are `!`, then the influence comes
                 // from elsewhere and we shouldn't point to any previous arm.
                 prior_arm = Some((arm_block_id, arm_ty, arm_span));
+
+                prior_non_diverging_arms.push(arm_span);
+                if prior_non_diverging_arms.len() > 5 {
+                    prior_non_diverging_arms.remove(0);
+                }
             }
         }
 
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index b953b25d6c4cf..aa92f91f24f83 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -777,7 +777,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 prior_arm_span,
                 prior_arm_ty,
                 source,
-                ref prior_arms,
+                ref prior_non_diverging_arms,
                 opt_suggest_box_span,
                 scrut_span,
                 scrut_hir_id,
@@ -817,12 +817,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     });
                     let source_map = self.tcx.sess.source_map();
                     let mut any_multiline_arm = source_map.is_multiline(arm_span);
-                    if prior_arms.len() <= 4 {
-                        for sp in prior_arms {
+                    if prior_non_diverging_arms.len() <= 4 {
+                        for sp in prior_non_diverging_arms {
                             any_multiline_arm |= source_map.is_multiline(*sp);
                             err.span_label(*sp, format!("this is found to be of type `{t}`"));
                         }
-                    } else if let Some(sp) = prior_arms.last() {
+                    } else if let Some(sp) = prior_non_diverging_arms.last() {
                         any_multiline_arm |= source_map.is_multiline(*sp);
                         err.span_label(
                             *sp,
@@ -865,7 +865,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         self.suggest_boxing_for_return_impl_trait(
                             err,
                             ret_sp,
-                            prior_arms.iter().chain(std::iter::once(&arm_span)).copied(),
+                            prior_non_diverging_arms
+                                .iter()
+                                .chain(std::iter::once(&arm_span))
+                                .copied(),
                         );
                     }
                 }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
index 248e1c0fcc878..c6f6c32fe60c2 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
@@ -203,10 +203,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     })
                 }
                 ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
-                    prior_arms,
+                    prior_non_diverging_arms,
                     ..
                 }) => {
-                    if let [.., arm_span] = &prior_arms[..] {
+                    if let [.., arm_span] = &prior_non_diverging_arms[..] {
                         Some(ConsiderAddingAwait::BothFuturesSugg {
                             first: arm_span.shrink_to_hi(),
                             second: exp_span.shrink_to_hi(),
@@ -234,11 +234,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     Some(ConsiderAddingAwait::FutureSugg { span: then_span.shrink_to_hi() })
                 }
                 ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
-                    ref prior_arms,
+                    ref prior_non_diverging_arms,
                     ..
                 }) => Some({
                     ConsiderAddingAwait::FutureSuggMultiple {
-                        spans: prior_arms.iter().map(|arm| arm.shrink_to_hi()).collect(),
+                        spans: prior_non_diverging_arms
+                            .iter()
+                            .map(|arm| arm.shrink_to_hi())
+                            .collect(),
                     }
                 }),
                 _ => None,
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 8e5f026b4c27c..683610ba3b6a3 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -571,7 +571,7 @@ pub struct MatchExpressionArmCause<'tcx> {
     pub scrut_span: Span,
     pub scrut_hir_id: hir::HirId,
     pub source: hir::MatchSource,
-    pub prior_arms: Vec<Span>,
+    pub prior_non_diverging_arms: Vec<Span>,
     pub opt_suggest_box_span: Option<Span>,
 }
 
diff --git a/tests/ui/match/dont-highlight-diverging-arms.rs b/tests/ui/match/dont-highlight-diverging-arms.rs
new file mode 100644
index 0000000000000..dc3b4ca9caad6
--- /dev/null
+++ b/tests/ui/match/dont-highlight-diverging-arms.rs
@@ -0,0 +1,17 @@
+fn main() {
+    let m = 42u32;
+
+    let value = 'out: {
+        match m {
+            1 => break 'out Some(1u16),
+            2 => Some(2u16),
+            3 => break 'out Some(3u16),
+            4 => break 'out Some(4u16),
+            5 => break 'out Some(5u16),
+            _ => {}
+            //~^ ERROR  `match` arms have incompatible types
+        }
+
+        None
+    };
+}
\ No newline at end of file
diff --git a/tests/ui/match/dont-highlight-diverging-arms.stderr b/tests/ui/match/dont-highlight-diverging-arms.stderr
new file mode 100644
index 0000000000000..886c1af13fa37
--- /dev/null
+++ b/tests/ui/match/dont-highlight-diverging-arms.stderr
@@ -0,0 +1,25 @@
+error[E0308]: `match` arms have incompatible types
+  --> $DIR/dont-highlight-diverging-arms.rs:11:18
+   |
+LL | /         match m {
+LL | |             1 => break 'out Some(1u16),
+LL | |             2 => Some(2u16),
+   | |                  ---------- this is found to be of type `Option<u16>`
+LL | |             3 => break 'out Some(3u16),
+...  |
+LL | |             _ => {}
+   | |                  ^^ expected `Option<u16>`, found `()`
+LL | |
+LL | |         }
+   | |_________- `match` arms have incompatible types
+   |
+   = note:   expected enum `Option<u16>`
+           found unit type `()`
+help: consider using a semicolon here, but this will discard any values in the match arms
+   |
+LL |         };
+   |          +
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/match/match-arm-resolving-to-never.stderr b/tests/ui/match/match-arm-resolving-to-never.stderr
index 6cbdf03d4c27d..fd0c8708b8ca3 100644
--- a/tests/ui/match/match-arm-resolving-to-never.stderr
+++ b/tests/ui/match/match-arm-resolving-to-never.stderr
@@ -3,11 +3,14 @@ error[E0308]: `match` arms have incompatible types
    |
 LL | /     match E::F {
 LL | |         E::A => 1,
+   | |                 - this is found to be of type `{integer}`
 LL | |         E::B => 2,
+   | |                 - this is found to be of type `{integer}`
 LL | |         E::C => 3,
+   | |                 - this is found to be of type `{integer}`
 LL | |         E::D => 4,
+   | |                 - this is found to be of type `{integer}`
 LL | |         E::E => unimplemented!(""),
-   | |                 ------------------ this and all prior arms are found to be of type `{integer}`
 LL | |         E::F => "",
    | |                 ^^ expected integer, found `&str`
 LL | |     };

From acb201af54e15b1beebb5b8a6691f6c851afe177 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Wed, 14 Feb 2024 23:52:57 +0000
Subject: [PATCH 54/58] make better async fn kind errors

---
 compiler/rustc_trait_selection/messages.ftl   |  12 +-
 compiler/rustc_trait_selection/src/errors.rs  |  10 ++
 .../error_reporting/type_err_ctxt_ext.rs      | 123 ++++++++++++++----
 tests/ui/async-await/async-closures/not-fn.rs |  15 +++
 .../async-await/async-closures/not-fn.stderr  |  16 +++
 .../async-closures/wrong-fn-kind.rs           |   3 +-
 .../async-closures/wrong-fn-kind.stderr       |  12 +-
 7 files changed, 154 insertions(+), 37 deletions(-)
 create mode 100644 tests/ui/async-await/async-closures/not-fn.rs
 create mode 100644 tests/ui/async-await/async-closures/not-fn.stderr

diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl
index 41db8059cbee3..0dcba0e05f76f 100644
--- a/compiler/rustc_trait_selection/messages.ftl
+++ b/compiler/rustc_trait_selection/messages.ftl
@@ -8,14 +8,16 @@ trait_selection_adjust_signature_remove_borrow = consider adjusting the signatur
         *[other] arguments
     }
 
-trait_selection_closure_fn_mut_label = closure is `FnMut` because it mutates the variable `{$place}` here
+trait_selection_async_closure_not_fn = async closure does not implement `{$kind}` because it captures state from its environment
 
-trait_selection_closure_fn_once_label = closure is `FnOnce` because it moves the variable `{$place}` out of its environment
+trait_selection_closure_fn_mut_label = closure is `{$trait_prefix}FnMut` because it mutates the variable `{$place}` here
 
-trait_selection_closure_kind_mismatch = expected a closure that implements the `{$expected}` trait, but this closure only implements `{$found}`
-    .label = this closure implements `{$found}`, not `{$expected}`
+trait_selection_closure_fn_once_label = closure is `{$trait_prefix}FnOnce` because it moves the variable `{$place}` out of its environment
 
-trait_selection_closure_kind_requirement = the requirement to implement `{$expected}` derives from here
+trait_selection_closure_kind_mismatch = expected a closure that implements the `{$trait_prefix}{$expected}` trait, but this closure only implements `{$trait_prefix}{$found}`
+    .label = this closure implements `{$trait_prefix}{$found}`, not `{$trait_prefix}{$expected}`
+
+trait_selection_closure_kind_requirement = the requirement to implement `{$trait_prefix}{$expected}` derives from here
 
 trait_selection_dump_vtable_entries = vtable entries for `{$trait_ref}`: {$entries}
 
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index 20cd573f46e9b..407fff03e1588 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -135,6 +135,8 @@ pub struct ClosureKindMismatch {
     #[label(trait_selection_closure_kind_requirement)]
     pub cause_span: Span,
 
+    pub trait_prefix: &'static str,
+
     #[subdiagnostic]
     pub fn_once_label: Option<ClosureFnOnceLabel>,
 
@@ -157,3 +159,11 @@ pub struct ClosureFnMutLabel {
     pub span: Span,
     pub place: String,
 }
+
+#[derive(Diagnostic)]
+#[diag(trait_selection_async_closure_not_fn)]
+pub(crate) struct AsyncClosureNotFn {
+    #[primary_span]
+    pub span: Span,
+    pub kind: &'static str,
+}
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
index 73effb3356065..68b1a0d4e61cd 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
@@ -2,7 +2,9 @@
 
 use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt as _};
 use super::suggestions::{get_explanation_based_on_obligation, TypeErrCtxtExt as _};
-use crate::errors::{ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch};
+use crate::errors::{
+    AsyncClosureNotFn, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch,
+};
 use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
 use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use crate::infer::InferCtxtExt as _;
@@ -959,34 +961,102 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
     fn emit_specialized_closure_kind_error(
         &self,
         obligation: &PredicateObligation<'tcx>,
-        trait_ref: ty::PolyTraitRef<'tcx>,
+        mut trait_ref: ty::PolyTraitRef<'tcx>,
     ) -> Option<ErrorGuaranteed> {
-        let self_ty = trait_ref.self_ty().skip_binder();
-        if let ty::Closure(closure_def_id, closure_args) = *self_ty.kind()
-            && let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id())
-            && let Some(found_kind) = self.closure_kind(self_ty)
+        // If `AsyncFnKindHelper` is not implemented, that means that the closure kind
+        // doesn't extend the goal kind. This is worth reporting, but we can only do so
+        // if we actually know which closure this goal comes from, so look at the cause
+        // to see if we can extract that information.
+        if Some(trait_ref.def_id()) == self.tcx.lang_items().async_fn_kind_helper()
+            && let Some(found_kind) = trait_ref.skip_binder().args.type_at(0).to_opt_closure_kind()
+            && let Some(expected_kind) =
+                trait_ref.skip_binder().args.type_at(1).to_opt_closure_kind()
             && !found_kind.extends(expected_kind)
-            && let sig = closure_args.as_closure().sig()
-            && self.can_sub(
-                obligation.param_env,
-                trait_ref,
-                sig.map_bound(|sig| {
-                    ty::TraitRef::new(
-                        self.tcx,
-                        trait_ref.def_id(),
-                        [trait_ref.self_ty().skip_binder(), sig.inputs()[0]],
-                    )
-                }),
-            )
         {
-            let mut err =
-                self.report_closure_error(&obligation, closure_def_id, found_kind, expected_kind);
-            self.note_obligation_cause(&mut err, &obligation);
-            self.point_at_returns_when_relevant(&mut err, &obligation);
-            Some(err.emit())
-        } else {
-            None
+            if let Some((_, Some(parent))) = obligation.cause.code().parent() {
+                // If we have a derived obligation, then the parent will be a `AsyncFn*` goal.
+                trait_ref = parent.to_poly_trait_ref();
+            } else if let &ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } =
+                obligation.cause.code()
+                && let Some(typeck_results) = &self.typeck_results
+                && let ty::Closure(closure_def_id, _) | ty::CoroutineClosure(closure_def_id, _) =
+                    *typeck_results.node_type(arg_hir_id).kind()
+            {
+                // Otherwise, extract the closure kind from the obligation.
+                let mut err = self.report_closure_error(
+                    &obligation,
+                    closure_def_id,
+                    found_kind,
+                    expected_kind,
+                    "async ",
+                );
+                self.note_obligation_cause(&mut err, &obligation);
+                self.point_at_returns_when_relevant(&mut err, &obligation);
+                return Some(err.emit());
+            }
+        }
+
+        let self_ty = trait_ref.self_ty().skip_binder();
+
+        if let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id()) {
+            let (closure_def_id, found_args, by_ref_captures) = match *self_ty.kind() {
+                ty::Closure(def_id, args) => {
+                    (def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), None)
+                }
+                ty::CoroutineClosure(def_id, args) => (
+                    def_id,
+                    args.as_coroutine_closure()
+                        .coroutine_closure_sig()
+                        .map_bound(|sig| sig.tupled_inputs_ty),
+                    Some(args.as_coroutine_closure().coroutine_captures_by_ref_ty()),
+                ),
+                _ => return None,
+            };
+
+            let expected_args = trait_ref.map_bound(|trait_ref| trait_ref.args.type_at(1));
+
+            // Verify that the arguments are compatible. If the signature is
+            // mismatched, then we have a totally different error to report.
+            if self.enter_forall(found_args, |found_args| {
+                self.enter_forall(expected_args, |expected_args| {
+                    !self.can_sub(obligation.param_env, expected_args, found_args)
+                })
+            }) {
+                return None;
+            }
+
+            if let Some(found_kind) = self.closure_kind(self_ty)
+                && !found_kind.extends(expected_kind)
+            {
+                let mut err = self.report_closure_error(
+                    &obligation,
+                    closure_def_id,
+                    found_kind,
+                    expected_kind,
+                    "",
+                );
+                self.note_obligation_cause(&mut err, &obligation);
+                self.point_at_returns_when_relevant(&mut err, &obligation);
+                return Some(err.emit());
+            }
+
+            // If the closure has captures, then perhaps the reason that the trait
+            // is unimplemented is because async closures don't implement `Fn`/`FnMut`
+            // if they have captures.
+            if let Some(by_ref_captures) = by_ref_captures
+                && let ty::FnPtr(sig) = by_ref_captures.kind()
+                && !sig.skip_binder().output().is_unit()
+            {
+                let mut err = self.tcx.dcx().create_err(AsyncClosureNotFn {
+                    span: self.tcx.def_span(closure_def_id),
+                    kind: expected_kind.as_str(),
+                });
+                self.note_obligation_cause(&mut err, &obligation);
+                self.point_at_returns_when_relevant(&mut err, &obligation);
+                return Some(err.emit());
+            }
         }
+        None
     }
 
     fn fn_arg_obligation(
@@ -1493,6 +1563,7 @@ pub(super) trait InferCtxtPrivExt<'tcx> {
         closure_def_id: DefId,
         found_kind: ty::ClosureKind,
         kind: ty::ClosureKind,
+        trait_prefix: &'static str,
     ) -> DiagnosticBuilder<'tcx>;
 
     fn report_cyclic_signature_error(
@@ -3376,6 +3447,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         closure_def_id: DefId,
         found_kind: ty::ClosureKind,
         kind: ty::ClosureKind,
+        trait_prefix: &'static str,
     ) -> DiagnosticBuilder<'tcx> {
         let closure_span = self.tcx.def_span(closure_def_id);
 
@@ -3384,6 +3456,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             expected: kind,
             found: found_kind,
             cause_span: obligation.cause.span,
+            trait_prefix,
             fn_once_label: None,
             fn_mut_label: None,
         };
diff --git a/tests/ui/async-await/async-closures/not-fn.rs b/tests/ui/async-await/async-closures/not-fn.rs
new file mode 100644
index 0000000000000..4505e6243e966
--- /dev/null
+++ b/tests/ui/async-await/async-closures/not-fn.rs
@@ -0,0 +1,15 @@
+// edition:2021
+
+// FIXME(async_closures): This needs a better error message!
+
+#![feature(async_closure)]
+
+fn main() {
+    fn needs_fn<T>(_: impl FnMut() -> T) {}
+
+    let mut x = 1;
+    needs_fn(async || {
+        //~^ ERROR  async closure does not implement `FnMut` because it captures state from its environment
+        x += 1;
+    });
+}
diff --git a/tests/ui/async-await/async-closures/not-fn.stderr b/tests/ui/async-await/async-closures/not-fn.stderr
new file mode 100644
index 0000000000000..9c40613599a8e
--- /dev/null
+++ b/tests/ui/async-await/async-closures/not-fn.stderr
@@ -0,0 +1,16 @@
+error: async closure does not implement `FnMut` because it captures state from its environment
+  --> $DIR/not-fn.rs:11:14
+   |
+LL |     needs_fn(async || {
+   |     -------- ^^^^^^^^
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `needs_fn`
+  --> $DIR/not-fn.rs:8:28
+   |
+LL |     fn needs_fn<T>(_: impl FnMut() -> T) {}
+   |                            ^^^^^^^^^^^^ required by this bound in `needs_fn`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/async-await/async-closures/wrong-fn-kind.rs b/tests/ui/async-await/async-closures/wrong-fn-kind.rs
index f86cee3e0709e..1e372deb984e2 100644
--- a/tests/ui/async-await/async-closures/wrong-fn-kind.rs
+++ b/tests/ui/async-await/async-closures/wrong-fn-kind.rs
@@ -9,8 +9,7 @@ fn main() {
 
     let mut x = 1;
     needs_async_fn(async || {
-        //~^ ERROR i16: ops::async_function::internal_implementation_detail::AsyncFnKindHelper<i8>
-        // FIXME: Should say "closure is `async FnMut` but it needs `async Fn`" or sth.
+        //~^ ERROR expected a closure that implements the `async Fn` trait, but this closure only implements `async FnMut`
         x += 1;
     });
 }
diff --git a/tests/ui/async-await/async-closures/wrong-fn-kind.stderr b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr
index 4ef8484cc34cd..34a6b3a485a60 100644
--- a/tests/ui/async-await/async-closures/wrong-fn-kind.stderr
+++ b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr
@@ -1,15 +1,17 @@
-error[E0277]: the trait bound `i16: ops::async_function::internal_implementation_detail::AsyncFnKindHelper<i8>` is not satisfied
+error[E0525]: expected a closure that implements the `async Fn` trait, but this closure only implements `async FnMut`
   --> $DIR/wrong-fn-kind.rs:11:20
    |
 LL |       needs_async_fn(async || {
-   |  _____--------------_^
+   |       -------------- -^^^^^^^
+   |       |              |
+   |  _____|______________this closure implements `async FnMut`, not `async Fn`
    | |     |
    | |     required by a bound introduced by this call
 LL | |
-LL | |         // FIXME: Should say "closure is `async FnMut` but it needs `async Fn`" or sth.
 LL | |         x += 1;
+   | |         - closure is `async FnMut` because it mutates the variable `x` here
 LL | |     });
-   | |_____^ the trait `ops::async_function::internal_implementation_detail::AsyncFnKindHelper<i8>` is not implemented for `i16`
+   | |_____- the requirement to implement `async Fn` derives from here
    |
 note: required by a bound in `needs_async_fn`
   --> $DIR/wrong-fn-kind.rs:8:31
@@ -19,4 +21,4 @@ LL |     fn needs_async_fn(_: impl async Fn()) {}
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0525`.

From 6018e21d8ad072d28dbd2e991dfd8295e2de321f Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Thu, 15 Feb 2024 14:38:52 +0000
Subject: [PATCH 55/58] Remove a suggestion that is redundant

---
 compiler/rustc_hir_typeck/src/_match.rs           |  1 -
 .../rustc_infer/src/infer/error_reporting/mod.rs  | 13 -------------
 compiler/rustc_middle/src/traits/mod.rs           |  1 -
 tests/ui/match/dont-highlight-diverging-arms.rs   |  2 +-
 .../ui/match/dont-highlight-diverging-arms.stderr |  4 ----
 tests/ui/suggestions/issue-81839.stderr           | 15 ++++-----------
 tests/ui/wf/wf-unsafe-trait-obj-match.stderr      |  4 ----
 7 files changed, 5 insertions(+), 35 deletions(-)

diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index 214066814221b..b0caf45b40afe 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -118,7 +118,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         prior_arm_ty,
                         prior_arm_span,
                         scrut_span: scrut.span,
-                        scrut_hir_id: scrut.hir_id,
                         source: match_src,
                         prior_non_diverging_arms: prior_non_diverging_arms.clone(),
                         opt_suggest_box_span,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index aa92f91f24f83..104bf4a5be873 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -780,7 +780,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 ref prior_non_diverging_arms,
                 opt_suggest_box_span,
                 scrut_span,
-                scrut_hir_id,
                 ..
             }) => match source {
                 hir::MatchSource::TryDesugar(scrut_hir_id) => {
@@ -848,18 +847,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     ) {
                         err.subdiagnostic(subdiag);
                     }
-                    if let hir::Node::Expr(m) = self.tcx.parent_hir_node(scrut_hir_id)
-                        && let hir::Node::Stmt(stmt) = self.tcx.parent_hir_node(m.hir_id)
-                        && let hir::StmtKind::Expr(_) = stmt.kind
-                    {
-                        err.span_suggestion_verbose(
-                            stmt.span.shrink_to_hi(),
-                            "consider using a semicolon here, but this will discard any values \
-                             in the match arms",
-                            ";",
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
                     if let Some(ret_sp) = opt_suggest_box_span {
                         // Get return type span and point to it.
                         self.suggest_boxing_for_return_impl_trait(
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 683610ba3b6a3..119e0a49acf1f 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -569,7 +569,6 @@ pub struct MatchExpressionArmCause<'tcx> {
     pub prior_arm_ty: Ty<'tcx>,
     pub prior_arm_span: Span,
     pub scrut_span: Span,
-    pub scrut_hir_id: hir::HirId,
     pub source: hir::MatchSource,
     pub prior_non_diverging_arms: Vec<Span>,
     pub opt_suggest_box_span: Option<Span>,
diff --git a/tests/ui/match/dont-highlight-diverging-arms.rs b/tests/ui/match/dont-highlight-diverging-arms.rs
index dc3b4ca9caad6..0fb614fa18a6f 100644
--- a/tests/ui/match/dont-highlight-diverging-arms.rs
+++ b/tests/ui/match/dont-highlight-diverging-arms.rs
@@ -14,4 +14,4 @@ fn main() {
 
         None
     };
-}
\ No newline at end of file
+}
diff --git a/tests/ui/match/dont-highlight-diverging-arms.stderr b/tests/ui/match/dont-highlight-diverging-arms.stderr
index 886c1af13fa37..f0aaecbb7adb1 100644
--- a/tests/ui/match/dont-highlight-diverging-arms.stderr
+++ b/tests/ui/match/dont-highlight-diverging-arms.stderr
@@ -15,10 +15,6 @@ LL | |         }
    |
    = note:   expected enum `Option<u16>`
            found unit type `()`
-help: consider using a semicolon here, but this will discard any values in the match arms
-   |
-LL |         };
-   |          +
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/suggestions/issue-81839.stderr b/tests/ui/suggestions/issue-81839.stderr
index de1ea98554bee..34ff16c653afa 100644
--- a/tests/ui/suggestions/issue-81839.stderr
+++ b/tests/ui/suggestions/issue-81839.stderr
@@ -4,22 +4,15 @@ error[E0308]: `match` arms have incompatible types
 LL | /     match num {
 LL | |         1 => {
 LL | |             cx.answer_str("hi");
-   | |             -------------------- this is found to be of type `()`
+   | |             --------------------
+   | |             |                  |
+   | |             |                  help: consider removing this semicolon
+   | |             this is found to be of type `()`
 LL | |         }
 LL | |         _ => cx.answer_str("hi"),
    | |              ^^^^^^^^^^^^^^^^^^^ expected `()`, found future
 LL | |     }
    | |_____- `match` arms have incompatible types
-   |
-help: consider removing this semicolon
-   |
-LL -             cx.answer_str("hi");
-LL +             cx.answer_str("hi")
-   |
-help: consider using a semicolon here, but this will discard any values in the match arms
-   |
-LL |     };
-   |      +
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/wf/wf-unsafe-trait-obj-match.stderr b/tests/ui/wf/wf-unsafe-trait-obj-match.stderr
index 3b53f55ffdc1d..e30cb8ff921a0 100644
--- a/tests/ui/wf/wf-unsafe-trait-obj-match.stderr
+++ b/tests/ui/wf/wf-unsafe-trait-obj-match.stderr
@@ -11,10 +11,6 @@ LL | |     }
    |
    = note: expected reference `&S`
               found reference `&R`
-help: consider using a semicolon here, but this will discard any values in the match arms
-   |
-LL |     };
-   |      +
 
 error[E0038]: the trait `Trait` cannot be made into an object
   --> $DIR/wf-unsafe-trait-obj-match.rs:26:21

From fdc56b68860a3e0fc9a9733d746a0f932f9e53cc Mon Sep 17 00:00:00 2001
From: Trevor Spiteri <tspiteri@ieee.org>
Date: Thu, 15 Feb 2024 18:38:36 +0100
Subject: [PATCH 56/58] doc: add note before panicking examples for
 strict_overflow_ops

---
 library/core/src/num/int_macros.rs  | 36 +++++++++++++++++++++++++++++
 library/core/src/num/uint_macros.rs | 16 +++++++++++++
 2 files changed, 52 insertions(+)

diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index d052dcc3e6ee6..434bcace616f2 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -472,6 +472,8 @@ macro_rules! int_impl {
         #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).strict_add(1), ", stringify!($SelfT), "::MAX - 1);")]
         /// ```
         ///
+        /// The following panics because of overflow:
+        ///
         /// ```should_panic
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add(3);")]
@@ -552,6 +554,8 @@ macro_rules! int_impl {
         #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_add_unsigned(2), 3);")]
         /// ```
         ///
+        /// The following panics because of overflow:
+        ///
         /// ```should_panic
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add_unsigned(3);")]
@@ -606,6 +610,8 @@ macro_rules! int_impl {
         #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).strict_sub(1), ", stringify!($SelfT), "::MIN + 1);")]
         /// ```
         ///
+        /// The following panics because of overflow:
+        ///
         /// ```should_panic
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("let _ = (", stringify!($SelfT), "::MIN + 2).strict_sub(3);")]
@@ -686,6 +692,8 @@ macro_rules! int_impl {
         #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_sub_unsigned(2), -1);")]
         /// ```
         ///
+        /// The following panics because of overflow:
+        ///
         /// ```should_panic
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("let _ = (", stringify!($SelfT), "::MIN + 2).strict_sub_unsigned(3);")]
@@ -740,6 +748,8 @@ macro_rules! int_impl {
         #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.strict_mul(1), ", stringify!($SelfT), "::MAX);")]
         /// ```
         ///
+        /// The following panics because of overflow:
+        ///
         /// ``` should_panic
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_mul(2);")]
@@ -831,11 +841,15 @@ macro_rules! int_impl {
         #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).strict_div(-1), ", stringify!($Max), ");")]
         /// ```
         ///
+        /// The following panics because of overflow:
+        ///
         /// ```should_panic
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_div(-1);")]
         /// ```
         ///
+        /// The following panics because of division by zero:
+        ///
         /// ```should_panic
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div(0);")]
@@ -901,11 +915,15 @@ macro_rules! int_impl {
         #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).strict_div_euclid(-1), ", stringify!($Max), ");")]
         /// ```
         ///
+        /// The following panics because of overflow:
+        ///
         /// ```should_panic
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_div_euclid(-1);")]
         /// ```
         ///
+        /// The following panics because of division by zero:
+        ///
         /// ```should_panic
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div_euclid(0);")]
@@ -970,11 +988,15 @@ macro_rules! int_impl {
         #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_rem(2), 1);")]
         /// ```
         ///
+        /// The following panics because of division by zero:
+        ///
         /// ```should_panic
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem(0);")]
         /// ```
         ///
+        /// The following panics because of overflow:
+        ///
         /// ```should_panic
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_rem(-1);")]
@@ -1039,11 +1061,15 @@ macro_rules! int_impl {
         #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_rem_euclid(2), 1);")]
         /// ```
         ///
+        /// The following panics because of division by zero:
+        ///
         /// ```should_panic
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem_euclid(0);")]
         /// ```
         ///
+        /// The following panics because of overflow:
+        ///
         /// ```should_panic
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_rem_euclid(-1);")]
@@ -1121,6 +1147,8 @@ macro_rules! int_impl {
         #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_neg(), -5);")]
         /// ```
         ///
+        /// The following panics because of overflow:
+        ///
         /// ```should_panic
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_neg();")]
@@ -1175,6 +1203,8 @@ macro_rules! int_impl {
         #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".strict_shl(4), 0x10);")]
         /// ```
         ///
+        /// The following panics because of overflow:
+        ///
         /// ```should_panic
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("let _ = 0x1", stringify!($SelfT), ".strict_shl(129);")]
@@ -1256,6 +1286,8 @@ macro_rules! int_impl {
         #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".strict_shr(4), 0x1);")]
         /// ```
         ///
+        /// The following panics because of overflow:
+        ///
         /// ```should_panic
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shr(128);")]
@@ -1340,6 +1372,8 @@ macro_rules! int_impl {
         #[doc = concat!("assert_eq!((-5", stringify!($SelfT), ").strict_abs(), 5);")]
         /// ```
         ///
+        /// The following panics because of overflow:
+        ///
         /// ```should_panic
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.strict_abs();")]
@@ -1414,6 +1448,8 @@ macro_rules! int_impl {
         #[doc = concat!("assert_eq!(8", stringify!($SelfT), ".strict_pow(2), 64);")]
         /// ```
         ///
+        /// The following panics because of overflow:
+        ///
         /// ```should_panic
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_pow(2);")]
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index a217c2e259d2b..5036a3b0c71cf 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -480,6 +480,8 @@ macro_rules! uint_impl {
         #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).strict_add(1), ", stringify!($SelfT), "::MAX - 1);")]
         /// ```
         ///
+        /// The following panics because of overflow:
+        ///
         /// ```should_panic
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("let _ = (", stringify!($SelfT), "::MAX - 2).strict_add(3);")]
@@ -561,6 +563,8 @@ macro_rules! uint_impl {
         #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_add_signed(2), 3);")]
         /// ```
         ///
+        /// The following panic because of overflow:
+        ///
         /// ```should_panic
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("let _ = 1", stringify!($SelfT), ".strict_add_signed(-2);")]
@@ -620,6 +624,8 @@ macro_rules! uint_impl {
         #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".strict_sub(1), 0);")]
         /// ```
         ///
+        /// The following panics because of overflow:
+        ///
         /// ```should_panic
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("let _ = 0", stringify!($SelfT), ".strict_sub(1);")]
@@ -700,6 +706,8 @@ macro_rules! uint_impl {
         #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".strict_mul(1), 5);")]
         /// ```
         ///
+        /// The following panics because of overflow:
+        ///
         /// ``` should_panic
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_mul(2);")]
@@ -1172,6 +1180,8 @@ macro_rules! uint_impl {
         #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".strict_neg(), 0);")]
         /// ```
         ///
+        /// The following panics because of overflow:
+        ///
         /// ```should_panic
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("let _ = 1", stringify!($SelfT), ".strict_neg();")]
@@ -1226,6 +1236,8 @@ macro_rules! uint_impl {
         #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".strict_shl(4), 0x10);")]
         /// ```
         ///
+        /// The following panics because of overflow:
+        ///
         /// ```should_panic
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shl(129);")]
@@ -1307,6 +1319,8 @@ macro_rules! uint_impl {
         #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".strict_shr(4), 0x1);")]
         /// ```
         ///
+        /// The following panics because of overflow:
+        ///
         /// ```should_panic
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("let _ = 0x10", stringify!($SelfT), ".strict_shr(129);")]
@@ -1406,6 +1420,8 @@ macro_rules! uint_impl {
         #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".strict_pow(5), 32);")]
         /// ```
         ///
+        /// The following panics because of overflow:
+        ///
         /// ```should_panic
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("let _ = ", stringify!($SelfT), "::MAX.strict_pow(2);")]

From 675d092e3e69e1ca6f0abcad4b18d746e6ed558a Mon Sep 17 00:00:00 2001
From: Trevor Spiteri <tspiteri@ieee.org>
Date: Thu, 15 Feb 2024 18:41:30 +0100
Subject: [PATCH 57/58] doc: panicking division by zero examples for unsigned
 strict div ops

---
 library/core/src/num/uint_macros.rs | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 5036a3b0c71cf..f2f29e4ad8194 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -793,6 +793,13 @@ macro_rules! uint_impl {
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_div(10), 10);")]
         /// ```
+        ///
+        /// The following panics because of division by zero:
+        ///
+        /// ```should_panic
+        /// #![feature(strict_overflow_ops)]
+        #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div(0);")]
+        /// ```
         #[unstable(feature = "strict_overflow_ops", issue = "118260")]
         #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
         #[must_use = "this returns the result of the operation, \
@@ -848,6 +855,12 @@ macro_rules! uint_impl {
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_div_euclid(10), 10);")]
         /// ```
+        /// The following panics because of division by zero:
+        ///
+        /// ```should_panic
+        /// #![feature(strict_overflow_ops)]
+        #[doc = concat!("let _ = (1", stringify!($SelfT), ").strict_div_euclid(0);")]
+        /// ```
         #[unstable(feature = "strict_overflow_ops", issue = "118260")]
         #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
         #[must_use = "this returns the result of the operation, \
@@ -903,6 +916,13 @@ macro_rules! uint_impl {
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_rem(10), 0);")]
         /// ```
+        ///
+        /// The following panics because of division by zero:
+        ///
+        /// ```should_panic
+        /// #![feature(strict_overflow_ops)]
+        #[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem(0);")]
+        /// ```
         #[unstable(feature = "strict_overflow_ops", issue = "118260")]
         #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
         #[must_use = "this returns the result of the operation, \
@@ -959,6 +979,13 @@ macro_rules! uint_impl {
         /// #![feature(strict_overflow_ops)]
         #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".strict_rem_euclid(10), 0);")]
         /// ```
+        ///
+        /// The following panics because of division by zero:
+        ///
+        /// ```should_panic
+        /// #![feature(strict_overflow_ops)]
+        #[doc = concat!("let _ = 5", stringify!($SelfT), ".strict_rem_euclid(0);")]
+        /// ```
         #[unstable(feature = "strict_overflow_ops", issue = "118260")]
         #[rustc_const_unstable(feature = "const_strict_overflow_ops", issue = "118260")]
         #[must_use = "this returns the result of the operation, \

From 954d56591cbbc057d53c233f86895658febe407d Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Thu, 15 Feb 2024 13:20:33 +0000
Subject: [PATCH 58/58] Fix closure kind docs

---
 compiler/rustc_middle/src/ty/sty.rs | 37 ++++++++++++++++++++---------
 1 file changed, 26 insertions(+), 11 deletions(-)

diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 66086ac87f16b..a581712526752 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -2363,28 +2363,42 @@ impl<'tcx> Ty<'tcx> {
     }
 
     /// When we create a closure, we record its kind (i.e., what trait
-    /// it implements) into its `ClosureArgs` using a type
+    /// it implements, constrained by how it uses its borrows) into its
+    /// [`ty::ClosureArgs`] or [`ty::CoroutineClosureArgs`] using a type
     /// parameter. This is kind of a phantom type, except that the
     /// most convenient thing for us to are the integral types. This
     /// function converts such a special type into the closure
-    /// kind. To go the other way, use `closure_kind.to_ty(tcx)`.
+    /// kind. To go the other way, use [`Ty::from_closure_kind`].
     ///
     /// Note that during type checking, we use an inference variable
     /// to represent the closure kind, because it has not yet been
     /// inferred. Once upvar inference (in `rustc_hir_analysis/src/check/upvar.rs`)
-    /// is complete, that type variable will be unified.
+    /// is complete, that type variable will be unified with one of
+    /// the integral types.
     ///
-    /// To be noted that you can use [`ClosureArgs::kind()`] or [`CoroutineClosureArgs::kind()`]
-    /// to get the same information, which you can get by calling [`GenericArgs::as_closure()`]
-    /// or [`GenericArgs::as_coroutine_closure()`], depending on the type of the closure.
+    /// ```rust,ignore (snippet of compiler code)
+    /// if let TyKind::Closure(def_id, args) = closure_ty.kind()
+    ///     && let Some(closure_kind) = args.as_closure().kind_ty().to_opt_closure_kind()
+    /// {
+    ///     println!("{closure_kind:?}");
+    /// } else if let TyKind::CoroutineClosure(def_id, args) = closure_ty.kind()
+    ///     && let Some(closure_kind) = args.as_coroutine_closure().kind_ty().to_opt_closure_kind()
+    /// {
+    ///     println!("{closure_kind:?}");
+    /// }
+    /// ```
     ///
-    /// Otherwise, this method can be used as follows:
+    /// After upvar analysis, you should instead use [`ClosureArgs::kind()`]
+    /// or [`CoroutineClosureArgs::kind()`] to assert that the `ClosureKind`
+    /// has been constrained instead of manually calling this method.
     ///
     /// ```rust,ignore (snippet of compiler code)
-    /// let TyKind::Closure(def_id, [closure_fn_kind_ty, ..]) = closure_ty.kind()
-    ///     && let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind()
+    /// if let TyKind::Closure(def_id, args) = closure_ty.kind()
+    /// {
+    ///     println!("{:?}", args.as_closure().kind());
+    /// } else if let TyKind::CoroutineClosure(def_id, args) = closure_ty.kind()
     /// {
-    ///     // your code
+    ///     println!("{:?}", args.as_coroutine_closure().kind());
     /// }
     /// ```
     pub fn to_opt_closure_kind(self) -> Option<ty::ClosureKind> {
@@ -2406,7 +2420,8 @@ impl<'tcx> Ty<'tcx> {
         }
     }
 
-    /// Inverse of [`Ty::to_opt_closure_kind`].
+    /// Inverse of [`Ty::to_opt_closure_kind`]. See docs on that method
+    /// for explanation of the relationship between `Ty` and [`ty::ClosureKind`].
     pub fn from_closure_kind(tcx: TyCtxt<'tcx>, kind: ty::ClosureKind) -> Ty<'tcx> {
         match kind {
             ty::ClosureKind::Fn => tcx.types.i8,