From dbcaeb9caefe11f9cb590c957f5aa98591665b74 Mon Sep 17 00:00:00 2001
From: Apersoma <95072312+Apersoma@users.noreply.github.com>
Date: Thu, 19 Mar 2026 20:49:38 +0000
Subject: [PATCH 01/34] added more assumptions and refactored

---
 library/core/src/num/imp/int_sqrt.rs | 55 ++++++++++++++++++++++++++++
 library/core/src/num/int_macros.rs   | 25 +------------
 library/core/src/num/uint_macros.rs  | 19 +---------
 3 files changed, 57 insertions(+), 42 deletions(-)

diff --git a/library/core/src/num/imp/int_sqrt.rs b/library/core/src/num/imp/int_sqrt.rs
index 152841793d56e..effe79df0857e 100644
--- a/library/core/src/num/imp/int_sqrt.rs
+++ b/library/core/src/num/imp/int_sqrt.rs
@@ -314,3 +314,58 @@ unsigned_fn!(u128, u64, u128_stages);
 pub(in crate::num) const fn panic_for_negative_argument() -> ! {
     panic!("argument of integer square root cannot be negative")
 }
+
+/// Takes the isqrt of `$n` assuming its non-negative.
+///
+/// # Safety:
+///
+/// `$n` must be nonnegative
+macro_rules! isqrt_of_nonnegative {
+    ($n:expr, $SelfT:ty, $ActualT:ident) => {{
+        #[allow(unused_comparisons, reason = "Unknown if `$n` is signed or unsigned.")]
+        let _ = debug_assert!($n >= 0, "`$n` is negative in `isqrt_of_nonnegative`");
+
+        // SAFETY: $n >= 0
+        let result = imp::int_sqrt::$ActualT($n as $ActualT) as $SelfT;
+
+        #[allow(unused_unsafe, reason = "Unknown if `$n` is signed or unsigned.")]
+        // SAFETY: `<$ActualT>::MAX` is nonnegative.
+        const MAX_RESULT: $SelfT = unsafe { imp::int_sqrt::$ActualT(<$ActualT>::MAX) } as $SelfT;
+
+        #[allow(
+            unused_unsafe,
+            reason = "Macro invocation may or may not be wrapped in an unsafe block"
+        )]
+        // SAFETY: Integer square root is a monotonically nondecreasing
+        // function, which means that increasing the input will never
+        // cause the output to decrease. Thus, since the input for
+        // nonnegative signed integers is bounded by
+        // `[0, <$ActualT>::MAX]`, sqrt(n) will be bounded by
+        // `[sqrt(0), sqrt(<$ActualT>::MAX)]`.
+        unsafe {
+            #[allow(unused_comparisons, reason = "Unknown if `$n` is signed or unsigned.")]
+            crate::hint::assert_unchecked(result >= 0);
+            crate::hint::assert_unchecked(result <= MAX_RESULT);
+            if $n > 0 {
+                crate::hint::assert_unchecked(result > 0);
+            }
+        }
+
+        #[allow(
+            unused_unsafe,
+            reason = "Macro invocation may or may not be wrapped in an unsafe block."
+        )]
+        // SAFETY: the definition of isqrt is that it returns
+        // the greatest integer for which the first assertion holds.
+        // Since these are integers, the first implies the second
+        // (though the compiler is too stupid to realize this).
+        unsafe {
+            crate::hint::assert_unchecked(result * result <= $n);
+            crate::hint::assert_unchecked(result <= $n);
+        }
+
+        result
+    }};
+}
+
+pub(in crate::num) use isqrt_of_nonnegative;
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index aba0eaf8d4842..11e18b9a3e09f 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -1846,32 +1846,9 @@ macro_rules! int_impl {
                 None
             } else {
                 // SAFETY: Input is nonnegative in this `else` branch.
-                let result = unsafe {
-                    imp::int_sqrt::$ActualT(self as $ActualT) as $SelfT
-                };
-
-                // Inform the optimizer what the range of outputs is. If
-                // testing `core` crashes with no panic message and a
-                // `num::int_sqrt::i*` test failed, it's because your edits
-                // caused these assertions to become false.
-                //
-                // SAFETY: Integer square root is a monotonically nondecreasing
-                // function, which means that increasing the input will never
-                // cause the output to decrease. Thus, since the input for
-                // nonnegative signed integers is bounded by
-                // `[0, <$ActualT>::MAX]`, sqrt(n) will be bounded by
-                // `[sqrt(0), sqrt(<$ActualT>::MAX)]`.
                 unsafe {
-                    // SAFETY: `<$ActualT>::MAX` is nonnegative.
-                    const MAX_RESULT: $SelfT = unsafe {
-                        imp::int_sqrt::$ActualT(<$ActualT>::MAX) as $SelfT
-                    };
-
-                    crate::hint::assert_unchecked(result >= 0);
-                    crate::hint::assert_unchecked(result <= MAX_RESULT);
+                    Some(imp::int_sqrt::isqrt_of_nonnegative!(self, $SelfT, $ActualT))
                 }
-
-                Some(result)
             }
         }
 
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index ae8324c13f0cb..f25ec5e0cf0c4 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -3541,24 +3541,7 @@ macro_rules! uint_impl {
                       without modifying the original"]
         #[inline]
         pub const fn isqrt(self) -> Self {
-            let result = imp::int_sqrt::$ActualT(self as $ActualT) as $SelfT;
-
-            // Inform the optimizer what the range of outputs is. If testing
-            // `core` crashes with no panic message and a `num::int_sqrt::u*`
-            // test failed, it's because your edits caused these assertions or
-            // the assertions in `fn isqrt` of `nonzero.rs` to become false.
-            //
-            // SAFETY: Integer square root is a monotonically nondecreasing
-            // function, which means that increasing the input will never
-            // cause the output to decrease. Thus, since the input for unsigned
-            // integers is bounded by `[0, <$ActualT>::MAX]`, sqrt(n) will be
-            // bounded by `[sqrt(0), sqrt(<$ActualT>::MAX)]`.
-            unsafe {
-                const MAX_RESULT: $SelfT = imp::int_sqrt::$ActualT(<$ActualT>::MAX) as $SelfT;
-                crate::hint::assert_unchecked(result <= MAX_RESULT);
-            }
-
-            result
+            imp::int_sqrt::isqrt_of_nonnegative!(self, $SelfT, $ActualT)
         }
 
         /// Performs Euclidean division.

From ce567f11d246e8283daf931aa211b9421fc4faa1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= <oss@mateuszmikula.dev>
Date: Thu, 19 Feb 2026 22:11:58 +0100
Subject: [PATCH 02/34] Do not enable split debuginfo for windows-gnu

Because rustc doesn't handle split debuginfo for these targets,
enabling that option causes them to be missing some of the debuginfo.
---
 bootstrap.example.toml                            | 7 ++++---
 src/bootstrap/src/core/config/target_selection.rs | 2 +-
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/bootstrap.example.toml b/bootstrap.example.toml
index 662bcc5d61e75..f3b2a64df853b 100644
--- a/bootstrap.example.toml
+++ b/bootstrap.example.toml
@@ -1013,9 +1013,10 @@
 # its historical default, but when compiling the compiler itself, we skip it by
 # default since we know it's safe to do so in that case.
 #
-# On Windows platforms, packed debuginfo is the only supported option,
-# producing a `.pdb` file.
-#split-debuginfo = if linux { off } else if windows { packed } else if apple { unpacked }
+# On Windows MSVC platforms, packed debuginfo is the only supported option,
+# producing a `.pdb` file. On Windows GNU rustc doesn't support splitting debuginfo,
+# and enabling it causes issues.
+#split-debuginfo = if linux || windows-gnu { off } else if windows-msvc { packed } else if apple { unpacked }
 
 # Path to the `llvm-config` binary of the installation of a custom LLVM to link
 # against. Note that if this is specified we don't compile LLVM at all for this
diff --git a/src/bootstrap/src/core/config/target_selection.rs b/src/bootstrap/src/core/config/target_selection.rs
index 47f6d6f386dfb..8457607b897dd 100644
--- a/src/bootstrap/src/core/config/target_selection.rs
+++ b/src/bootstrap/src/core/config/target_selection.rs
@@ -142,7 +142,7 @@ impl SplitDebuginfo {
     pub fn default_for_platform(target: TargetSelection) -> Self {
         if target.contains("apple") {
             SplitDebuginfo::Unpacked
-        } else if target.is_windows() {
+        } else if target.is_msvc() {
             SplitDebuginfo::Packed
         } else {
             SplitDebuginfo::Off

From 906fd6b984b6f200712d00cba51b4cd569d29bcf Mon Sep 17 00:00:00 2001
From: Bhavya Gautam <gautambhavya899@gmail.com>
Date: Tue, 3 Mar 2026 06:35:43 +0000
Subject: [PATCH 03/34] Fix rust build failure for vxworks

---
 library/std/build.rs                          | 24 +++++++++++++++
 library/std/src/os/vxworks/fs.rs              | 30 +++++++++++++++++++
 library/std/src/sys/fs/unix.rs                | 18 ++++++++---
 src/doc/rustc/src/platform-support/vxworks.md |  6 ++++
 4 files changed, 74 insertions(+), 4 deletions(-)

diff --git a/library/std/build.rs b/library/std/build.rs
index c0a6e30b38082..5f2e441bf7d83 100644
--- a/library/std/build.rs
+++ b/library/std/build.rs
@@ -79,4 +79,28 @@ fn main() {
     println!("cargo:rustc-cfg=backtrace_in_libstd");
 
     println!("cargo:rustc-env=STD_ENV_ARCH={}", env::var("CARGO_CFG_TARGET_ARCH").unwrap());
+
+    println!("cargo:rustc-check-cfg=cfg(vxworks_lt_25_09)");
+
+    if target_os == "vxworks" {
+        match vxworks_version_code() {
+            Some((major, minor)) if (major, minor) < (25, 9) => {
+                println!("cargo:rustc-cfg=vxworks_lt_25_09");
+            }
+            _ => {}
+        }
+    }
+}
+
+/// Retrieve the VxWorks release version from the environment variable set by the VxWorks build
+/// environment, in `(minor, patch)` form.
+fn vxworks_version_code() -> Option<(u32, u32)> {
+    let version = env::var("WIND_RELEASE_ID").ok()?;
+
+    let mut pieces = version.trim().split(['.']);
+
+    let major: u32 = pieces.next().and_then(|x| x.parse().ok()).unwrap_or(0);
+    let minor: u32 = pieces.next().and_then(|x| x.parse().ok()).unwrap_or(0);
+
+    Some((major, minor))
 }
diff --git a/library/std/src/os/vxworks/fs.rs b/library/std/src/os/vxworks/fs.rs
index b88ed19b067a5..a21748ce9fe00 100644
--- a/library/std/src/os/vxworks/fs.rs
+++ b/library/std/src/os/vxworks/fs.rs
@@ -69,24 +69,54 @@ impl MetadataExt for Metadata {
     fn st_size(&self) -> u64 {
         self.as_inner().as_inner().st_size as u64
     }
+    #[cfg(vxworks_lt_25_09)]
     fn st_atime(&self) -> i64 {
         self.as_inner().as_inner().st_atime as i64
     }
+    #[cfg(not(vxworks_lt_25_09))]
+    fn st_atime(&self) -> i64 {
+        self.as_inner().as_inner().st_atim.tv_sec as i64
+    }
+    #[cfg(vxworks_lt_25_09)]
     fn st_atime_nsec(&self) -> i64 {
         0
     }
+    #[cfg(not(vxworks_lt_25_09))]
+    fn st_atime_nsec(&self) -> i64 {
+        self.as_inner().as_inner().st_atim.tv_nsec as i64
+    }
+    #[cfg(vxworks_lt_25_09)]
     fn st_mtime(&self) -> i64 {
         self.as_inner().as_inner().st_mtime as i64
     }
+    #[cfg(not(vxworks_lt_25_09))]
+    fn st_mtime(&self) -> i64 {
+        self.as_inner().as_inner().st_mtim.tv_sec as i64
+    }
+    #[cfg(vxworks_lt_25_09)]
     fn st_mtime_nsec(&self) -> i64 {
         0
     }
+    #[cfg(not(vxworks_lt_25_09))]
+    fn st_mtime_nsec(&self) -> i64 {
+        self.as_inner().as_inner().st_mtim.tv_nsec as i64
+    }
+    #[cfg(vxworks_lt_25_09)]
     fn st_ctime(&self) -> i64 {
         self.as_inner().as_inner().st_ctime as i64
     }
+    #[cfg(not(vxworks_lt_25_09))]
+    fn st_ctime(&self) -> i64 {
+        self.as_inner().as_inner().st_ctim.tv_sec as i64
+    }
+    #[cfg(vxworks_lt_25_09)]
     fn st_ctime_nsec(&self) -> i64 {
         0
     }
+    #[cfg(not(vxworks_lt_25_09))]
+    fn st_ctime_nsec(&self) -> i64 {
+        self.as_inner().as_inner().st_ctim.tv_nsec as i64
+    }
     fn st_blksize(&self) -> u64 {
         self.as_inner().as_inner().st_blksize as u64
     }
diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs
index 7db474544f04a..2a8571871b732 100644
--- a/library/std/src/sys/fs/unix.rs
+++ b/library/std/src/sys/fs/unix.rs
@@ -634,7 +634,7 @@ impl FileAttr {
     }
 
     #[cfg(any(
-        target_os = "vxworks",
+        all(target_os = "vxworks", vxworks_lt_25_09),
         target_os = "espidf",
         target_os = "vita",
         target_os = "rtems",
@@ -643,7 +643,12 @@ impl FileAttr {
         SystemTime::new(self.stat.st_mtime as i64, 0)
     }
 
-    #[cfg(any(target_os = "horizon", target_os = "hurd", target_os = "nuttx"))]
+    #[cfg(any(
+        target_os = "horizon",
+        target_os = "hurd",
+        target_os = "nuttx",
+        all(target_os = "vxworks", not(vxworks_lt_25_09))
+    ))]
     pub fn modified(&self) -> io::Result<SystemTime> {
         SystemTime::new(self.stat.st_mtim.tv_sec as i64, self.stat.st_mtim.tv_nsec as i64)
     }
@@ -669,7 +674,7 @@ impl FileAttr {
     }
 
     #[cfg(any(
-        target_os = "vxworks",
+        all(target_os = "vxworks", vxworks_lt_25_09),
         target_os = "espidf",
         target_os = "vita",
         target_os = "rtems"
@@ -678,7 +683,12 @@ impl FileAttr {
         SystemTime::new(self.stat.st_atime as i64, 0)
     }
 
-    #[cfg(any(target_os = "horizon", target_os = "hurd", target_os = "nuttx"))]
+    #[cfg(any(
+        target_os = "horizon",
+        target_os = "hurd",
+        target_os = "nuttx",
+        all(target_os = "vxworks", not(vxworks_lt_25_09))
+    ))]
     pub fn accessed(&self) -> io::Result<SystemTime> {
         SystemTime::new(self.stat.st_atim.tv_sec as i64, self.stat.st_atim.tv_nsec as i64)
     }
diff --git a/src/doc/rustc/src/platform-support/vxworks.md b/src/doc/rustc/src/platform-support/vxworks.md
index 091c757a2ee36..0cf3822f759e7 100644
--- a/src/doc/rustc/src/platform-support/vxworks.md
+++ b/src/doc/rustc/src/platform-support/vxworks.md
@@ -28,6 +28,12 @@ Target triplets available:
 
 The minimum supported version is VxWorks 7.
 
+### Environment
+
+#### `WIND_RELEASE_ID`
+
+In VxWorks build environment, the environment variable `WIND_RELEASE_ID` indicates the VxWorks release version used for the build. The `WIND_RELEASE_ID` can be used to conditionally compile features/code or handle version specific behaviour.
+
 ## Building
 
 Rust for each target can be cross-compiled with its specific target vsb configuration. Std support is added but not yet fully tested.

From a31879588c132dc75c0208214229c4c4cb2aee1b Mon Sep 17 00:00:00 2001
From: Josh Stone <jistone@redhat.com>
Date: Tue, 10 Mar 2026 17:06:59 -0700
Subject: [PATCH 04/34] ci: add runners for vanilla LLVM 22

Ubuntu 26.04 has `llvm-22` packages that we can test with.
The `Dockerfile` is otherwise the same as the `llvm-21` runners.
---
 .../host-x86_64/x86_64-gnu-llvm-22/Dockerfile | 66 +++++++++++++++++++
 src/ci/github-actions/jobs.yml                | 25 +++++++
 2 files changed, 91 insertions(+)
 create mode 100644 src/ci/docker/host-x86_64/x86_64-gnu-llvm-22/Dockerfile

diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-22/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-22/Dockerfile
new file mode 100644
index 0000000000000..a22e8de90804f
--- /dev/null
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-22/Dockerfile
@@ -0,0 +1,66 @@
+FROM ubuntu:26.04
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+  bzip2 \
+  g++ \
+  gcc-multilib \
+  make \
+  ninja-build \
+  file \
+  curl \
+  ca-certificates \
+  python3 \
+  git \
+  cmake \
+  sudo \
+  gdb \
+  llvm-22-tools \
+  llvm-22-dev \
+  libedit-dev \
+  libssl-dev \
+  pkg-config \
+  zlib1g-dev \
+  xz-utils \
+  nodejs \
+  mingw-w64 \
+  # libgccjit dependencies
+  flex \
+  libmpfr-dev \
+  libgmp-dev \
+  libmpc3 \
+  libmpc-dev \
+  && rm -rf /var/lib/apt/lists/*
+
+# Install powershell (universal package) so we can test x.ps1 on Linux
+# FIXME: need a "universal" version that supports libicu74, but for now it still works to ignore that dep.
+RUN curl -sL "https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/powershell_7.3.1-1.deb_amd64.deb" > powershell.deb && \
+    dpkg --ignore-depends=libicu72 -i powershell.deb && \
+    rm -f powershell.deb
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+# We are disabling CI LLVM since this builder is intentionally using a host
+# LLVM, rather than the typical src/llvm-project LLVM.
+ENV NO_DOWNLOAD_CI_LLVM 1
+ENV EXTERNAL_LLVM 1
+
+# Using llvm-link-shared due to libffi issues -- see #34486
+ENV RUST_CONFIGURE_ARGS \
+      --build=x86_64-unknown-linux-gnu \
+      --llvm-root=/usr/lib/llvm-22 \
+      --enable-llvm-link-shared \
+      --set rust.randomize-layout=true \
+      --set rust.thin-lto-import-instr-limit=10
+
+COPY scripts/shared.sh /scripts/
+
+COPY scripts/x86_64-gnu-llvm.sh /scripts/
+COPY scripts/x86_64-gnu-llvm2.sh /scripts/
+COPY scripts/x86_64-gnu-llvm3.sh /scripts/
+COPY scripts/stage_2_test_set1.sh /scripts/
+COPY scripts/stage_2_test_set2.sh /scripts/
+
+ENV SCRIPT "Must specify DOCKER_SCRIPT for this image"
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index a70e4acf94a36..7c0f1d3f29305 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -406,6 +406,31 @@ auto:
       DOCKER_SCRIPT: x86_64-gnu-llvm3.sh
     <<: *job-linux-4c
 
+  # The x86_64-gnu-llvm-22 job is split into multiple jobs to run tests in parallel.
+  # x86_64-gnu-llvm-22-1 skips tests that run in x86_64-gnu-llvm-22-{2,3}.
+  - name: x86_64-gnu-llvm-22-1
+    env:
+      RUST_BACKTRACE: 1
+      IMAGE: x86_64-gnu-llvm-22
+      DOCKER_SCRIPT: stage_2_test_set2.sh
+    <<: *job-linux-4c
+
+  # Skip tests that run in x86_64-gnu-llvm-22-{1,3}
+  - name: x86_64-gnu-llvm-22-2
+    env:
+      RUST_BACKTRACE: 1
+      IMAGE: x86_64-gnu-llvm-22
+      DOCKER_SCRIPT: x86_64-gnu-llvm2.sh
+    <<: *job-linux-4c
+
+  # Skip tests that run in x86_64-gnu-llvm-22-{1,2}
+  - name: x86_64-gnu-llvm-22-3
+    env:
+      RUST_BACKTRACE: 1
+      IMAGE: x86_64-gnu-llvm-22
+      DOCKER_SCRIPT: x86_64-gnu-llvm3.sh
+    <<: *job-linux-4c
+
   - name: x86_64-gnu-nopt
     <<: *job-linux-4c
 

From 1dc0d533274f88af932d6f512739e72ca091803a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 11 Mar 2026 16:39:03 +0000
Subject: [PATCH 05/34] When single impl can satisfy inference error, suggest
 type

When encountering an inference error where a return type must be known, like when calling `Iterator::sum::<T>()` without specifying `T`, look for all `T` that would satisfy `Sum<S>`. If only one, suggest it.

```
error[E0283]: type annotations needed
  --> $DIR/cannot-infer-iterator-sum-return-type.rs:4:9
   |
LL |     let sum = v
   |         ^^^
...
LL |         .sum(); // `sum::<T>` needs `T` to be specified
   |          --- type must be known at this point
   |
   = note: cannot satisfy `_: Sum<i32>`
help: the trait `Sum` is implemented for `i32`
  --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL
  ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL
   |
   = note: in this macro invocation
note: required by a bound in `std::iter::Iterator::sum`
  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
   = note: this error originates in the macro `integer_sum_product` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider giving `sum` an explicit type, where the type for type parameter `S` is specified
   |
LL |     let sum: i32 = v
   |            +++++
```
---
 .../error_reporting/infer/need_type_info.rs   | 64 ++++++++++++++++---
 .../src/error_reporting/traits/ambiguity.rs   | 27 +++++++-
 .../traits/fulfillment_errors.rs              | 10 +++
 .../const-generics/issues/issue-83249.stderr  |  6 +-
 ...annot-infer-iterator-sum-return-type.fixed | 13 ++++
 .../cannot-infer-iterator-sum-return-type.rs  | 13 ++++
 ...nnot-infer-iterator-sum-return-type.stderr | 26 ++++++++
 7 files changed, 145 insertions(+), 14 deletions(-)
 create mode 100644 tests/ui/inference/cannot-infer-iterator-sum-return-type.fixed
 create mode 100644 tests/ui/inference/cannot-infer-iterator-sum-return-type.rs
 create mode 100644 tests/ui/inference/cannot-infer-iterator-sum-return-type.stderr

diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
index 5cb8922574b61..7fcaea3a629f1 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
@@ -158,6 +158,7 @@ impl UnderspecifiedArgKind {
 
 struct ClosureEraser<'a, 'tcx> {
     infcx: &'a InferCtxt<'tcx>,
+    depth: usize,
 }
 
 impl<'a, 'tcx> ClosureEraser<'a, 'tcx> {
@@ -172,7 +173,8 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ClosureEraser<'a, 'tcx> {
     }
 
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        match ty.kind() {
+        self.depth += 1;
+        let ty = match ty.kind() {
             ty::Closure(_, args) => {
                 // For a closure type, we turn it into a function pointer so that it gets rendered
                 // as `fn(args) -> Ret`.
@@ -233,9 +235,15 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ClosureEraser<'a, 'tcx> {
                 // its type parameters.
                 ty.super_fold_with(self)
             }
-            // We don't have an unknown type parameter anywhere, replace with `_`.
+            // We are in the top-level type, not one of its type parameters. Name it with its
+            // parameters replaced.
+            _ if self.depth == 1 => ty.super_fold_with(self),
+            // We don't have an unknown type parameter anywhere, and we are in a type parameter.
+            // Replace with `_`.
             _ => self.new_infer(),
-        }
+        };
+        self.depth -= 1;
+        ty
     }
 
     fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
@@ -287,7 +295,7 @@ fn ty_to_string<'tcx>(
     let ty = infcx.resolve_vars_if_possible(ty);
     // We use `fn` ptr syntax for closures, but this only works when the closure does not capture
     // anything. We also remove all type parameters that are fully known to the type system.
-    let ty = ty.fold_with(&mut ClosureEraser { infcx });
+    let ty = ty.fold_with(&mut ClosureEraser { infcx, depth: 0 });
 
     match (ty.kind(), called_method_def_id) {
         // We don't want the regular output for `fn`s because it includes its path in
@@ -467,6 +475,25 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         term: Term<'tcx>,
         error_code: TypeAnnotationNeeded,
         should_label_span: bool,
+    ) -> Diag<'a> {
+        self.emit_inference_failure_err_with_type_hint(
+            body_def_id,
+            failure_span,
+            term,
+            error_code,
+            should_label_span,
+            None,
+        )
+    }
+
+    pub fn emit_inference_failure_err_with_type_hint(
+        &self,
+        body_def_id: LocalDefId,
+        failure_span: Span,
+        term: Term<'tcx>,
+        error_code: TypeAnnotationNeeded,
+        should_label_span: bool,
+        ty: Option<Ty<'tcx>>,
     ) -> Diag<'a> {
         let term = self.resolve_vars_if_possible(term);
         let arg_data = self
@@ -479,7 +506,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             return self.bad_inference_failure_err(failure_span, arg_data, error_code);
         };
 
-        let mut local_visitor = FindInferSourceVisitor::new(self, typeck_results, term);
+        let mut local_visitor = FindInferSourceVisitor::new(self, typeck_results, term, ty);
         if let Some(body) = self.tcx.hir_maybe_body_owned_by(
             self.tcx.typeck_root_def_id(body_def_id.to_def_id()).expect_local(),
         ) {
@@ -779,10 +806,20 @@ impl<'tcx> InferSourceKind<'tcx> {
             | InferSourceKind::ClosureReturn { ty, .. } => {
                 if ty.is_closure() {
                     ("closure", closure_as_fn_str(infcx, ty), long_ty_path)
-                } else if !ty.is_ty_or_numeric_infer() {
-                    ("normal", infcx.tcx.short_string(ty, &mut long_ty_path), long_ty_path)
-                } else {
+                } else if ty.is_ty_or_numeric_infer()
+                    || ty.is_primitive()
+                    || matches!(
+                        ty.kind(),
+                        ty::Adt(_, args)
+                        if args.types().count() == 0 && args.consts().count() == 0
+                    )
+                {
+                    // `ty` is either `_`, a primitive type like `u32` or a type with no type or
+                    // const parameters. We will not mention the type in the main inference error
+                    // message.
                     ("other", String::new(), long_ty_path)
+                } else {
+                    ("normal", infcx.tcx.short_string(ty, &mut long_ty_path), long_ty_path)
                 }
             }
             // FIXME: We should be able to add some additional info here.
@@ -815,6 +852,7 @@ struct FindInferSourceVisitor<'a, 'tcx> {
     typeck_results: &'a TypeckResults<'tcx>,
 
     target: Term<'tcx>,
+    ty: Option<Ty<'tcx>>,
 
     attempt: usize,
     infer_source_cost: usize,
@@ -826,12 +864,14 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
         tecx: &'a TypeErrCtxt<'a, 'tcx>,
         typeck_results: &'a TypeckResults<'tcx>,
         target: Term<'tcx>,
+        ty: Option<Ty<'tcx>>,
     ) -> Self {
         FindInferSourceVisitor {
             tecx,
             typeck_results,
 
             target,
+            ty,
 
             attempt: 0,
             infer_source_cost: usize::MAX,
@@ -1213,7 +1253,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
     fn visit_local(&mut self, local: &'tcx LetStmt<'tcx>) {
         intravisit::walk_local(self, local);
 
-        if let Some(ty) = self.opt_node_type(local.hir_id) {
+        if let Some(mut ty) = self.opt_node_type(local.hir_id) {
             if self.generic_arg_contains_target(ty.into()) {
                 fn get_did(
                     typeck_results: &TypeckResults<'_>,
@@ -1241,7 +1281,11 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
                         _ => None,
                     }
                 }
-
+                if let Some(t) = self.ty
+                    && ty.has_infer()
+                {
+                    ty = t;
+                }
                 if let LocalSource::Normal = local.source
                     && local.ty.is_none()
                 {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
index 7de8891196d85..7f5ed9ecb6d11 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
@@ -246,12 +246,37 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     .find(|s| s.has_non_region_infer());
 
                 let mut err = if let Some(term) = term {
-                    self.emit_inference_failure_err(
+                    let candidates: Vec<_> = self
+                        .tcx
+                        .all_impls(trait_pred.def_id())
+                        .filter_map(|def_id| {
+                            let imp = self.tcx.impl_trait_header(def_id);
+                            if imp.polarity != ty::ImplPolarity::Positive
+                                || !self.tcx.is_user_visible_dep(def_id.krate)
+                            {
+                                return None;
+                            }
+                            let imp = imp.trait_ref.skip_binder();
+                            if imp
+                                .with_replaced_self_ty(self.tcx, trait_pred.skip_binder().self_ty())
+                                == trait_pred.skip_binder().trait_ref
+                            {
+                                Some(imp.self_ty())
+                            } else {
+                                None
+                            }
+                        })
+                        .collect();
+                    self.emit_inference_failure_err_with_type_hint(
                         obligation.cause.body_id,
                         span,
                         term,
                         TypeAnnotationNeeded::E0283,
                         true,
+                        match &candidates[..] {
+                            [candidate] => Some(*candidate),
+                            _ => None,
+                        },
                     )
                 } else {
                     struct_span_code_err!(
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index d5383fd4d0831..6bf08170bcf7e 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -2251,6 +2251,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             if candidates.is_empty() {
                 return false;
             }
+            let mut specific_candidates = candidates.clone();
+            specific_candidates.retain(|(tr, _)| {
+                tr.with_replaced_self_ty(self.tcx, trait_pred.skip_binder().self_ty())
+                    == trait_pred.skip_binder().trait_ref
+            });
+            if !specific_candidates.is_empty() {
+                // We have found a subset of impls that fully satisfy the expected trait, only
+                // mention those types.
+                candidates = specific_candidates;
+            }
             if let &[(cand, def_id)] = &candidates[..] {
                 if self.tcx.is_diagnostic_item(sym::FromResidual, cand.def_id)
                     && !self.tcx.features().enabled(sym::try_trait_v2)
diff --git a/tests/ui/const-generics/issues/issue-83249.stderr b/tests/ui/const-generics/issues/issue-83249.stderr
index 2668348613a40..0f00f70700f52 100644
--- a/tests/ui/const-generics/issues/issue-83249.stderr
+++ b/tests/ui/const-generics/issues/issue-83249.stderr
@@ -17,10 +17,10 @@ note: required by a bound in `foo`
    |
 LL | fn foo<T: Foo>(_: [u8; T::N]) -> T {
    |           ^^^ required by this bound in `foo`
-help: consider giving this pattern a type
+help: consider giving this pattern a type, where the type for type parameter `T` is specified
    |
-LL |     let _: /* Type */ = foo([0; 1]);
-   |          ++++++++++++
+LL |     let _: u8 = foo([0; 1]);
+   |          ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/inference/cannot-infer-iterator-sum-return-type.fixed b/tests/ui/inference/cannot-infer-iterator-sum-return-type.fixed
new file mode 100644
index 0000000000000..9a494391f0e4f
--- /dev/null
+++ b/tests/ui/inference/cannot-infer-iterator-sum-return-type.fixed
@@ -0,0 +1,13 @@
+//@ run-rustfix
+fn main() {
+    let v = vec![1, 2];
+    let sum: i32 = v //~ ERROR: type annotations needed
+        .iter()
+        .map(|val| *val)
+        .sum(); // `sum::<T>` needs `T` to be specified
+    // In this case any integer would fit, but we resolve to `i32` because that's what `{integer}`
+    // got coerced to. If the user needs further hinting that they can change the integer type, that
+    // can come from other suggestions. (#100802)
+    let bool = sum > 0;
+    assert_eq!(bool, true);
+}
diff --git a/tests/ui/inference/cannot-infer-iterator-sum-return-type.rs b/tests/ui/inference/cannot-infer-iterator-sum-return-type.rs
new file mode 100644
index 0000000000000..013a2f9148586
--- /dev/null
+++ b/tests/ui/inference/cannot-infer-iterator-sum-return-type.rs
@@ -0,0 +1,13 @@
+//@ run-rustfix
+fn main() {
+    let v = vec![1, 2];
+    let sum = v //~ ERROR: type annotations needed
+        .iter()
+        .map(|val| *val)
+        .sum(); // `sum::<T>` needs `T` to be specified
+    // In this case any integer would fit, but we resolve to `i32` because that's what `{integer}`
+    // got coerced to. If the user needs further hinting that they can change the integer type, that
+    // can come from other suggestions. (#100802)
+    let bool = sum > 0;
+    assert_eq!(bool, true);
+}
diff --git a/tests/ui/inference/cannot-infer-iterator-sum-return-type.stderr b/tests/ui/inference/cannot-infer-iterator-sum-return-type.stderr
new file mode 100644
index 0000000000000..594b6f0181db0
--- /dev/null
+++ b/tests/ui/inference/cannot-infer-iterator-sum-return-type.stderr
@@ -0,0 +1,26 @@
+error[E0283]: type annotations needed
+  --> $DIR/cannot-infer-iterator-sum-return-type.rs:4:9
+   |
+LL |     let sum = v
+   |         ^^^
+...
+LL |         .sum(); // `sum::<T>` needs `T` to be specified
+   |          --- type must be known at this point
+   |
+   = note: the type must implement `Sum<i32>`
+help: the trait `Sum` is implemented for `i32`
+  --> $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL
+  ::: $SRC_DIR/core/src/iter/traits/accum.rs:LL:COL
+   |
+   = note: in this macro invocation
+note: required by a bound in `std::iter::Iterator::sum`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+   = note: this error originates in the macro `integer_sum_product` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider giving `sum` an explicit type, where the type for type parameter `S` is specified
+   |
+LL |     let sum: i32 = v
+   |            +++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0283`.

From 3b4b9fc593e7a599bcb1004edd67e3b2e008af1a Mon Sep 17 00:00:00 2001
From: Samuel Tardieu <sam@rfc1149.net>
Date: Thu, 12 Mar 2026 16:43:36 +0100
Subject: [PATCH 06/34] Add `Wake` diagnostic item for `alloc::task::Wake`

---
 library/alloc/src/task.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs
index aa1901314e37c..bc668f78bf740 100644
--- a/library/alloc/src/task.rs
+++ b/library/alloc/src/task.rs
@@ -87,6 +87,7 @@ use crate::sync::Arc;
 /// ```
 #[cfg(target_has_atomic = "ptr")]
 #[stable(feature = "wake_trait", since = "1.51.0")]
+#[rustc_diagnostic_item = "Wake"]
 pub trait Wake {
     /// Wake this task.
     #[stable(feature = "wake_trait", since = "1.51.0")]

From 87e5e7944f6ca8bec7a664920d32e24eb40bede3 Mon Sep 17 00:00:00 2001
From: Jacob Pratt <jacob@jhpratt.dev>
Date: Thu, 19 Mar 2026 01:08:01 -0400
Subject: [PATCH 07/34] Optimize 128-bit integer formatting

The compiler is unaware of the restricted range of the input, so it is
unable to optimize out the final division and modulus. By doing this
manually, we get a nontrivial performance gain.
---
 library/core/src/fmt/num.rs | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs
index d3d6495e75a2a..dfa27e32bc722 100644
--- a/library/core/src/fmt/num.rs
+++ b/library/core/src/fmt/num.rs
@@ -823,7 +823,7 @@ fn enc_16lsd<const OFFSET: usize>(buf: &mut [MaybeUninit<u8>], n: u64) {
     let mut remain = n;
 
     // Format per four digits from the lookup table.
-    for quad_index in (0..4).rev() {
+    for quad_index in (1..4).rev() {
         // pull two pairs
         let quad = remain % 1_00_00;
         remain /= 1_00_00;
@@ -834,6 +834,14 @@ fn enc_16lsd<const OFFSET: usize>(buf: &mut [MaybeUninit<u8>], n: u64) {
         buf[quad_index * 4 + OFFSET + 2].write(DECIMAL_PAIRS[pair2 * 2 + 0]);
         buf[quad_index * 4 + OFFSET + 3].write(DECIMAL_PAIRS[pair2 * 2 + 1]);
     }
+
+    // final two pairs
+    let pair1 = (remain / 100) as usize;
+    let pair2 = (remain % 100) as usize;
+    buf[OFFSET + 0].write(DECIMAL_PAIRS[pair1 * 2 + 0]);
+    buf[OFFSET + 1].write(DECIMAL_PAIRS[pair1 * 2 + 1]);
+    buf[OFFSET + 2].write(DECIMAL_PAIRS[pair2 * 2 + 0]);
+    buf[OFFSET + 3].write(DECIMAL_PAIRS[pair2 * 2 + 1]);
 }
 
 /// Euclidean division plus remainder with constant 1E16 basically consumes 16

From e11d17739a32a6e3fa111d3b58bb3e9393a98ce1 Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <n.nethercote@gmail.com>
Date: Thu, 19 Mar 2026 15:59:16 +1100
Subject: [PATCH 08/34] Reorder `define_callbacks`.

This is nitpicky, but the lack of a sensible order has been bugging me.

- Within `mod $name`, put all the typedefs together.
- After that:
  - First, types definitions and their impls.
  - Then the `TyCtxt*` impls, in a sensible order.
    - Likewise, put `TyCtxt::at` before the similar methods.
- Also reflow some overly long lines.
---
 compiler/rustc_middle/src/query/plumbing.rs | 258 ++++++++++----------
 1 file changed, 133 insertions(+), 125 deletions(-)

diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index d4e7bb52be974..f4e1ead7c5859 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -201,6 +201,13 @@ pub struct TyCtxtEnsureDone<'tcx> {
 }
 
 impl<'tcx> TyCtxt<'tcx> {
+    /// Returns a transparent wrapper for `TyCtxt` which uses
+    /// `span` as the location of queries performed through it.
+    #[inline(always)]
+    pub fn at(self, span: Span) -> TyCtxtAt<'tcx> {
+        TyCtxtAt { tcx: self, span }
+    }
+
     /// FIXME: `ensure_ok`'s effects are subtle. Is this comment fully accurate?
     ///
     /// Wrapper that calls queries in a special "ensure OK" mode, for callers
@@ -258,13 +265,6 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn ensure_done(self) -> TyCtxtEnsureDone<'tcx> {
         TyCtxtEnsureDone { tcx: self }
     }
-
-    /// Returns a transparent wrapper for `TyCtxt` which uses
-    /// `span` as the location of queries performed through it.
-    #[inline(always)]
-    pub fn at(self, span: Span) -> TyCtxtAt<'tcx> {
-        TyCtxtAt { tcx: self, span }
-    }
 }
 
 macro_rules! query_helper_param_ty {
@@ -323,6 +323,9 @@ macro_rules! define_callbacks {
                 #[cfg(not($arena_cache))]
                 pub type ProvidedValue<'tcx> = Value<'tcx>;
 
+                pub type Cache<'tcx> =
+                    <Key<'tcx> as $crate::query::QueryKey>::Cache<Erased<Value<'tcx>>>;
+
                 /// This helper function takes a value returned by the query provider
                 /// (or loaded from disk, or supplied by query feeding), allocates
                 /// it in an arena if requested by the `arena_cache` modifier, and
@@ -354,9 +357,6 @@ macro_rules! define_callbacks {
                     erase::erase_val(value)
                 }
 
-                pub type Cache<'tcx> =
-                    <Key<'tcx> as $crate::query::QueryKey>::Cache<Erased<Value<'tcx>>>;
-
                 // Ensure that keys grow no larger than 88 bytes by accident.
                 // Increase this limit if necessary, but do try to keep the size low if possible
                 #[cfg(target_pointer_width = "64")]
@@ -390,116 +390,8 @@ macro_rules! define_callbacks {
             }
         )*
 
-        /// Holds per-query arenas for queries with the `arena_cache` modifier.
-        #[derive(Default)]
-        pub struct QueryArenas<'tcx> {
-            $(
-                // Use the `ArenaCached` helper trait to determine the arena's value type.
-                #[cfg($arena_cache)]
-                pub $name: TypedArena<
-                    <$V as $crate::query::arena_cached::ArenaCached<'tcx>>::Allocated,
-                >,
-            )*
-        }
-
-        impl<'tcx> $crate::query::TyCtxtEnsureOk<'tcx> {
-            $(
-                $(#[$attr])*
-                #[inline(always)]
-                pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
-                    crate::query::inner::query_ensure_ok_or_done(
-                        self.tcx,
-                        &self.tcx.query_system.query_vtables.$name,
-                        $crate::query::IntoQueryKey::into_query_key(key),
-                        $crate::query::EnsureMode::Ok,
-                    )
-                }
-            )*
-        }
-
-        // Only defined when the `ensure_result` modifier is present.
-        impl<'tcx> $crate::query::TyCtxtEnsureResult<'tcx> {
-            $(
-                #[cfg($returns_error_guaranteed)]
-                $(#[$attr])*
-                #[inline(always)]
-                pub fn $name(
-                    self,
-                    key: query_helper_param_ty!($($K)*),
-                ) -> Result<(), rustc_errors::ErrorGuaranteed> {
-                    crate::query::inner::query_ensure_result(
-                        self.tcx,
-                        &self.tcx.query_system.query_vtables.$name,
-                        $crate::query::IntoQueryKey::into_query_key(key),
-                    )
-                }
-            )*
-        }
-
-        impl<'tcx> $crate::query::TyCtxtEnsureDone<'tcx> {
-            $(
-                $(#[$attr])*
-                #[inline(always)]
-                pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
-                    crate::query::inner::query_ensure_ok_or_done(
-                        self.tcx,
-                        &self.tcx.query_system.query_vtables.$name,
-                        $crate::query::IntoQueryKey::into_query_key(key),
-                        $crate::query::EnsureMode::Done,
-                    );
-                }
-            )*
-        }
-
-        impl<'tcx> TyCtxt<'tcx> {
-            $(
-                $(#[$attr])*
-                #[inline(always)]
-                #[must_use]
-                pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V {
-                    self.at(DUMMY_SP).$name(key)
-                }
-            )*
-        }
-
-        impl<'tcx> $crate::query::TyCtxtAt<'tcx> {
-            $(
-                $(#[$attr])*
-                #[inline(always)]
-                pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V {
-                    use $crate::query::{erase, inner};
-
-                    erase::restore_val::<$V>(inner::query_get_at(
-                        self.tcx,
-                        self.span,
-                        &self.tcx.query_system.query_vtables.$name,
-                        $crate::query::IntoQueryKey::into_query_key(key),
-                    ))
-                }
-            )*
-        }
-
-        $(
-            #[cfg($feedable)]
-            impl<'tcx, K: $crate::query::IntoQueryKey<$name::Key<'tcx>> + Copy>
-                TyCtxtFeed<'tcx, K>
-            {
-                $(#[$attr])*
-                #[inline(always)]
-                pub fn $name(self, value: $name::ProvidedValue<'tcx>) {
-                    let key = self.key().into_query_key();
-                    let erased_value = $name::provided_to_erased(self.tcx, value);
-                    $crate::query::inner::query_feed(
-                        self.tcx,
-                        &self.tcx.query_system.query_vtables.$name,
-                        key,
-                        erased_value,
-                    );
-                }
-            }
-        )*
-
-        /// Identifies a query by kind and key. This is in contrast to `QueryJobId` which is just a number.
+        /// Identifies a query by kind and key. This is in contrast to `QueryJobId` which is just a
+        /// number.
         #[allow(non_camel_case_types)]
         #[derive(Clone, Copy, Debug)]
         pub enum TaggedQueryKey<'tcx> {
@@ -528,7 +420,8 @@ macro_rules! define_callbacks {
             pub fn description(&self, tcx: TyCtxt<'tcx>) -> String {
                 let (name, description) = ty::print::with_no_queries!(match self {
                     $(
-                        TaggedQueryKey::$name(key) => (stringify!($name), _description_fns::$name(tcx, *key)),
+                        TaggedQueryKey::$name(key) =>
+                            (stringify!($name), _description_fns::$name(tcx, *key)),
                     )*
                 });
                 if tcx.sess.verbose_internals() {
@@ -550,7 +443,8 @@ macro_rules! define_callbacks {
                 }
                 match self {
                     $(
-                        TaggedQueryKey::$name(key) => crate::query::QueryKey::default_span(key, tcx),
+                        TaggedQueryKey::$name(key) =>
+                            crate::query::QueryKey::default_span(key, tcx),
                     )*
                 }
             }
@@ -558,8 +452,13 @@ macro_rules! define_callbacks {
             pub fn def_kind(&self, tcx: TyCtxt<'tcx>) -> Option<DefKind> {
                 // This is used to reduce code generation as it
                 // can be reused for queries with the same key type.
-                fn inner<'tcx>(key: &impl crate::query::QueryKey, tcx: TyCtxt<'tcx>) -> Option<DefKind> {
-                    key.key_as_def_id().and_then(|def_id| def_id.as_local()).map(|def_id| tcx.def_kind(def_id))
+                fn inner<'tcx>(key: &impl crate::query::QueryKey, tcx: TyCtxt<'tcx>)
+                    -> Option<DefKind>
+                {
+                    key
+                        .key_as_def_id()
+                        .and_then(|def_id| def_id.as_local())
+                        .map(|def_id| tcx.def_kind(def_id))
                 }
 
                 if let TaggedQueryKey::def_kind(..) = self {
@@ -577,7 +476,19 @@ macro_rules! define_callbacks {
         /// Holds a `QueryVTable` for each query.
         pub struct QueryVTables<'tcx> {
             $(
-                pub $name: crate::query::QueryVTable<'tcx, $name::Cache<'tcx>>,
+                pub $name: $crate::query::QueryVTable<'tcx, $name::Cache<'tcx>>,
+            )*
+        }
+
+        /// Holds per-query arenas for queries with the `arena_cache` modifier.
+        #[derive(Default)]
+        pub struct QueryArenas<'tcx> {
+            $(
+                // Use the `ArenaCached` helper trait to determine the arena's value type.
+                #[cfg($arena_cache)]
+                pub $name: TypedArena<
+                    <$V as $crate::query::arena_cached::ArenaCached<'tcx>>::Allocated,
+                >,
             )*
         }
 
@@ -637,6 +548,103 @@ macro_rules! define_callbacks {
         impl Clone for ExternProviders {
             fn clone(&self) -> Self { *self }
         }
+
+        impl<'tcx> TyCtxt<'tcx> {
+            $(
+                $(#[$attr])*
+                #[inline(always)]
+                #[must_use]
+                pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V {
+                    self.at(DUMMY_SP).$name(key)
+                }
+            )*
+        }
+
+        impl<'tcx> $crate::query::TyCtxtAt<'tcx> {
+            $(
+                $(#[$attr])*
+                #[inline(always)]
+                pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V {
+                    use $crate::query::{erase, inner};
+
+                    erase::restore_val::<$V>(inner::query_get_at(
+                        self.tcx,
+                        self.span,
+                        &self.tcx.query_system.query_vtables.$name,
+                        $crate::query::IntoQueryKey::into_query_key(key),
+                    ))
+                }
+            )*
+        }
+
+        impl<'tcx> $crate::query::TyCtxtEnsureOk<'tcx> {
+            $(
+                $(#[$attr])*
+                #[inline(always)]
+                pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
+                    crate::query::inner::query_ensure_ok_or_done(
+                        self.tcx,
+                        &self.tcx.query_system.query_vtables.$name,
+                        $crate::query::IntoQueryKey::into_query_key(key),
+                        $crate::query::EnsureMode::Ok,
+                    )
+                }
+            )*
+        }
+
+        // Only defined when the `ensure_result` modifier is present.
+        impl<'tcx> $crate::query::TyCtxtEnsureResult<'tcx> {
+            $(
+                #[cfg($returns_error_guaranteed)]
+                $(#[$attr])*
+                #[inline(always)]
+                pub fn $name(
+                    self,
+                    key: query_helper_param_ty!($($K)*),
+                ) -> Result<(), rustc_errors::ErrorGuaranteed> {
+                    crate::query::inner::query_ensure_result(
+                        self.tcx,
+                        &self.tcx.query_system.query_vtables.$name,
+                        $crate::query::IntoQueryKey::into_query_key(key),
+                    )
+                }
+            )*
+        }
+
+        impl<'tcx> $crate::query::TyCtxtEnsureDone<'tcx> {
+            $(
+                $(#[$attr])*
+                #[inline(always)]
+                pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
+                    crate::query::inner::query_ensure_ok_or_done(
+                        self.tcx,
+                        &self.tcx.query_system.query_vtables.$name,
+                        $crate::query::IntoQueryKey::into_query_key(key),
+                        $crate::query::EnsureMode::Done,
+                    );
+                }
+            )*
+        }
+
+        $(
+            #[cfg($feedable)]
+            impl<'tcx, K: $crate::query::IntoQueryKey<$name::Key<'tcx>> + Copy>
+                TyCtxtFeed<'tcx, K>
+            {
+                $(#[$attr])*
+                #[inline(always)]
+                pub fn $name(self, value: $name::ProvidedValue<'tcx>) {
+                    let key = self.key().into_query_key();
+                    let erased_value = $name::provided_to_erased(self.tcx, value);
+                    $crate::query::inner::query_feed(
+                        self.tcx,
+                        &self.tcx.query_system.query_vtables.$name,
+                        key,
+                        erased_value,
+                    );
+                }
+            }
+        )*
     };
 }
 

From 56f91dc8397dba59298b327811120f8bef14fef7 Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <n.nethercote@gmail.com>
Date: Thu, 19 Mar 2026 16:23:37 +1100
Subject: [PATCH 09/34] Minor `define_callbacks` tweaks.

- Use `$crate` more consistently.
- Add a couple of useful comments.
- Remove some unnecessary local variables.
---
 compiler/rustc_middle/src/query/plumbing.rs | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index f4e1ead7c5859..56a8f5e974aea 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -444,7 +444,7 @@ macro_rules! define_callbacks {
                 match self {
                     $(
                         TaggedQueryKey::$name(key) =>
-                            crate::query::QueryKey::default_span(key, tcx),
+                            $crate::query::QueryKey::default_span(key, tcx),
                     )*
                 }
             }
@@ -452,7 +452,7 @@ macro_rules! define_callbacks {
             pub fn def_kind(&self, tcx: TyCtxt<'tcx>) -> Option<DefKind> {
                 // This is used to reduce code generation as it
                 // can be reused for queries with the same key type.
-                fn inner<'tcx>(key: &impl crate::query::QueryKey, tcx: TyCtxt<'tcx>)
+                fn inner<'tcx>(key: &impl $crate::query::QueryKey, tcx: TyCtxt<'tcx>)
                     -> Option<DefKind>
                 {
                     key
@@ -465,6 +465,7 @@ macro_rules! define_callbacks {
                     // Try to avoid infinite recursion.
                     return None
                 }
+
                 match self {
                     $(
                         TaggedQueryKey::$name(key) => inner(key, tcx),
@@ -582,7 +583,7 @@ macro_rules! define_callbacks {
                 $(#[$attr])*
                 #[inline(always)]
                 pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
-                    crate::query::inner::query_ensure_ok_or_done(
+                    $crate::query::inner::query_ensure_ok_or_done(
                         self.tcx,
                         &self.tcx.query_system.query_vtables.$name,
                         $crate::query::IntoQueryKey::into_query_key(key),
@@ -592,7 +593,7 @@ macro_rules! define_callbacks {
             )*
         }
 
-        // Only defined when the `ensure_result` modifier is present.
+        // Only defined when the `returns_error_guaranteed` modifier is present.
         impl<'tcx> $crate::query::TyCtxtEnsureResult<'tcx> {
             $(
                 #[cfg($returns_error_guaranteed)]
@@ -602,7 +603,7 @@ macro_rules! define_callbacks {
                     self,
                     key: query_helper_param_ty!($($K)*),
                 ) -> Result<(), rustc_errors::ErrorGuaranteed> {
-                    crate::query::inner::query_ensure_result(
+                    $crate::query::inner::query_ensure_result(
                         self.tcx,
                         &self.tcx.query_system.query_vtables.$name,
                         $crate::query::IntoQueryKey::into_query_key(key),
@@ -616,7 +617,7 @@ macro_rules! define_callbacks {
                 $(#[$attr])*
                 #[inline(always)]
                 pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
-                    crate::query::inner::query_ensure_ok_or_done(
+                    $crate::query::inner::query_ensure_ok_or_done(
                         self.tcx,
                         &self.tcx.query_system.query_vtables.$name,
                         $crate::query::IntoQueryKey::into_query_key(key),
@@ -627,6 +628,7 @@ macro_rules! define_callbacks {
         }
 
         $(
+            // Only defined when the `feedable` modifier is present.
             #[cfg($feedable)]
             impl<'tcx, K: $crate::query::IntoQueryKey<$name::Key<'tcx>> + Copy>
                 TyCtxtFeed<'tcx, K>
@@ -634,13 +636,11 @@ macro_rules! define_callbacks {
                 $(#[$attr])*
                 #[inline(always)]
                 pub fn $name(self, value: $name::ProvidedValue<'tcx>) {
-                    let key = self.key().into_query_key();
-                    let erased_value = $name::provided_to_erased(self.tcx, value);
                     $crate::query::inner::query_feed(
                         self.tcx,
                         &self.tcx.query_system.query_vtables.$name,
-                        key,
-                        erased_value,
+                        self.key().into_query_key(),
+                        $name::provided_to_erased(self.tcx, value),
                     );
                 }
             }

From ee1d49abcd23ce0a851597ccde4e1f769169e28f Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <n.nethercote@gmail.com>
Date: Thu, 19 Mar 2026 16:54:06 +1100
Subject: [PATCH 10/34] Rename `query_helper_param_ty`.

As `maybe_into_query_key`. Partly to use `key` instead of `param`, and
also to make the link to the trait more obvious.
---
 compiler/rustc_middle/src/queries.rs        |  2 +-
 compiler/rustc_middle/src/query/plumbing.rs | 16 ++++++++--------
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs
index 4dd68db4f9135..b07b220865948 100644
--- a/compiler/rustc_middle/src/queries.rs
+++ b/compiler/rustc_middle/src/queries.rs
@@ -101,7 +101,7 @@ use crate::mir::mono::{
     CodegenUnit, CollectionMode, MonoItem, MonoItemPartitions, NormalizationErrorInMono,
 };
 use crate::query::describe_as_module;
-use crate::query::plumbing::{define_callbacks, query_helper_param_ty};
+use crate::query::plumbing::{define_callbacks, maybe_into_query_key};
 use crate::traits::query::{
     CanonicalAliasGoal, CanonicalDropckOutlivesGoal, CanonicalImpliedOutlivesBoundsGoal,
     CanonicalMethodAutoderefStepsGoal, CanonicalPredicateGoal, CanonicalTypeOpAscribeUserTypeGoal,
diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index 56a8f5e974aea..4ef1b0adf581d 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -267,7 +267,7 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 }
 
-macro_rules! query_helper_param_ty {
+macro_rules! maybe_into_query_key {
     (DefId) => { impl $crate::query::IntoQueryKey<DefId> };
     (LocalDefId) => { impl $crate::query::IntoQueryKey<LocalDefId> };
     ($K:ty) => { $K };
@@ -276,7 +276,7 @@ macro_rules! query_helper_param_ty {
 macro_rules! define_callbacks {
     (
         // You might expect the key to be `$K:ty`, but it needs to be `$($K:tt)*` so that
-        // `query_helper_param_ty!` can match on specific type names.
+        // `maybe_into_query_key!` can match on specific type names.
         queries {
             $(
                 $(#[$attr:meta])*
@@ -555,7 +555,7 @@ macro_rules! define_callbacks {
                 $(#[$attr])*
                 #[inline(always)]
                 #[must_use]
-                pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V {
+                pub fn $name(self, key: maybe_into_query_key!($($K)*)) -> $V {
                     self.at(DUMMY_SP).$name(key)
                 }
             )*
@@ -565,7 +565,7 @@ macro_rules! define_callbacks {
             $(
                 $(#[$attr])*
                 #[inline(always)]
-                pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V {
+                pub fn $name(self, key: maybe_into_query_key!($($K)*)) -> $V {
                     use $crate::query::{erase, inner};
 
                     erase::restore_val::<$V>(inner::query_get_at(
@@ -582,7 +582,7 @@ macro_rules! define_callbacks {
             $(
                 $(#[$attr])*
                 #[inline(always)]
-                pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
+                pub fn $name(self, key: maybe_into_query_key!($($K)*)) {
                     $crate::query::inner::query_ensure_ok_or_done(
                         self.tcx,
                         &self.tcx.query_system.query_vtables.$name,
@@ -601,7 +601,7 @@ macro_rules! define_callbacks {
                 #[inline(always)]
                 pub fn $name(
                     self,
-                    key: query_helper_param_ty!($($K)*),
+                    key: maybe_into_query_key!($($K)*),
                 ) -> Result<(), rustc_errors::ErrorGuaranteed> {
                     $crate::query::inner::query_ensure_result(
                         self.tcx,
@@ -616,7 +616,7 @@ macro_rules! define_callbacks {
             $(
                 $(#[$attr])*
                 #[inline(always)]
-                pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
+                pub fn $name(self, key: maybe_into_query_key!($($K)*)) {
                     $crate::query::inner::query_ensure_ok_or_done(
                         self.tcx,
                         &self.tcx.query_system.query_vtables.$name,
@@ -650,7 +650,7 @@ macro_rules! define_callbacks {
 
 // Re-export `macro_rules!` macros as normal items, so that they can be imported normally.
 pub(crate) use define_callbacks;
-pub(crate) use query_helper_param_ty;
+pub(crate) use maybe_into_query_key;
 
 #[cold]
 pub(crate) fn default_query(name: &str, key: &dyn std::fmt::Debug) -> ! {

From 88bc4fb20b5d8818576c01c0ecdde7c8121baa67 Mon Sep 17 00:00:00 2001
From: Trevor Gross <tg@trevorgross.com>
Date: Sat, 31 Jan 2026 02:10:07 -0600
Subject: [PATCH 11/34] dec2flt: Rename `Integer` to `Int`

This is more consistent with what the trait is called elsewhere in tree
(specifically compiler-builtins and test-float-parse).
---
 library/core/src/num/imp/dec2flt/float.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/library/core/src/num/imp/dec2flt/float.rs b/library/core/src/num/imp/dec2flt/float.rs
index 21aabdc8addb4..1ccc50fde5904 100644
--- a/library/core/src/num/imp/dec2flt/float.rs
+++ b/library/core/src/num/imp/dec2flt/float.rs
@@ -12,7 +12,7 @@ pub trait CastInto<T: Copy>: Copy {
 }
 
 /// Collection of traits that allow us to be generic over integer size.
-pub trait Integer:
+pub trait Int:
     Sized
     + Clone
     + Copy
@@ -37,7 +37,7 @@ macro_rules! int {
                 }
             }
 
-            impl Integer for $ty {
+            impl Int for $ty {
                 const ZERO: Self = 0;
                 const ONE: Self = 1;
             }
@@ -68,7 +68,7 @@ pub trait RawFloat:
     + Debug
 {
     /// The unsigned integer with the same size as the float
-    type Int: Integer + Into<u64>;
+    type Int: Int + Into<u64>;
 
     /* general constants */
 

From 8a2f24547b7d959c5345dc3d0126cd82b0610a31 Mon Sep 17 00:00:00 2001
From: Trevor Gross <tg@trevorgross.com>
Date: Sat, 31 Jan 2026 02:57:22 -0600
Subject: [PATCH 12/34] dec2flt: Split up the `RawFloat` trait

`RawFloat` is currently used specifically for the implementation of the
lemire algorithm, but it is useful for more than that. Split it into
three different traits:

* `Float`: Anything that is reasonably applicable to all floating point
  types.
* `FloatExt`: Items that should be part of `Float` but don't work for
  all float types. This will eventually be merged back into `Float`.
* `Lemire`: Items that are specific to the Lemire algorithm.
---
 library/core/src/num/imp/dec2flt/decimal.rs   |   9 +-
 library/core/src/num/imp/dec2flt/float.rs     | 161 ++++++++++--------
 library/core/src/num/imp/dec2flt/lemire.rs    |   4 +-
 library/core/src/num/imp/dec2flt/mod.rs       |   6 +-
 library/core/src/num/imp/dec2flt/parse.rs     |   4 +-
 library/core/src/num/imp/dec2flt/slow.rs      |   4 +-
 library/core/src/num/imp/flt2dec/decoder.rs   |   4 +-
 library/coretests/tests/num/dec2flt/float.rs  |  95 ++++++-----
 library/coretests/tests/num/dec2flt/lemire.rs |   2 +-
 9 files changed, 156 insertions(+), 133 deletions(-)

diff --git a/library/core/src/num/imp/dec2flt/decimal.rs b/library/core/src/num/imp/dec2flt/decimal.rs
index 27a53d4b9e75b..583f6bcf3302c 100644
--- a/library/core/src/num/imp/dec2flt/decimal.rs
+++ b/library/core/src/num/imp/dec2flt/decimal.rs
@@ -1,9 +1,8 @@
 //! Representation of a float as the significant digits and exponent.
 
-use dec2flt::float::RawFloat;
-use dec2flt::fpu::set_precision;
-
 use crate::num::imp::dec2flt;
+use dec2flt::float::Lemire;
+use dec2flt::fpu::set_precision;
 
 const INT_POW10: [u64; 16] = [
     1,
@@ -36,7 +35,7 @@ pub struct Decimal {
 impl Decimal {
     /// Detect if the float can be accurately reconstructed from native floats.
     #[inline]
-    fn can_use_fast_path<F: RawFloat>(&self) -> bool {
+    fn can_use_fast_path<F: Lemire>(&self) -> bool {
         F::MIN_EXPONENT_FAST_PATH <= self.exponent
             && self.exponent <= F::MAX_EXPONENT_DISGUISED_FAST_PATH
             && self.mantissa <= F::MAX_MANTISSA_FAST_PATH
@@ -53,7 +52,7 @@ impl Decimal {
     ///
     /// There is an exception: disguised fast-path cases, where we can shift
     /// powers-of-10 from the exponent to the significant digits.
-    pub fn try_fast_path<F: RawFloat>(&self) -> Option<F> {
+    pub fn try_fast_path<F: Lemire>(&self) -> Option<F> {
         // Here we need to work around <https://github.com/rust-lang/rust/issues/114479>.
         // The fast path crucially depends on arithmetic being rounded to the correct number of bits
         // without any intermediate rounding. On x86 (without SSE or SSE2) this requires the precision
diff --git a/library/core/src/num/imp/dec2flt/float.rs b/library/core/src/num/imp/dec2flt/float.rs
index 1ccc50fde5904..da581a457f495 100644
--- a/library/core/src/num/imp/dec2flt/float.rs
+++ b/library/core/src/num/imp/dec2flt/float.rs
@@ -48,12 +48,8 @@ macro_rules! int {
 int!(u16, u32, u64);
 
 /// A helper trait to avoid duplicating basically all the conversion code for IEEE floats.
-///
-/// See the parent module's doc comment for why this is necessary.
-///
-/// Should **never ever** be implemented for other types or be used outside the `dec2flt` module.
 #[doc(hidden)]
-pub trait RawFloat:
+pub trait Float:
     Sized
     + Div<Output = Self>
     + Neg<Output = Self>
@@ -128,8 +124,6 @@ pub trait RawFloat:
     const MIN_EXPONENT_ROUND_TO_EVEN: i32;
     const MAX_EXPONENT_ROUND_TO_EVEN: i32;
 
-    /* limits related to Fast pathing */
-
     /// Largest decimal exponent for a non-infinite value.
     ///
     /// This is the max exponent in binary converted to the max exponent in decimal. Allows fast
@@ -151,41 +145,19 @@ pub trait RawFloat:
     /// compile time since intermediates exceed the range of an `f64`.
     const SMALLEST_POWER_OF_TEN: i32;
 
-    /// Maximum exponent for a fast path case, or `⌊(SIG_BITS+1)/log2(5)⌋`
-    // assuming FLT_EVAL_METHOD = 0
-    const MAX_EXPONENT_FAST_PATH: i64 = {
-        let log2_5 = f64::consts::LOG2_10 - 1.0;
-        (Self::SIG_TOTAL_BITS as f64 / log2_5) as i64
-    };
-
-    /// Minimum exponent for a fast path case, or `-⌊(SIG_BITS+1)/log2(5)⌋`
-    const MIN_EXPONENT_FAST_PATH: i64 = -Self::MAX_EXPONENT_FAST_PATH;
-
-    /// Maximum exponent that can be represented for a disguised-fast path case.
-    /// This is `MAX_EXPONENT_FAST_PATH + ⌊(SIG_BITS+1)/log2(10)⌋`
-    const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 =
-        Self::MAX_EXPONENT_FAST_PATH + (Self::SIG_TOTAL_BITS as f64 / f64::consts::LOG2_10) as i64;
-
-    /// Maximum mantissa for the fast-path (`1 << 53` for f64).
-    const MAX_MANTISSA_FAST_PATH: u64 = 1 << Self::SIG_TOTAL_BITS;
-
-    /// Converts integer into float through an as cast.
-    /// This is only called in the fast-path algorithm, and therefore
-    /// will not lose precision, since the value will always have
-    /// only if the value is <= Self::MAX_MANTISSA_FAST_PATH.
-    fn from_u64(v: u64) -> Self;
-
-    /// Performs a raw transmutation from an integer.
-    fn from_u64_bits(v: u64) -> Self;
-
-    /// Gets a small power-of-ten for fast-path multiplication.
-    fn pow10_fast_path(exponent: usize) -> Self;
-
     /// Returns the category that this number falls into.
     fn classify(self) -> FpCategory;
 
     /// Transmute to the integer representation
     fn to_bits(self) -> Self::Int;
+}
+
+/// Items that ideally would be on `Float`, but don't apply to all float types because they
+/// rely on the mantissa fitting into a `u64` (which isn't true for `f128`).
+#[doc(hidden)]
+pub trait FloatExt: Float {
+    /// Performs a raw transmutation from an integer.
+    fn from_u64_bits(v: u64) -> Self;
 
     /// Returns the mantissa, exponent and sign as integers.
     ///
@@ -212,6 +184,41 @@ pub trait RawFloat:
     }
 }
 
+/// Extension to `Float` that are necessary for parsing using the Lemire method.
+///
+/// See the parent module's doc comment for why this is necessary.
+///
+/// Not intended for use outside of the `dec2flt` module.
+#[doc(hidden)]
+pub trait Lemire: FloatExt {
+    /// Maximum exponent for a fast path case, or `⌊(SIG_BITS+1)/log2(5)⌋`
+    // assuming FLT_EVAL_METHOD = 0
+    const MAX_EXPONENT_FAST_PATH: i64 = {
+        let log2_5 = f64::consts::LOG2_10 - 1.0;
+        (Self::SIG_TOTAL_BITS as f64 / log2_5) as i64
+    };
+
+    /// Minimum exponent for a fast path case, or `-⌊(SIG_BITS+1)/log2(5)⌋`
+    const MIN_EXPONENT_FAST_PATH: i64 = -Self::MAX_EXPONENT_FAST_PATH;
+
+    /// Maximum exponent that can be represented for a disguised-fast path case.
+    /// This is `MAX_EXPONENT_FAST_PATH + ⌊(SIG_BITS+1)/log2(10)⌋`
+    const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 =
+        Self::MAX_EXPONENT_FAST_PATH + (Self::SIG_TOTAL_BITS as f64 / f64::consts::LOG2_10) as i64;
+
+    /// Maximum mantissa for the fast-path (`1 << 53` for f64).
+    const MAX_MANTISSA_FAST_PATH: u64 = 1 << Self::SIG_TOTAL_BITS;
+
+    /// Gets a small power-of-ten for fast-path multiplication.
+    fn pow10_fast_path(exponent: usize) -> Self;
+
+    /// Converts integer into float through an as cast.
+    /// This is only called in the fast-path algorithm, and therefore
+    /// will not lose precision, since the value will always have
+    /// only if the value is <= Self::MAX_MANTISSA_FAST_PATH.
+    fn from_u64(v: u64) -> Self;
+}
+
 /// Solve for `b` in `10^b = 2^a`
 const fn pow2_to_pow10(a: i64) -> i64 {
     let res = (a as f64) / f64::consts::LOG2_10;
@@ -219,7 +226,7 @@ const fn pow2_to_pow10(a: i64) -> i64 {
 }
 
 #[cfg(target_has_reliable_f16)]
-impl RawFloat for f16 {
+impl Float for f16 {
     type Int = u16;
 
     const INFINITY: Self = Self::INFINITY;
@@ -236,33 +243,39 @@ impl RawFloat for f16 {
     const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 5;
     const SMALLEST_POWER_OF_TEN: i32 = -27;
 
-    #[inline]
-    fn from_u64(v: u64) -> Self {
-        debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
-        v as _
+    fn to_bits(self) -> Self::Int {
+        self.to_bits()
+    }
+
+    fn classify(self) -> FpCategory {
+        self.classify()
     }
+}
 
+#[cfg(target_has_reliable_f16)]
+impl FloatExt for f16 {
     #[inline]
     fn from_u64_bits(v: u64) -> Self {
         Self::from_bits((v & 0xFFFF) as u16)
     }
+}
 
+#[cfg(target_has_reliable_f16)]
+impl Lemire for f16 {
     fn pow10_fast_path(exponent: usize) -> Self {
         #[allow(clippy::use_self)]
         const TABLE: [f16; 8] = [1e0, 1e1, 1e2, 1e3, 1e4, 0.0, 0.0, 0.];
         TABLE[exponent & 7]
     }
 
-    fn to_bits(self) -> Self::Int {
-        self.to_bits()
-    }
-
-    fn classify(self) -> FpCategory {
-        self.classify()
+    #[inline]
+    fn from_u64(v: u64) -> Self {
+        debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
+        v as _
     }
 }
 
-impl RawFloat for f32 {
+impl Float for f32 {
     type Int = u32;
 
     const INFINITY: Self = f32::INFINITY;
@@ -279,17 +292,23 @@ impl RawFloat for f32 {
     const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 10;
     const SMALLEST_POWER_OF_TEN: i32 = -65;
 
-    #[inline]
-    fn from_u64(v: u64) -> Self {
-        debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
-        v as _
+    fn to_bits(self) -> Self::Int {
+        self.to_bits()
     }
 
+    fn classify(self) -> FpCategory {
+        self.classify()
+    }
+}
+
+impl FloatExt for f32 {
     #[inline]
     fn from_u64_bits(v: u64) -> Self {
         f32::from_bits((v & 0xFFFFFFFF) as u32)
     }
+}
 
+impl Lemire for f32 {
     fn pow10_fast_path(exponent: usize) -> Self {
         #[allow(clippy::use_self)]
         const TABLE: [f32; 16] =
@@ -297,16 +316,14 @@ impl RawFloat for f32 {
         TABLE[exponent & 15]
     }
 
-    fn to_bits(self) -> Self::Int {
-        self.to_bits()
-    }
-
-    fn classify(self) -> FpCategory {
-        self.classify()
+    #[inline]
+    fn from_u64(v: u64) -> Self {
+        debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
+        v as _
     }
 }
 
-impl RawFloat for f64 {
+impl Float for f64 {
     type Int = u64;
 
     const INFINITY: Self = Self::INFINITY;
@@ -323,17 +340,23 @@ impl RawFloat for f64 {
     const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 23;
     const SMALLEST_POWER_OF_TEN: i32 = -342;
 
-    #[inline]
-    fn from_u64(v: u64) -> Self {
-        debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
-        v as _
+    fn to_bits(self) -> Self::Int {
+        self.to_bits()
     }
 
+    fn classify(self) -> FpCategory {
+        self.classify()
+    }
+}
+
+impl FloatExt for f64 {
     #[inline]
     fn from_u64_bits(v: u64) -> Self {
         f64::from_bits(v)
     }
+}
 
+impl Lemire for f64 {
     fn pow10_fast_path(exponent: usize) -> Self {
         const TABLE: [f64; 32] = [
             1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
@@ -342,11 +365,9 @@ impl RawFloat for f64 {
         TABLE[exponent & 31]
     }
 
-    fn to_bits(self) -> Self::Int {
-        self.to_bits()
-    }
-
-    fn classify(self) -> FpCategory {
-        self.classify()
+    #[inline]
+    fn from_u64(v: u64) -> Self {
+        debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
+        v as _
     }
 }
diff --git a/library/core/src/num/imp/dec2flt/lemire.rs b/library/core/src/num/imp/dec2flt/lemire.rs
index c3f2723509d05..8a97618cf7385 100644
--- a/library/core/src/num/imp/dec2flt/lemire.rs
+++ b/library/core/src/num/imp/dec2flt/lemire.rs
@@ -1,7 +1,7 @@
 //! Implementation of the Eisel-Lemire algorithm.
 
 use dec2flt::common::BiasedFp;
-use dec2flt::float::RawFloat;
+use dec2flt::float::Float;
 use dec2flt::table::{LARGEST_POWER_OF_FIVE, POWER_OF_FIVE_128, SMALLEST_POWER_OF_FIVE};
 
 use crate::num::imp::dec2flt;
@@ -24,7 +24,7 @@ use crate::num::imp::dec2flt;
 /// at a Gigabyte per Second" in section 5, "Fast Algorithm", and
 /// section 6, "Exact Numbers And Ties", available online:
 /// <https://arxiv.org/abs/2101.11408.pdf>.
-pub fn compute_float<F: RawFloat>(q: i64, mut w: u64) -> BiasedFp {
+pub fn compute_float<F: Float>(q: i64, mut w: u64) -> BiasedFp {
     let fp_zero = BiasedFp::zero_pow2(0);
     let fp_inf = BiasedFp::zero_pow2(F::INFINITE_POWER);
     let fp_error = BiasedFp::zero_pow2(-1);
diff --git a/library/core/src/num/imp/dec2flt/mod.rs b/library/core/src/num/imp/dec2flt/mod.rs
index 3f5724add62bb..33e606694bc3e 100644
--- a/library/core/src/num/imp/dec2flt/mod.rs
+++ b/library/core/src/num/imp/dec2flt/mod.rs
@@ -88,7 +88,7 @@
 )]
 
 use common::BiasedFp;
-use float::RawFloat;
+use float::{FloatExt, Lemire};
 use lemire::compute_float;
 use parse::{parse_inf_nan, parse_number};
 use slow::parse_long_mantissa;
@@ -120,7 +120,7 @@ pub fn pfe_invalid() -> ParseFloatError {
 }
 
 /// Converts a `BiasedFp` to the closest machine float type.
-fn biased_fp_to_float<F: RawFloat>(x: BiasedFp) -> F {
+fn biased_fp_to_float<F: FloatExt>(x: BiasedFp) -> F {
     let mut word = x.m;
     word |= (x.p_biased as u64) << F::SIG_BITS;
     F::from_u64_bits(word)
@@ -128,7 +128,7 @@ fn biased_fp_to_float<F: RawFloat>(x: BiasedFp) -> F {
 
 /// Converts a decimal string into a floating point number.
 #[inline(always)] // Will be inlined into a function with `#[inline(never)]`, see above
-pub fn dec2flt<F: RawFloat>(s: &str) -> Result<F, ParseFloatError> {
+pub fn dec2flt<F: Lemire>(s: &str) -> Result<F, ParseFloatError> {
     let mut s = s.as_bytes();
     let Some(&c) = s.first() else { return Err(pfe_empty()) };
     let negative = c == b'-';
diff --git a/library/core/src/num/imp/dec2flt/parse.rs b/library/core/src/num/imp/dec2flt/parse.rs
index e4049bc164c61..e4e3e5bc0c0e3 100644
--- a/library/core/src/num/imp/dec2flt/parse.rs
+++ b/library/core/src/num/imp/dec2flt/parse.rs
@@ -2,7 +2,7 @@
 
 use dec2flt::common::{ByteSlice, is_8digits};
 use dec2flt::decimal::Decimal;
-use dec2flt::float::RawFloat;
+use dec2flt::float::Float;
 
 use crate::num::imp::dec2flt;
 
@@ -197,7 +197,7 @@ pub fn parse_number(s: &[u8]) -> Option<Decimal> {
 }
 
 /// Try to parse a special, non-finite float.
-pub(crate) fn parse_inf_nan<F: RawFloat>(s: &[u8], negative: bool) -> Option<F> {
+pub(crate) fn parse_inf_nan<F: Float>(s: &[u8], negative: bool) -> Option<F> {
     // Since a valid string has at most the length 8, we can load
     // all relevant characters into a u64 and work from there.
     // This also generates much better code.
diff --git a/library/core/src/num/imp/dec2flt/slow.rs b/library/core/src/num/imp/dec2flt/slow.rs
index 089b12f5be22e..784f3e00f5b48 100644
--- a/library/core/src/num/imp/dec2flt/slow.rs
+++ b/library/core/src/num/imp/dec2flt/slow.rs
@@ -2,7 +2,7 @@
 
 use dec2flt::common::BiasedFp;
 use dec2flt::decimal_seq::{DecimalSeq, parse_decimal_seq};
-use dec2flt::float::RawFloat;
+use dec2flt::float::Float;
 
 use crate::num::imp::dec2flt;
 
@@ -25,7 +25,7 @@ use crate::num::imp::dec2flt;
 ///
 /// The algorithms described here are based on "Processing Long Numbers Quickly",
 /// available here: <https://arxiv.org/pdf/2101.11408.pdf#section.11>.
-pub(crate) fn parse_long_mantissa<F: RawFloat>(s: &[u8]) -> BiasedFp {
+pub(crate) fn parse_long_mantissa<F: Float>(s: &[u8]) -> BiasedFp {
     const MAX_SHIFT: usize = 60;
     const NUM_POWERS: usize = 19;
     const POWERS: [u8; 19] =
diff --git a/library/core/src/num/imp/flt2dec/decoder.rs b/library/core/src/num/imp/flt2dec/decoder.rs
index 3d6ad6608efe3..6f8fb2b954f3a 100644
--- a/library/core/src/num/imp/flt2dec/decoder.rs
+++ b/library/core/src/num/imp/flt2dec/decoder.rs
@@ -1,7 +1,7 @@
 //! Decodes a floating-point value into individual parts and error ranges.
 
 use crate::num::FpCategory;
-use crate::num::imp::dec2flt::float::RawFloat;
+use crate::num::imp::dec2flt::float::FloatExt;
 
 /// Decoded unsigned finite value, such that:
 ///
@@ -40,7 +40,7 @@ pub enum FullDecoded {
 }
 
 /// A floating point type which can be `decode`d.
-pub trait DecodableFloat: RawFloat + Copy {
+pub trait DecodableFloat: FloatExt + Copy {
     /// The minimum positive normalized value.
     fn min_pos_norm_value() -> Self;
 }
diff --git a/library/coretests/tests/num/dec2flt/float.rs b/library/coretests/tests/num/dec2flt/float.rs
index 25e12435b4728..aa4c59dd66ea0 100644
--- a/library/coretests/tests/num/dec2flt/float.rs
+++ b/library/coretests/tests/num/dec2flt/float.rs
@@ -1,4 +1,4 @@
-use core::num::imp::dec2flt::float::RawFloat;
+use core::num::imp::dec2flt::float::{Float, FloatExt, Lemire};
 
 use crate::num::{ldexp_f32, ldexp_f64};
 
@@ -56,57 +56,60 @@ fn test_f64_integer_decode() {
 #[test]
 #[cfg(target_has_reliable_f16)]
 fn test_f16_consts() {
-    assert_eq!(<f16 as RawFloat>::INFINITY, f16::INFINITY);
-    assert_eq!(<f16 as RawFloat>::NEG_INFINITY, -f16::INFINITY);
-    assert_eq!(<f16 as RawFloat>::NAN.to_bits(), f16::NAN.to_bits());
-    assert_eq!(<f16 as RawFloat>::NEG_NAN.to_bits(), (-f16::NAN).to_bits());
-    assert_eq!(<f16 as RawFloat>::SIG_BITS, 10);
-    assert_eq!(<f16 as RawFloat>::MIN_EXPONENT_ROUND_TO_EVEN, -22);
-    assert_eq!(<f16 as RawFloat>::MAX_EXPONENT_ROUND_TO_EVEN, 5);
-    assert_eq!(<f16 as RawFloat>::MIN_EXPONENT_FAST_PATH, -4);
-    assert_eq!(<f16 as RawFloat>::MAX_EXPONENT_FAST_PATH, 4);
-    assert_eq!(<f16 as RawFloat>::MAX_EXPONENT_DISGUISED_FAST_PATH, 7);
-    assert_eq!(<f16 as RawFloat>::EXP_MIN, -14);
-    assert_eq!(<f16 as RawFloat>::EXP_SAT, 0x1f);
-    assert_eq!(<f16 as RawFloat>::SMALLEST_POWER_OF_TEN, -27);
-    assert_eq!(<f16 as RawFloat>::LARGEST_POWER_OF_TEN, 4);
-    assert_eq!(<f16 as RawFloat>::MAX_MANTISSA_FAST_PATH, 2048);
+    assert_eq!(<f16 as Float>::INFINITY, f16::INFINITY);
+    assert_eq!(<f16 as Float>::NEG_INFINITY, -f16::INFINITY);
+    assert_eq!(<f16 as Float>::NAN.to_bits(), f16::NAN.to_bits());
+    assert_eq!(<f16 as Float>::NEG_NAN.to_bits(), (-f16::NAN).to_bits());
+    assert_eq!(<f16 as Float>::SIG_BITS, 10);
+    assert_eq!(<f16 as Float>::MIN_EXPONENT_ROUND_TO_EVEN, -22);
+    assert_eq!(<f16 as Float>::MAX_EXPONENT_ROUND_TO_EVEN, 5);
+    assert_eq!(<f16 as Float>::EXP_MIN, -14);
+    assert_eq!(<f16 as Float>::EXP_SAT, 0x1f);
+    assert_eq!(<f16 as Float>::SMALLEST_POWER_OF_TEN, -27);
+    assert_eq!(<f16 as Float>::LARGEST_POWER_OF_TEN, 4);
+
+    assert_eq!(<f16 as Lemire>::MIN_EXPONENT_FAST_PATH, -4);
+    assert_eq!(<f16 as Lemire>::MAX_EXPONENT_FAST_PATH, 4);
+    assert_eq!(<f16 as Lemire>::MAX_EXPONENT_DISGUISED_FAST_PATH, 7);
+    assert_eq!(<f16 as Lemire>::MAX_MANTISSA_FAST_PATH, 2048);
 }
 
 #[test]
 fn test_f32_consts() {
-    assert_eq!(<f32 as RawFloat>::INFINITY, f32::INFINITY);
-    assert_eq!(<f32 as RawFloat>::NEG_INFINITY, -f32::INFINITY);
-    assert_eq!(<f32 as RawFloat>::NAN.to_bits(), f32::NAN.to_bits());
-    assert_eq!(<f32 as RawFloat>::NEG_NAN.to_bits(), (-f32::NAN).to_bits());
-    assert_eq!(<f32 as RawFloat>::SIG_BITS, 23);
-    assert_eq!(<f32 as RawFloat>::MIN_EXPONENT_ROUND_TO_EVEN, -17);
-    assert_eq!(<f32 as RawFloat>::MAX_EXPONENT_ROUND_TO_EVEN, 10);
-    assert_eq!(<f32 as RawFloat>::MIN_EXPONENT_FAST_PATH, -10);
-    assert_eq!(<f32 as RawFloat>::MAX_EXPONENT_FAST_PATH, 10);
-    assert_eq!(<f32 as RawFloat>::MAX_EXPONENT_DISGUISED_FAST_PATH, 17);
-    assert_eq!(<f32 as RawFloat>::EXP_MIN, -126);
-    assert_eq!(<f32 as RawFloat>::EXP_SAT, 0xff);
-    assert_eq!(<f32 as RawFloat>::SMALLEST_POWER_OF_TEN, -65);
-    assert_eq!(<f32 as RawFloat>::LARGEST_POWER_OF_TEN, 38);
-    assert_eq!(<f32 as RawFloat>::MAX_MANTISSA_FAST_PATH, 16777216);
+    assert_eq!(<f32 as Float>::INFINITY, f32::INFINITY);
+    assert_eq!(<f32 as Float>::NEG_INFINITY, -f32::INFINITY);
+    assert_eq!(<f32 as Float>::NAN.to_bits(), f32::NAN.to_bits());
+    assert_eq!(<f32 as Float>::NEG_NAN.to_bits(), (-f32::NAN).to_bits());
+    assert_eq!(<f32 as Float>::SIG_BITS, 23);
+    assert_eq!(<f32 as Float>::MIN_EXPONENT_ROUND_TO_EVEN, -17);
+    assert_eq!(<f32 as Float>::MAX_EXPONENT_ROUND_TO_EVEN, 10);
+    assert_eq!(<f32 as Float>::EXP_MIN, -126);
+    assert_eq!(<f32 as Float>::EXP_SAT, 0xff);
+    assert_eq!(<f32 as Float>::SMALLEST_POWER_OF_TEN, -65);
+    assert_eq!(<f32 as Float>::LARGEST_POWER_OF_TEN, 38);
+
+    assert_eq!(<f32 as Lemire>::MIN_EXPONENT_FAST_PATH, -10);
+    assert_eq!(<f32 as Lemire>::MAX_EXPONENT_FAST_PATH, 10);
+    assert_eq!(<f32 as Lemire>::MAX_EXPONENT_DISGUISED_FAST_PATH, 17);
+    assert_eq!(<f32 as Lemire>::MAX_MANTISSA_FAST_PATH, 16777216);
 }
 
 #[test]
 fn test_f64_consts() {
-    assert_eq!(<f64 as RawFloat>::INFINITY, f64::INFINITY);
-    assert_eq!(<f64 as RawFloat>::NEG_INFINITY, -f64::INFINITY);
-    assert_eq!(<f64 as RawFloat>::NAN.to_bits(), f64::NAN.to_bits());
-    assert_eq!(<f64 as RawFloat>::NEG_NAN.to_bits(), (-f64::NAN).to_bits());
-    assert_eq!(<f64 as RawFloat>::SIG_BITS, 52);
-    assert_eq!(<f64 as RawFloat>::MIN_EXPONENT_ROUND_TO_EVEN, -4);
-    assert_eq!(<f64 as RawFloat>::MAX_EXPONENT_ROUND_TO_EVEN, 23);
-    assert_eq!(<f64 as RawFloat>::MIN_EXPONENT_FAST_PATH, -22);
-    assert_eq!(<f64 as RawFloat>::MAX_EXPONENT_FAST_PATH, 22);
-    assert_eq!(<f64 as RawFloat>::MAX_EXPONENT_DISGUISED_FAST_PATH, 37);
-    assert_eq!(<f64 as RawFloat>::EXP_MIN, -1022);
-    assert_eq!(<f64 as RawFloat>::EXP_SAT, 0x7ff);
-    assert_eq!(<f64 as RawFloat>::SMALLEST_POWER_OF_TEN, -342);
-    assert_eq!(<f64 as RawFloat>::LARGEST_POWER_OF_TEN, 308);
-    assert_eq!(<f64 as RawFloat>::MAX_MANTISSA_FAST_PATH, 9007199254740992);
+    assert_eq!(<f64 as Float>::INFINITY, f64::INFINITY);
+    assert_eq!(<f64 as Float>::NEG_INFINITY, -f64::INFINITY);
+    assert_eq!(<f64 as Float>::NAN.to_bits(), f64::NAN.to_bits());
+    assert_eq!(<f64 as Float>::NEG_NAN.to_bits(), (-f64::NAN).to_bits());
+    assert_eq!(<f64 as Float>::SIG_BITS, 52);
+    assert_eq!(<f64 as Float>::MIN_EXPONENT_ROUND_TO_EVEN, -4);
+    assert_eq!(<f64 as Float>::MAX_EXPONENT_ROUND_TO_EVEN, 23);
+    assert_eq!(<f64 as Float>::EXP_MIN, -1022);
+    assert_eq!(<f64 as Float>::EXP_SAT, 0x7ff);
+    assert_eq!(<f64 as Float>::SMALLEST_POWER_OF_TEN, -342);
+    assert_eq!(<f64 as Float>::LARGEST_POWER_OF_TEN, 308);
+
+    assert_eq!(<f64 as Lemire>::MIN_EXPONENT_FAST_PATH, -22);
+    assert_eq!(<f64 as Lemire>::MAX_EXPONENT_FAST_PATH, 22);
+    assert_eq!(<f64 as Lemire>::MAX_EXPONENT_DISGUISED_FAST_PATH, 37);
+    assert_eq!(<f64 as Lemire>::MAX_MANTISSA_FAST_PATH, 9007199254740992);
 }
diff --git a/library/coretests/tests/num/dec2flt/lemire.rs b/library/coretests/tests/num/dec2flt/lemire.rs
index e4ce533ba44da..6679dca148aa6 100644
--- a/library/coretests/tests/num/dec2flt/lemire.rs
+++ b/library/coretests/tests/num/dec2flt/lemire.rs
@@ -1,6 +1,6 @@
 use core::num::imp::dec2flt;
 
-use dec2flt::float::RawFloat;
+use dec2flt::float::Float;
 use dec2flt::lemire::compute_float;
 
 #[cfg(target_has_reliable_f16)]

From ee200a52d3fbf043508e73e05e55f4110ca9a5c7 Mon Sep 17 00:00:00 2001
From: Trevor Gross <tg@trevorgross.com>
Date: Sat, 31 Jan 2026 03:13:08 -0600
Subject: [PATCH 13/34] dec2flt: Move internal traits to better locations

`Float` and `FloatExt` are already used by both parsing and printing, so
move them out of `dec2flt` to a new module in `num::imp`. `Int` `Cast`
have the potential to be used more places in the future, so move them
there as well. `Lemire` is the only remaining trait; since it is small,
move it into the `dec2flt` root.

The `fmt::LowerExp` bound is removed from `Float` here since the trait
is moving into a module without `#[cfg(not(no_fp_fmt_parse))]` and it
isn't implemented with that config (it's not easily possible to add
`cfg` attributes to a single supertrait, unfortunately). This isn't a
problem since it isn't actually being used.
---
 library/core/src/num/imp/dec2flt/decimal.rs   |   5 +-
 library/core/src/num/imp/dec2flt/lemire.rs    |   3 +-
 library/core/src/num/imp/dec2flt/mod.rs       |  90 ++++++++++++++-
 library/core/src/num/imp/dec2flt/parse.rs     |   3 +-
 library/core/src/num/imp/dec2flt/slow.rs      |   3 +-
 library/core/src/num/imp/flt2dec/decoder.rs   |   2 +-
 library/core/src/num/imp/mod.rs               |   3 +
 .../num/imp/{dec2flt/float.rs => traits.rs}   | 106 +++---------------
 library/coretests/tests/lib.rs                |   1 +
 library/coretests/tests/num/dec2flt/float.rs  |   3 +-
 library/coretests/tests/num/dec2flt/lemire.rs |   3 +-
 11 files changed, 113 insertions(+), 109 deletions(-)
 rename library/core/src/num/imp/{dec2flt/float.rs => traits.rs} (74%)

diff --git a/library/core/src/num/imp/dec2flt/decimal.rs b/library/core/src/num/imp/dec2flt/decimal.rs
index 583f6bcf3302c..c9b0cc531b386 100644
--- a/library/core/src/num/imp/dec2flt/decimal.rs
+++ b/library/core/src/num/imp/dec2flt/decimal.rs
@@ -1,9 +1,10 @@
 //! Representation of a float as the significant digits and exponent.
 
-use crate::num::imp::dec2flt;
-use dec2flt::float::Lemire;
+use dec2flt::Lemire;
 use dec2flt::fpu::set_precision;
 
+use crate::num::imp::dec2flt;
+
 const INT_POW10: [u64; 16] = [
     1,
     10,
diff --git a/library/core/src/num/imp/dec2flt/lemire.rs b/library/core/src/num/imp/dec2flt/lemire.rs
index 8a97618cf7385..f89d16c843477 100644
--- a/library/core/src/num/imp/dec2flt/lemire.rs
+++ b/library/core/src/num/imp/dec2flt/lemire.rs
@@ -1,10 +1,9 @@
 //! Implementation of the Eisel-Lemire algorithm.
 
 use dec2flt::common::BiasedFp;
-use dec2flt::float::Float;
 use dec2flt::table::{LARGEST_POWER_OF_FIVE, POWER_OF_FIVE_128, SMALLEST_POWER_OF_FIVE};
 
-use crate::num::imp::dec2flt;
+use crate::num::imp::{Float, dec2flt};
 
 /// Compute w * 10^q using an extended-precision float representation.
 ///
diff --git a/library/core/src/num/imp/dec2flt/mod.rs b/library/core/src/num/imp/dec2flt/mod.rs
index 33e606694bc3e..76b8d416ee0f1 100644
--- a/library/core/src/num/imp/dec2flt/mod.rs
+++ b/library/core/src/num/imp/dec2flt/mod.rs
@@ -88,24 +88,104 @@
 )]
 
 use common::BiasedFp;
-use float::{FloatExt, Lemire};
 use lemire::compute_float;
 use parse::{parse_inf_nan, parse_number};
 use slow::parse_long_mantissa;
 
+use crate::f64;
 use crate::num::ParseFloatError;
 use crate::num::float_parse::FloatErrorKind;
+use crate::num::imp::FloatExt;
 
 mod common;
 pub mod decimal;
 pub mod decimal_seq;
 mod fpu;
-mod slow;
-mod table;
-// float is used in flt2dec, and all are used in unit tests.
-pub mod float;
 pub mod lemire;
 pub mod parse;
+mod slow;
+mod table;
+
+/// Extension to `Float` that are necessary for parsing using the Lemire method.
+///
+/// See the parent module's doc comment for why this is necessary.
+///
+/// Not intended for use outside of the `dec2flt` module.
+#[doc(hidden)]
+pub trait Lemire: FloatExt {
+    /// Maximum exponent for a fast path case, or `⌊(SIG_BITS+1)/log2(5)⌋`
+    // assuming FLT_EVAL_METHOD = 0
+    const MAX_EXPONENT_FAST_PATH: i64 = {
+        let log2_5 = f64::consts::LOG2_10 - 1.0;
+        (Self::SIG_TOTAL_BITS as f64 / log2_5) as i64
+    };
+
+    /// Minimum exponent for a fast path case, or `-⌊(SIG_BITS+1)/log2(5)⌋`
+    const MIN_EXPONENT_FAST_PATH: i64 = -Self::MAX_EXPONENT_FAST_PATH;
+
+    /// Maximum exponent that can be represented for a disguised-fast path case.
+    /// This is `MAX_EXPONENT_FAST_PATH + ⌊(SIG_BITS+1)/log2(10)⌋`
+    const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 =
+        Self::MAX_EXPONENT_FAST_PATH + (Self::SIG_TOTAL_BITS as f64 / f64::consts::LOG2_10) as i64;
+
+    /// Maximum mantissa for the fast-path (`1 << 53` for f64).
+    const MAX_MANTISSA_FAST_PATH: u64 = 1 << Self::SIG_TOTAL_BITS;
+
+    /// Gets a small power-of-ten for fast-path multiplication.
+    fn pow10_fast_path(exponent: usize) -> Self;
+
+    /// Converts integer into float through an as cast.
+    /// This is only called in the fast-path algorithm, and therefore
+    /// will not lose precision, since the value will always have
+    /// only if the value is <= Self::MAX_MANTISSA_FAST_PATH.
+    fn from_u64(v: u64) -> Self;
+}
+
+#[cfg(target_has_reliable_f16)]
+impl Lemire for f16 {
+    fn pow10_fast_path(exponent: usize) -> Self {
+        #[allow(clippy::use_self)]
+        const TABLE: [f16; 8] = [1e0, 1e1, 1e2, 1e3, 1e4, 0.0, 0.0, 0.];
+        TABLE[exponent & 7]
+    }
+
+    #[inline]
+    fn from_u64(v: u64) -> Self {
+        debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
+        v as _
+    }
+}
+
+impl Lemire for f32 {
+    fn pow10_fast_path(exponent: usize) -> Self {
+        #[allow(clippy::use_self)]
+        const TABLE: [f32; 16] =
+            [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 0., 0., 0., 0., 0.];
+        TABLE[exponent & 15]
+    }
+
+    #[inline]
+    fn from_u64(v: u64) -> Self {
+        debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
+        v as _
+    }
+}
+
+impl Lemire for f64 {
+    fn pow10_fast_path(exponent: usize) -> Self {
+        const TABLE: [f64; 32] = [
+            1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
+            1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 0., 0., 0., 0., 0., 0., 0., 0., 0.,
+        ];
+        TABLE[exponent & 31]
+    }
+
+    #[inline]
+    fn from_u64(v: u64) -> Self {
+        debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
+        v as _
+    }
+}
 
 #[inline]
 pub(super) fn pfe_empty() -> ParseFloatError {
diff --git a/library/core/src/num/imp/dec2flt/parse.rs b/library/core/src/num/imp/dec2flt/parse.rs
index e4e3e5bc0c0e3..ee55eadbc7b9e 100644
--- a/library/core/src/num/imp/dec2flt/parse.rs
+++ b/library/core/src/num/imp/dec2flt/parse.rs
@@ -2,9 +2,8 @@
 
 use dec2flt::common::{ByteSlice, is_8digits};
 use dec2flt::decimal::Decimal;
-use dec2flt::float::Float;
 
-use crate::num::imp::dec2flt;
+use crate::num::imp::{Float, dec2flt};
 
 const MIN_19DIGIT_INT: u64 = 100_0000_0000_0000_0000;
 
diff --git a/library/core/src/num/imp/dec2flt/slow.rs b/library/core/src/num/imp/dec2flt/slow.rs
index 784f3e00f5b48..f1b2525cf38e6 100644
--- a/library/core/src/num/imp/dec2flt/slow.rs
+++ b/library/core/src/num/imp/dec2flt/slow.rs
@@ -2,9 +2,8 @@
 
 use dec2flt::common::BiasedFp;
 use dec2flt::decimal_seq::{DecimalSeq, parse_decimal_seq};
-use dec2flt::float::Float;
 
-use crate::num::imp::dec2flt;
+use crate::num::imp::{Float, dec2flt};
 
 /// Parse the significant digits and biased, binary exponent of a float.
 ///
diff --git a/library/core/src/num/imp/flt2dec/decoder.rs b/library/core/src/num/imp/flt2dec/decoder.rs
index 6f8fb2b954f3a..5ccc91f4c9faf 100644
--- a/library/core/src/num/imp/flt2dec/decoder.rs
+++ b/library/core/src/num/imp/flt2dec/decoder.rs
@@ -1,7 +1,7 @@
 //! Decodes a floating-point value into individual parts and error ranges.
 
 use crate::num::FpCategory;
-use crate::num::imp::dec2flt::float::FloatExt;
+use crate::num::imp::FloatExt;
 
 /// Decoded unsigned finite value, such that:
 ///
diff --git a/library/core/src/num/imp/mod.rs b/library/core/src/num/imp/mod.rs
index d35409f91bde9..6fccfd1c238ed 100644
--- a/library/core/src/num/imp/mod.rs
+++ b/library/core/src/num/imp/mod.rs
@@ -16,3 +16,6 @@ pub(crate) mod int_log10;
 pub(crate) mod int_sqrt;
 pub(crate) mod libm;
 pub(crate) mod overflow_panic;
+mod traits;
+
+pub use traits::{Float, FloatExt, Int};
diff --git a/library/core/src/num/imp/dec2flt/float.rs b/library/core/src/num/imp/traits.rs
similarity index 74%
rename from library/core/src/num/imp/dec2flt/float.rs
rename to library/core/src/num/imp/traits.rs
index da581a457f495..7b84f7a4a5aa2 100644
--- a/library/core/src/num/imp/dec2flt/float.rs
+++ b/library/core/src/num/imp/traits.rs
@@ -1,10 +1,14 @@
-//! Helper trait for generic float types.
+//! Numeric traits used for internal implementations.
 
-use core::f64;
+#![doc(hidden)]
+#![unstable(
+    feature = "num_internals",
+    reason = "internal routines only exposed for testing",
+    issue = "none"
+)]
 
-use crate::fmt::{Debug, LowerExp};
 use crate::num::FpCategory;
-use crate::ops::{self, Add, Div, Mul, Neg};
+use crate::{f64, fmt, ops};
 
 /// Lossy `as` casting between two types.
 pub trait CastInto<T: Copy>: Copy {
@@ -16,7 +20,7 @@ pub trait Int:
     Sized
     + Clone
     + Copy
-    + Debug
+    + fmt::Debug
     + ops::Shr<u32, Output = Self>
     + ops::Shl<u32, Output = Self>
     + ops::BitAnd<Output = Self>
@@ -51,17 +55,16 @@ int!(u16, u32, u64);
 #[doc(hidden)]
 pub trait Float:
     Sized
-    + Div<Output = Self>
-    + Neg<Output = Self>
-    + Mul<Output = Self>
-    + Add<Output = Self>
-    + LowerExp
+    + ops::Div<Output = Self>
+    + ops::Neg<Output = Self>
+    + ops::Mul<Output = Self>
+    + ops::Add<Output = Self>
+    + fmt::Debug
     + PartialEq
     + PartialOrd
     + Default
     + Clone
     + Copy
-    + Debug
 {
     /// The unsigned integer with the same size as the float
     type Int: Int + Into<u64>;
@@ -184,41 +187,6 @@ pub trait FloatExt: Float {
     }
 }
 
-/// Extension to `Float` that are necessary for parsing using the Lemire method.
-///
-/// See the parent module's doc comment for why this is necessary.
-///
-/// Not intended for use outside of the `dec2flt` module.
-#[doc(hidden)]
-pub trait Lemire: FloatExt {
-    /// Maximum exponent for a fast path case, or `⌊(SIG_BITS+1)/log2(5)⌋`
-    // assuming FLT_EVAL_METHOD = 0
-    const MAX_EXPONENT_FAST_PATH: i64 = {
-        let log2_5 = f64::consts::LOG2_10 - 1.0;
-        (Self::SIG_TOTAL_BITS as f64 / log2_5) as i64
-    };
-
-    /// Minimum exponent for a fast path case, or `-⌊(SIG_BITS+1)/log2(5)⌋`
-    const MIN_EXPONENT_FAST_PATH: i64 = -Self::MAX_EXPONENT_FAST_PATH;
-
-    /// Maximum exponent that can be represented for a disguised-fast path case.
-    /// This is `MAX_EXPONENT_FAST_PATH + ⌊(SIG_BITS+1)/log2(10)⌋`
-    const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 =
-        Self::MAX_EXPONENT_FAST_PATH + (Self::SIG_TOTAL_BITS as f64 / f64::consts::LOG2_10) as i64;
-
-    /// Maximum mantissa for the fast-path (`1 << 53` for f64).
-    const MAX_MANTISSA_FAST_PATH: u64 = 1 << Self::SIG_TOTAL_BITS;
-
-    /// Gets a small power-of-ten for fast-path multiplication.
-    fn pow10_fast_path(exponent: usize) -> Self;
-
-    /// Converts integer into float through an as cast.
-    /// This is only called in the fast-path algorithm, and therefore
-    /// will not lose precision, since the value will always have
-    /// only if the value is <= Self::MAX_MANTISSA_FAST_PATH.
-    fn from_u64(v: u64) -> Self;
-}
-
 /// Solve for `b` in `10^b = 2^a`
 const fn pow2_to_pow10(a: i64) -> i64 {
     let res = (a as f64) / f64::consts::LOG2_10;
@@ -260,21 +228,6 @@ impl FloatExt for f16 {
     }
 }
 
-#[cfg(target_has_reliable_f16)]
-impl Lemire for f16 {
-    fn pow10_fast_path(exponent: usize) -> Self {
-        #[allow(clippy::use_self)]
-        const TABLE: [f16; 8] = [1e0, 1e1, 1e2, 1e3, 1e4, 0.0, 0.0, 0.];
-        TABLE[exponent & 7]
-    }
-
-    #[inline]
-    fn from_u64(v: u64) -> Self {
-        debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
-        v as _
-    }
-}
-
 impl Float for f32 {
     type Int = u32;
 
@@ -308,21 +261,6 @@ impl FloatExt for f32 {
     }
 }
 
-impl Lemire for f32 {
-    fn pow10_fast_path(exponent: usize) -> Self {
-        #[allow(clippy::use_self)]
-        const TABLE: [f32; 16] =
-            [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 0., 0., 0., 0., 0.];
-        TABLE[exponent & 15]
-    }
-
-    #[inline]
-    fn from_u64(v: u64) -> Self {
-        debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
-        v as _
-    }
-}
-
 impl Float for f64 {
     type Int = u64;
 
@@ -355,19 +293,3 @@ impl FloatExt for f64 {
         f64::from_bits(v)
     }
 }
-
-impl Lemire for f64 {
-    fn pow10_fast_path(exponent: usize) -> Self {
-        const TABLE: [f64; 32] = [
-            1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
-            1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 0., 0., 0., 0., 0., 0., 0., 0., 0.,
-        ];
-        TABLE[exponent & 31]
-    }
-
-    #[inline]
-    fn from_u64(v: u64) -> Self {
-        debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
-        v as _
-    }
-}
diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs
index 72112f8b01133..b3fd53cbb9dce 100644
--- a/library/coretests/tests/lib.rs
+++ b/library/coretests/tests/lib.rs
@@ -88,6 +88,7 @@
 #![feature(next_index)]
 #![feature(non_exhaustive_omitted_patterns_lint)]
 #![feature(nonzero_from_str_radix)]
+#![feature(num_internals)]
 #![feature(numfmt)]
 #![feature(one_sided_range)]
 #![feature(panic_internals)]
diff --git a/library/coretests/tests/num/dec2flt/float.rs b/library/coretests/tests/num/dec2flt/float.rs
index aa4c59dd66ea0..0713c5c651fb3 100644
--- a/library/coretests/tests/num/dec2flt/float.rs
+++ b/library/coretests/tests/num/dec2flt/float.rs
@@ -1,4 +1,5 @@
-use core::num::imp::dec2flt::float::{Float, FloatExt, Lemire};
+use core::num::imp::dec2flt::Lemire;
+use core::num::imp::{Float, FloatExt};
 
 use crate::num::{ldexp_f32, ldexp_f64};
 
diff --git a/library/coretests/tests/num/dec2flt/lemire.rs b/library/coretests/tests/num/dec2flt/lemire.rs
index 6679dca148aa6..e5a7ae346f425 100644
--- a/library/coretests/tests/num/dec2flt/lemire.rs
+++ b/library/coretests/tests/num/dec2flt/lemire.rs
@@ -1,6 +1,5 @@
-use core::num::imp::dec2flt;
+use core::num::imp::{Float, dec2flt};
 
-use dec2flt::float::Float;
 use dec2flt::lemire::compute_float;
 
 #[cfg(target_has_reliable_f16)]

From 580182baddd78c02f2948aa6a8bea9859a3f682c Mon Sep 17 00:00:00 2001
From: "LevitatingBusinessMan (Rein Fernhout)" <me@levitati.ng>
Date: Fri, 27 Feb 2026 09:30:27 +0100
Subject: [PATCH 14/34] Add is_disconnected functions to mpsc and mpmc channels

---
 library/std/src/sync/mpmc/mod.rs  | 46 +++++++++++++++++++++++++++++++
 library/std/src/sync/mpmc/zero.rs |  6 ++++
 library/std/src/sync/mpsc.rs      | 38 +++++++++++++++++++++++++
 3 files changed, 90 insertions(+)

diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs
index 8df81a580f7b8..6249e8a033e8d 100644
--- a/library/std/src/sync/mpmc/mod.rs
+++ b/library/std/src/sync/mpmc/mod.rs
@@ -623,6 +623,29 @@ impl<T> Sender<T> {
             _ => false,
         }
     }
+
+    /// Returns `true` if the channel is disconnected.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc::channel;
+    ///
+    /// let (tx, rx) = channel::<i32>();
+    /// assert!(!tx.is_disconnected());
+    /// drop(rx);
+    /// assert!(tx.is_disconnected());
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
+    pub fn is_disconnected(&self) -> bool {
+        match &self.flavor {
+            SenderFlavor::Array(chan) => chan.is_disconnected(),
+            SenderFlavor::List(chan) => chan.is_disconnected(),
+            SenderFlavor::Zero(chan) => chan.is_disconnected(),
+        }
+    }
 }
 
 #[unstable(feature = "mpmc_channel", issue = "126840")]
@@ -1349,6 +1372,29 @@ impl<T> Receiver<T> {
     pub fn iter(&self) -> Iter<'_, T> {
         Iter { rx: self }
     }
+
+    /// Returns `true` if the channel is disconnected.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpmc_channel)]
+    ///
+    /// use std::sync::mpmc::channel;
+    ///
+    /// let (tx, rx) = channel::<i32>();
+    /// assert!(!rx.is_disconnected());
+    /// drop(tx);
+    /// assert!(rx.is_disconnected());
+    /// ```
+    #[unstable(feature = "mpmc_channel", issue = "126840")]
+    pub fn is_disconnected(&self) -> bool {
+        match &self.flavor {
+            ReceiverFlavor::Array(chan) => chan.is_disconnected(),
+            ReceiverFlavor::List(chan) => chan.is_disconnected(),
+            ReceiverFlavor::Zero(chan) => chan.is_disconnected(),
+        }
+    }
 }
 
 #[unstable(feature = "mpmc_channel", issue = "126840")]
diff --git a/library/std/src/sync/mpmc/zero.rs b/library/std/src/sync/mpmc/zero.rs
index f1ecf80fcb9f6..c743462501922 100644
--- a/library/std/src/sync/mpmc/zero.rs
+++ b/library/std/src/sync/mpmc/zero.rs
@@ -316,4 +316,10 @@ impl<T> Channel<T> {
     pub(crate) fn is_full(&self) -> bool {
         true
     }
+
+    /// Returns `true` if the channel is disconnected.
+    pub(crate) fn is_disconnected(&self) -> bool {
+        let inner = self.inner.lock().unwrap();
+        inner.is_disconnected
+    }
 }
diff --git a/library/std/src/sync/mpsc.rs b/library/std/src/sync/mpsc.rs
index 0ae23f6e13bf2..81bb5849fb77f 100644
--- a/library/std/src/sync/mpsc.rs
+++ b/library/std/src/sync/mpsc.rs
@@ -607,6 +607,25 @@ impl<T> Sender<T> {
     pub fn send(&self, t: T) -> Result<(), SendError<T>> {
         self.inner.send(t)
     }
+
+    /// Returns `true` if the channel is disconnected.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpsc_is_disconnected)]
+    ///
+    /// use std::sync::mpsc::channel;
+    ///
+    /// let (tx, rx) = channel::<i32>();
+    /// assert!(!tx.is_disconnected());
+    /// drop(rx);
+    /// assert!(tx.is_disconnected());
+    /// ```
+    #[unstable(feature = "mpsc_is_disconnected", issue = "none")]
+    pub fn is_disconnected(&self) -> bool {
+        self.inner.is_disconnected()
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1038,6 +1057,25 @@ impl<T> Receiver<T> {
     pub fn try_iter(&self) -> TryIter<'_, T> {
         TryIter { rx: self }
     }
+
+    /// Returns `true` if the channel is disconnected.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(mpsc_is_disconnected)]
+    ///
+    /// use std::sync::mpsc::channel;
+    ///
+    /// let (tx, rx) = channel::<i32>();
+    /// assert!(!rx.is_disconnected());
+    /// drop(tx);
+    /// assert!(rx.is_disconnected());
+    /// ```
+    #[unstable(feature = "mpsc_is_disconnected", issue = "none")]
+    pub fn is_disconnected(&self) -> bool {
+        self.inner.is_disconnected()
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]

From d9104d3ab51bccafe8af70ed3d7fc7b2917fbec3 Mon Sep 17 00:00:00 2001
From: "LevitatingBusinessMan (Rein Fernhout)" <me@levitati.ng>
Date: Sat, 28 Feb 2026 19:52:50 +0100
Subject: [PATCH 15/34] warn of possible race condition in channel
 is_disconnected doc

---
 library/std/src/sync/mpmc/mod.rs | 8 ++++++++
 library/std/src/sync/mpsc.rs     | 8 ++++++++
 2 files changed, 16 insertions(+)

diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs
index 6249e8a033e8d..16ae8a88370be 100644
--- a/library/std/src/sync/mpmc/mod.rs
+++ b/library/std/src/sync/mpmc/mod.rs
@@ -626,6 +626,10 @@ impl<T> Sender<T> {
 
     /// Returns `true` if the channel is disconnected.
     ///
+    /// Note that a return value of `false` does not guarantee the channel will
+    /// remain connected. The channel may be disconnected immediately after this method
+    /// returns, so a subsequent [`Sender::send`] may still fail with [`SendError`].
+    ///
     /// # Examples
     ///
     /// ```
@@ -1375,6 +1379,10 @@ impl<T> Receiver<T> {
 
     /// Returns `true` if the channel is disconnected.
     ///
+    /// Note that a return value of `false` does not guarantee the channel will
+    /// remain connected. The channel may be disconnected immediately after this method
+    /// returns, so a subsequent [`Receiver::recv`] may still fail with [`RecvError`].
+    ///
     /// # Examples
     ///
     /// ```
diff --git a/library/std/src/sync/mpsc.rs b/library/std/src/sync/mpsc.rs
index 81bb5849fb77f..2abf7bfe341d4 100644
--- a/library/std/src/sync/mpsc.rs
+++ b/library/std/src/sync/mpsc.rs
@@ -610,6 +610,10 @@ impl<T> Sender<T> {
 
     /// Returns `true` if the channel is disconnected.
     ///
+    /// Note that a return value of `false` does not guarantee the channel will
+    /// remain connected. The channel may be disconnected immediately after this method
+    /// returns, so a subsequent [`Sender::send`] may still fail with [`SendError`].
+    ///
     /// # Examples
     ///
     /// ```
@@ -1060,6 +1064,10 @@ impl<T> Receiver<T> {
 
     /// Returns `true` if the channel is disconnected.
     ///
+    /// Note that a return value of `false` does not guarantee the channel will
+    /// remain connected. The channel may be disconnected immediately after this method
+    /// returns, so a subsequent [`Receiver::recv`] may still fail with [`RecvError`].
+    ///
     /// # Examples
     ///
     /// ```

From 0303b6cdfe160d8739c90e46bacc2a5897e166fa Mon Sep 17 00:00:00 2001
From: "LevitatingBusinessMan (Rein Fernhout)" <me@levitati.ng>
Date: Tue, 10 Mar 2026 19:21:19 +0100
Subject: [PATCH 16/34] assign mpsc_is_disconnected issue 153668

---
 library/std/src/sync/mpsc.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/library/std/src/sync/mpsc.rs b/library/std/src/sync/mpsc.rs
index 2abf7bfe341d4..a1c49bb83010c 100644
--- a/library/std/src/sync/mpsc.rs
+++ b/library/std/src/sync/mpsc.rs
@@ -626,7 +626,7 @@ impl<T> Sender<T> {
     /// drop(rx);
     /// assert!(tx.is_disconnected());
     /// ```
-    #[unstable(feature = "mpsc_is_disconnected", issue = "none")]
+    #[unstable(feature = "mpsc_is_disconnected", issue = "153668")]
     pub fn is_disconnected(&self) -> bool {
         self.inner.is_disconnected()
     }
@@ -1080,7 +1080,7 @@ impl<T> Receiver<T> {
     /// drop(tx);
     /// assert!(rx.is_disconnected());
     /// ```
-    #[unstable(feature = "mpsc_is_disconnected", issue = "none")]
+    #[unstable(feature = "mpsc_is_disconnected", issue = "153668")]
     pub fn is_disconnected(&self) -> bool {
         self.inner.is_disconnected()
     }

From ba761e1be29fc6357e4b96e741542430f170a013 Mon Sep 17 00:00:00 2001
From: "Andrew V. Teylu" <andrew.teylu@vector.com>
Date: Mon, 2 Mar 2026 20:28:16 +0000
Subject: [PATCH 17/34] Add hygiene annotations for tokens in macro_rules!
 bodies
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

`-Zunpretty=expanded,hygiene` was not printing syntax context annotations
for identifiers and lifetimes inside `macro_rules!` bodies. These tokens
are printed via `print_tt()` → `token_to_string_ext()`, which converts
tokens to strings without calling `ann_post()`. This meant that
macro-generated `macro_rules!` definitions with hygienic metavar
parameters (e.g. multiple `$marg` distinguished only by hygiene) were
printed with no way to tell them apart.

This was fixed by adding a match on `token.kind` in `print_tt()` to call
`ann_post()` for `Ident`, `NtIdent`, `Lifetime`, and `NtLifetime`
tokens, matching how `print_ident()` and `print_lifetime()` already
handle AST-level identifiers and lifetimes.

Signed-off-by: Andrew V. Teylu <andrew.teylu@vector.com>
---
 compiler/rustc_ast_pretty/src/pprust/state.rs | 17 ++++++
 .../hygiene/unpretty-debug-lifetimes.stdout   |  8 +--
 tests/ui/hygiene/unpretty-debug-metavars.rs   | 25 +++++++++
 .../ui/hygiene/unpretty-debug-metavars.stdout | 52 +++++++++++++++++++
 tests/ui/hygiene/unpretty-debug.stdout        | 10 +++-
 tests/ui/proc-macro/meta-macro-hygiene.stdout |  5 +-
 .../nonterminal-token-hygiene.stdout          | 17 ++++--
 7 files changed, 122 insertions(+), 12 deletions(-)
 create mode 100644 tests/ui/hygiene/unpretty-debug-metavars.rs
 create mode 100644 tests/ui/hygiene/unpretty-debug-metavars.stdout

diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 4ba5dc541342a..be97d4f17dba8 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -737,6 +737,23 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
             TokenTree::Token(token, spacing) => {
                 let token_str = self.token_to_string_ext(token, convert_dollar_crate);
                 self.word(token_str);
+                // Emit hygiene annotations for identity-bearing tokens,
+                // matching how print_ident() and print_lifetime() call ann_post().
+                match token.kind {
+                    token::Ident(name, _) => {
+                        self.ann_post(Ident::new(name, token.span));
+                    }
+                    token::NtIdent(ident, _) => {
+                        self.ann_post(ident);
+                    }
+                    token::Lifetime(name, _) => {
+                        self.ann_post(Ident::new(name, token.span));
+                    }
+                    token::NtLifetime(ident, _) => {
+                        self.ann_post(ident);
+                    }
+                    _ => {}
+                }
                 if let token::DocComment(..) = token.kind {
                     self.hardbreak()
                 }
diff --git a/tests/ui/hygiene/unpretty-debug-lifetimes.stdout b/tests/ui/hygiene/unpretty-debug-lifetimes.stdout
index 28a5c70a02d79..689453326c0b5 100644
--- a/tests/ui/hygiene/unpretty-debug-lifetimes.stdout
+++ b/tests/ui/hygiene/unpretty-debug-lifetimes.stdout
@@ -7,15 +7,17 @@
 // Don't break whenever Symbol numbering changes
 //@ normalize-stdout: "\d+#" -> "0#"
 
-#![feature /* 0#0 */(decl_macro)]
-#![feature /* 0#0 */(no_core)]
+#![feature /* 0#0 */(decl_macro /* 0#0 */)]
+#![feature /* 0#0 */(no_core /* 0#0 */)]
 #![no_core /* 0#0 */]
 
 macro lifetime_hygiene
     /*
     0#0
     */ {
-    ($f:ident<$a:lifetime>) => { fn $f<$a, 'a>() {} }
+    ($f /* 0#0 */:ident /* 0#0 */<$a /* 0#0 */:lifetime /* 0#0 */>)
+    =>
+    { fn /* 0#0 */ $f /* 0#0 */<$a /* 0#0 */, 'a /* 0#0 */>() {} }
 }
 fn f /* 0#0 */<'a /* 0#0 */, 'a /* 0#1 */>() {}
 
diff --git a/tests/ui/hygiene/unpretty-debug-metavars.rs b/tests/ui/hygiene/unpretty-debug-metavars.rs
new file mode 100644
index 0000000000000..a0c47bec3ccf7
--- /dev/null
+++ b/tests/ui/hygiene/unpretty-debug-metavars.rs
@@ -0,0 +1,25 @@
+//@ check-pass
+//@ compile-flags: -Zunpretty=expanded,hygiene
+
+// Regression test: metavar parameters in macro-generated macro_rules!
+// definitions should have hygiene annotations so that textually identical
+// `$marg` bindings are distinguishable by their syntax contexts.
+
+// Don't break whenever Symbol numbering changes
+//@ normalize-stdout: "\d+#" -> "0#"
+
+#![feature(no_core)]
+#![no_core]
+
+macro_rules! make_macro {
+    (@inner $name:ident ($dol:tt) $a:ident) => {
+        macro_rules! $name {
+            ($dol $a : expr, $dol marg : expr) => {}
+        }
+    };
+    ($name:ident) => {
+        make_macro!{@inner $name ($) marg}
+    };
+}
+
+make_macro!(add2);
diff --git a/tests/ui/hygiene/unpretty-debug-metavars.stdout b/tests/ui/hygiene/unpretty-debug-metavars.stdout
new file mode 100644
index 0000000000000..307c5e1b8de97
--- /dev/null
+++ b/tests/ui/hygiene/unpretty-debug-metavars.stdout
@@ -0,0 +1,52 @@
+//@ check-pass
+//@ compile-flags: -Zunpretty=expanded,hygiene
+
+// Regression test: metavar parameters in macro-generated macro_rules!
+// definitions should have hygiene annotations so that textually identical
+// `$marg` bindings are distinguishable by their syntax contexts.
+
+// Don't break whenever Symbol numbering changes
+//@ normalize-stdout: "\d+#" -> "0#"
+
+#![feature /* 0#0 */(no_core /* 0#0 */)]
+#![no_core /* 0#0 */]
+
+macro_rules! make_macro
+    /*
+    0#0
+    */ {
+    (@inner /* 0#0 */ $name /* 0#0 */:ident /* 0#0
+    */($dol /* 0#0 */:tt /* 0#0 */) $a /* 0#0 */:ident /* 0#0 */)
+    =>
+    {
+        macro_rules /* 0#0 */! $name /* 0#0 */
+        {
+            ($dol /* 0#0 */ $a /* 0#0 */ : expr /* 0#0 */, $dol /*
+            0#0 */ marg /* 0#0 */ : expr /* 0#0 */) => {}
+        }
+    }; ($name /* 0#0 */:ident /* 0#0 */) =>
+    {
+        make_macro /* 0#0
+        */!{@inner /* 0#0 */ $name /* 0#0 */($) marg /* 0#0 */}
+    };
+}
+macro_rules! add2
+    /*
+    0#0
+    */ {
+    ($ marg /* 0#1 */ : expr /* 0#2 */, $marg /* 0#2 */ : expr /*
+    0#2 */) => {}
+}
+
+
+/*
+Expansions:
+crate0::{{expn0}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Root
+crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "make_macro")
+crate0::{{expn2}}: parent: crate0::{{expn1}}, call_site_ctxt: #1, def_site_ctxt: #0, kind: Macro(Bang, "make_macro")
+
+SyntaxContexts:
+#0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque)
+#1: parent: #0, outer_mark: (crate0::{{expn1}}, SemiOpaque)
+#2: parent: #0, outer_mark: (crate0::{{expn2}}, SemiOpaque)
+*/
diff --git a/tests/ui/hygiene/unpretty-debug.stdout b/tests/ui/hygiene/unpretty-debug.stdout
index f35bd7a7cb2ca..ac6051e2d542e 100644
--- a/tests/ui/hygiene/unpretty-debug.stdout
+++ b/tests/ui/hygiene/unpretty-debug.stdout
@@ -5,10 +5,16 @@
 //@ normalize-stdout: "\d+#" -> "0#"
 
 // minimal junk
-#![feature /* 0#0 */(no_core)]
+#![feature /* 0#0 */(no_core /* 0#0 */)]
 #![no_core /* 0#0 */]
 
-macro_rules! foo /* 0#0 */ { ($x: ident) => { y + $x } }
+macro_rules! foo
+    /*
+    0#0
+    */ {
+    ($x /* 0#0 */: ident /* 0#0 */) =>
+    { y /* 0#0 */ + $x /* 0#0 */ }
+}
 
 fn bar /* 0#0 */() {
     let x /* 0#0 */ = 1;
diff --git a/tests/ui/proc-macro/meta-macro-hygiene.stdout b/tests/ui/proc-macro/meta-macro-hygiene.stdout
index b5db9922b31a8..a03e567bd48aa 100644
--- a/tests/ui/proc-macro/meta-macro-hygiene.stdout
+++ b/tests/ui/proc-macro/meta-macro-hygiene.stdout
@@ -1,7 +1,7 @@
 Def site: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4)
 Input: TokenStream [Ident { ident: "$crate", span: $DIR/meta-macro-hygiene.rs:26:37: 26:43 (#3) }, Punct { ch: ':', spacing: Joint, span: $DIR/meta-macro-hygiene.rs:26:43: 26:44 (#3) }, Punct { ch: ':', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:26:44: 26:45 (#3) }, Ident { ident: "dummy", span: $DIR/meta-macro-hygiene.rs:26:45: 26:50 (#3) }, Punct { ch: '!', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:26:50: 26:51 (#3) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/meta-macro-hygiene.rs:26:51: 26:53 (#3) }]
 Respanned: TokenStream [Ident { ident: "$crate", span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) }, Punct { ch: ':', spacing: Joint, span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) }, Punct { ch: ':', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) }, Ident { ident: "dummy", span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) }, Punct { ch: '!', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) }]
-#![feature /* 0#0 */(prelude_import)]
+#![feature /* 0#0 */(prelude_import /* 0#0 */)]
 //@ aux-build:make-macro.rs
 //@ proc-macro: meta-macro.rs
 //@ edition:2018
@@ -30,7 +30,8 @@ macro_rules! produce_it
     */ {
     () =>
     {
-        meta_macro::print_def_site!($crate::dummy!());
+        meta_macro /* 0#0 */::print_def_site /* 0#0
+        */!($crate /* 0#0 */::dummy /* 0#0 */!());
         // `print_def_site!` will respan the `$crate` identifier
         // with `Span::def_site()`. This should cause it to resolve
         // relative to `meta_macro`, *not* `make_macro` (despite
diff --git a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout
index e45abab03b4c4..61b55782e6e9d 100644
--- a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout
+++ b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout
@@ -20,7 +20,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
         span: $DIR/nonterminal-token-hygiene.rs:23:27: 23:32 (#4),
     },
 ]
-#![feature /* 0#0 */(prelude_import)]
+#![feature /* 0#0 */(prelude_import /* 0#0 */)]
 #![no_std /* 0#0 */]
 // Make sure that marks from declarative macros are applied to tokens in nonterminal.
 
@@ -34,7 +34,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
 //@ proc-macro: test-macros.rs
 //@ edition: 2015
 
-#![feature /* 0#0 */(decl_macro)]
+#![feature /* 0#0 */(decl_macro /* 0#0 */)]
 #![no_std /* 0#0 */]
 extern crate core /* 0#2 */;
 #[prelude_import /* 0#1 */]
@@ -49,15 +49,22 @@ macro_rules! outer
     /*
     0#0
     */ {
-    ($item:item) =>
+    ($item /* 0#0 */:item /* 0#0 */) =>
     {
-        macro inner() { print_bang! { $item } } inner!();
+        macro /* 0#0 */ inner /* 0#0 */()
+        { print_bang /* 0#0 */! { $item /* 0#0 */ } } inner /* 0#0
+        */!();
 
     };
 }
 
 struct S /* 0#0 */;
-macro inner /* 0#3 */ { () => { print_bang! { struct S; } } }
+macro inner
+    /*
+    0#3
+    */ {
+    () => { print_bang /* 0#3 */! { struct /* 0#0 */ S /* 0#0 */; } }
+}
 
 struct S /* 0#5 */;
 // OK, not a duplicate definition of `S`

From 705608bd0c26d72c1b20820d653d1e70ae666c25 Mon Sep 17 00:00:00 2001
From: "Andrew V. Teylu" <andrew.teylu@vector.com>
Date: Tue, 3 Mar 2026 13:06:55 +0000
Subject: [PATCH 18/34] Add regression tests for token hygiene annotations in
 macro bodies

Add `unpretty-debug-shadow` test covering macro body tokens that
reference a shadowed variable, and simplify the `unpretty-debug-metavars`
test macro.

Signed-off-by: Andrew V. Teylu <andrew.teylu@vector.com>
---
 tests/ui/hygiene/unpretty-debug-metavars.rs   |  7 +++--
 .../ui/hygiene/unpretty-debug-metavars.stdout |  7 +++--
 tests/ui/hygiene/unpretty-debug-shadow.rs     | 20 +++++++++++++
 tests/ui/hygiene/unpretty-debug-shadow.stdout | 30 +++++++++++++++++++
 4 files changed, 58 insertions(+), 6 deletions(-)
 create mode 100644 tests/ui/hygiene/unpretty-debug-shadow.rs
 create mode 100644 tests/ui/hygiene/unpretty-debug-shadow.stdout

diff --git a/tests/ui/hygiene/unpretty-debug-metavars.rs b/tests/ui/hygiene/unpretty-debug-metavars.rs
index a0c47bec3ccf7..41bf75cd0d98b 100644
--- a/tests/ui/hygiene/unpretty-debug-metavars.rs
+++ b/tests/ui/hygiene/unpretty-debug-metavars.rs
@@ -1,9 +1,10 @@
 //@ check-pass
 //@ compile-flags: -Zunpretty=expanded,hygiene
 
-// Regression test: metavar parameters in macro-generated macro_rules!
-// definitions should have hygiene annotations so that textually identical
-// `$marg` bindings are distinguishable by their syntax contexts.
+// Regression test for token hygiene annotations in -Zunpretty=expanded,hygiene
+// Previously, metavar parameters in macro-generated macro_rules! definitions
+// were missing hygiene annotations, making identical `$marg` bindings
+// indistinguishable.
 
 // Don't break whenever Symbol numbering changes
 //@ normalize-stdout: "\d+#" -> "0#"
diff --git a/tests/ui/hygiene/unpretty-debug-metavars.stdout b/tests/ui/hygiene/unpretty-debug-metavars.stdout
index 307c5e1b8de97..89658bc909a13 100644
--- a/tests/ui/hygiene/unpretty-debug-metavars.stdout
+++ b/tests/ui/hygiene/unpretty-debug-metavars.stdout
@@ -1,9 +1,10 @@
 //@ check-pass
 //@ compile-flags: -Zunpretty=expanded,hygiene
 
-// Regression test: metavar parameters in macro-generated macro_rules!
-// definitions should have hygiene annotations so that textually identical
-// `$marg` bindings are distinguishable by their syntax contexts.
+// Regression test for token hygiene annotations in -Zunpretty=expanded,hygiene
+// Previously, metavar parameters in macro-generated macro_rules! definitions
+// were missing hygiene annotations, making identical `$marg` bindings
+// indistinguishable.
 
 // Don't break whenever Symbol numbering changes
 //@ normalize-stdout: "\d+#" -> "0#"
diff --git a/tests/ui/hygiene/unpretty-debug-shadow.rs b/tests/ui/hygiene/unpretty-debug-shadow.rs
new file mode 100644
index 0000000000000..2aa68c8aec110
--- /dev/null
+++ b/tests/ui/hygiene/unpretty-debug-shadow.rs
@@ -0,0 +1,20 @@
+//@ check-pass
+//@ compile-flags: -Zunpretty=expanded,hygiene
+
+// Regression test for token hygiene annotations in -Zunpretty=expanded,hygiene
+// Previously, tokens in macro_rules! bodies were missing hygiene annotations,
+// making it impossible to see how a macro's reference to a shadowed variable
+// is distinguished from the shadowing binding.
+
+// Don't break whenever Symbol numbering changes
+//@ normalize-stdout: "\d+#" -> "0#"
+
+#![feature(no_core)]
+#![no_core]
+
+fn f() {
+    let x = 0;
+    macro_rules! use_x { () => { x }; }
+    let x = 1;
+    use_x!();
+}
diff --git a/tests/ui/hygiene/unpretty-debug-shadow.stdout b/tests/ui/hygiene/unpretty-debug-shadow.stdout
new file mode 100644
index 0000000000000..36076b6a968fe
--- /dev/null
+++ b/tests/ui/hygiene/unpretty-debug-shadow.stdout
@@ -0,0 +1,30 @@
+//@ check-pass
+//@ compile-flags: -Zunpretty=expanded,hygiene
+
+// Regression test for token hygiene annotations in -Zunpretty=expanded,hygiene
+// Previously, tokens in macro_rules! bodies were missing hygiene annotations,
+// making it impossible to see how a macro's reference to a shadowed variable
+// is distinguished from the shadowing binding.
+
+// Don't break whenever Symbol numbering changes
+//@ normalize-stdout: "\d+#" -> "0#"
+
+#![feature /* 0#0 */(no_core /* 0#0 */)]
+#![no_core /* 0#0 */]
+
+fn f /* 0#0 */() {
+    let x /* 0#0 */ = 0;
+    macro_rules! use_x /* 0#0 */ { () => { x /* 0#0 */ }; }
+    let x /* 0#0 */ = 1;
+    x /* 0#1 */;
+}
+
+/*
+Expansions:
+crate0::{{expn0}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Root
+crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "use_x")
+
+SyntaxContexts:
+#0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque)
+#1: parent: #0, outer_mark: (crate0::{{expn1}}, SemiOpaque)
+*/

From 01b1fd07b90d7cf6e7b8001e63174ed92982e0aa Mon Sep 17 00:00:00 2001
From: human9000 <human9000.2021@gmail.com>
Date: Sun, 8 Mar 2026 10:49:21 +0500
Subject: [PATCH 19/34] fix inference variables leaking into HIR const lowering
 logic

---
 .../src/hir_ty_lowering/mod.rs                |  6 ++++++
 .../mgca/infer-vars-in-const-args.rs          | 16 ++++++++++++++
 .../mgca/infer-vars-in-const-args.stderr      | 21 +++++++++++++++++++
 3 files changed, 43 insertions(+)
 create mode 100644 tests/ui/const-generics/mgca/infer-vars-in-const-args.rs
 create mode 100644 tests/ui/const-generics/mgca/infer-vars-in-const-args.stderr

diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index bf97bfb1ebbce..00791ed194c52 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -2874,6 +2874,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         span: Span,
     ) -> Const<'tcx> {
         let tcx = self.tcx();
+
+        if ty.has_infer() {
+            let e = self.dcx().span_err(span, "inference variables are not supported in constants");
+            return ty::Const::new_error(tcx, e);
+        }
+
         if let LitKind::Err(guar) = *kind {
             return ty::Const::new_error(tcx, guar);
         }
diff --git a/tests/ui/const-generics/mgca/infer-vars-in-const-args.rs b/tests/ui/const-generics/mgca/infer-vars-in-const-args.rs
new file mode 100644
index 0000000000000..cbc59d461694f
--- /dev/null
+++ b/tests/ui/const-generics/mgca/infer-vars-in-const-args.rs
@@ -0,0 +1,16 @@
+#![allow(incomplete_features)]
+#![feature(adt_const_params, min_generic_const_args, generic_const_parameter_types)]
+
+fn main() {
+    foo::<_, { 2 }>();
+    //~^ ERROR: inference variables are not supported in constants
+    let _: PC<_, { 42 }> = PC { a: 1, b: 1 };
+    //~^ ERROR: inference variables are not supported in constants
+}
+
+struct PC<T, const N: T> {
+//~^ ERROR: `T` can't be used as a const parameter type [E0741]
+    a: T,
+}
+
+fn foo<const N: usize, const A: [u8; N]>() {}
diff --git a/tests/ui/const-generics/mgca/infer-vars-in-const-args.stderr b/tests/ui/const-generics/mgca/infer-vars-in-const-args.stderr
new file mode 100644
index 0000000000000..0f64582c1cef6
--- /dev/null
+++ b/tests/ui/const-generics/mgca/infer-vars-in-const-args.stderr
@@ -0,0 +1,21 @@
+error[E0741]: `T` can't be used as a const parameter type
+  --> $DIR/infer-vars-in-const-args.rs:11:23
+   |
+LL | struct PC<T, const N: T> {
+   |                       ^
+
+error: inference variables are not supported in constants
+  --> $DIR/infer-vars-in-const-args.rs:5:16
+   |
+LL |     foo::<_, { 2 }>();
+   |                ^
+
+error: inference variables are not supported in constants
+  --> $DIR/infer-vars-in-const-args.rs:7:20
+   |
+LL |     let _: PC<_, { 42 }> = PC { a: 1, b: 1 };
+   |                    ^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0741`.

From 5f8e24e1566862c9ee52e055c7c5517668922ba9 Mon Sep 17 00:00:00 2001
From: human9000 <human9000.2021@gmail.com>
Date: Tue, 17 Mar 2026 09:36:08 +0500
Subject: [PATCH 20/34] Improve `ty::Infer` handling during const literal
 lowering

Co-authored-by: BoxyUwU <rust@boxyuwu.dev>
---
 .../src/hir_ty_lowering/mod.rs                | 15 +++++++------
 compiler/rustc_middle/src/ty/consts/lit.rs    |  5 ++++-
 .../src/builder/expr/as_constant.rs           |  5 ++++-
 compiler/rustc_mir_build/src/thir/constant.rs | 22 ++++++++++---------
 .../rustc_mir_build/src/thir/pattern/mod.rs   |  2 +-
 compiler/rustc_ty_utils/src/consts.rs         |  3 ++-
 ...> infer-vars-in-const-args-conflicting.rs} |  9 ++++++--
 ...fer-vars-in-const-args-conflicting.stderr} | 10 ++++-----
 .../mgca/infer-vars-in-const-args-correct.rs  | 22 +++++++++++++++++++
 9 files changed, 65 insertions(+), 28 deletions(-)
 rename tests/ui/const-generics/mgca/{infer-vars-in-const-args.rs => infer-vars-in-const-args-conflicting.rs} (52%)
 rename tests/ui/const-generics/mgca/{infer-vars-in-const-args.stderr => infer-vars-in-const-args-conflicting.stderr} (58%)
 create mode 100644 tests/ui/const-generics/mgca/infer-vars-in-const-args-correct.rs

diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 00791ed194c52..9396bf6352c59 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -2875,10 +2875,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     ) -> Const<'tcx> {
         let tcx = self.tcx();
 
-        if ty.has_infer() {
-            let e = self.dcx().span_err(span, "inference variables are not supported in constants");
-            return ty::Const::new_error(tcx, e);
-        }
+        let ty = if !ty.has_infer() { Some(ty) } else { None };
 
         if let LitKind::Err(guar) = *kind {
             return ty::Const::new_error(tcx, guar);
@@ -2911,16 +2908,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         };
 
         let lit_input = match expr.kind {
-            hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: lit.node, ty, neg: false }),
+            hir::ExprKind::Lit(lit) => {
+                Some(LitToConstInput { lit: lit.node, ty: Some(ty), neg: false })
+            }
             hir::ExprKind::Unary(hir::UnOp::Neg, expr) => match expr.kind {
-                hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: lit.node, ty, neg: true }),
+                hir::ExprKind::Lit(lit) => {
+                    Some(LitToConstInput { lit: lit.node, ty: Some(ty), neg: true })
+                }
                 _ => None,
             },
             _ => None,
         };
 
         lit_input.and_then(|l| {
-            if const_lit_matches_ty(tcx, &l.lit, l.ty, l.neg) {
+            if const_lit_matches_ty(tcx, &l.lit, ty, l.neg) {
                 tcx.at(expr.span)
                     .lit_to_const(l)
                     .map(|value| ty::Const::new_value(tcx, value.valtree, value.ty))
diff --git a/compiler/rustc_middle/src/ty/consts/lit.rs b/compiler/rustc_middle/src/ty/consts/lit.rs
index be6dfb20e0433..7be225a9e9215 100644
--- a/compiler/rustc_middle/src/ty/consts/lit.rs
+++ b/compiler/rustc_middle/src/ty/consts/lit.rs
@@ -10,7 +10,10 @@ pub struct LitToConstInput<'tcx> {
     /// The absolute value of the resultant constant.
     pub lit: LitKind,
     /// The type of the constant.
-    pub ty: Ty<'tcx>,
+    ///
+    /// `None` is used by const generics when the type of the constant is unknown, e.g.
+    /// if there are inference variables
+    pub ty: Option<Ty<'tcx>>,
     /// If the constant is negative.
     pub neg: bool,
 }
diff --git a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs
index ad6c1f7dce5b8..c67d99a8eb7de 100644
--- a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs
@@ -50,7 +50,8 @@ pub(crate) fn as_constant_inner<'tcx>(
 
     match *kind {
         ExprKind::Literal { lit, neg } => {
-            let const_ = lit_to_mir_constant(tcx, LitToConstInput { lit: lit.node, ty, neg });
+            let const_ =
+                lit_to_mir_constant(tcx, LitToConstInput { lit: lit.node, ty: Some(ty), neg });
 
             ConstOperand { span, user_ty: None, const_ }
         }
@@ -109,6 +110,8 @@ pub(crate) fn as_constant_inner<'tcx>(
 fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx>) -> Const<'tcx> {
     let LitToConstInput { lit, ty, neg } = lit_input;
 
+    let ty = ty.expect("type of literal must be known at this point");
+
     if let Err(guar) = ty.error_reported() {
         return Const::Ty(Ty::new_error(tcx, guar), ty::Const::new_error(tcx, guar));
     }
diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs
index b4eedb15033c8..019af24613541 100644
--- a/compiler/rustc_mir_build/src/thir/constant.rs
+++ b/compiler/rustc_mir_build/src/thir/constant.rs
@@ -31,25 +31,27 @@ pub(crate) fn lit_to_const<'tcx>(
             .unwrap_or_else(|| bug!("expected to create ScalarInt from uint {:?}", result))
     };
 
-    let (valtree, valtree_ty) = match (lit, expected_ty.kind()) {
+    let (valtree, valtree_ty) = match (lit, expected_ty.map(|ty| ty.kind())) {
         (ast::LitKind::Str(s, _), _) => {
             let str_bytes = s.as_str().as_bytes();
             let valtree_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, tcx.types.str_);
             (ty::ValTree::from_raw_bytes(tcx, str_bytes), valtree_ty)
         }
-        (ast::LitKind::ByteStr(byte_sym, _), ty::Ref(_, inner_ty, _))
+        (ast::LitKind::ByteStr(byte_sym, _), Some(ty::Ref(_, inner_ty, _)))
             if let ty::Slice(ty) | ty::Array(ty, _) = inner_ty.kind()
                 && let ty::Uint(UintTy::U8) = ty.kind() =>
         {
-            (ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty)
+            (ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty.unwrap())
         }
-        (ast::LitKind::ByteStr(byte_sym, _), ty::Slice(inner_ty) | ty::Array(inner_ty, _))
-            if tcx.features().deref_patterns()
-                && let ty::Uint(UintTy::U8) = inner_ty.kind() =>
+        (
+            ast::LitKind::ByteStr(byte_sym, _),
+            Some(ty::Slice(inner_ty) | ty::Array(inner_ty, _)),
+        ) if tcx.features().deref_patterns()
+            && let ty::Uint(UintTy::U8) = inner_ty.kind() =>
         {
             // Byte string literal patterns may have type `[u8]` or `[u8; N]` if `deref_patterns` is
             // enabled, in order to allow, e.g., `deref!(b"..."): Vec<u8>`.
-            (ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty)
+            (ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty.unwrap())
         }
         (ast::LitKind::ByteStr(byte_sym, _), _) => {
             let valtree = ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str());
@@ -79,11 +81,11 @@ pub(crate) fn lit_to_const<'tcx>(
                 trunc(if neg { u128::wrapping_neg(n.get()) } else { n.get() }, i.to_unsigned());
             (ty::ValTree::from_scalar_int(tcx, scalar_int), Ty::new_int(tcx, i))
         }
-        (ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), ty::Uint(ui)) if !neg => {
+        (ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), Some(ty::Uint(ui))) if !neg => {
             let scalar_int = trunc(n.get(), *ui);
             (ty::ValTree::from_scalar_int(tcx, scalar_int), Ty::new_uint(tcx, *ui))
         }
-        (ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), ty::Int(i)) => {
+        (ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), Some(ty::Int(i))) => {
             // Unsigned "negation" has the same bitwise effect as signed negation,
             // which gets the result we want without additional casts.
             let scalar_int =
@@ -101,7 +103,7 @@ pub(crate) fn lit_to_const<'tcx>(
             let bits = parse_float_into_scalar(n, fty, neg)?;
             (ty::ValTree::from_scalar_int(tcx, bits), Ty::new_float(tcx, fty))
         }
-        (ast::LitKind::Float(n, ast::LitFloatType::Unsuffixed), ty::Float(fty)) => {
+        (ast::LitKind::Float(n, ast::LitFloatType::Unsuffixed), Some(ty::Float(fty))) => {
             let bits = parse_float_into_scalar(n, *fty, neg)?;
             (ty::ValTree::from_scalar_int(tcx, bits), Ty::new_float(tcx, *fty))
         }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 67cde0e2c8866..fec2fb9ca5719 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -696,7 +696,7 @@ impl<'tcx> PatCtxt<'tcx> {
                 // patterns to `str`, and byte-string literal patterns to `[u8; N]` or `[u8]`.
 
                 let pat_ty = self.typeck_results.node_type(pat.hir_id);
-                let lit_input = LitToConstInput { lit: lit.node, ty: pat_ty, neg: *negated };
+                let lit_input = LitToConstInput { lit: lit.node, ty: Some(pat_ty), neg: *negated };
                 let constant = const_lit_matches_ty(self.tcx, &lit.node, pat_ty, *negated)
                     .then(|| self.tcx.at(expr.span).lit_to_const(lit_input))
                     .flatten()
diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs
index 1d444079f8968..49e0bdde37870 100644
--- a/compiler/rustc_ty_utils/src/consts.rs
+++ b/compiler/rustc_ty_utils/src/consts.rs
@@ -58,7 +58,8 @@ fn recurse_build<'tcx>(
         }
         &ExprKind::Literal { lit, neg } => {
             let sp = node.span;
-            match tcx.at(sp).lit_to_const(LitToConstInput { lit: lit.node, ty: node.ty, neg }) {
+            match tcx.at(sp).lit_to_const(LitToConstInput { lit: lit.node, ty: Some(node.ty), neg })
+            {
                 Some(value) => ty::Const::new_value(tcx, value.valtree, value.ty),
                 None => ty::Const::new_misc_error(tcx),
             }
diff --git a/tests/ui/const-generics/mgca/infer-vars-in-const-args.rs b/tests/ui/const-generics/mgca/infer-vars-in-const-args-conflicting.rs
similarity index 52%
rename from tests/ui/const-generics/mgca/infer-vars-in-const-args.rs
rename to tests/ui/const-generics/mgca/infer-vars-in-const-args-conflicting.rs
index cbc59d461694f..eeb76683eedf1 100644
--- a/tests/ui/const-generics/mgca/infer-vars-in-const-args.rs
+++ b/tests/ui/const-generics/mgca/infer-vars-in-const-args-conflicting.rs
@@ -1,11 +1,16 @@
+//! This test ensures compilation failure when trying to pass literals
+//! without explicitly stated type as inference variables in generic arguments.
+//!
+//! See https://github.com/rust-lang/rust/pull/153557
+
 #![allow(incomplete_features)]
 #![feature(adt_const_params, min_generic_const_args, generic_const_parameter_types)]
 
 fn main() {
     foo::<_, { 2 }>();
-    //~^ ERROR: inference variables are not supported in constants
+    //~^ ERROR: type annotations needed for the literal
     let _: PC<_, { 42 }> = PC { a: 1, b: 1 };
-    //~^ ERROR: inference variables are not supported in constants
+    //~^ ERROR: type annotations needed for the literal
 }
 
 struct PC<T, const N: T> {
diff --git a/tests/ui/const-generics/mgca/infer-vars-in-const-args.stderr b/tests/ui/const-generics/mgca/infer-vars-in-const-args-conflicting.stderr
similarity index 58%
rename from tests/ui/const-generics/mgca/infer-vars-in-const-args.stderr
rename to tests/ui/const-generics/mgca/infer-vars-in-const-args-conflicting.stderr
index 0f64582c1cef6..a4b13f41aef07 100644
--- a/tests/ui/const-generics/mgca/infer-vars-in-const-args.stderr
+++ b/tests/ui/const-generics/mgca/infer-vars-in-const-args-conflicting.stderr
@@ -1,17 +1,17 @@
 error[E0741]: `T` can't be used as a const parameter type
-  --> $DIR/infer-vars-in-const-args.rs:11:23
+  --> $DIR/infer-vars-in-const-args-conflicting.rs:16:23
    |
 LL | struct PC<T, const N: T> {
    |                       ^
 
-error: inference variables are not supported in constants
-  --> $DIR/infer-vars-in-const-args.rs:5:16
+error: type annotations needed for the literal
+  --> $DIR/infer-vars-in-const-args-conflicting.rs:10:16
    |
 LL |     foo::<_, { 2 }>();
    |                ^
 
-error: inference variables are not supported in constants
-  --> $DIR/infer-vars-in-const-args.rs:7:20
+error: type annotations needed for the literal
+  --> $DIR/infer-vars-in-const-args-conflicting.rs:12:20
    |
 LL |     let _: PC<_, { 42 }> = PC { a: 1, b: 1 };
    |                    ^^
diff --git a/tests/ui/const-generics/mgca/infer-vars-in-const-args-correct.rs b/tests/ui/const-generics/mgca/infer-vars-in-const-args-correct.rs
new file mode 100644
index 0000000000000..f1c0e0b2b4c30
--- /dev/null
+++ b/tests/ui/const-generics/mgca/infer-vars-in-const-args-correct.rs
@@ -0,0 +1,22 @@
+//! This test ensures no errors are emitted when lowering literals with
+//! explicitly stated types and inference variables in the type of the const
+//! generic parameter.
+//!
+//! See https://github.com/rust-lang/rust/pull/153557
+
+//@check-pass
+
+#![allow(incomplete_features)]
+#![feature(adt_const_params,
+    min_generic_const_args,
+    generic_const_parameter_types,
+    unsized_const_params
+)]
+
+use std::marker::ConstParamTy_;
+
+fn main() {
+    foo::<_, 2_i32>();
+}
+
+fn foo<T: ConstParamTy_, const N: T>() {}

From 32fbf98c6b550d0703166ffb360f10588dc65c87 Mon Sep 17 00:00:00 2001
From: Daniel Scherzer <daniel.e.scherzer@gmail.com>
Date: Thu, 12 Mar 2026 19:55:48 -0700
Subject: [PATCH 21/34] Derive Macro Eq: link to more detailed documentation

Match the other derive macros in the module (Ord, PartialEq, PartialOrd) by
linking to the section in the trait documentation about how the derive macro
works.
---
 library/core/src/cmp.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index b3dc435dda176..49d7487c2803b 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -357,6 +357,7 @@ pub const trait Eq: [const] PartialEq<Self> + PointeeSized {
 }
 
 /// Derive macro generating an impl of the trait [`Eq`].
+/// The behavior of this macro is described in detail [here](Eq#derivable).
 #[rustc_builtin_macro]
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
 #[allow_internal_unstable(core_intrinsics, derive_eq_internals, structural_match)]

From e0cd9c85ddfc2a954385fb866eeb4807872e1d05 Mon Sep 17 00:00:00 2001
From: Yuki Okushi <huyuumi.dev@gmail.com>
Date: Sun, 15 Mar 2026 20:29:39 +0900
Subject: [PATCH 22/34] Fix invalid suggestion on `for-loops-over-fallibles`

---
 .../src/for_loops_over_fallibles.rs           |  2 ++
 .../macro-iterator-next.rs                    | 21 ++++++++++++++++
 .../macro-iterator-next.stderr                | 24 +++++++++++++++++++
 3 files changed, 47 insertions(+)
 create mode 100644 tests/ui/lint/for-loops-over-falibles/macro-iterator-next.rs
 create mode 100644 tests/ui/lint/for-loops-over-falibles/macro-iterator-next.stderr

diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
index fe95a682c6376..24220e035b1dd 100644
--- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs
+++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
@@ -77,6 +77,8 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles {
         };
 
         let sub = if let Some(recv) = extract_iterator_next_call(cx, arg)
+            && recv.span.can_be_used_for_suggestions()
+            && recv.span.between(arg_span.shrink_to_hi()).can_be_used_for_suggestions()
             && let Ok(recv_snip) = cx.sess().source_map().span_to_snippet(recv.span)
         {
             ForLoopsOverFalliblesLoopSub::RemoveNext {
diff --git a/tests/ui/lint/for-loops-over-falibles/macro-iterator-next.rs b/tests/ui/lint/for-loops-over-falibles/macro-iterator-next.rs
new file mode 100644
index 0000000000000..0fe88734099c7
--- /dev/null
+++ b/tests/ui/lint/for-loops-over-falibles/macro-iterator-next.rs
@@ -0,0 +1,21 @@
+// This test ensures that the `for-loops-over-fallibles` lint doesn't suggest
+// removing `next`.
+// ref. <https://github.com/rust-lang/rust-clippy/issues/16133>
+
+#![forbid(for_loops_over_fallibles)]
+//~^ NOTE: the lint level is defined here
+
+fn main() {
+    macro_rules! mac {
+        (next $e:expr) => {
+            $e.iter().next()
+        };
+    }
+
+    for _ in mac!(next [1, 2]) {}
+    //~^ ERROR: for loop over an `Option`. This is more readably written as an `if let` statement
+    //~| NOTE: in this expansion of desugaring of `for` loop
+    //~| NOTE: in this expansion of desugaring of `for` loop
+    //~| HELP: to check pattern in a loop use `while let`
+    //~| HELP: consider using `if let` to clear intent
+}
diff --git a/tests/ui/lint/for-loops-over-falibles/macro-iterator-next.stderr b/tests/ui/lint/for-loops-over-falibles/macro-iterator-next.stderr
new file mode 100644
index 0000000000000..36848fffa4394
--- /dev/null
+++ b/tests/ui/lint/for-loops-over-falibles/macro-iterator-next.stderr
@@ -0,0 +1,24 @@
+error: for loop over an `Option`. This is more readably written as an `if let` statement
+  --> $DIR/macro-iterator-next.rs:15:14
+   |
+LL |     for _ in mac!(next [1, 2]) {}
+   |              ^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/macro-iterator-next.rs:5:11
+   |
+LL | #![forbid(for_loops_over_fallibles)]
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^
+help: to check pattern in a loop use `while let`
+   |
+LL -     for _ in mac!(next [1, 2]) {}
+LL +     while let Some(_) = mac!(next [1, 2]) {}
+   |
+help: consider using `if let` to clear intent
+   |
+LL -     for _ in mac!(next [1, 2]) {}
+LL +     if let Some(_) = mac!(next [1, 2]) {}
+   |
+
+error: aborting due to 1 previous error
+

From 0fa347e086a756929004f423671d0c5edef52774 Mon Sep 17 00:00:00 2001
From: Yuki Okushi <huyuumi.dev@gmail.com>
Date: Sun, 15 Mar 2026 20:34:25 +0900
Subject: [PATCH 23/34] Do not lint `for-loops-over-fallibles` on external
 macros

---
 .../rustc_lint/src/for_loops_over_fallibles.rs     |  5 +++++
 tests/crashes/147973.rs                            | 14 --------------
 .../auxiliary/external-macro-issue-148114.rs       | 13 +++++++++++++
 .../external-macro-issue-148114.rs                 | 14 ++++++++++++++
 4 files changed, 32 insertions(+), 14 deletions(-)
 delete mode 100644 tests/crashes/147973.rs
 create mode 100644 tests/ui/lint/for-loops-over-falibles/auxiliary/external-macro-issue-148114.rs
 create mode 100644 tests/ui/lint/for-loops-over-falibles/external-macro-issue-148114.rs

diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
index 24220e035b1dd..a7c5943c250b8 100644
--- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs
+++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
@@ -49,6 +49,11 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         let Some((pat, arg)) = extract_for_loop(expr) else { return };
 
+        // Do not put suggestions for external macros.
+        if pat.span.from_expansion() {
+            return;
+        }
+
         let arg_span = arg.span.source_callsite();
 
         let ty = cx.typeck_results().expr_ty(arg);
diff --git a/tests/crashes/147973.rs b/tests/crashes/147973.rs
deleted file mode 100644
index 7271c54846f15..0000000000000
--- a/tests/crashes/147973.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-// This is part of series of regression tests for some diagnostics ICEs encountered in the wild with
-// suggestions having overlapping parts under https://github.com/rust-lang/rust/pull/146121.
-// This is one MCVE from the beta crater run regressions from issue 147973.
-
-//@ needs-rustc-debug-assertions
-//@ known-bug: #147973
-
-//@ aux-build: overlapping_spans_helper.rs
-extern crate overlapping_spans_helper;
-
-fn main() {
-    let _name = Some(1);
-    overlapping_spans_helper::do_loop!(_name);
-}
diff --git a/tests/ui/lint/for-loops-over-falibles/auxiliary/external-macro-issue-148114.rs b/tests/ui/lint/for-loops-over-falibles/auxiliary/external-macro-issue-148114.rs
new file mode 100644
index 0000000000000..68eff33cb3f10
--- /dev/null
+++ b/tests/ui/lint/for-loops-over-falibles/auxiliary/external-macro-issue-148114.rs
@@ -0,0 +1,13 @@
+#[macro_export]
+macro_rules! identity {
+    ($x:ident) => {
+        $x
+    };
+}
+
+#[macro_export]
+macro_rules! do_loop {
+    ($x:ident) => {
+        for $crate::identity!($x) in $x {}
+    };
+}
diff --git a/tests/ui/lint/for-loops-over-falibles/external-macro-issue-148114.rs b/tests/ui/lint/for-loops-over-falibles/external-macro-issue-148114.rs
new file mode 100644
index 0000000000000..ca3ac3b9a8647
--- /dev/null
+++ b/tests/ui/lint/for-loops-over-falibles/external-macro-issue-148114.rs
@@ -0,0 +1,14 @@
+//@ check-pass
+//@ aux-build:external-macro-issue-148114.rs
+
+// This test ensures we do not trigger the lint on external macros
+// ref. <https://github.com/rust-lang/rust/issues/148114>
+
+#![deny(for_loops_over_fallibles)]
+
+extern crate external_macro_issue_148114 as dep;
+
+fn main() {
+    let _name = Some(1);
+    dep::do_loop!(_name);
+}

From eae2ad8c6c3988bdb192db8a46bda8955d407c61 Mon Sep 17 00:00:00 2001
From: Yuki Okushi <huyuumi.dev@gmail.com>
Date: Sun, 15 Mar 2026 20:35:16 +0900
Subject: [PATCH 24/34] Correct dir name

---
 .../auxiliary/external-macro-issue-148114.rs                      | 0
 .../external-macro-issue-148114.rs                                | 0
 .../macro-issue-140747.rs                                         | 0
 .../macro-issue-140747.stderr                                     | 0
 .../macro-iterator-next.rs                                        | 0
 .../macro-iterator-next.stderr                                    | 0
 6 files changed, 0 insertions(+), 0 deletions(-)
 rename tests/ui/lint/{for-loops-over-falibles => for-loops-over-fallibles}/auxiliary/external-macro-issue-148114.rs (100%)
 rename tests/ui/lint/{for-loops-over-falibles => for-loops-over-fallibles}/external-macro-issue-148114.rs (100%)
 rename tests/ui/lint/{for-loops-over-falibles => for-loops-over-fallibles}/macro-issue-140747.rs (100%)
 rename tests/ui/lint/{for-loops-over-falibles => for-loops-over-fallibles}/macro-issue-140747.stderr (100%)
 rename tests/ui/lint/{for-loops-over-falibles => for-loops-over-fallibles}/macro-iterator-next.rs (100%)
 rename tests/ui/lint/{for-loops-over-falibles => for-loops-over-fallibles}/macro-iterator-next.stderr (100%)

diff --git a/tests/ui/lint/for-loops-over-falibles/auxiliary/external-macro-issue-148114.rs b/tests/ui/lint/for-loops-over-fallibles/auxiliary/external-macro-issue-148114.rs
similarity index 100%
rename from tests/ui/lint/for-loops-over-falibles/auxiliary/external-macro-issue-148114.rs
rename to tests/ui/lint/for-loops-over-fallibles/auxiliary/external-macro-issue-148114.rs
diff --git a/tests/ui/lint/for-loops-over-falibles/external-macro-issue-148114.rs b/tests/ui/lint/for-loops-over-fallibles/external-macro-issue-148114.rs
similarity index 100%
rename from tests/ui/lint/for-loops-over-falibles/external-macro-issue-148114.rs
rename to tests/ui/lint/for-loops-over-fallibles/external-macro-issue-148114.rs
diff --git a/tests/ui/lint/for-loops-over-falibles/macro-issue-140747.rs b/tests/ui/lint/for-loops-over-fallibles/macro-issue-140747.rs
similarity index 100%
rename from tests/ui/lint/for-loops-over-falibles/macro-issue-140747.rs
rename to tests/ui/lint/for-loops-over-fallibles/macro-issue-140747.rs
diff --git a/tests/ui/lint/for-loops-over-falibles/macro-issue-140747.stderr b/tests/ui/lint/for-loops-over-fallibles/macro-issue-140747.stderr
similarity index 100%
rename from tests/ui/lint/for-loops-over-falibles/macro-issue-140747.stderr
rename to tests/ui/lint/for-loops-over-fallibles/macro-issue-140747.stderr
diff --git a/tests/ui/lint/for-loops-over-falibles/macro-iterator-next.rs b/tests/ui/lint/for-loops-over-fallibles/macro-iterator-next.rs
similarity index 100%
rename from tests/ui/lint/for-loops-over-falibles/macro-iterator-next.rs
rename to tests/ui/lint/for-loops-over-fallibles/macro-iterator-next.rs
diff --git a/tests/ui/lint/for-loops-over-falibles/macro-iterator-next.stderr b/tests/ui/lint/for-loops-over-fallibles/macro-iterator-next.stderr
similarity index 100%
rename from tests/ui/lint/for-loops-over-falibles/macro-iterator-next.stderr
rename to tests/ui/lint/for-loops-over-fallibles/macro-iterator-next.stderr

From e54c3e15308538f3b0c250e2e4ac70b1781af644 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Mon, 16 Mar 2026 22:38:16 +0000
Subject: [PATCH 25/34] Point at return type when it is the source of the type
 expectation

When calling an fn that returns a return type as a returned expression, point at the return type to explain that it affects the expected type.

```
error[E0308]: mismatched types
    --> f56.rs:5:15
     |
   3 | fn main() {
     |          - the call expression's return type is influenced by this return type
   4 |     let a = 0;
   5 |     ptr::read(&a)
     |     --------- ^^ expected `*const ()`, found `&{integer}`
     |     |
     |     arguments to this function are incorrect
     |
     = note: expected raw pointer `*const ()`
                  found reference `&{integer}`
note: function defined here
    --> library/core/src/ptr/mod.rs:1681:21
     |
1681 | pub const unsafe fn read<T>(src: *const T) -> T {
     |                     ^^^^
```
---
 .../rustc_hir_typeck/src/fn_ctxt/checks.rs    | 41 ++++++++++++++++++-
 .../expectation-from-return-type.rs           | 21 ++++++++++
 .../expectation-from-return-type.stderr       | 35 ++++++++++++++++
 ...ransforming-option-ref-issue-127545.stderr |  6 +++
 ...call-return-type-due-to-generic-arg.stderr |  3 ++
 5 files changed, 105 insertions(+), 1 deletion(-)
 create mode 100644 tests/ui/mismatched_types/expectation-from-return-type.rs
 create mode 100644 tests/ui/mismatched_types/expectation-from-return-type.stderr

diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 166c1b79576c0..0471fd965cd82 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -11,7 +11,7 @@ use rustc_hir::attrs::DivergingBlockBehavior;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
-use rustc_hir::{Expr, ExprKind, HirId, LangItem, Node, QPath, is_range_literal};
+use rustc_hir::{Expr, ExprKind, FnRetTy, HirId, LangItem, Node, QPath, is_range_literal};
 use rustc_hir_analysis::check::potentially_plural_count;
 use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, PermitVariants};
 use rustc_index::IndexVec;
@@ -1582,6 +1582,45 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
             }
             err.span_note(spans, format!("{} defined here", self.tcx.def_descr(def_id)));
+            if let DefKind::Fn | DefKind::AssocFn = self.tcx.def_kind(def_id)
+                && let ty::Param(_) =
+                    self.tcx.fn_sig(def_id).instantiate_identity().skip_binder().output().kind()
+                && let parent = self.tcx.hir_get_parent_item(call_expr.hir_id).def_id
+                && let Some((output, body_id)) = match self.tcx.hir_node_by_def_id(parent) {
+                    hir::Node::Item(hir::Item {
+                        kind: hir::ItemKind::Fn { sig, body, .. },
+                        ..
+                    })
+                    | hir::Node::TraitItem(hir::TraitItem {
+                        kind: hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body)),
+                        ..
+                    })
+                    | hir::Node::ImplItem(hir::ImplItem {
+                        kind: hir::ImplItemKind::Fn(sig, body),
+                        ..
+                    }) => Some((sig.decl.output, body)),
+                    _ => None,
+                }
+                && let expr = self.tcx.hir_body(*body_id).value
+                && (expr.peel_blocks().span == call_expr.span
+                    || matches!(
+                        self.tcx.parent_hir_node(call_expr.hir_id),
+                        hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. })
+                    ))
+            {
+                err.span_label(
+                    output.span(),
+                    match output {
+                        FnRetTy::DefaultReturn(_) => format!(
+                            "this implicit `()` return type influences the call expression's return type"
+                        ),
+                        FnRetTy::Return(_) => {
+                            "this return type influences the call expression's return type"
+                                .to_string()
+                        }
+                    },
+                );
+            }
         } else if let Some(hir::Node::Expr(e)) = self.tcx.hir_get_if_local(def_id)
             && let hir::ExprKind::Closure(hir::Closure { body, .. }) = &e.kind
         {
diff --git a/tests/ui/mismatched_types/expectation-from-return-type.rs b/tests/ui/mismatched_types/expectation-from-return-type.rs
new file mode 100644
index 0000000000000..ffe3d929984df
--- /dev/null
+++ b/tests/ui/mismatched_types/expectation-from-return-type.rs
@@ -0,0 +1,21 @@
+use std::ptr;
+
+fn main() { //~ NOTE: this implicit `()` return type influences the call expression's return type
+    let a = 0;
+    ptr::read(&a)
+    //~^ ERROR: mismatched types
+    //~| NOTE: expected `*const ()`, found `&{integer}`
+    //~| NOTE: arguments to this function are incorrect
+    //~| NOTE: expected raw pointer
+    //~| NOTE: function defined here
+}
+
+fn foo() { //~ NOTE: this implicit `()` return type influences the call expression's return type
+    let a = 0;
+    return ptr::read(&a);
+    //~^ ERROR: mismatched types
+    //~| NOTE: expected `*const ()`, found `&{integer}`
+    //~| NOTE: arguments to this function are incorrect
+    //~| NOTE: expected raw pointer
+    //~| NOTE: function defined here
+}
diff --git a/tests/ui/mismatched_types/expectation-from-return-type.stderr b/tests/ui/mismatched_types/expectation-from-return-type.stderr
new file mode 100644
index 0000000000000..3bd7a21f987fc
--- /dev/null
+++ b/tests/ui/mismatched_types/expectation-from-return-type.stderr
@@ -0,0 +1,35 @@
+error[E0308]: mismatched types
+  --> $DIR/expectation-from-return-type.rs:5:15
+   |
+LL | fn main() {
+   |          - this implicit `()` return type influences the call expression's return type
+LL |     let a = 0;
+LL |     ptr::read(&a)
+   |     --------- ^^ expected `*const ()`, found `&{integer}`
+   |     |
+   |     arguments to this function are incorrect
+   |
+   = note: expected raw pointer `*const ()`
+                found reference `&{integer}`
+note: function defined here
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+
+error[E0308]: mismatched types
+  --> $DIR/expectation-from-return-type.rs:15:22
+   |
+LL | fn foo() {
+   |         - this implicit `()` return type influences the call expression's return type
+LL |     let a = 0;
+LL |     return ptr::read(&a);
+   |            --------- ^^ expected `*const ()`, found `&{integer}`
+   |            |
+   |            arguments to this function are incorrect
+   |
+   = note: expected raw pointer `*const ()`
+                found reference `&{integer}`
+note: function defined here
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr
index 9a18798db2139..6243a9a729a2f 100644
--- a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr
+++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr
@@ -16,6 +16,8 @@ LL |     arg.map(|v| &**v)
 error[E0308]: mismatched types
   --> $DIR/transforming-option-ref-issue-127545.rs:9:19
    |
+LL | pub fn bar(arg: Option<&Vec<i32>>) -> &[i32] {
+   |                                       ------ this return type influences the call expression's return type
 LL |     arg.unwrap_or(&[])
    |         --------- ^^^ expected `&Vec<i32>`, found `&[_; 0]`
    |         |
@@ -41,6 +43,8 @@ LL +     arg.map_or(&[], |v| v)
 error[E0308]: mismatched types
   --> $DIR/transforming-option-ref-issue-127545.rs:13:19
    |
+LL | pub fn barzz<'a>(arg: Option<&'a Vec<i32>>, v: &'a [i32]) -> &'a [i32] {
+   |                                                              --------- this return type influences the call expression's return type
 LL |     arg.unwrap_or(v)
    |         --------- ^ expected `&Vec<i32>`, found `&[i32]`
    |         |
@@ -66,6 +70,8 @@ LL +     arg.map_or(v, |v| v)
 error[E0308]: mismatched types
   --> $DIR/transforming-option-ref-issue-127545.rs:17:19
    |
+LL | pub fn convert_result(arg: Result<&Vec<i32>, ()>) -> &[i32] {
+   |                                                      ------ this return type influences the call expression's return type
 LL |     arg.unwrap_or(&[])
    |         --------- ^^^ expected `&Vec<i32>`, found `&[_; 0]`
    |         |
diff --git a/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr b/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr
index 53920bc9e02ec..fd07d5b09aeb0 100644
--- a/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr
+++ b/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr
@@ -112,6 +112,9 @@ LL +     let x: u16 = (S {}).method(0u16);
 error[E0308]: arguments to this function are incorrect
   --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:27:5
    |
+LL | fn main() {
+   |          - this implicit `()` return type influences the call expression's return type
+...
 LL |     function(0u32, 8u8)
    |     ^^^^^^^^ ----  --- expected `bool`, found `u8`
    |              |

From 3795c3b51c3081cdf90e305ddb6962ba20b681a6 Mon Sep 17 00:00:00 2001
From: Redddy <rust@redddy.com>
Date: Tue, 17 Mar 2026 06:30:04 +0000
Subject: [PATCH 26/34] mGCA: Lower const generic args to infer when needed

---
 compiler/rustc_ast_lowering/src/lib.rs        | 10 +++--
 .../const-generics/mgca/braced-const-infer.rs |  9 ++++
 .../mgca/braced-const-infer.stderr            |  9 ++++
 .../mgca/macro-const-arg-infer.rs             | 20 +++++++++
 .../mgca/macro-const-arg-infer.stderr         | 44 +++++++++++++++++++
 5 files changed, 89 insertions(+), 3 deletions(-)
 create mode 100644 tests/ui/const-generics/mgca/braced-const-infer.rs
 create mode 100644 tests/ui/const-generics/mgca/braced-const-infer.stderr
 create mode 100644 tests/ui/const-generics/mgca/macro-const-arg-infer.rs
 create mode 100644 tests/ui/const-generics/mgca/macro-const-arg-infer.stderr

diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index eafa30b4e86cf..fa44a37125fd2 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1310,9 +1310,13 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
                 }
                 GenericArg::Type(self.lower_ty_alloc(ty, itctx).try_as_ambig_ty().unwrap())
             }
-            ast::GenericArg::Const(ct) => GenericArg::Const(
-                self.lower_anon_const_to_const_arg_and_alloc(ct).try_as_ambig_ct().unwrap(),
-            ),
+            ast::GenericArg::Const(ct) => {
+                let ct = self.lower_anon_const_to_const_arg_and_alloc(ct);
+                match ct.try_as_ambig_ct() {
+                    Some(ct) => GenericArg::Const(ct),
+                    None => GenericArg::Infer(hir::InferArg { hir_id: ct.hir_id, span: ct.span }),
+                }
+            }
         }
     }
 
diff --git a/tests/ui/const-generics/mgca/braced-const-infer.rs b/tests/ui/const-generics/mgca/braced-const-infer.rs
new file mode 100644
index 0000000000000..9b007d338d1da
--- /dev/null
+++ b/tests/ui/const-generics/mgca/braced-const-infer.rs
@@ -0,0 +1,9 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/153198
+#![feature(min_generic_const_args)]
+#![allow(incomplete_features, rust_2021_compatibility)]
+
+trait Trait<T> {}
+
+impl dyn Trait<{_}> {} //~ ERROR: the placeholder `_` is not allowed within types on item signatures
+
+fn main() {}
diff --git a/tests/ui/const-generics/mgca/braced-const-infer.stderr b/tests/ui/const-generics/mgca/braced-const-infer.stderr
new file mode 100644
index 0000000000000..d8ffee4cd0e8f
--- /dev/null
+++ b/tests/ui/const-generics/mgca/braced-const-infer.stderr
@@ -0,0 +1,9 @@
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for implementations
+  --> $DIR/braced-const-infer.rs:7:17
+   |
+LL | impl dyn Trait<{_}> {}
+   |                 ^ not allowed in type signatures
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0121`.
diff --git a/tests/ui/const-generics/mgca/macro-const-arg-infer.rs b/tests/ui/const-generics/mgca/macro-const-arg-infer.rs
new file mode 100644
index 0000000000000..017c63d8b0db5
--- /dev/null
+++ b/tests/ui/const-generics/mgca/macro-const-arg-infer.rs
@@ -0,0 +1,20 @@
+//! Regression test for https://github.com/rust-lang/rust/issues/153198
+#![feature(min_generic_const_args)]
+#![allow(incomplete_features)]
+macro_rules! y {
+    ( $($matcher:tt)*) => {
+        _ //~ ERROR: the placeholder `_` is not allowed within types on item signatures
+    };
+}
+
+struct A<T>; //~ ERROR: type parameter `T` is never used
+
+const y: A<
+    {
+        y! {
+            x
+        }
+    },
+> = 1; //~ ERROR: mismatched types
+
+fn main() {}
diff --git a/tests/ui/const-generics/mgca/macro-const-arg-infer.stderr b/tests/ui/const-generics/mgca/macro-const-arg-infer.stderr
new file mode 100644
index 0000000000000..406206c59e18f
--- /dev/null
+++ b/tests/ui/const-generics/mgca/macro-const-arg-infer.stderr
@@ -0,0 +1,44 @@
+error[E0392]: type parameter `T` is never used
+  --> $DIR/macro-const-arg-infer.rs:10:10
+   |
+LL | struct A<T>;
+   |          ^ unused type parameter
+   |
+   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
+
+error[E0308]: mismatched types
+  --> $DIR/macro-const-arg-infer.rs:18:5
+   |
+LL |   const y: A<
+   |  __________-
+LL | |     {
+LL | |         y! {
+LL | |             x
+LL | |         }
+LL | |     },
+LL | | > = 1;
+   | | -   ^ expected `A<_>`, found integer
+   | |_|
+   |   expected because of the type of the constant
+   |
+   = note: expected struct `A<_>`
+                found type `{integer}`
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
+  --> $DIR/macro-const-arg-infer.rs:6:9
+   |
+LL |           _
+   |           ^ not allowed in type signatures
+...
+LL | /         y! {
+LL | |             x
+LL | |         }
+   | |_________- in this macro invocation
+   |
+   = note: this error originates in the macro `y` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0121, E0308, E0392.
+For more information about an error, try `rustc --explain E0121`.

From c9e97df366c4ab3247bb81f28e98e495e2fae5f5 Mon Sep 17 00:00:00 2001
From: cyrgani <ansgar.w.zielke@gmail.com>
Date: Tue, 17 Mar 2026 16:15:14 +0000
Subject: [PATCH 27/34] merge `kindck/send-*` tests

---
 tests/ui/kindck/kindck-send-object.rs         |  26 ----
 tests/ui/kindck/kindck-send-object.stderr     |  33 -----
 tests/ui/kindck/kindck-send-object1.rs        |  33 -----
 tests/ui/kindck/kindck-send-object1.stderr    |  41 ------
 tests/ui/kindck/kindck-send-object2.rs        |  24 ----
 tests/ui/kindck/kindck-send-object2.stderr    |  33 -----
 tests/ui/kindck/kindck-send-owned.rs          |  16 ---
 tests/ui/kindck/kindck-send-owned.stderr      |  19 ---
 tests/ui/kindck/kindck-send-unsafe.rs         |  15 ---
 tests/ui/kindck/kindck-send-unsafe.stderr     |  29 ----
 tests/ui/kindck/send-trait-objects-basic.rs   |  55 ++++++++
 .../ui/kindck/send-trait-objects-basic.stderr | 127 ++++++++++++++++++
 12 files changed, 182 insertions(+), 269 deletions(-)
 delete mode 100644 tests/ui/kindck/kindck-send-object.rs
 delete mode 100644 tests/ui/kindck/kindck-send-object.stderr
 delete mode 100644 tests/ui/kindck/kindck-send-object1.rs
 delete mode 100644 tests/ui/kindck/kindck-send-object1.stderr
 delete mode 100644 tests/ui/kindck/kindck-send-object2.rs
 delete mode 100644 tests/ui/kindck/kindck-send-object2.stderr
 delete mode 100644 tests/ui/kindck/kindck-send-owned.rs
 delete mode 100644 tests/ui/kindck/kindck-send-owned.stderr
 delete mode 100644 tests/ui/kindck/kindck-send-unsafe.rs
 delete mode 100644 tests/ui/kindck/kindck-send-unsafe.stderr
 create mode 100644 tests/ui/kindck/send-trait-objects-basic.rs
 create mode 100644 tests/ui/kindck/send-trait-objects-basic.stderr

diff --git a/tests/ui/kindck/kindck-send-object.rs b/tests/ui/kindck/kindck-send-object.rs
deleted file mode 100644
index f5d44246efe5a..0000000000000
--- a/tests/ui/kindck/kindck-send-object.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-// Test which of the builtin types are considered sendable. The tests
-// in this file all test the "kind" violates detected during kindck.
-// See all `regions-bounded-by-send.rs`
-
-fn assert_send<T:Send>() { }
-trait Dummy { }
-trait Message : Send { }
-
-// careful with object types, who knows what they close over...
-
-fn object_ref_with_static_bound_not_ok() {
-    assert_send::<&'static (dyn Dummy + 'static)>();
-    //~^ ERROR `&'static (dyn Dummy + 'static)` cannot be sent between threads safely [E0277]
-}
-
-fn box_object_with_no_bound_not_ok<'a>() {
-    assert_send::<Box<dyn Dummy>>();
-    //~^ ERROR `dyn Dummy` cannot be sent between threads safely
-}
-
-fn object_with_send_bound_ok() {
-    assert_send::<&'static (dyn Dummy + Sync)>();
-    assert_send::<Box<dyn Dummy + Send>>();
-}
-
-fn main() { }
diff --git a/tests/ui/kindck/kindck-send-object.stderr b/tests/ui/kindck/kindck-send-object.stderr
deleted file mode 100644
index b71d4029350e1..0000000000000
--- a/tests/ui/kindck/kindck-send-object.stderr
+++ /dev/null
@@ -1,33 +0,0 @@
-error[E0277]: `&'static (dyn Dummy + 'static)` cannot be sent between threads safely
-  --> $DIR/kindck-send-object.rs:12:19
-   |
-LL |     assert_send::<&'static (dyn Dummy + 'static)>();
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&'static (dyn Dummy + 'static)` cannot be sent between threads safely
-   |
-   = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)`
-   = note: required for `&'static (dyn Dummy + 'static)` to implement `Send`
-note: required by a bound in `assert_send`
-  --> $DIR/kindck-send-object.rs:5:18
-   |
-LL | fn assert_send<T:Send>() { }
-   |                  ^^^^ required by this bound in `assert_send`
-
-error[E0277]: `dyn Dummy` cannot be sent between threads safely
-  --> $DIR/kindck-send-object.rs:17:19
-   |
-LL |     assert_send::<Box<dyn Dummy>>();
-   |                   ^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely
-   |
-   = help: the trait `Send` is not implemented for `dyn Dummy`
-   = note: required for `std::ptr::Unique<dyn Dummy>` to implement `Send`
-note: required because it appears within the type `Box<dyn Dummy>`
-  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
-note: required by a bound in `assert_send`
-  --> $DIR/kindck-send-object.rs:5:18
-   |
-LL | fn assert_send<T:Send>() { }
-   |                  ^^^^ required by this bound in `assert_send`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/kindck/kindck-send-object1.rs b/tests/ui/kindck/kindck-send-object1.rs
deleted file mode 100644
index 76a9fc6019abc..0000000000000
--- a/tests/ui/kindck/kindck-send-object1.rs
+++ /dev/null
@@ -1,33 +0,0 @@
-// Test which object types are considered sendable. This test
-// is broken into two parts because some errors occur in distinct
-// phases in the compiler. See kindck-send-object2.rs as well!
-
-fn assert_send<T:Send+'static>() { }
-trait Dummy { }
-
-// careful with object types, who knows what they close over...
-fn test51<'a>() {
-    assert_send::<&'a dyn Dummy>();
-    //~^ ERROR `&'a (dyn Dummy + 'a)` cannot be sent between threads safely [E0277]
-}
-fn test52<'a>() {
-    assert_send::<&'a (dyn Dummy + Sync)>();
-    //~^ ERROR: lifetime may not live long enough
-}
-
-// ...unless they are properly bounded
-fn test60() {
-    assert_send::<&'static (dyn Dummy + Sync)>();
-}
-fn test61() {
-    assert_send::<Box<dyn Dummy + Send>>();
-}
-
-// closure and object types can have lifetime bounds which make
-// them not ok
-fn test_71<'a>() {
-    assert_send::<Box<dyn Dummy + 'a>>();
-    //~^ ERROR `(dyn Dummy + 'a)` cannot be sent between threads safely
-}
-
-fn main() { }
diff --git a/tests/ui/kindck/kindck-send-object1.stderr b/tests/ui/kindck/kindck-send-object1.stderr
deleted file mode 100644
index 2184ae704673d..0000000000000
--- a/tests/ui/kindck/kindck-send-object1.stderr
+++ /dev/null
@@ -1,41 +0,0 @@
-error[E0277]: `&'a (dyn Dummy + 'a)` cannot be sent between threads safely
-  --> $DIR/kindck-send-object1.rs:10:19
-   |
-LL |     assert_send::<&'a dyn Dummy>();
-   |                   ^^^^^^^^^^^^^ `&'a (dyn Dummy + 'a)` cannot be sent between threads safely
-   |
-   = help: the trait `Sync` is not implemented for `(dyn Dummy + 'a)`
-   = note: required for `&'a (dyn Dummy + 'a)` to implement `Send`
-note: required by a bound in `assert_send`
-  --> $DIR/kindck-send-object1.rs:5:18
-   |
-LL | fn assert_send<T:Send+'static>() { }
-   |                  ^^^^ required by this bound in `assert_send`
-
-error[E0277]: `(dyn Dummy + 'a)` cannot be sent between threads safely
-  --> $DIR/kindck-send-object1.rs:29:19
-   |
-LL |     assert_send::<Box<dyn Dummy + 'a>>();
-   |                   ^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be sent between threads safely
-   |
-   = help: the trait `Send` is not implemented for `(dyn Dummy + 'a)`
-   = note: required for `std::ptr::Unique<(dyn Dummy + 'a)>` to implement `Send`
-note: required because it appears within the type `Box<(dyn Dummy + 'a)>`
-  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
-note: required by a bound in `assert_send`
-  --> $DIR/kindck-send-object1.rs:5:18
-   |
-LL | fn assert_send<T:Send+'static>() { }
-   |                  ^^^^ required by this bound in `assert_send`
-
-error: lifetime may not live long enough
-  --> $DIR/kindck-send-object1.rs:14:5
-   |
-LL | fn test52<'a>() {
-   |           -- lifetime `'a` defined here
-LL |     assert_send::<&'a (dyn Dummy + Sync)>();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/kindck/kindck-send-object2.rs b/tests/ui/kindck/kindck-send-object2.rs
deleted file mode 100644
index d37074e657462..0000000000000
--- a/tests/ui/kindck/kindck-send-object2.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-// Continue kindck-send-object1.rs.
-
-fn assert_send<T:Send>() { }
-trait Dummy { }
-
-fn test50() {
-    assert_send::<&'static dyn Dummy>();
-    //~^ ERROR `&'static (dyn Dummy + 'static)` cannot be sent between threads safely [E0277]
-}
-
-fn test53() {
-    assert_send::<Box<dyn Dummy>>();
-    //~^ ERROR `dyn Dummy` cannot be sent between threads safely
-}
-
-// ...unless they are properly bounded
-fn test60() {
-    assert_send::<&'static (dyn Dummy + Sync)>();
-}
-fn test61() {
-    assert_send::<Box<dyn Dummy + Send>>();
-}
-
-fn main() { }
diff --git a/tests/ui/kindck/kindck-send-object2.stderr b/tests/ui/kindck/kindck-send-object2.stderr
deleted file mode 100644
index 52a7055b42291..0000000000000
--- a/tests/ui/kindck/kindck-send-object2.stderr
+++ /dev/null
@@ -1,33 +0,0 @@
-error[E0277]: `&'static (dyn Dummy + 'static)` cannot be sent between threads safely
-  --> $DIR/kindck-send-object2.rs:7:19
-   |
-LL |     assert_send::<&'static dyn Dummy>();
-   |                   ^^^^^^^^^^^^^^^^^^ `&'static (dyn Dummy + 'static)` cannot be sent between threads safely
-   |
-   = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)`
-   = note: required for `&'static (dyn Dummy + 'static)` to implement `Send`
-note: required by a bound in `assert_send`
-  --> $DIR/kindck-send-object2.rs:3:18
-   |
-LL | fn assert_send<T:Send>() { }
-   |                  ^^^^ required by this bound in `assert_send`
-
-error[E0277]: `dyn Dummy` cannot be sent between threads safely
-  --> $DIR/kindck-send-object2.rs:12:19
-   |
-LL |     assert_send::<Box<dyn Dummy>>();
-   |                   ^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely
-   |
-   = help: the trait `Send` is not implemented for `dyn Dummy`
-   = note: required for `std::ptr::Unique<dyn Dummy>` to implement `Send`
-note: required because it appears within the type `Box<dyn Dummy>`
-  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
-note: required by a bound in `assert_send`
-  --> $DIR/kindck-send-object2.rs:3:18
-   |
-LL | fn assert_send<T:Send>() { }
-   |                  ^^^^ required by this bound in `assert_send`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/kindck/kindck-send-owned.rs b/tests/ui/kindck/kindck-send-owned.rs
deleted file mode 100644
index 65efb69041d59..0000000000000
--- a/tests/ui/kindck/kindck-send-owned.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-// Test which of the builtin types are considered sendable.
-
-fn assert_send<T:Send>() { }
-
-// owned content are ok
-fn test30() { assert_send::<Box<isize>>(); }
-fn test31() { assert_send::<String>(); }
-fn test32() { assert_send::<Vec<isize> >(); }
-
-// but not if they own a bad thing
-fn test40() {
-    assert_send::<Box<*mut u8>>();
-    //~^ ERROR `*mut u8` cannot be sent between threads safely
-}
-
-fn main() { }
diff --git a/tests/ui/kindck/kindck-send-owned.stderr b/tests/ui/kindck/kindck-send-owned.stderr
deleted file mode 100644
index c433d80cf140c..0000000000000
--- a/tests/ui/kindck/kindck-send-owned.stderr
+++ /dev/null
@@ -1,19 +0,0 @@
-error[E0277]: `*mut u8` cannot be sent between threads safely
-  --> $DIR/kindck-send-owned.rs:12:19
-   |
-LL |     assert_send::<Box<*mut u8>>();
-   |                   ^^^^^^^^^^^^ `*mut u8` cannot be sent between threads safely
-   |
-   = help: the trait `Send` is not implemented for `*mut u8`
-   = note: required for `std::ptr::Unique<*mut u8>` to implement `Send`
-note: required because it appears within the type `Box<*mut u8>`
-  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
-note: required by a bound in `assert_send`
-  --> $DIR/kindck-send-owned.rs:3:18
-   |
-LL | fn assert_send<T:Send>() { }
-   |                  ^^^^ required by this bound in `assert_send`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/kindck/kindck-send-unsafe.rs b/tests/ui/kindck/kindck-send-unsafe.rs
deleted file mode 100644
index eb1f2a549b16b..0000000000000
--- a/tests/ui/kindck/kindck-send-unsafe.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-extern crate core;
-
-fn assert_send<T: Send>() {}
-
-fn test70() {
-    assert_send::<*mut isize>();
-    //~^ ERROR `*mut isize` cannot be sent between threads safely
-}
-
-fn test71<'a>() {
-    assert_send::<*mut &'a isize>();
-    //~^ ERROR `*mut &'a isize` cannot be sent between threads safely
-}
-
-fn main() {}
diff --git a/tests/ui/kindck/kindck-send-unsafe.stderr b/tests/ui/kindck/kindck-send-unsafe.stderr
deleted file mode 100644
index f1a5054abbc47..0000000000000
--- a/tests/ui/kindck/kindck-send-unsafe.stderr
+++ /dev/null
@@ -1,29 +0,0 @@
-error[E0277]: `*mut isize` cannot be sent between threads safely
-  --> $DIR/kindck-send-unsafe.rs:6:19
-   |
-LL |     assert_send::<*mut isize>();
-   |                   ^^^^^^^^^^ `*mut isize` cannot be sent between threads safely
-   |
-   = help: the trait `Send` is not implemented for `*mut isize`
-note: required by a bound in `assert_send`
-  --> $DIR/kindck-send-unsafe.rs:3:19
-   |
-LL | fn assert_send<T: Send>() {}
-   |                   ^^^^ required by this bound in `assert_send`
-
-error[E0277]: `*mut &'a isize` cannot be sent between threads safely
-  --> $DIR/kindck-send-unsafe.rs:11:19
-   |
-LL |     assert_send::<*mut &'a isize>();
-   |                   ^^^^^^^^^^^^^^ `*mut &'a isize` cannot be sent between threads safely
-   |
-   = help: the trait `Send` is not implemented for `*mut &'a isize`
-note: required by a bound in `assert_send`
-  --> $DIR/kindck-send-unsafe.rs:3:19
-   |
-LL | fn assert_send<T: Send>() {}
-   |                   ^^^^ required by this bound in `assert_send`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/kindck/send-trait-objects-basic.rs b/tests/ui/kindck/send-trait-objects-basic.rs
new file mode 100644
index 0000000000000..c999d4d0f6950
--- /dev/null
+++ b/tests/ui/kindck/send-trait-objects-basic.rs
@@ -0,0 +1,55 @@
+// Test which trait objects and basic types are considered sendable, considering lifetimes.
+
+fn assert_send_static<T: Send + 'static>() {}
+fn assert_send<T: Send>() {}
+
+trait Dummy {}
+
+fn test1<'a>() {
+    assert_send_static::<&'a dyn Dummy>();
+    //~^ ERROR `&'a (dyn Dummy + 'a)` cannot be sent between threads safely [E0277]
+}
+
+fn test2<'a>() {
+    assert_send_static::<&'a (dyn Dummy + Sync)>();
+    //~^ ERROR: lifetime may not live long enough
+}
+
+fn test3<'a>() {
+    assert_send_static::<Box<dyn Dummy + 'a>>();
+    //~^ ERROR `(dyn Dummy + 'a)` cannot be sent between threads safely
+}
+
+fn test4<'a>() {
+    assert_send::<*mut &'a isize>();
+    //~^ ERROR `*mut &'a isize` cannot be sent between threads safely
+}
+
+fn main() {
+    assert_send_static::<&'static (dyn Dummy + Sync)>();
+    assert_send_static::<Box<dyn Dummy + Send>>();
+
+    assert_send::<&'static dyn Dummy>();
+    //~^ ERROR `&'static (dyn Dummy + 'static)` cannot be sent between threads safely [E0277]
+    assert_send::<Box<dyn Dummy>>();
+    //~^ ERROR `dyn Dummy` cannot be sent between threads safely
+    assert_send::<&'static (dyn Dummy + Sync)>();
+    assert_send::<Box<dyn Dummy + Send>>();
+
+    // owned content is ok
+    assert_send::<Box<isize>>();
+    assert_send::<String>();
+    assert_send::<Vec<isize>>();
+
+    // but not if it owns a bad thing
+    assert_send::<Box<*mut u8>>();
+    //~^ ERROR `*mut u8` cannot be sent between threads safely
+
+    assert_send::<*mut isize>();
+    //~^ ERROR `*mut isize` cannot be sent between threads safely
+}
+
+fn object_ref_with_static_bound_not_ok() {
+    assert_send::<&'static (dyn Dummy + 'static)>();
+    //~^ ERROR `&'static (dyn Dummy + 'static)` cannot be sent between threads safely [E0277]
+}
diff --git a/tests/ui/kindck/send-trait-objects-basic.stderr b/tests/ui/kindck/send-trait-objects-basic.stderr
new file mode 100644
index 0000000000000..0393f7bc19df7
--- /dev/null
+++ b/tests/ui/kindck/send-trait-objects-basic.stderr
@@ -0,0 +1,127 @@
+error[E0277]: `&'a (dyn Dummy + 'a)` cannot be sent between threads safely
+  --> $DIR/send-trait-objects-basic.rs:9:26
+   |
+LL |     assert_send_static::<&'a dyn Dummy>();
+   |                          ^^^^^^^^^^^^^ `&'a (dyn Dummy + 'a)` cannot be sent between threads safely
+   |
+   = help: the trait `Sync` is not implemented for `(dyn Dummy + 'a)`
+   = note: required for `&'a (dyn Dummy + 'a)` to implement `Send`
+note: required by a bound in `assert_send_static`
+  --> $DIR/send-trait-objects-basic.rs:3:26
+   |
+LL | fn assert_send_static<T: Send + 'static>() {}
+   |                          ^^^^ required by this bound in `assert_send_static`
+
+error[E0277]: `(dyn Dummy + 'a)` cannot be sent between threads safely
+  --> $DIR/send-trait-objects-basic.rs:19:26
+   |
+LL |     assert_send_static::<Box<dyn Dummy + 'a>>();
+   |                          ^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be sent between threads safely
+   |
+   = help: the trait `Send` is not implemented for `(dyn Dummy + 'a)`
+   = note: required for `std::ptr::Unique<(dyn Dummy + 'a)>` to implement `Send`
+note: required because it appears within the type `Box<(dyn Dummy + 'a)>`
+  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+note: required by a bound in `assert_send_static`
+  --> $DIR/send-trait-objects-basic.rs:3:26
+   |
+LL | fn assert_send_static<T: Send + 'static>() {}
+   |                          ^^^^ required by this bound in `assert_send_static`
+
+error[E0277]: `*mut &'a isize` cannot be sent between threads safely
+  --> $DIR/send-trait-objects-basic.rs:24:19
+   |
+LL |     assert_send::<*mut &'a isize>();
+   |                   ^^^^^^^^^^^^^^ `*mut &'a isize` cannot be sent between threads safely
+   |
+   = help: the trait `Send` is not implemented for `*mut &'a isize`
+note: required by a bound in `assert_send`
+  --> $DIR/send-trait-objects-basic.rs:4:19
+   |
+LL | fn assert_send<T: Send>() {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error[E0277]: `&'static (dyn Dummy + 'static)` cannot be sent between threads safely
+  --> $DIR/send-trait-objects-basic.rs:32:19
+   |
+LL |     assert_send::<&'static dyn Dummy>();
+   |                   ^^^^^^^^^^^^^^^^^^ `&'static (dyn Dummy + 'static)` cannot be sent between threads safely
+   |
+   = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)`
+   = note: required for `&'static (dyn Dummy + 'static)` to implement `Send`
+note: required by a bound in `assert_send`
+  --> $DIR/send-trait-objects-basic.rs:4:19
+   |
+LL | fn assert_send<T: Send>() {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error[E0277]: `dyn Dummy` cannot be sent between threads safely
+  --> $DIR/send-trait-objects-basic.rs:34:19
+   |
+LL |     assert_send::<Box<dyn Dummy>>();
+   |                   ^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely
+   |
+   = help: the trait `Send` is not implemented for `dyn Dummy`
+   = note: required for `std::ptr::Unique<dyn Dummy>` to implement `Send`
+note: required because it appears within the type `Box<dyn Dummy>`
+  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+note: required by a bound in `assert_send`
+  --> $DIR/send-trait-objects-basic.rs:4:19
+   |
+LL | fn assert_send<T: Send>() {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error[E0277]: `*mut u8` cannot be sent between threads safely
+  --> $DIR/send-trait-objects-basic.rs:45:19
+   |
+LL |     assert_send::<Box<*mut u8>>();
+   |                   ^^^^^^^^^^^^ `*mut u8` cannot be sent between threads safely
+   |
+   = help: the trait `Send` is not implemented for `*mut u8`
+   = note: required for `std::ptr::Unique<*mut u8>` to implement `Send`
+note: required because it appears within the type `Box<*mut u8>`
+  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+note: required by a bound in `assert_send`
+  --> $DIR/send-trait-objects-basic.rs:4:19
+   |
+LL | fn assert_send<T: Send>() {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error[E0277]: `*mut isize` cannot be sent between threads safely
+  --> $DIR/send-trait-objects-basic.rs:48:19
+   |
+LL |     assert_send::<*mut isize>();
+   |                   ^^^^^^^^^^ `*mut isize` cannot be sent between threads safely
+   |
+   = help: the trait `Send` is not implemented for `*mut isize`
+note: required by a bound in `assert_send`
+  --> $DIR/send-trait-objects-basic.rs:4:19
+   |
+LL | fn assert_send<T: Send>() {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error[E0277]: `&'static (dyn Dummy + 'static)` cannot be sent between threads safely
+  --> $DIR/send-trait-objects-basic.rs:53:19
+   |
+LL |     assert_send::<&'static (dyn Dummy + 'static)>();
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&'static (dyn Dummy + 'static)` cannot be sent between threads safely
+   |
+   = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)`
+   = note: required for `&'static (dyn Dummy + 'static)` to implement `Send`
+note: required by a bound in `assert_send`
+  --> $DIR/send-trait-objects-basic.rs:4:19
+   |
+LL | fn assert_send<T: Send>() {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error: lifetime may not live long enough
+  --> $DIR/send-trait-objects-basic.rs:14:5
+   |
+LL | fn test2<'a>() {
+   |          -- lifetime `'a` defined here
+LL |     assert_send_static::<&'a (dyn Dummy + Sync)>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0277`.

From 56779812f61029c956fb53e72ac63df2660cf3c3 Mon Sep 17 00:00:00 2001
From: cyrgani <ansgar.w.zielke@gmail.com>
Date: Tue, 17 Mar 2026 21:49:58 +0000
Subject: [PATCH 28/34] reformat and update remaining `ui/kindck` tests

---
 tests/ui/kindck/kindck-copy.rs                | 31 ++++-----
 tests/ui/kindck/kindck-copy.stderr            | 68 +++++++++----------
 tests/ui/kindck/kindck-impl-type-params-2.rs  | 15 ----
 .../kindck/kindck-impl-type-params-2.stderr   | 24 -------
 tests/ui/kindck/kindck-impl-type-params.rs    |  6 +-
 .../ui/kindck/kindck-impl-type-params.stderr  | 30 ++++----
 .../kindck-inherited-copy-bound.curr.stderr   | 56 ---------------
 .../ui/kindck/kindck-inherited-copy-bound.rs  | 10 ++-
 .../kindck/kindck-inherited-copy-bound.stderr | 26 +++----
 tests/ui/kindck/kindck-nonsendable-1.rs       |  4 +-
 tests/ui/kindck/kindck-nonsendable-1.stderr   | 18 ++---
 11 files changed, 96 insertions(+), 192 deletions(-)
 delete mode 100644 tests/ui/kindck/kindck-impl-type-params-2.rs
 delete mode 100644 tests/ui/kindck/kindck-impl-type-params-2.stderr
 delete mode 100644 tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr

diff --git a/tests/ui/kindck/kindck-copy.rs b/tests/ui/kindck/kindck-copy.rs
index 36bf0d2b785f6..c953b60260df4 100644
--- a/tests/ui/kindck/kindck-copy.rs
+++ b/tests/ui/kindck/kindck-copy.rs
@@ -2,9 +2,9 @@
 
 use std::rc::Rc;
 
-fn assert_copy<T:Copy>() { }
+fn assert_copy<T: Copy>() {}
 
-trait Dummy { }
+trait Dummy {}
 
 #[derive(Copy, Clone)]
 struct MyStruct {
@@ -16,8 +16,8 @@ struct MyNoncopyStruct {
     x: Box<char>,
 }
 
-fn test<'a,T,U:Copy>(_: &'a isize) {
-    // lifetime pointers are ok...
+fn test<'a, T, U: Copy>(_: &'a isize) {
+    // references are ok...
     assert_copy::<&'static isize>();
     assert_copy::<&'a isize>();
     assert_copy::<&'a str>();
@@ -25,25 +25,25 @@ fn test<'a,T,U:Copy>(_: &'a isize) {
 
     // ...unless they are mutable
     assert_copy::<&'static mut isize>(); //~ ERROR : Copy` is not satisfied
-    assert_copy::<&'a mut isize>();  //~ ERROR : Copy` is not satisfied
+    assert_copy::<&'a mut isize>(); //~ ERROR : Copy` is not satisfied
 
     // boxes are not ok
-    assert_copy::<Box<isize>>();   //~ ERROR : Copy` is not satisfied
-    assert_copy::<String>();   //~ ERROR : Copy` is not satisfied
-    assert_copy::<Vec<isize> >(); //~ ERROR : Copy` is not satisfied
+    assert_copy::<Box<isize>>(); //~ ERROR : Copy` is not satisfied
+    assert_copy::<String>(); //~ ERROR : Copy` is not satisfied
+    assert_copy::<Vec<isize>>(); //~ ERROR : Copy` is not satisfied
     assert_copy::<Box<&'a mut isize>>(); //~ ERROR : Copy` is not satisfied
 
-    // borrowed object types are generally ok
+    // borrowed trait objects are generally ok
     assert_copy::<&'a dyn Dummy>();
     assert_copy::<&'a (dyn Dummy + Send)>();
     assert_copy::<&'static (dyn Dummy + Send)>();
 
-    // owned object types are not ok
+    // boxed trait objects are not ok
     assert_copy::<Box<dyn Dummy>>(); //~ ERROR : Copy` is not satisfied
     assert_copy::<Box<dyn Dummy + Send>>(); //~ ERROR : Copy` is not satisfied
 
-    // mutable object types are not ok
-    assert_copy::<&'a mut (dyn Dummy + Send)>();  //~ ERROR : Copy` is not satisfied
+    // mutable references to trait objects are not ok
+    assert_copy::<&'a mut (dyn Dummy + Send)>(); //~ ERROR : Copy` is not satisfied
 
     // raw ptrs are ok
     assert_copy::<*const isize>();
@@ -55,7 +55,7 @@ fn test<'a,T,U:Copy>(_: &'a isize) {
     assert_copy::<()>();
 
     // tuples are ok
-    assert_copy::<(isize,isize)>();
+    assert_copy::<(isize, isize)>();
 
     // structs of POD are ok
     assert_copy::<MyStruct>();
@@ -64,8 +64,7 @@ fn test<'a,T,U:Copy>(_: &'a isize) {
     assert_copy::<MyNoncopyStruct>(); //~ ERROR : Copy` is not satisfied
 
     // ref counted types are not ok
-    assert_copy::<Rc<isize>>();   //~ ERROR : Copy` is not satisfied
+    assert_copy::<Rc<isize>>(); //~ ERROR : Copy` is not satisfied
 }
 
-pub fn main() {
-}
+pub fn main() {}
diff --git a/tests/ui/kindck/kindck-copy.stderr b/tests/ui/kindck/kindck-copy.stderr
index f5623ddd4f795..01b4a5a646476 100644
--- a/tests/ui/kindck/kindck-copy.stderr
+++ b/tests/ui/kindck/kindck-copy.stderr
@@ -5,10 +5,10 @@ LL |     assert_copy::<&'static mut isize>();
    |                   ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'static mut isize`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:18
+  --> $DIR/kindck-copy.rs:5:19
    |
-LL | fn assert_copy<T:Copy>() { }
-   |                  ^^^^ required by this bound in `assert_copy`
+LL | fn assert_copy<T: Copy>() {}
+   |                   ^^^^ required by this bound in `assert_copy`
 help: consider removing the leading `&`-reference
    |
 LL -     assert_copy::<&'static mut isize>();
@@ -22,10 +22,10 @@ LL |     assert_copy::<&'a mut isize>();
    |                   ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'a mut isize`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:18
+  --> $DIR/kindck-copy.rs:5:19
    |
-LL | fn assert_copy<T:Copy>() { }
-   |                  ^^^^ required by this bound in `assert_copy`
+LL | fn assert_copy<T: Copy>() {}
+   |                   ^^^^ required by this bound in `assert_copy`
 help: consider removing the leading `&`-reference
    |
 LL -     assert_copy::<&'a mut isize>();
@@ -39,10 +39,10 @@ LL |     assert_copy::<Box<isize>>();
    |                   ^^^^^^^^^^ the trait `Copy` is not implemented for `Box<isize>`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:18
+  --> $DIR/kindck-copy.rs:5:19
    |
-LL | fn assert_copy<T:Copy>() { }
-   |                  ^^^^ required by this bound in `assert_copy`
+LL | fn assert_copy<T: Copy>() {}
+   |                   ^^^^ required by this bound in `assert_copy`
 
 error[E0277]: the trait bound `String: Copy` is not satisfied
   --> $DIR/kindck-copy.rs:32:19
@@ -51,22 +51,22 @@ LL |     assert_copy::<String>();
    |                   ^^^^^^ the trait `Copy` is not implemented for `String`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:18
+  --> $DIR/kindck-copy.rs:5:19
    |
-LL | fn assert_copy<T:Copy>() { }
-   |                  ^^^^ required by this bound in `assert_copy`
+LL | fn assert_copy<T: Copy>() {}
+   |                   ^^^^ required by this bound in `assert_copy`
 
 error[E0277]: the trait bound `Vec<isize>: Copy` is not satisfied
   --> $DIR/kindck-copy.rs:33:19
    |
-LL |     assert_copy::<Vec<isize> >();
+LL |     assert_copy::<Vec<isize>>();
    |                   ^^^^^^^^^^ the trait `Copy` is not implemented for `Vec<isize>`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:18
+  --> $DIR/kindck-copy.rs:5:19
    |
-LL | fn assert_copy<T:Copy>() { }
-   |                  ^^^^ required by this bound in `assert_copy`
+LL | fn assert_copy<T: Copy>() {}
+   |                   ^^^^ required by this bound in `assert_copy`
 
 error[E0277]: the trait bound `Box<&'a mut isize>: Copy` is not satisfied
   --> $DIR/kindck-copy.rs:34:19
@@ -75,10 +75,10 @@ LL |     assert_copy::<Box<&'a mut isize>>();
    |                   ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box<&'a mut isize>`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:18
+  --> $DIR/kindck-copy.rs:5:19
    |
-LL | fn assert_copy<T:Copy>() { }
-   |                  ^^^^ required by this bound in `assert_copy`
+LL | fn assert_copy<T: Copy>() {}
+   |                   ^^^^ required by this bound in `assert_copy`
 
 error[E0277]: the trait bound `Box<dyn Dummy>: Copy` is not satisfied
   --> $DIR/kindck-copy.rs:42:19
@@ -87,10 +87,10 @@ LL |     assert_copy::<Box<dyn Dummy>>();
    |                   ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box<dyn Dummy>`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:18
+  --> $DIR/kindck-copy.rs:5:19
    |
-LL | fn assert_copy<T:Copy>() { }
-   |                  ^^^^ required by this bound in `assert_copy`
+LL | fn assert_copy<T: Copy>() {}
+   |                   ^^^^ required by this bound in `assert_copy`
 
 error[E0277]: the trait bound `Box<dyn Dummy + Send>: Copy` is not satisfied
   --> $DIR/kindck-copy.rs:43:19
@@ -99,10 +99,10 @@ LL |     assert_copy::<Box<dyn Dummy + Send>>();
    |                   ^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box<dyn Dummy + Send>`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:18
+  --> $DIR/kindck-copy.rs:5:19
    |
-LL | fn assert_copy<T:Copy>() { }
-   |                  ^^^^ required by this bound in `assert_copy`
+LL | fn assert_copy<T: Copy>() {}
+   |                   ^^^^ required by this bound in `assert_copy`
 
 error[E0277]: the trait bound `&'a mut (dyn Dummy + Send + 'a): Copy` is not satisfied
   --> $DIR/kindck-copy.rs:46:19
@@ -111,10 +111,10 @@ LL |     assert_copy::<&'a mut (dyn Dummy + Send)>();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'a mut (dyn Dummy + Send + 'a)`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:18
+  --> $DIR/kindck-copy.rs:5:19
    |
-LL | fn assert_copy<T:Copy>() { }
-   |                  ^^^^ required by this bound in `assert_copy`
+LL | fn assert_copy<T: Copy>() {}
+   |                   ^^^^ required by this bound in `assert_copy`
 
 error[E0277]: the trait bound `MyNoncopyStruct: Copy` is not satisfied
   --> $DIR/kindck-copy.rs:64:19
@@ -128,10 +128,10 @@ help: the trait `Copy` is not implemented for `MyNoncopyStruct`
 LL | struct MyNoncopyStruct {
    | ^^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:18
+  --> $DIR/kindck-copy.rs:5:19
    |
-LL | fn assert_copy<T:Copy>() { }
-   |                  ^^^^ required by this bound in `assert_copy`
+LL | fn assert_copy<T: Copy>() {}
+   |                   ^^^^ required by this bound in `assert_copy`
 
 error[E0277]: the trait bound `Rc<isize>: Copy` is not satisfied
   --> $DIR/kindck-copy.rs:67:19
@@ -140,10 +140,10 @@ LL |     assert_copy::<Rc<isize>>();
    |                   ^^^^^^^^^ the trait `Copy` is not implemented for `Rc<isize>`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:18
+  --> $DIR/kindck-copy.rs:5:19
    |
-LL | fn assert_copy<T:Copy>() { }
-   |                  ^^^^ required by this bound in `assert_copy`
+LL | fn assert_copy<T: Copy>() {}
+   |                   ^^^^ required by this bound in `assert_copy`
 
 error: aborting due to 11 previous errors
 
diff --git a/tests/ui/kindck/kindck-impl-type-params-2.rs b/tests/ui/kindck/kindck-impl-type-params-2.rs
deleted file mode 100644
index 8b0771985dc3f..0000000000000
--- a/tests/ui/kindck/kindck-impl-type-params-2.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-trait Foo {
-}
-
-
-
-impl<T:Copy> Foo for T {
-}
-
-fn take_param<T:Foo>(foo: &T) { }
-
-fn main() {
-    let x: Box<_> = Box::new(3);
-    take_param(&x);
-    //~^ ERROR the trait bound `Box<{integer}>: Foo` is not satisfied
-}
diff --git a/tests/ui/kindck/kindck-impl-type-params-2.stderr b/tests/ui/kindck/kindck-impl-type-params-2.stderr
deleted file mode 100644
index 38dc94f9104d5..0000000000000
--- a/tests/ui/kindck/kindck-impl-type-params-2.stderr
+++ /dev/null
@@ -1,24 +0,0 @@
-error[E0277]: the trait bound `Box<{integer}>: Foo` is not satisfied
-  --> $DIR/kindck-impl-type-params-2.rs:13:16
-   |
-LL |     take_param(&x);
-   |     ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>`
-   |     |
-   |     required by a bound introduced by this call
-   |
-note: required for `Box<{integer}>` to implement `Foo`
-  --> $DIR/kindck-impl-type-params-2.rs:6:14
-   |
-LL | impl<T:Copy> Foo for T {
-   |        ----  ^^^     ^
-   |        |
-   |        unsatisfied trait bound introduced here
-note: required by a bound in `take_param`
-  --> $DIR/kindck-impl-type-params-2.rs:9:17
-   |
-LL | fn take_param<T:Foo>(foo: &T) { }
-   |                 ^^^ required by this bound in `take_param`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/kindck/kindck-impl-type-params.rs b/tests/ui/kindck/kindck-impl-type-params.rs
index 707c5dbaec30e..ba54bc313c089 100644
--- a/tests/ui/kindck/kindck-impl-type-params.rs
+++ b/tests/ui/kindck/kindck-impl-type-params.rs
@@ -6,7 +6,9 @@ use std::marker;
 struct S<T>(marker::PhantomData<T>);
 
 trait Gettable<T> {
-    fn get(&self) -> T { panic!() }
+    fn get(&self) -> T {
+        panic!()
+    }
 }
 
 impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
@@ -45,4 +47,4 @@ fn foo3<'a>() {
     //~^ ERROR : Copy` is not satisfied
 }
 
-fn main() { }
+fn main() {}
diff --git a/tests/ui/kindck/kindck-impl-type-params.stderr b/tests/ui/kindck/kindck-impl-type-params.stderr
index 0c9ab13f4774a..b2e52ae57ea4a 100644
--- a/tests/ui/kindck/kindck-impl-type-params.stderr
+++ b/tests/ui/kindck/kindck-impl-type-params.stderr
@@ -1,11 +1,11 @@
 error[E0277]: `T` cannot be sent between threads safely
-  --> $DIR/kindck-impl-type-params.rs:16:13
+  --> $DIR/kindck-impl-type-params.rs:18:13
    |
 LL |     let a = &t as &dyn Gettable<T>;
    |             ^^ `T` cannot be sent between threads safely
    |
 note: required for `S<T>` to implement `Gettable<T>`
-  --> $DIR/kindck-impl-type-params.rs:12:32
+  --> $DIR/kindck-impl-type-params.rs:14:32
    |
 LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    |         ----                   ^^^^^^^^^^^     ^^^^
@@ -18,13 +18,13 @@ LL | fn f<T: std::marker::Send>(val: T) {
    |       +++++++++++++++++++
 
 error[E0277]: the trait bound `T: Copy` is not satisfied
-  --> $DIR/kindck-impl-type-params.rs:16:13
+  --> $DIR/kindck-impl-type-params.rs:18:13
    |
 LL |     let a = &t as &dyn Gettable<T>;
    |             ^^ the trait `Copy` is not implemented for `T`
    |
 note: required for `S<T>` to implement `Gettable<T>`
-  --> $DIR/kindck-impl-type-params.rs:12:32
+  --> $DIR/kindck-impl-type-params.rs:14:32
    |
 LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    |                ----            ^^^^^^^^^^^     ^^^^
@@ -37,13 +37,13 @@ LL | fn f<T: std::marker::Copy>(val: T) {
    |       +++++++++++++++++++
 
 error[E0277]: `T` cannot be sent between threads safely
-  --> $DIR/kindck-impl-type-params.rs:23:31
+  --> $DIR/kindck-impl-type-params.rs:25:31
    |
 LL |     let a: &dyn Gettable<T> = &t;
    |                               ^^ `T` cannot be sent between threads safely
    |
 note: required for `S<T>` to implement `Gettable<T>`
-  --> $DIR/kindck-impl-type-params.rs:12:32
+  --> $DIR/kindck-impl-type-params.rs:14:32
    |
 LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    |         ----                   ^^^^^^^^^^^     ^^^^
@@ -56,13 +56,13 @@ LL | fn g<T: std::marker::Send>(val: T) {
    |       +++++++++++++++++++
 
 error[E0277]: the trait bound `T: Copy` is not satisfied
-  --> $DIR/kindck-impl-type-params.rs:23:31
+  --> $DIR/kindck-impl-type-params.rs:25:31
    |
 LL |     let a: &dyn Gettable<T> = &t;
    |                               ^^ the trait `Copy` is not implemented for `T`
    |
 note: required for `S<T>` to implement `Gettable<T>`
-  --> $DIR/kindck-impl-type-params.rs:12:32
+  --> $DIR/kindck-impl-type-params.rs:14:32
    |
 LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    |                ----            ^^^^^^^^^^^     ^^^^
@@ -75,18 +75,18 @@ LL | fn g<T: std::marker::Copy>(val: T) {
    |       +++++++++++++++++++
 
 error[E0277]: the trait bound `String: Copy` is not satisfied
-  --> $DIR/kindck-impl-type-params.rs:36:13
+  --> $DIR/kindck-impl-type-params.rs:38:13
    |
 LL |     let a = t as Box<dyn Gettable<String>>;
    |             ^ the trait `Copy` is not implemented for `String`
    |
 help: the trait `Gettable<T>` is implemented for `S<T>`
-  --> $DIR/kindck-impl-type-params.rs:12:1
+  --> $DIR/kindck-impl-type-params.rs:14:1
    |
 LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: required for `S<String>` to implement `Gettable<String>`
-  --> $DIR/kindck-impl-type-params.rs:12:32
+  --> $DIR/kindck-impl-type-params.rs:14:32
    |
 LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    |                ----            ^^^^^^^^^^^     ^^^^
@@ -95,18 +95,18 @@ LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    = note: required for the cast from `Box<S<String>>` to `Box<dyn Gettable<String>>`
 
 error[E0277]: the trait bound `Foo: Copy` is not satisfied
-  --> $DIR/kindck-impl-type-params.rs:44:37
+  --> $DIR/kindck-impl-type-params.rs:46:37
    |
 LL |     let a: Box<dyn Gettable<Foo>> = t;
    |                                     ^ the trait `Copy` is not implemented for `Foo`
    |
 help: the trait `Gettable<T>` is implemented for `S<T>`
-  --> $DIR/kindck-impl-type-params.rs:12:1
+  --> $DIR/kindck-impl-type-params.rs:14:1
    |
 LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: required for `S<Foo>` to implement `Gettable<Foo>`
-  --> $DIR/kindck-impl-type-params.rs:12:32
+  --> $DIR/kindck-impl-type-params.rs:14:32
    |
 LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    |                ----            ^^^^^^^^^^^     ^^^^
@@ -120,7 +120,7 @@ LL |     struct Foo; // does not impl Copy
    |
 
 error: lifetime may not live long enough
-  --> $DIR/kindck-impl-type-params.rs:30:13
+  --> $DIR/kindck-impl-type-params.rs:32:13
    |
 LL | fn foo<'a>() {
    |        -- lifetime `'a` defined here
diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr b/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr
deleted file mode 100644
index 95048c4454b31..0000000000000
--- a/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr
+++ /dev/null
@@ -1,56 +0,0 @@
-error[E0277]: the trait bound `Box<{integer}>: Foo` is not satisfied
-  --> $DIR/kindck-inherited-copy-bound.rs:21:16
-   |
-LL |     take_param(&x);
-   |     ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>`
-   |     |
-   |     required by a bound introduced by this call
-   |
-note: required for `Box<{integer}>` to implement `Foo`
-  --> $DIR/kindck-inherited-copy-bound.rs:14:14
-   |
-LL | impl<T:Copy> Foo for T {
-   |        ----  ^^^     ^
-   |        |
-   |        unsatisfied trait bound introduced here
-note: required by a bound in `take_param`
-  --> $DIR/kindck-inherited-copy-bound.rs:17:17
-   |
-LL | fn take_param<T:Foo>(foo: &T) { }
-   |                 ^^^ required by this bound in `take_param`
-
-error[E0038]: the trait `Foo` is not dyn compatible
-  --> $DIR/kindck-inherited-copy-bound.rs:28:19
-   |
-LL |     let z = &x as &dyn Foo;
-   |                   ^^^^^^^^ `Foo` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/kindck-inherited-copy-bound.rs:10:13
-   |
-LL | trait Foo : Copy {
-   |       ---   ^^^^ ...because it requires `Self: Sized`
-   |       |
-   |       this trait is not dyn compatible...
-
-error[E0038]: the trait `Foo` is not dyn compatible
-  --> $DIR/kindck-inherited-copy-bound.rs:28:13
-   |
-LL |     let z = &x as &dyn Foo;
-   |             ^^ `Foo` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/kindck-inherited-copy-bound.rs:10:13
-   |
-LL | trait Foo : Copy {
-   |       ---   ^^^^ ...because it requires `Self: Sized`
-   |       |
-   |       this trait is not dyn compatible...
-   = note: required for the cast from `&Box<{integer}>` to `&dyn Foo`
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0038, E0277.
-For more information about an error, try `rustc --explain E0038`.
diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.rs b/tests/ui/kindck/kindck-inherited-copy-bound.rs
index 92c2b273c2c15..dd9fea3dcde35 100644
--- a/tests/ui/kindck/kindck-inherited-copy-bound.rs
+++ b/tests/ui/kindck/kindck-inherited-copy-bound.rs
@@ -1,16 +1,14 @@
 // Test that Copy bounds inherited by trait are checked.
 
-
 use std::any::Any;
 
-trait Foo : Copy {
+trait Foo: Copy {
     fn foo(&self) {}
 }
 
-impl<T:Copy> Foo for T {
-}
+impl<T: Copy> Foo for T {}
 
-fn take_param<T:Foo>(foo: &T) { }
+fn take_param<T: Foo>(foo: &T) {}
 
 fn a() {
     let x: Box<_> = Box::new(3);
@@ -24,4 +22,4 @@ fn b() {
     //~^ ERROR E0038
 }
 
-fn main() { }
+fn main() {}
diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.stderr b/tests/ui/kindck/kindck-inherited-copy-bound.stderr
index c15aabacddd17..d6c9cab5b57a7 100644
--- a/tests/ui/kindck/kindck-inherited-copy-bound.stderr
+++ b/tests/ui/kindck/kindck-inherited-copy-bound.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `Box<{integer}>: Foo` is not satisfied
-  --> $DIR/kindck-inherited-copy-bound.rs:17:16
+  --> $DIR/kindck-inherited-copy-bound.rs:15:16
    |
 LL |     take_param(&x);
    |     ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>`
@@ -7,30 +7,30 @@ LL |     take_param(&x);
    |     required by a bound introduced by this call
    |
 note: required for `Box<{integer}>` to implement `Foo`
-  --> $DIR/kindck-inherited-copy-bound.rs:10:14
+  --> $DIR/kindck-inherited-copy-bound.rs:9:15
    |
-LL | impl<T:Copy> Foo for T {
-   |        ----  ^^^     ^
-   |        |
-   |        unsatisfied trait bound introduced here
+LL | impl<T: Copy> Foo for T {}
+   |         ----  ^^^     ^
+   |         |
+   |         unsatisfied trait bound introduced here
 note: required by a bound in `take_param`
-  --> $DIR/kindck-inherited-copy-bound.rs:13:17
+  --> $DIR/kindck-inherited-copy-bound.rs:11:18
    |
-LL | fn take_param<T:Foo>(foo: &T) { }
-   |                 ^^^ required by this bound in `take_param`
+LL | fn take_param<T: Foo>(foo: &T) {}
+   |                  ^^^ required by this bound in `take_param`
 
 error[E0038]: the trait `Foo` is not dyn compatible
-  --> $DIR/kindck-inherited-copy-bound.rs:23:24
+  --> $DIR/kindck-inherited-copy-bound.rs:21:24
    |
 LL |     let z = &x as &dyn Foo;
    |                        ^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
       for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/kindck-inherited-copy-bound.rs:6:13
+  --> $DIR/kindck-inherited-copy-bound.rs:5:12
    |
-LL | trait Foo : Copy {
-   |       ---   ^^^^ ...because it requires `Self: Sized`
+LL | trait Foo: Copy {
+   |       ---  ^^^^ ...because it requires `Self: Sized`
    |       |
    |       this trait is not dyn compatible...
 
diff --git a/tests/ui/kindck/kindck-nonsendable-1.rs b/tests/ui/kindck/kindck-nonsendable-1.rs
index b32fd78624b8e..78ef834afabdb 100644
--- a/tests/ui/kindck/kindck-nonsendable-1.rs
+++ b/tests/ui/kindck/kindck-nonsendable-1.rs
@@ -2,10 +2,10 @@ use std::rc::Rc;
 
 fn foo(_x: Rc<usize>) {}
 
-fn bar<F:FnOnce() + Send>(_: F) { }
+fn bar<F: FnOnce() + Send>(_: F) {}
 
 fn main() {
     let x = Rc::new(3);
-    bar(move|| foo(x));
+    bar(move || foo(x));
     //~^ ERROR `Rc<usize>` cannot be sent between threads safely
 }
diff --git a/tests/ui/kindck/kindck-nonsendable-1.stderr b/tests/ui/kindck/kindck-nonsendable-1.stderr
index 8bb784d1d4966..4bf8e17e3ed96 100644
--- a/tests/ui/kindck/kindck-nonsendable-1.stderr
+++ b/tests/ui/kindck/kindck-nonsendable-1.stderr
@@ -1,24 +1,24 @@
 error[E0277]: `Rc<usize>` cannot be sent between threads safely
   --> $DIR/kindck-nonsendable-1.rs:9:9
    |
-LL |     bar(move|| foo(x));
-   |     --- ------^^^^^^^
+LL |     bar(move || foo(x));
+   |     --- -------^^^^^^^
    |     |   |
    |     |   `Rc<usize>` cannot be sent between threads safely
-   |     |   within this `{closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:15}`
+   |     |   within this `{closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:16}`
    |     required by a bound introduced by this call
    |
-   = help: within `{closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:15}`, the trait `Send` is not implemented for `Rc<usize>`
+   = help: within `{closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:16}`, the trait `Send` is not implemented for `Rc<usize>`
 note: required because it's used within this closure
   --> $DIR/kindck-nonsendable-1.rs:9:9
    |
-LL |     bar(move|| foo(x));
-   |         ^^^^^^
+LL |     bar(move || foo(x));
+   |         ^^^^^^^
 note: required by a bound in `bar`
-  --> $DIR/kindck-nonsendable-1.rs:5:21
+  --> $DIR/kindck-nonsendable-1.rs:5:22
    |
-LL | fn bar<F:FnOnce() + Send>(_: F) { }
-   |                     ^^^^ required by this bound in `bar`
+LL | fn bar<F: FnOnce() + Send>(_: F) {}
+   |                      ^^^^ required by this bound in `bar`
 
 error: aborting due to 1 previous error
 

From 0a83cf9ca3d311664491dc30fb5efdccc64ba59a Mon Sep 17 00:00:00 2001
From: cyrgani <ansgar.w.zielke@gmail.com>
Date: Tue, 17 Mar 2026 22:02:05 +0000
Subject: [PATCH 29/34] move tests from `ui/kindck` to `ui/traits`

---
 tests/ui/README.md                            |  4 --
 .../basic-copyable-types.rs}                  |  0
 .../basic-copyable-types.stderr}              | 46 +++++++++----------
 .../closure-rc-not-send.rs}                   |  0
 .../closure-rc-not-send.stderr}               | 10 ++--
 .../copy-bounds-impl-type-params.rs}          |  0
 .../copy-bounds-impl-type-params.stderr}      | 30 ++++++------
 .../inherited-copy-bound.rs}                  |  0
 .../inherited-copy-bound.stderr}              | 10 ++--
 .../send-trait-objects-basic.rs               |  0
 .../send-trait-objects-basic.stderr           |  0
 11 files changed, 48 insertions(+), 52 deletions(-)
 rename tests/ui/{kindck/kindck-copy.rs => traits/basic-copyable-types.rs} (100%)
 rename tests/ui/{kindck/kindck-copy.stderr => traits/basic-copyable-types.stderr} (83%)
 rename tests/ui/{kindck/kindck-nonsendable-1.rs => traits/closure-rc-not-send.rs} (100%)
 rename tests/ui/{kindck/kindck-nonsendable-1.stderr => traits/closure-rc-not-send.stderr} (66%)
 rename tests/ui/{kindck/kindck-impl-type-params.rs => traits/copy-bounds-impl-type-params.rs} (100%)
 rename tests/ui/{kindck/kindck-impl-type-params.stderr => traits/copy-bounds-impl-type-params.stderr} (86%)
 rename tests/ui/{kindck/kindck-inherited-copy-bound.rs => traits/inherited-copy-bound.rs} (100%)
 rename tests/ui/{kindck/kindck-inherited-copy-bound.stderr => traits/inherited-copy-bound.stderr} (83%)
 rename tests/ui/{kindck => traits}/send-trait-objects-basic.rs (100%)
 rename tests/ui/{kindck => traits}/send-trait-objects-basic.stderr (100%)

diff --git a/tests/ui/README.md b/tests/ui/README.md
index 45728822b3cf8..b6e6557088922 100644
--- a/tests/ui/README.md
+++ b/tests/ui/README.md
@@ -778,10 +778,6 @@ These tests revolve around the `--json` compiler flag. See [JSON Output](https:/
 
 Tests exercising keywords, such as attempting to use them as identifiers when not contextual keywords.
 
-## `tests/ui/kindck/`
-
-**FIXME**: `kindck` is no longer a thing, these tests probably need to be audited and rehomed.
-
 ## `tests/ui/label/`
 
 Exercises block and loop `'label`s.
diff --git a/tests/ui/kindck/kindck-copy.rs b/tests/ui/traits/basic-copyable-types.rs
similarity index 100%
rename from tests/ui/kindck/kindck-copy.rs
rename to tests/ui/traits/basic-copyable-types.rs
diff --git a/tests/ui/kindck/kindck-copy.stderr b/tests/ui/traits/basic-copyable-types.stderr
similarity index 83%
rename from tests/ui/kindck/kindck-copy.stderr
rename to tests/ui/traits/basic-copyable-types.stderr
index 01b4a5a646476..b4fa957533357 100644
--- a/tests/ui/kindck/kindck-copy.stderr
+++ b/tests/ui/traits/basic-copyable-types.stderr
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `&'static mut isize: Copy` is not satisfied
-  --> $DIR/kindck-copy.rs:27:19
+  --> $DIR/basic-copyable-types.rs:27:19
    |
 LL |     assert_copy::<&'static mut isize>();
    |                   ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'static mut isize`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:19
+  --> $DIR/basic-copyable-types.rs:5:19
    |
 LL | fn assert_copy<T: Copy>() {}
    |                   ^^^^ required by this bound in `assert_copy`
@@ -16,13 +16,13 @@ LL +     assert_copy::<isize>();
    |
 
 error[E0277]: the trait bound `&'a mut isize: Copy` is not satisfied
-  --> $DIR/kindck-copy.rs:28:19
+  --> $DIR/basic-copyable-types.rs:28:19
    |
 LL |     assert_copy::<&'a mut isize>();
    |                   ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'a mut isize`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:19
+  --> $DIR/basic-copyable-types.rs:5:19
    |
 LL | fn assert_copy<T: Copy>() {}
    |                   ^^^^ required by this bound in `assert_copy`
@@ -33,114 +33,114 @@ LL +     assert_copy::<isize>();
    |
 
 error[E0277]: the trait bound `Box<isize>: Copy` is not satisfied
-  --> $DIR/kindck-copy.rs:31:19
+  --> $DIR/basic-copyable-types.rs:31:19
    |
 LL |     assert_copy::<Box<isize>>();
    |                   ^^^^^^^^^^ the trait `Copy` is not implemented for `Box<isize>`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:19
+  --> $DIR/basic-copyable-types.rs:5:19
    |
 LL | fn assert_copy<T: Copy>() {}
    |                   ^^^^ required by this bound in `assert_copy`
 
 error[E0277]: the trait bound `String: Copy` is not satisfied
-  --> $DIR/kindck-copy.rs:32:19
+  --> $DIR/basic-copyable-types.rs:32:19
    |
 LL |     assert_copy::<String>();
    |                   ^^^^^^ the trait `Copy` is not implemented for `String`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:19
+  --> $DIR/basic-copyable-types.rs:5:19
    |
 LL | fn assert_copy<T: Copy>() {}
    |                   ^^^^ required by this bound in `assert_copy`
 
 error[E0277]: the trait bound `Vec<isize>: Copy` is not satisfied
-  --> $DIR/kindck-copy.rs:33:19
+  --> $DIR/basic-copyable-types.rs:33:19
    |
 LL |     assert_copy::<Vec<isize>>();
    |                   ^^^^^^^^^^ the trait `Copy` is not implemented for `Vec<isize>`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:19
+  --> $DIR/basic-copyable-types.rs:5:19
    |
 LL | fn assert_copy<T: Copy>() {}
    |                   ^^^^ required by this bound in `assert_copy`
 
 error[E0277]: the trait bound `Box<&'a mut isize>: Copy` is not satisfied
-  --> $DIR/kindck-copy.rs:34:19
+  --> $DIR/basic-copyable-types.rs:34:19
    |
 LL |     assert_copy::<Box<&'a mut isize>>();
    |                   ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box<&'a mut isize>`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:19
+  --> $DIR/basic-copyable-types.rs:5:19
    |
 LL | fn assert_copy<T: Copy>() {}
    |                   ^^^^ required by this bound in `assert_copy`
 
 error[E0277]: the trait bound `Box<dyn Dummy>: Copy` is not satisfied
-  --> $DIR/kindck-copy.rs:42:19
+  --> $DIR/basic-copyable-types.rs:42:19
    |
 LL |     assert_copy::<Box<dyn Dummy>>();
    |                   ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box<dyn Dummy>`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:19
+  --> $DIR/basic-copyable-types.rs:5:19
    |
 LL | fn assert_copy<T: Copy>() {}
    |                   ^^^^ required by this bound in `assert_copy`
 
 error[E0277]: the trait bound `Box<dyn Dummy + Send>: Copy` is not satisfied
-  --> $DIR/kindck-copy.rs:43:19
+  --> $DIR/basic-copyable-types.rs:43:19
    |
 LL |     assert_copy::<Box<dyn Dummy + Send>>();
    |                   ^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box<dyn Dummy + Send>`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:19
+  --> $DIR/basic-copyable-types.rs:5:19
    |
 LL | fn assert_copy<T: Copy>() {}
    |                   ^^^^ required by this bound in `assert_copy`
 
 error[E0277]: the trait bound `&'a mut (dyn Dummy + Send + 'a): Copy` is not satisfied
-  --> $DIR/kindck-copy.rs:46:19
+  --> $DIR/basic-copyable-types.rs:46:19
    |
 LL |     assert_copy::<&'a mut (dyn Dummy + Send)>();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'a mut (dyn Dummy + Send + 'a)`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:19
+  --> $DIR/basic-copyable-types.rs:5:19
    |
 LL | fn assert_copy<T: Copy>() {}
    |                   ^^^^ required by this bound in `assert_copy`
 
 error[E0277]: the trait bound `MyNoncopyStruct: Copy` is not satisfied
-  --> $DIR/kindck-copy.rs:64:19
+  --> $DIR/basic-copyable-types.rs:64:19
    |
 LL |     assert_copy::<MyNoncopyStruct>();
    |                   ^^^^^^^^^^^^^^^ unsatisfied trait bound
    |
 help: the trait `Copy` is not implemented for `MyNoncopyStruct`
-  --> $DIR/kindck-copy.rs:15:1
+  --> $DIR/basic-copyable-types.rs:15:1
    |
 LL | struct MyNoncopyStruct {
    | ^^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:19
+  --> $DIR/basic-copyable-types.rs:5:19
    |
 LL | fn assert_copy<T: Copy>() {}
    |                   ^^^^ required by this bound in `assert_copy`
 
 error[E0277]: the trait bound `Rc<isize>: Copy` is not satisfied
-  --> $DIR/kindck-copy.rs:67:19
+  --> $DIR/basic-copyable-types.rs:67:19
    |
 LL |     assert_copy::<Rc<isize>>();
    |                   ^^^^^^^^^ the trait `Copy` is not implemented for `Rc<isize>`
    |
 note: required by a bound in `assert_copy`
-  --> $DIR/kindck-copy.rs:5:19
+  --> $DIR/basic-copyable-types.rs:5:19
    |
 LL | fn assert_copy<T: Copy>() {}
    |                   ^^^^ required by this bound in `assert_copy`
diff --git a/tests/ui/kindck/kindck-nonsendable-1.rs b/tests/ui/traits/closure-rc-not-send.rs
similarity index 100%
rename from tests/ui/kindck/kindck-nonsendable-1.rs
rename to tests/ui/traits/closure-rc-not-send.rs
diff --git a/tests/ui/kindck/kindck-nonsendable-1.stderr b/tests/ui/traits/closure-rc-not-send.stderr
similarity index 66%
rename from tests/ui/kindck/kindck-nonsendable-1.stderr
rename to tests/ui/traits/closure-rc-not-send.stderr
index 4bf8e17e3ed96..5e73f13648d5c 100644
--- a/tests/ui/kindck/kindck-nonsendable-1.stderr
+++ b/tests/ui/traits/closure-rc-not-send.stderr
@@ -1,21 +1,21 @@
 error[E0277]: `Rc<usize>` cannot be sent between threads safely
-  --> $DIR/kindck-nonsendable-1.rs:9:9
+  --> $DIR/closure-rc-not-send.rs:9:9
    |
 LL |     bar(move || foo(x));
    |     --- -------^^^^^^^
    |     |   |
    |     |   `Rc<usize>` cannot be sent between threads safely
-   |     |   within this `{closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:16}`
+   |     |   within this `{closure@$DIR/closure-rc-not-send.rs:9:9: 9:16}`
    |     required by a bound introduced by this call
    |
-   = help: within `{closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:16}`, the trait `Send` is not implemented for `Rc<usize>`
+   = help: within `{closure@$DIR/closure-rc-not-send.rs:9:9: 9:16}`, the trait `Send` is not implemented for `Rc<usize>`
 note: required because it's used within this closure
-  --> $DIR/kindck-nonsendable-1.rs:9:9
+  --> $DIR/closure-rc-not-send.rs:9:9
    |
 LL |     bar(move || foo(x));
    |         ^^^^^^^
 note: required by a bound in `bar`
-  --> $DIR/kindck-nonsendable-1.rs:5:22
+  --> $DIR/closure-rc-not-send.rs:5:22
    |
 LL | fn bar<F: FnOnce() + Send>(_: F) {}
    |                      ^^^^ required by this bound in `bar`
diff --git a/tests/ui/kindck/kindck-impl-type-params.rs b/tests/ui/traits/copy-bounds-impl-type-params.rs
similarity index 100%
rename from tests/ui/kindck/kindck-impl-type-params.rs
rename to tests/ui/traits/copy-bounds-impl-type-params.rs
diff --git a/tests/ui/kindck/kindck-impl-type-params.stderr b/tests/ui/traits/copy-bounds-impl-type-params.stderr
similarity index 86%
rename from tests/ui/kindck/kindck-impl-type-params.stderr
rename to tests/ui/traits/copy-bounds-impl-type-params.stderr
index b2e52ae57ea4a..08fde8fb5df35 100644
--- a/tests/ui/kindck/kindck-impl-type-params.stderr
+++ b/tests/ui/traits/copy-bounds-impl-type-params.stderr
@@ -1,11 +1,11 @@
 error[E0277]: `T` cannot be sent between threads safely
-  --> $DIR/kindck-impl-type-params.rs:18:13
+  --> $DIR/copy-bounds-impl-type-params.rs:18:13
    |
 LL |     let a = &t as &dyn Gettable<T>;
    |             ^^ `T` cannot be sent between threads safely
    |
 note: required for `S<T>` to implement `Gettable<T>`
-  --> $DIR/kindck-impl-type-params.rs:14:32
+  --> $DIR/copy-bounds-impl-type-params.rs:14:32
    |
 LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    |         ----                   ^^^^^^^^^^^     ^^^^
@@ -18,13 +18,13 @@ LL | fn f<T: std::marker::Send>(val: T) {
    |       +++++++++++++++++++
 
 error[E0277]: the trait bound `T: Copy` is not satisfied
-  --> $DIR/kindck-impl-type-params.rs:18:13
+  --> $DIR/copy-bounds-impl-type-params.rs:18:13
    |
 LL |     let a = &t as &dyn Gettable<T>;
    |             ^^ the trait `Copy` is not implemented for `T`
    |
 note: required for `S<T>` to implement `Gettable<T>`
-  --> $DIR/kindck-impl-type-params.rs:14:32
+  --> $DIR/copy-bounds-impl-type-params.rs:14:32
    |
 LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    |                ----            ^^^^^^^^^^^     ^^^^
@@ -37,13 +37,13 @@ LL | fn f<T: std::marker::Copy>(val: T) {
    |       +++++++++++++++++++
 
 error[E0277]: `T` cannot be sent between threads safely
-  --> $DIR/kindck-impl-type-params.rs:25:31
+  --> $DIR/copy-bounds-impl-type-params.rs:25:31
    |
 LL |     let a: &dyn Gettable<T> = &t;
    |                               ^^ `T` cannot be sent between threads safely
    |
 note: required for `S<T>` to implement `Gettable<T>`
-  --> $DIR/kindck-impl-type-params.rs:14:32
+  --> $DIR/copy-bounds-impl-type-params.rs:14:32
    |
 LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    |         ----                   ^^^^^^^^^^^     ^^^^
@@ -56,13 +56,13 @@ LL | fn g<T: std::marker::Send>(val: T) {
    |       +++++++++++++++++++
 
 error[E0277]: the trait bound `T: Copy` is not satisfied
-  --> $DIR/kindck-impl-type-params.rs:25:31
+  --> $DIR/copy-bounds-impl-type-params.rs:25:31
    |
 LL |     let a: &dyn Gettable<T> = &t;
    |                               ^^ the trait `Copy` is not implemented for `T`
    |
 note: required for `S<T>` to implement `Gettable<T>`
-  --> $DIR/kindck-impl-type-params.rs:14:32
+  --> $DIR/copy-bounds-impl-type-params.rs:14:32
    |
 LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    |                ----            ^^^^^^^^^^^     ^^^^
@@ -75,18 +75,18 @@ LL | fn g<T: std::marker::Copy>(val: T) {
    |       +++++++++++++++++++
 
 error[E0277]: the trait bound `String: Copy` is not satisfied
-  --> $DIR/kindck-impl-type-params.rs:38:13
+  --> $DIR/copy-bounds-impl-type-params.rs:38:13
    |
 LL |     let a = t as Box<dyn Gettable<String>>;
    |             ^ the trait `Copy` is not implemented for `String`
    |
 help: the trait `Gettable<T>` is implemented for `S<T>`
-  --> $DIR/kindck-impl-type-params.rs:14:1
+  --> $DIR/copy-bounds-impl-type-params.rs:14:1
    |
 LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: required for `S<String>` to implement `Gettable<String>`
-  --> $DIR/kindck-impl-type-params.rs:14:32
+  --> $DIR/copy-bounds-impl-type-params.rs:14:32
    |
 LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    |                ----            ^^^^^^^^^^^     ^^^^
@@ -95,18 +95,18 @@ LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    = note: required for the cast from `Box<S<String>>` to `Box<dyn Gettable<String>>`
 
 error[E0277]: the trait bound `Foo: Copy` is not satisfied
-  --> $DIR/kindck-impl-type-params.rs:46:37
+  --> $DIR/copy-bounds-impl-type-params.rs:46:37
    |
 LL |     let a: Box<dyn Gettable<Foo>> = t;
    |                                     ^ the trait `Copy` is not implemented for `Foo`
    |
 help: the trait `Gettable<T>` is implemented for `S<T>`
-  --> $DIR/kindck-impl-type-params.rs:14:1
+  --> $DIR/copy-bounds-impl-type-params.rs:14:1
    |
 LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: required for `S<Foo>` to implement `Gettable<Foo>`
-  --> $DIR/kindck-impl-type-params.rs:14:32
+  --> $DIR/copy-bounds-impl-type-params.rs:14:32
    |
 LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {}
    |                ----            ^^^^^^^^^^^     ^^^^
@@ -120,7 +120,7 @@ LL |     struct Foo; // does not impl Copy
    |
 
 error: lifetime may not live long enough
-  --> $DIR/kindck-impl-type-params.rs:32:13
+  --> $DIR/copy-bounds-impl-type-params.rs:32:13
    |
 LL | fn foo<'a>() {
    |        -- lifetime `'a` defined here
diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.rs b/tests/ui/traits/inherited-copy-bound.rs
similarity index 100%
rename from tests/ui/kindck/kindck-inherited-copy-bound.rs
rename to tests/ui/traits/inherited-copy-bound.rs
diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.stderr b/tests/ui/traits/inherited-copy-bound.stderr
similarity index 83%
rename from tests/ui/kindck/kindck-inherited-copy-bound.stderr
rename to tests/ui/traits/inherited-copy-bound.stderr
index d6c9cab5b57a7..c251d59224463 100644
--- a/tests/ui/kindck/kindck-inherited-copy-bound.stderr
+++ b/tests/ui/traits/inherited-copy-bound.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `Box<{integer}>: Foo` is not satisfied
-  --> $DIR/kindck-inherited-copy-bound.rs:15:16
+  --> $DIR/inherited-copy-bound.rs:15:16
    |
 LL |     take_param(&x);
    |     ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>`
@@ -7,27 +7,27 @@ LL |     take_param(&x);
    |     required by a bound introduced by this call
    |
 note: required for `Box<{integer}>` to implement `Foo`
-  --> $DIR/kindck-inherited-copy-bound.rs:9:15
+  --> $DIR/inherited-copy-bound.rs:9:15
    |
 LL | impl<T: Copy> Foo for T {}
    |         ----  ^^^     ^
    |         |
    |         unsatisfied trait bound introduced here
 note: required by a bound in `take_param`
-  --> $DIR/kindck-inherited-copy-bound.rs:11:18
+  --> $DIR/inherited-copy-bound.rs:11:18
    |
 LL | fn take_param<T: Foo>(foo: &T) {}
    |                  ^^^ required by this bound in `take_param`
 
 error[E0038]: the trait `Foo` is not dyn compatible
-  --> $DIR/kindck-inherited-copy-bound.rs:21:24
+  --> $DIR/inherited-copy-bound.rs:21:24
    |
 LL |     let z = &x as &dyn Foo;
    |                        ^^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
       for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/kindck-inherited-copy-bound.rs:5:12
+  --> $DIR/inherited-copy-bound.rs:5:12
    |
 LL | trait Foo: Copy {
    |       ---  ^^^^ ...because it requires `Self: Sized`
diff --git a/tests/ui/kindck/send-trait-objects-basic.rs b/tests/ui/traits/send-trait-objects-basic.rs
similarity index 100%
rename from tests/ui/kindck/send-trait-objects-basic.rs
rename to tests/ui/traits/send-trait-objects-basic.rs
diff --git a/tests/ui/kindck/send-trait-objects-basic.stderr b/tests/ui/traits/send-trait-objects-basic.stderr
similarity index 100%
rename from tests/ui/kindck/send-trait-objects-basic.stderr
rename to tests/ui/traits/send-trait-objects-basic.stderr

From dcd00a81944d13545bf5cf845d09cbfdcab68972 Mon Sep 17 00:00:00 2001
From: cyrgani <ansgar.w.zielke@gmail.com>
Date: Tue, 17 Mar 2026 22:08:51 +0000
Subject: [PATCH 30/34] delete incorrect test

---
 .../kindck-implicit-close-over-mut-var.rs     | 49 -------------------
 1 file changed, 49 deletions(-)
 delete mode 100644 tests/ui/borrowck/kindck-implicit-close-over-mut-var.rs

diff --git a/tests/ui/borrowck/kindck-implicit-close-over-mut-var.rs b/tests/ui/borrowck/kindck-implicit-close-over-mut-var.rs
deleted file mode 100644
index 22ed8bd3beefa..0000000000000
--- a/tests/ui/borrowck/kindck-implicit-close-over-mut-var.rs
+++ /dev/null
@@ -1,49 +0,0 @@
-//@ run-pass
-
-#![allow(unused_must_use)]
-#![allow(dead_code)]
-use std::thread;
-
-fn user(_i: isize) {}
-
-fn foo() {
-    // Here, i is *copied* into the proc (heap closure).
-    // Requires allocation.  The proc's copy is not mutable.
-    let mut i = 0;
-    let t = thread::spawn(move|| {
-        user(i);
-        println!("spawned {}", i)
-    });
-    i += 1;
-    println!("original {}", i);
-    t.join();
-}
-
-fn bar() {
-    // Here, the original i has not been moved, only copied, so is still
-    // mutable outside of the proc.
-    let mut i = 0;
-    while i < 10 {
-        let t = thread::spawn(move|| {
-            user(i);
-        });
-        i += 1;
-        t.join();
-    }
-}
-
-fn car() {
-    // Here, i must be shadowed in the proc to be mutable.
-    let mut i = 0;
-    while i < 10 {
-        let t = thread::spawn(move|| {
-            let mut i = i;
-            i += 1;
-            user(i);
-        });
-        i += 1;
-        t.join();
-    }
-}
-
-pub fn main() {}

From c3e54001ee450a7530ccc25b92688d2b46a5eb6a Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Wed, 18 Mar 2026 08:32:52 +0100
Subject: [PATCH 31/34] borrowck/type_check: remove helper left-over from
 unsized locals

---
 compiler/rustc_borrowck/src/type_check/mod.rs | 17 +++++++----------
 1 file changed, 7 insertions(+), 10 deletions(-)

diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 9aa8f7a2067a5..47f14dc3df62e 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -374,10 +374,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         self.body
     }
 
-    fn unsized_feature_enabled(&self) -> bool {
-        self.tcx().features().unsized_fn_params()
-    }
-
     /// Equate the inferred type and the annotated type for user type annotations
     #[instrument(skip(self), level = "debug")]
     fn check_user_type_annotations(&mut self) {
@@ -660,7 +656,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                     );
                 }
 
-                if !self.unsized_feature_enabled() {
+                if !self.tcx().features().unsized_fn_params() {
                     let trait_ref = ty::TraitRef::new(
                         tcx,
                         tcx.require_lang_item(LangItem::Sized, self.last_span),
@@ -936,9 +932,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
             }
         }
 
-        // When `unsized_fn_params` is enabled, only function calls
-        // and nullary ops are checked in `check_call_dest`.
-        if !self.unsized_feature_enabled() {
+        // When `unsized_fn_params` is enabled, this is checked in `check_call_dest`,
+        // and `hir_typeck` still forces all non-argument locals to be sized (i.e., we don't
+        // fully re-check what was already checked on HIR).
+        if !self.tcx().features().unsized_fn_params() {
             match self.body.local_kind(local) {
                 LocalKind::ReturnPointer | LocalKind::Arg => {
                     // return values of normal functions are required to be
@@ -1953,8 +1950,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             }
 
             // When `unsized_fn_params` is not enabled,
-            // this check is done at `check_local`.
-            if self.unsized_feature_enabled() {
+            // this check is done at `visit_local_decl`.
+            if self.tcx().features().unsized_fn_params() {
                 let span = term.source_info.span;
                 self.ensure_place_sized(dest_ty, span);
             }

From f5b84a97670cf98cecc277f08025e6f4ecf82588 Mon Sep 17 00:00:00 2001
From: cyrgani <ansgar.w.zielke@gmail.com>
Date: Wed, 18 Mar 2026 09:37:35 +0000
Subject: [PATCH 32/34] merge `regions-outlives-nominal-type-*` tests into one
 file

---
 ...s-outlives-nominal-type-enum-region-rev.rs | 20 -----
 ...gions-outlives-nominal-type-enum-region.rs | 20 -----
 ...ons-outlives-nominal-type-enum-type-rev.rs | 20 -----
 ...regions-outlives-nominal-type-enum-type.rs | 20 -----
 ...outlives-nominal-type-struct-region-rev.rs | 20 -----
 ...ons-outlives-nominal-type-struct-region.rs | 20 -----
 ...s-outlives-nominal-type-struct-type-rev.rs | 20 -----
 ...gions-outlives-nominal-type-struct-type.rs | 20 -----
 .../regions/regions-outlives-nominal-type.rs  | 80 +++++++++++++++++++
 9 files changed, 80 insertions(+), 160 deletions(-)
 delete mode 100644 tests/ui/regions/regions-outlives-nominal-type-enum-region-rev.rs
 delete mode 100644 tests/ui/regions/regions-outlives-nominal-type-enum-region.rs
 delete mode 100644 tests/ui/regions/regions-outlives-nominal-type-enum-type-rev.rs
 delete mode 100644 tests/ui/regions/regions-outlives-nominal-type-enum-type.rs
 delete mode 100644 tests/ui/regions/regions-outlives-nominal-type-struct-region-rev.rs
 delete mode 100644 tests/ui/regions/regions-outlives-nominal-type-struct-region.rs
 delete mode 100644 tests/ui/regions/regions-outlives-nominal-type-struct-type-rev.rs
 delete mode 100644 tests/ui/regions/regions-outlives-nominal-type-struct-type.rs
 create mode 100644 tests/ui/regions/regions-outlives-nominal-type.rs

diff --git a/tests/ui/regions/regions-outlives-nominal-type-enum-region-rev.rs b/tests/ui/regions/regions-outlives-nominal-type-enum-region-rev.rs
deleted file mode 100644
index 3d4a305078843..0000000000000
--- a/tests/ui/regions/regions-outlives-nominal-type-enum-region-rev.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its
-// arguments (like `'a`) outlive `'b`.
-//
-// Rule OutlivesNominalType from RFC 1214.
-
-//@ check-pass
-
-#![feature(rustc_attrs)]
-#![allow(dead_code)]
-
-mod rev_variant_struct_region {
-    struct Foo<'a> {
-        x: fn(&'a i32),
-    }
-    enum Bar<'a,'b> {
-        V(&'a Foo<'b>)
-    }
-}
-
-fn main() { }
diff --git a/tests/ui/regions/regions-outlives-nominal-type-enum-region.rs b/tests/ui/regions/regions-outlives-nominal-type-enum-region.rs
deleted file mode 100644
index 2e0d1b36ca59e..0000000000000
--- a/tests/ui/regions/regions-outlives-nominal-type-enum-region.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its
-// arguments (like `'a`) outlive `'b`.
-//
-// Rule OutlivesNominalType from RFC 1214.
-
-//@ check-pass
-
-#![feature(rustc_attrs)]
-#![allow(dead_code)]
-
-mod variant_struct_region {
-    struct Foo<'a> {
-        x: &'a i32,
-    }
-    enum Bar<'a,'b> {
-        V(&'a Foo<'b>)
-    }
-}
-
-fn main() { }
diff --git a/tests/ui/regions/regions-outlives-nominal-type-enum-type-rev.rs b/tests/ui/regions/regions-outlives-nominal-type-enum-type-rev.rs
deleted file mode 100644
index baf7874bc1a61..0000000000000
--- a/tests/ui/regions/regions-outlives-nominal-type-enum-type-rev.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its
-// arguments (like `'a`) outlive `'b`.
-//
-// Rule OutlivesNominalType from RFC 1214.
-
-//@ check-pass
-
-#![feature(rustc_attrs)]
-#![allow(dead_code)]
-
-mod variant_struct_type {
-    struct Foo<T> {
-        x: fn(T)
-    }
-    enum Bar<'a,'b> {
-        V(&'a Foo<&'b i32>)
-    }
-}
-
-fn main() { }
diff --git a/tests/ui/regions/regions-outlives-nominal-type-enum-type.rs b/tests/ui/regions/regions-outlives-nominal-type-enum-type.rs
deleted file mode 100644
index b8392c967b10a..0000000000000
--- a/tests/ui/regions/regions-outlives-nominal-type-enum-type.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its
-// arguments (like `'a`) outlive `'b`.
-//
-// Rule OutlivesNominalType from RFC 1214.
-
-//@ check-pass
-
-#![feature(rustc_attrs)]
-#![allow(dead_code)]
-
-mod variant_struct_type {
-    struct Foo<T> {
-        x: T
-    }
-    enum Bar<'a,'b> {
-        V(&'a Foo<&'b i32>)
-    }
-}
-
-fn main() { }
diff --git a/tests/ui/regions/regions-outlives-nominal-type-struct-region-rev.rs b/tests/ui/regions/regions-outlives-nominal-type-struct-region-rev.rs
deleted file mode 100644
index 6a50248cb70b0..0000000000000
--- a/tests/ui/regions/regions-outlives-nominal-type-struct-region-rev.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its
-// arguments (like `'a`) outlive `'b`.
-//
-// Rule OutlivesNominalType from RFC 1214.
-
-//@ check-pass
-
-#![feature(rustc_attrs)]
-#![allow(dead_code)]
-
-mod rev_variant_struct_region {
-    struct Foo<'a> {
-        x: fn(&'a i32),
-    }
-    struct Bar<'a,'b> {
-        f: &'a Foo<'b>
-    }
-}
-
-fn main() { }
diff --git a/tests/ui/regions/regions-outlives-nominal-type-struct-region.rs b/tests/ui/regions/regions-outlives-nominal-type-struct-region.rs
deleted file mode 100644
index 17564bcbf269f..0000000000000
--- a/tests/ui/regions/regions-outlives-nominal-type-struct-region.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its
-// arguments (like `'a`) outlive `'b`.
-//
-// Rule OutlivesNominalType from RFC 1214.
-
-//@ check-pass
-
-#![feature(rustc_attrs)]
-#![allow(dead_code)]
-
-mod variant_struct_region {
-    struct Foo<'a> {
-        x: &'a i32,
-    }
-    struct Bar<'a,'b> {
-        f: &'a Foo<'b>
-    }
-}
-
-fn main() { }
diff --git a/tests/ui/regions/regions-outlives-nominal-type-struct-type-rev.rs b/tests/ui/regions/regions-outlives-nominal-type-struct-type-rev.rs
deleted file mode 100644
index 33961de7d6a45..0000000000000
--- a/tests/ui/regions/regions-outlives-nominal-type-struct-type-rev.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its
-// arguments (like `'a`) outlive `'b`.
-//
-// Rule OutlivesNominalType from RFC 1214.
-
-//@ check-pass
-
-#![feature(rustc_attrs)]
-#![allow(dead_code)]
-
-mod rev_variant_struct_type {
-    struct Foo<T> {
-        x: fn(T)
-    }
-    struct Bar<'a,'b> {
-        f: &'a Foo<&'b i32>
-    }
-}
-
-fn main() { }
diff --git a/tests/ui/regions/regions-outlives-nominal-type-struct-type.rs b/tests/ui/regions/regions-outlives-nominal-type-struct-type.rs
deleted file mode 100644
index c5238086fc05d..0000000000000
--- a/tests/ui/regions/regions-outlives-nominal-type-struct-type.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its
-// arguments (like `'a`) outlive `'b`.
-//
-// Rule OutlivesNominalType from RFC 1214.
-
-//@ check-pass
-
-#![feature(rustc_attrs)]
-#![allow(dead_code)]
-
-mod variant_struct_type {
-    struct Foo<T> {
-        x: T
-    }
-    struct Bar<'a,'b> {
-        f: &'a Foo<&'b i32>
-    }
-}
-
-fn main() { }
diff --git a/tests/ui/regions/regions-outlives-nominal-type.rs b/tests/ui/regions/regions-outlives-nominal-type.rs
new file mode 100644
index 0000000000000..177d064042dd8
--- /dev/null
+++ b/tests/ui/regions/regions-outlives-nominal-type.rs
@@ -0,0 +1,80 @@
+// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its
+// arguments (like `'a`) outlive `'b`.
+//
+// Rule OutlivesNominalType from RFC 1214.
+
+//@ check-pass
+
+mod variant_enum_region {
+    struct Foo<'a> {
+        x: &'a i32,
+    }
+    enum Bar<'a, 'b> {
+        V(&'a Foo<'b>),
+    }
+}
+
+mod rev_variant_enum_region {
+    struct Foo<'a> {
+        x: fn(&'a i32),
+    }
+    enum Bar<'a, 'b> {
+        V(&'a Foo<'b>),
+    }
+}
+
+mod variant_enum_type {
+    struct Foo<T> {
+        x: T,
+    }
+    enum Bar<'a, 'b> {
+        V(&'a Foo<&'b i32>),
+    }
+}
+
+mod rev_variant_enum_type {
+    struct Foo<T> {
+        x: fn(T),
+    }
+    enum Bar<'a, 'b> {
+        V(&'a Foo<&'b i32>),
+    }
+}
+
+mod variant_struct_region {
+    struct Foo<'a> {
+        x: &'a i32,
+    }
+    struct Bar<'a, 'b> {
+        f: &'a Foo<'b>,
+    }
+}
+
+mod rev_variant_struct_region {
+    struct Foo<'a> {
+        x: fn(&'a i32),
+    }
+    struct Bar<'a, 'b> {
+        f: &'a Foo<'b>,
+    }
+}
+
+mod variant_struct_type {
+    struct Foo<T> {
+        x: T,
+    }
+    struct Bar<'a, 'b> {
+        f: &'a Foo<&'b i32>,
+    }
+}
+
+mod rev_variant_struct_type {
+    struct Foo<T> {
+        x: fn(T),
+    }
+    struct Bar<'a, 'b> {
+        f: &'a Foo<&'b i32>,
+    }
+}
+
+fn main() {}

From 2e59baf6572e09b5a3cf911a0010292772b8c80c Mon Sep 17 00:00:00 2001
From: Jynn Nelson <jynn.nelson@ferrous-systems.com>
Date: Wed, 18 Mar 2026 12:21:09 +0100
Subject: [PATCH 33/34] Move hashes into a separate json file

---
 src/bootstrap/src/core/build_steps/setup.rs   | 66 ++++---------------
 .../src/core/build_steps/setup/hashes.json    | 53 +++++++++++++++
 .../src/core/build_steps/setup/tests.rs       | 10 ++-
 3 files changed, 69 insertions(+), 60 deletions(-)
 create mode 100644 src/bootstrap/src/core/build_steps/setup/hashes.json

diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs
index f4e6a20ec8497..1854637fc93ba 100644
--- a/src/bootstrap/src/core/build_steps/setup.rs
+++ b/src/bootstrap/src/core/build_steps/setup.rs
@@ -12,7 +12,10 @@ use std::io::Write;
 use std::path::{MAIN_SEPARATOR_STR, Path, PathBuf};
 use std::str::FromStr;
 use std::{fmt, fs, io};
+use std::collections::HashMap;
+use std::sync::LazyLock;
 
+use serde_derive::Deserialize;
 use sha2::Digest;
 
 use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
@@ -529,7 +532,8 @@ undesirable, simply delete the `pre-push` file from .git/hooks."
 }
 
 /// Handles editor-specific setup differences
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq, Hash, Deserialize)]
+#[serde(rename_all = "lowercase")]
 enum EditorKind {
     Emacs,
     Helix,
@@ -588,59 +592,13 @@ Select which editor you would like to set up [default: None]: ";
     /// New entries should be appended whenever this is updated so we can detect
     /// outdated vs. user-modified settings files.
     fn hashes(&self) -> &'static [&'static str] {
-        match self {
-            EditorKind::Emacs => &[
-                "51068d4747a13732440d1a8b8f432603badb1864fa431d83d0fd4f8fa57039e0",
-                "d29af4d949bbe2371eac928a3c31cf9496b1701aa1c45f11cd6c759865ad5c45",
-                "b5dd299b93dca3ceeb9b335f929293cb3d4bf4977866fbe7ceeac2a8a9f99088",
-                "631c837b0e98ae35fd48b0e5f743b1ca60adadf2d0a2b23566ba25df372cf1a9",
-                "080955765db84bb6cbf178879f489c4e2369397626a6ecb3debedb94a9d0b3ce",
-                "f501475c6654187091c924ae26187fa5791d74d4a8ab3fb61fbbe4c0275aade1",
-                "54bc48fe1996177f5eef86d7231b33978e6d8b737cb0a899e622b7e975c95308",
-                "08d30e455ceec6e01d9bcef8b9449f2ddd14d278ca8627cdad90e02d9f44e938",
-            ],
-            EditorKind::Helix => &[
-                "2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233",
-                "6736d61409fbebba0933afd2e4c44ff2f97c1cb36cf0299a7f4a7819b8775040",
-                "f252dcc30ca85a193a699581e5e929d5bd6c19d40d7a7ade5e257a9517a124a5",
-                "198c195ed0c070d15907b279b8b4ea96198ca71b939f5376454f3d636ab54da5",
-                "1c43ead340b20792b91d02b08494ee68708e7e09f56b6766629b4b72079208f1",
-                "eec09a09452682060afd23dd5d3536ccac5615b3cdbf427366446901215fb9f6",
-                "cb653043852d9d5ff4a5be56407b859ff9928be055ad3f307eb309aad04765e6",
-                "e28b1930d16d3d8bbdeed7bd4a995613e648b49e08c9b6f5271880f520637fed",
-            ],
-            EditorKind::Vim | EditorKind::VsCode => &[
-                "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8",
-                "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922",
-                "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0",
-                "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541",
-                "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923",
-                "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a",
-                "828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000",
-                "811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d",
-                "4eecb58a2168b252077369da446c30ed0e658301efe69691979d1ef0443928f4",
-                "c394386e6133bbf29ffd32c8af0bb3d4aac354cba9ee051f29612aa9350f8f8d",
-                "e53e9129ca5ee5dcbd6ec8b68c2d87376474eb154992deba3c6d9ab1703e0717",
-                "f954316090936c7e590c253ca9d524008375882fa13c5b41d7e2547a896ff893",
-                "701b73751efd7abd6487f2c79348dab698af7ac4427b79fa3d2087c867144b12",
-                "a61df796c0c007cb6512127330564e49e57d558dec715703916a928b072a1054",
-                "02a49ac2d31f00ef6e4531c44e00dac51cea895112e480553f1ba060b3942a47",
-                "0aa4748848de0d1cb7ece92a0123c8897fef6de2f58aff8fda1426f098b7a798",
-                "e5e357862e5d6d0d9da335e9823c07b8a7dc42bbf18d72cc5206ad1049cd8fcc",
-                "a68fd5828e75f3e921f265e29ce1e9efa554083c3773fdb4b8e1ab3b2d9dc6cd",
-            ],
-            EditorKind::Zed => &[
-                "bbce727c269d1bd0c98afef4d612eb4ce27aea3c3a8968c5f10b31affbc40b6c",
-                "a5380cf5dd9328731aecc5dfb240d16dac46ed272126b9728006151ef42f5909",
-                "2e96bf0d443852b12f016c8fc9840ab3d0a2b4fe0b0fb3a157e8d74d5e7e0e26",
-                "4fadd4c87389a601a27db0d3d74a142fa3a2e656ae78982e934dbe24bee32ad6",
-                "f0bb3d23ab1a49175ab0ef5c4071af95bb03d01d460776cdb716d91333443382",
-                "5ef83292111d9a8bb63b6afc3abf42d0bc78fe24985f0d2e039e73258b5dab8f",
-                "74420c13094b530a986b37c4f1d23cb58c0e8e2295f5858ded129fb1574e66f9",
-                "2d3b592c089b2ad2c528686a1e371af49922edad1c59accd5d5f31612a441568",
-                "0767a2398ccc253274b184adbb9e018ce931bd0ef45baad06dad19b652c52951",
-            ],
-        }
+        const ALL_HASHES: &str = include_str!("setup/hashes.json");
+        static PARSED_HASHES: LazyLock<HashMap<EditorKind, Vec<&'static str>>> = LazyLock::new(|| {
+            let mut map: HashMap<_, Vec<_>> = serde_json::from_str(ALL_HASHES).unwrap();
+            map.insert(EditorKind::Vim, map.get(&EditorKind::VsCode).unwrap().clone());
+            map
+        });
+        &*PARSED_HASHES.get(self).unwrap()
     }
 
     fn settings_path(&self, config: &Config) -> PathBuf {
diff --git a/src/bootstrap/src/core/build_steps/setup/hashes.json b/src/bootstrap/src/core/build_steps/setup/hashes.json
new file mode 100644
index 0000000000000..be657b5772002
--- /dev/null
+++ b/src/bootstrap/src/core/build_steps/setup/hashes.json
@@ -0,0 +1,53 @@
+{
+    "emacs": [
+        "51068d4747a13732440d1a8b8f432603badb1864fa431d83d0fd4f8fa57039e0",
+        "d29af4d949bbe2371eac928a3c31cf9496b1701aa1c45f11cd6c759865ad5c45",
+        "b5dd299b93dca3ceeb9b335f929293cb3d4bf4977866fbe7ceeac2a8a9f99088",
+        "631c837b0e98ae35fd48b0e5f743b1ca60adadf2d0a2b23566ba25df372cf1a9",
+        "080955765db84bb6cbf178879f489c4e2369397626a6ecb3debedb94a9d0b3ce",
+        "f501475c6654187091c924ae26187fa5791d74d4a8ab3fb61fbbe4c0275aade1",
+        "54bc48fe1996177f5eef86d7231b33978e6d8b737cb0a899e622b7e975c95308",
+        "08d30e455ceec6e01d9bcef8b9449f2ddd14d278ca8627cdad90e02d9f44e938"
+    ],
+    "helix": [
+        "2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233",
+        "6736d61409fbebba0933afd2e4c44ff2f97c1cb36cf0299a7f4a7819b8775040",
+        "f252dcc30ca85a193a699581e5e929d5bd6c19d40d7a7ade5e257a9517a124a5",
+        "198c195ed0c070d15907b279b8b4ea96198ca71b939f5376454f3d636ab54da5",
+        "1c43ead340b20792b91d02b08494ee68708e7e09f56b6766629b4b72079208f1",
+        "eec09a09452682060afd23dd5d3536ccac5615b3cdbf427366446901215fb9f6",
+        "cb653043852d9d5ff4a5be56407b859ff9928be055ad3f307eb309aad04765e6",
+        "e28b1930d16d3d8bbdeed7bd4a995613e648b49e08c9b6f5271880f520637fed"
+    ],
+    "vscode": [
+        "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8",
+        "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922",
+        "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0",
+        "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541",
+        "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923",
+        "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a",
+        "828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000",
+        "811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d",
+        "4eecb58a2168b252077369da446c30ed0e658301efe69691979d1ef0443928f4",
+        "c394386e6133bbf29ffd32c8af0bb3d4aac354cba9ee051f29612aa9350f8f8d",
+        "e53e9129ca5ee5dcbd6ec8b68c2d87376474eb154992deba3c6d9ab1703e0717",
+        "f954316090936c7e590c253ca9d524008375882fa13c5b41d7e2547a896ff893",
+        "701b73751efd7abd6487f2c79348dab698af7ac4427b79fa3d2087c867144b12",
+        "a61df796c0c007cb6512127330564e49e57d558dec715703916a928b072a1054",
+        "02a49ac2d31f00ef6e4531c44e00dac51cea895112e480553f1ba060b3942a47",
+        "0aa4748848de0d1cb7ece92a0123c8897fef6de2f58aff8fda1426f098b7a798",
+        "e5e357862e5d6d0d9da335e9823c07b8a7dc42bbf18d72cc5206ad1049cd8fcc",
+        "a68fd5828e75f3e921f265e29ce1e9efa554083c3773fdb4b8e1ab3b2d9dc6cd"
+    ],
+    "zed": [
+        "bbce727c269d1bd0c98afef4d612eb4ce27aea3c3a8968c5f10b31affbc40b6c",
+        "a5380cf5dd9328731aecc5dfb240d16dac46ed272126b9728006151ef42f5909",
+        "2e96bf0d443852b12f016c8fc9840ab3d0a2b4fe0b0fb3a157e8d74d5e7e0e26",
+        "4fadd4c87389a601a27db0d3d74a142fa3a2e656ae78982e934dbe24bee32ad6",
+        "f0bb3d23ab1a49175ab0ef5c4071af95bb03d01d460776cdb716d91333443382",
+        "5ef83292111d9a8bb63b6afc3abf42d0bc78fe24985f0d2e039e73258b5dab8f",
+        "74420c13094b530a986b37c4f1d23cb58c0e8e2295f5858ded129fb1574e66f9",
+        "2d3b592c089b2ad2c528686a1e371af49922edad1c59accd5d5f31612a441568",
+        "0767a2398ccc253274b184adbb9e018ce931bd0ef45baad06dad19b652c52951"
+    ]
+}
diff --git a/src/bootstrap/src/core/build_steps/setup/tests.rs b/src/bootstrap/src/core/build_steps/setup/tests.rs
index e8f83ff75e404..6eafbb40b4674 100644
--- a/src/bootstrap/src/core/build_steps/setup/tests.rs
+++ b/src/bootstrap/src/core/build_steps/setup/tests.rs
@@ -8,13 +8,11 @@ fn check_matching_settings_hash() {
     for editor in EditorKind::ALL {
         let mut hasher = sha2::Sha256::new();
         hasher.update(&editor.settings_template());
-        let hash = hex_encode(hasher.finalize().as_slice());
+        let actual = hex_encode(hasher.finalize().as_slice());
+        let expected = *editor.hashes().last().unwrap();
         assert_eq!(
-            &hash,
-            editor.hashes().last().unwrap(),
-            "Update `EditorKind::hashes()` with the new hash of `{}` for `EditorKind::{:?}`",
-            editor.settings_template(),
-            editor,
+            expected, actual,
+            "Update `setup/hashes.json` with the new hash of `{actual}` for `EditorKind::{editor:?}`",
         );
     }
 }

From 4a39306be2ec6e3078669249010a006983f74879 Mon Sep 17 00:00:00 2001
From: Jynn Nelson <jynn.nelson@ferrous-systems.com>
Date: Wed, 18 Mar 2026 13:35:58 +0100
Subject: [PATCH 34/34] Support `--bless`-ing editor hashes

---
 src/bootstrap/src/core/build_steps/setup.rs   |  23 ++--
 .../src/core/build_steps/setup/hashes.json    | 122 ++++++++++--------
 .../src/core/build_steps/setup/tests.rs       |  40 +++++-
 3 files changed, 119 insertions(+), 66 deletions(-)

diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs
index 1854637fc93ba..85c23ac18e763 100644
--- a/src/bootstrap/src/core/build_steps/setup.rs
+++ b/src/bootstrap/src/core/build_steps/setup.rs
@@ -5,17 +5,17 @@
 //! allows setting up things that cannot be simply captured inside the bootstrap.toml, in addition to
 //! leading people away from manually editing most of the bootstrap.toml values.
 
+use std::collections::BTreeMap;
 use std::env::consts::EXE_SUFFIX;
 use std::fmt::Write as _;
 use std::fs::File;
 use std::io::Write;
 use std::path::{MAIN_SEPARATOR_STR, Path, PathBuf};
 use std::str::FromStr;
-use std::{fmt, fs, io};
-use std::collections::HashMap;
 use std::sync::LazyLock;
+use std::{fmt, fs, io};
 
-use serde_derive::Deserialize;
+use serde_derive::{Deserialize, Serialize};
 use sha2::Digest;
 
 use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
@@ -532,7 +532,7 @@ undesirable, simply delete the `pre-push` file from .git/hooks."
 }
 
 /// Handles editor-specific setup differences
-#[derive(Clone, Debug, Eq, PartialEq, Hash, Deserialize)]
+#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
 #[serde(rename_all = "lowercase")]
 enum EditorKind {
     Emacs,
@@ -542,6 +542,13 @@ enum EditorKind {
     Zed,
 }
 
+static PARSED_HASHES: LazyLock<BTreeMap<EditorKind, Vec<&'static str>>> = LazyLock::new(|| {
+    const ALL_HASHES: &str = include_str!("setup/hashes.json");
+    let mut map: BTreeMap<_, Vec<_>> = serde_json::from_str(ALL_HASHES).unwrap();
+    map.insert(EditorKind::Vim, map.get(&EditorKind::VsCode).unwrap().clone());
+    map
+});
+
 impl EditorKind {
     // Used in `./tests.rs`.
     #[cfg(test)]
@@ -592,13 +599,7 @@ Select which editor you would like to set up [default: None]: ";
     /// New entries should be appended whenever this is updated so we can detect
     /// outdated vs. user-modified settings files.
     fn hashes(&self) -> &'static [&'static str] {
-        const ALL_HASHES: &str = include_str!("setup/hashes.json");
-        static PARSED_HASHES: LazyLock<HashMap<EditorKind, Vec<&'static str>>> = LazyLock::new(|| {
-            let mut map: HashMap<_, Vec<_>> = serde_json::from_str(ALL_HASHES).unwrap();
-            map.insert(EditorKind::Vim, map.get(&EditorKind::VsCode).unwrap().clone());
-            map
-        });
-        &*PARSED_HASHES.get(self).unwrap()
+        PARSED_HASHES.get(self).unwrap()
     }
 
     fn settings_path(&self, config: &Config) -> PathBuf {
diff --git a/src/bootstrap/src/core/build_steps/setup/hashes.json b/src/bootstrap/src/core/build_steps/setup/hashes.json
index be657b5772002..067c8fffe0d50 100644
--- a/src/bootstrap/src/core/build_steps/setup/hashes.json
+++ b/src/bootstrap/src/core/build_steps/setup/hashes.json
@@ -1,53 +1,73 @@
 {
-    "emacs": [
-        "51068d4747a13732440d1a8b8f432603badb1864fa431d83d0fd4f8fa57039e0",
-        "d29af4d949bbe2371eac928a3c31cf9496b1701aa1c45f11cd6c759865ad5c45",
-        "b5dd299b93dca3ceeb9b335f929293cb3d4bf4977866fbe7ceeac2a8a9f99088",
-        "631c837b0e98ae35fd48b0e5f743b1ca60adadf2d0a2b23566ba25df372cf1a9",
-        "080955765db84bb6cbf178879f489c4e2369397626a6ecb3debedb94a9d0b3ce",
-        "f501475c6654187091c924ae26187fa5791d74d4a8ab3fb61fbbe4c0275aade1",
-        "54bc48fe1996177f5eef86d7231b33978e6d8b737cb0a899e622b7e975c95308",
-        "08d30e455ceec6e01d9bcef8b9449f2ddd14d278ca8627cdad90e02d9f44e938"
-    ],
-    "helix": [
-        "2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233",
-        "6736d61409fbebba0933afd2e4c44ff2f97c1cb36cf0299a7f4a7819b8775040",
-        "f252dcc30ca85a193a699581e5e929d5bd6c19d40d7a7ade5e257a9517a124a5",
-        "198c195ed0c070d15907b279b8b4ea96198ca71b939f5376454f3d636ab54da5",
-        "1c43ead340b20792b91d02b08494ee68708e7e09f56b6766629b4b72079208f1",
-        "eec09a09452682060afd23dd5d3536ccac5615b3cdbf427366446901215fb9f6",
-        "cb653043852d9d5ff4a5be56407b859ff9928be055ad3f307eb309aad04765e6",
-        "e28b1930d16d3d8bbdeed7bd4a995613e648b49e08c9b6f5271880f520637fed"
-    ],
-    "vscode": [
-        "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8",
-        "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922",
-        "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0",
-        "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541",
-        "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923",
-        "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a",
-        "828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000",
-        "811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d",
-        "4eecb58a2168b252077369da446c30ed0e658301efe69691979d1ef0443928f4",
-        "c394386e6133bbf29ffd32c8af0bb3d4aac354cba9ee051f29612aa9350f8f8d",
-        "e53e9129ca5ee5dcbd6ec8b68c2d87376474eb154992deba3c6d9ab1703e0717",
-        "f954316090936c7e590c253ca9d524008375882fa13c5b41d7e2547a896ff893",
-        "701b73751efd7abd6487f2c79348dab698af7ac4427b79fa3d2087c867144b12",
-        "a61df796c0c007cb6512127330564e49e57d558dec715703916a928b072a1054",
-        "02a49ac2d31f00ef6e4531c44e00dac51cea895112e480553f1ba060b3942a47",
-        "0aa4748848de0d1cb7ece92a0123c8897fef6de2f58aff8fda1426f098b7a798",
-        "e5e357862e5d6d0d9da335e9823c07b8a7dc42bbf18d72cc5206ad1049cd8fcc",
-        "a68fd5828e75f3e921f265e29ce1e9efa554083c3773fdb4b8e1ab3b2d9dc6cd"
-    ],
-    "zed": [
-        "bbce727c269d1bd0c98afef4d612eb4ce27aea3c3a8968c5f10b31affbc40b6c",
-        "a5380cf5dd9328731aecc5dfb240d16dac46ed272126b9728006151ef42f5909",
-        "2e96bf0d443852b12f016c8fc9840ab3d0a2b4fe0b0fb3a157e8d74d5e7e0e26",
-        "4fadd4c87389a601a27db0d3d74a142fa3a2e656ae78982e934dbe24bee32ad6",
-        "f0bb3d23ab1a49175ab0ef5c4071af95bb03d01d460776cdb716d91333443382",
-        "5ef83292111d9a8bb63b6afc3abf42d0bc78fe24985f0d2e039e73258b5dab8f",
-        "74420c13094b530a986b37c4f1d23cb58c0e8e2295f5858ded129fb1574e66f9",
-        "2d3b592c089b2ad2c528686a1e371af49922edad1c59accd5d5f31612a441568",
-        "0767a2398ccc253274b184adbb9e018ce931bd0ef45baad06dad19b652c52951"
-    ]
+  "emacs": [
+    "51068d4747a13732440d1a8b8f432603badb1864fa431d83d0fd4f8fa57039e0",
+    "d29af4d949bbe2371eac928a3c31cf9496b1701aa1c45f11cd6c759865ad5c45",
+    "b5dd299b93dca3ceeb9b335f929293cb3d4bf4977866fbe7ceeac2a8a9f99088",
+    "631c837b0e98ae35fd48b0e5f743b1ca60adadf2d0a2b23566ba25df372cf1a9",
+    "080955765db84bb6cbf178879f489c4e2369397626a6ecb3debedb94a9d0b3ce",
+    "f501475c6654187091c924ae26187fa5791d74d4a8ab3fb61fbbe4c0275aade1",
+    "54bc48fe1996177f5eef86d7231b33978e6d8b737cb0a899e622b7e975c95308",
+    "08d30e455ceec6e01d9bcef8b9449f2ddd14d278ca8627cdad90e02d9f44e938"
+  ],
+  "helix": [
+    "2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233",
+    "6736d61409fbebba0933afd2e4c44ff2f97c1cb36cf0299a7f4a7819b8775040",
+    "f252dcc30ca85a193a699581e5e929d5bd6c19d40d7a7ade5e257a9517a124a5",
+    "198c195ed0c070d15907b279b8b4ea96198ca71b939f5376454f3d636ab54da5",
+    "1c43ead340b20792b91d02b08494ee68708e7e09f56b6766629b4b72079208f1",
+    "eec09a09452682060afd23dd5d3536ccac5615b3cdbf427366446901215fb9f6",
+    "cb653043852d9d5ff4a5be56407b859ff9928be055ad3f307eb309aad04765e6",
+    "e28b1930d16d3d8bbdeed7bd4a995613e648b49e08c9b6f5271880f520637fed"
+  ],
+  "vim": [
+    "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8",
+    "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922",
+    "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0",
+    "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541",
+    "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923",
+    "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a",
+    "828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000",
+    "811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d",
+    "4eecb58a2168b252077369da446c30ed0e658301efe69691979d1ef0443928f4",
+    "c394386e6133bbf29ffd32c8af0bb3d4aac354cba9ee051f29612aa9350f8f8d",
+    "e53e9129ca5ee5dcbd6ec8b68c2d87376474eb154992deba3c6d9ab1703e0717",
+    "f954316090936c7e590c253ca9d524008375882fa13c5b41d7e2547a896ff893",
+    "701b73751efd7abd6487f2c79348dab698af7ac4427b79fa3d2087c867144b12",
+    "a61df796c0c007cb6512127330564e49e57d558dec715703916a928b072a1054",
+    "02a49ac2d31f00ef6e4531c44e00dac51cea895112e480553f1ba060b3942a47",
+    "0aa4748848de0d1cb7ece92a0123c8897fef6de2f58aff8fda1426f098b7a798",
+    "e5e357862e5d6d0d9da335e9823c07b8a7dc42bbf18d72cc5206ad1049cd8fcc",
+    "a68fd5828e75f3e921f265e29ce1e9efa554083c3773fdb4b8e1ab3b2d9dc6cd"
+  ],
+  "vscode": [
+    "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8",
+    "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922",
+    "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0",
+    "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541",
+    "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923",
+    "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a",
+    "828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000",
+    "811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d",
+    "4eecb58a2168b252077369da446c30ed0e658301efe69691979d1ef0443928f4",
+    "c394386e6133bbf29ffd32c8af0bb3d4aac354cba9ee051f29612aa9350f8f8d",
+    "e53e9129ca5ee5dcbd6ec8b68c2d87376474eb154992deba3c6d9ab1703e0717",
+    "f954316090936c7e590c253ca9d524008375882fa13c5b41d7e2547a896ff893",
+    "701b73751efd7abd6487f2c79348dab698af7ac4427b79fa3d2087c867144b12",
+    "a61df796c0c007cb6512127330564e49e57d558dec715703916a928b072a1054",
+    "02a49ac2d31f00ef6e4531c44e00dac51cea895112e480553f1ba060b3942a47",
+    "0aa4748848de0d1cb7ece92a0123c8897fef6de2f58aff8fda1426f098b7a798",
+    "e5e357862e5d6d0d9da335e9823c07b8a7dc42bbf18d72cc5206ad1049cd8fcc",
+    "a68fd5828e75f3e921f265e29ce1e9efa554083c3773fdb4b8e1ab3b2d9dc6cd"
+  ],
+  "zed": [
+    "bbce727c269d1bd0c98afef4d612eb4ce27aea3c3a8968c5f10b31affbc40b6c",
+    "a5380cf5dd9328731aecc5dfb240d16dac46ed272126b9728006151ef42f5909",
+    "2e96bf0d443852b12f016c8fc9840ab3d0a2b4fe0b0fb3a157e8d74d5e7e0e26",
+    "4fadd4c87389a601a27db0d3d74a142fa3a2e656ae78982e934dbe24bee32ad6",
+    "f0bb3d23ab1a49175ab0ef5c4071af95bb03d01d460776cdb716d91333443382",
+    "5ef83292111d9a8bb63b6afc3abf42d0bc78fe24985f0d2e039e73258b5dab8f",
+    "74420c13094b530a986b37c4f1d23cb58c0e8e2295f5858ded129fb1574e66f9",
+    "2d3b592c089b2ad2c528686a1e371af49922edad1c59accd5d5f31612a441568",
+    "0767a2398ccc253274b184adbb9e018ce931bd0ef45baad06dad19b652c52951"
+  ]
 }
diff --git a/src/bootstrap/src/core/build_steps/setup/tests.rs b/src/bootstrap/src/core/build_steps/setup/tests.rs
index 6eafbb40b4674..57b5492866614 100644
--- a/src/bootstrap/src/core/build_steps/setup/tests.rs
+++ b/src/bootstrap/src/core/build_steps/setup/tests.rs
@@ -1,3 +1,8 @@
+use std::collections::BTreeMap;
+use std::fs::File;
+use std::io::Write;
+use std::path::Path;
+
 use sha2::Digest;
 
 use super::EditorKind;
@@ -5,14 +10,41 @@ use crate::utils::helpers::hex_encode;
 
 #[test]
 fn check_matching_settings_hash() {
+    // Needs to be a btree so we serialize in a deterministic order.
+    let mut mismatched = BTreeMap::new();
+
     for editor in EditorKind::ALL {
         let mut hasher = sha2::Sha256::new();
         hasher.update(&editor.settings_template());
         let actual = hex_encode(hasher.finalize().as_slice());
         let expected = *editor.hashes().last().unwrap();
-        assert_eq!(
-            expected, actual,
-            "Update `setup/hashes.json` with the new hash of `{actual}` for `EditorKind::{editor:?}`",
-        );
+
+        if expected != actual {
+            mismatched.insert(editor, (expected, actual));
+        }
+    }
+
+    if mismatched.is_empty() {
+        return;
+    }
+
+    if option_env!("INSTA_UPDATE").is_some_and(|s| s != "0") {
+        let mut updated = super::PARSED_HASHES.clone();
+        for (editor, (_, actual)) in &mismatched {
+            *updated.get_mut(editor).unwrap().last_mut().unwrap() = actual;
+        }
+        let hash_path =
+            Path::new(env!("CARGO_MANIFEST_DIR")).join("src/core/build_steps/setup/hashes.json");
+        let mut hash_file = File::create(hash_path).unwrap();
+        serde_json::to_writer_pretty(&mut hash_file, &updated).unwrap();
+        hash_file.write_all(b"\n").unwrap();
+    } else {
+        for (editor, (expected, actual)) in &mismatched {
+            eprintln!("recorded hash did not match actual hash: {expected} != {actual}");
+            eprintln!(
+                "Run `x test --bless -- hash`, or manually update `setup/hashes.json` with the new hash of `{actual}` for `EditorKind::{editor:?}`"
+            );
+        }
+        panic!("mismatched hashes");
     }
 }
