From ec921db289ea87fd4030cb7f8a70f6ba3a31c2c7 Mon Sep 17 00:00:00 2001
From: Pavel Grigorenko <GrigorenkoPV@ya.ru>
Date: Sun, 23 Jun 2024 22:11:35 +0300
Subject: [PATCH 1/7] impl CloneToUninit for str and CStr

---
 library/core/src/clone.rs   | 21 +++++++++++++++++++
 library/core/tests/clone.rs | 40 +++++++++++++++++++++++++++++++++++++
 2 files changed, 61 insertions(+)

diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs
index 76a89eaaff86e..409fd2746f588 100644
--- a/library/core/src/clone.rs
+++ b/library/core/src/clone.rs
@@ -346,6 +346,27 @@ unsafe impl<T: Copy> CloneToUninit for [T] {
     }
 }
 
+#[unstable(feature = "clone_to_uninit", issue = "126799")]
+unsafe impl CloneToUninit for str {
+    #[cfg_attr(debug_assertions, track_caller)]
+    unsafe fn clone_to_uninit(&self, dst: *mut Self) {
+        // SAFETY: str is just a [u8] with UTF-8 invariant
+        unsafe { self.as_bytes().clone_to_uninit(dst as *mut [u8]) }
+    }
+}
+
+#[unstable(feature = "clone_to_uninit", issue = "126799")]
+unsafe impl CloneToUninit for crate::ffi::CStr {
+    #[cfg_attr(debug_assertions, track_caller)]
+    unsafe fn clone_to_uninit(&self, dst: *mut Self) {
+        // SAFETY: For now, CStr is just a #[repr(trasnsparent)] [c_char] with some invariants.
+        // And we can cast [c_char] to [u8] on all supported platforms (see: to_bytes_with_nul).
+        // The pointer metadata properly preserves the length (NUL included).
+        // See: `cstr_metadata_is_length_with_nul` in tests.
+        unsafe { self.to_bytes_with_nul().clone_to_uninit(dst as *mut [u8]) }
+    }
+}
+
 /// Ownership of a collection of values stored in a non-owned `[MaybeUninit<T>]`, some of which
 /// are not yet initialized. This is sort of like a `Vec` that doesn't own its allocation.
 /// Its responsibility is to provide cleanup on unwind by dropping the values that *are*
diff --git a/library/core/tests/clone.rs b/library/core/tests/clone.rs
index b7130f16f8795..71a328733b7c4 100644
--- a/library/core/tests/clone.rs
+++ b/library/core/tests/clone.rs
@@ -1,5 +1,7 @@
 use core::clone::CloneToUninit;
+use core::ffi::CStr;
 use core::mem::MaybeUninit;
+use core::ptr;
 
 #[test]
 #[allow(suspicious_double_ref_op)]
@@ -81,3 +83,41 @@ fn test_clone_to_uninit_slice_drops_on_panic() {
     drop(a);
     assert_eq!(COUNTER.load(Relaxed), 0);
 }
+
+#[test]
+fn test_clone_to_uninit_str() {
+    let a = "hello";
+
+    let mut storage: MaybeUninit<[u8; 5]> = MaybeUninit::uninit();
+    unsafe { a.clone_to_uninit(storage.as_mut_ptr() as *mut [u8] as *mut str) };
+    assert_eq!(a.as_bytes(), unsafe { storage.assume_init() }.as_slice());
+
+    let mut b: Box<str> = "world".into();
+    assert_eq!(a.len(), b.len());
+    assert_ne!(a, &*b);
+    unsafe { a.clone_to_uninit(ptr::from_mut::<str>(&mut b)) };
+    assert_eq!(a, &*b);
+}
+
+#[test]
+fn test_clone_to_uninit_cstr() {
+    let a = c"hello";
+
+    let mut storage: MaybeUninit<[u8; 6]> = MaybeUninit::uninit();
+    unsafe { a.clone_to_uninit(storage.as_mut_ptr() as *mut [u8] as *mut CStr) };
+    assert_eq!(a.to_bytes_with_nul(), unsafe { storage.assume_init() }.as_slice());
+
+    let mut b: Box<CStr> = c"world".into();
+    assert_eq!(a.count_bytes(), b.count_bytes());
+    assert_ne!(a, &*b);
+    unsafe { a.clone_to_uninit(ptr::from_mut::<CStr>(&mut b)) };
+    assert_eq!(a, &*b);
+}
+
+#[test]
+fn cstr_metadata_is_length_with_nul() {
+    let s: &CStr = c"abcdef";
+    let p: *const CStr = ptr::from_ref(s);
+    let bytes: *const [u8] = p as *const [u8];
+    assert_eq!(s.to_bytes_with_nul().len(), bytes.len());
+}

From afabc583f7f646d45f506263a1c331383ebdc252 Mon Sep 17 00:00:00 2001
From: Pavel Grigorenko <GrigorenkoPV@ya.ru>
Date: Sun, 23 Jun 2024 23:05:10 +0300
Subject: [PATCH 2/7] impl CloneToUninit for Path and OsStr

---
 library/std/src/ffi/os_str.rs       | 12 ++++++++++++
 library/std/src/ffi/os_str/tests.rs | 17 +++++++++++++++++
 library/std/src/lib.rs              |  1 +
 library/std/src/path.rs             | 11 +++++++++++
 library/std/src/path/tests.rs       | 19 +++++++++++++++++++
 library/std/src/sys/os_str/bytes.rs | 12 ++++++++++++
 library/std/src/sys/os_str/wtf8.rs  | 12 ++++++++++++
 library/std/src/sys_common/wtf8.rs  | 11 +++++++++++
 8 files changed, 95 insertions(+)

diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index a501bcc98cf38..f68ea3c562a5e 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -3,10 +3,13 @@
 #[cfg(test)]
 mod tests;
 
+use core::clone::CloneToUninit;
+
 use crate::borrow::{Borrow, Cow};
 use crate::collections::TryReserveError;
 use crate::hash::{Hash, Hasher};
 use crate::ops::{self, Range};
+use crate::ptr::addr_of_mut;
 use crate::rc::Rc;
 use crate::str::FromStr;
 use crate::sync::Arc;
@@ -1261,6 +1264,15 @@ impl Clone for Box<OsStr> {
     }
 }
 
+#[unstable(feature = "clone_to_uninit", issue = "126799")]
+unsafe impl CloneToUninit for OsStr {
+    #[cfg_attr(debug_assertions, track_caller)]
+    unsafe fn clone_to_uninit(&self, dst: *mut Self) {
+        // SAFETY: we're just a wrapper around a platform-specific Slice
+        unsafe { self.inner.clone_to_uninit(addr_of_mut!((*dst).inner)) }
+    }
+}
+
 #[stable(feature = "shared_from_slice2", since = "1.24.0")]
 impl From<OsString> for Arc<OsStr> {
     /// Converts an [`OsString`] into an <code>[Arc]<[OsStr]></code> by moving the [`OsString`]
diff --git a/library/std/src/ffi/os_str/tests.rs b/library/std/src/ffi/os_str/tests.rs
index 5b39b9e34d8c7..67147934b4db3 100644
--- a/library/std/src/ffi/os_str/tests.rs
+++ b/library/std/src/ffi/os_str/tests.rs
@@ -1,4 +1,6 @@
 use super::*;
+use crate::mem::MaybeUninit;
+use crate::ptr;
 
 #[test]
 fn test_os_string_with_capacity() {
@@ -286,3 +288,18 @@ fn slice_surrogate_edge() {
     assert_eq!(post_crab.slice_encoded_bytes(..4), "🦀");
     assert_eq!(post_crab.slice_encoded_bytes(4..), surrogate);
 }
+
+#[test]
+fn clone_to_uninit() {
+    let a = OsStr::new("hello.txt");
+
+    let mut storage = vec![MaybeUninit::<u8>::uninit(); size_of_val::<OsStr>(a)];
+    unsafe { a.clone_to_uninit(ptr::from_mut::<[_]>(storage.as_mut_slice()) as *mut OsStr) };
+    assert_eq!(a.as_encoded_bytes(), unsafe { MaybeUninit::slice_assume_init_ref(&storage) });
+
+    let mut b: Box<OsStr> = OsStr::new("world.exe").into();
+    assert_eq!(size_of_val::<OsStr>(a), size_of_val::<OsStr>(&b));
+    assert_ne!(a, &*b);
+    unsafe { a.clone_to_uninit(ptr::from_mut::<OsStr>(&mut b)) };
+    assert_eq!(a, &*b);
+}
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index ee6f5a6f3c0d5..5cc6376a32d72 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -323,6 +323,7 @@
 // tidy-alphabetical-start
 #![feature(c_str_module)]
 #![feature(char_internals)]
+#![feature(clone_to_uninit)]
 #![feature(core_intrinsics)]
 #![feature(core_io_borrowed_buf)]
 #![feature(duration_constants)]
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 80163667636ae..d6c78883f2804 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -70,6 +70,8 @@
 #[cfg(test)]
 mod tests;
 
+use core::clone::CloneToUninit;
+
 use crate::borrow::{Borrow, Cow};
 use crate::collections::TryReserveError;
 use crate::error::Error;
@@ -3109,6 +3111,15 @@ impl Path {
     }
 }
 
+#[unstable(feature = "clone_to_uninit", issue = "126799")]
+unsafe impl CloneToUninit for Path {
+    #[cfg_attr(debug_assertions, track_caller)]
+    unsafe fn clone_to_uninit(&self, dst: *mut Self) {
+        // SAFETY: Path is just a wrapper around OsStr
+        unsafe { self.inner.clone_to_uninit(core::ptr::addr_of_mut!((*dst).inner)) }
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl AsRef<OsStr> for Path {
     #[inline]
diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs
index a12e42cba0c5c..6436872087d6c 100644
--- a/library/std/src/path/tests.rs
+++ b/library/std/src/path/tests.rs
@@ -3,6 +3,8 @@ use core::hint::black_box;
 use super::*;
 use crate::collections::{BTreeSet, HashSet};
 use crate::hash::DefaultHasher;
+use crate::mem::MaybeUninit;
+use crate::ptr;
 
 #[allow(unknown_lints, unused_macro_rules)]
 macro_rules! t (
@@ -2054,3 +2056,20 @@ fn bench_hash_path_long(b: &mut test::Bencher) {
 
     black_box(hasher.finish());
 }
+
+#[test]
+fn clone_to_uninit() {
+    let a = Path::new("hello.txt");
+
+    let mut storage = vec![MaybeUninit::<u8>::uninit(); size_of_val::<Path>(a)];
+    unsafe { a.clone_to_uninit(ptr::from_mut::<[_]>(storage.as_mut_slice()) as *mut Path) };
+    assert_eq!(a.as_os_str().as_encoded_bytes(), unsafe {
+        MaybeUninit::slice_assume_init_ref(&storage)
+    });
+
+    let mut b: Box<Path> = Path::new("world.exe").into();
+    assert_eq!(size_of_val::<Path>(a), size_of_val::<Path>(&b));
+    assert_ne!(a, &*b);
+    unsafe { a.clone_to_uninit(ptr::from_mut::<Path>(&mut b)) };
+    assert_eq!(a, &*b);
+}
diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs
index 0f8bd6453528e..8529207366e93 100644
--- a/library/std/src/sys/os_str/bytes.rs
+++ b/library/std/src/sys/os_str/bytes.rs
@@ -1,6 +1,9 @@
 //! The underlying OsString/OsStr implementation on Unix and many other
 //! systems: just a `Vec<u8>`/`[u8]`.
 
+use core::clone::CloneToUninit;
+use core::ptr::addr_of_mut;
+
 use crate::borrow::Cow;
 use crate::collections::TryReserveError;
 use crate::fmt::Write;
@@ -345,3 +348,12 @@ impl Slice {
         self.inner.eq_ignore_ascii_case(&other.inner)
     }
 }
+
+#[unstable(feature = "clone_to_uninit", issue = "126799")]
+unsafe impl CloneToUninit for Slice {
+    #[cfg_attr(debug_assertions, track_caller)]
+    unsafe fn clone_to_uninit(&self, dst: *mut Self) {
+        // SAFETY: we're just a wrapper around [u8]
+        unsafe { self.inner.clone_to_uninit(addr_of_mut!((*dst).inner)) }
+    }
+}
diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs
index ed975ba58b5e2..e5755a4b87443 100644
--- a/library/std/src/sys/os_str/wtf8.rs
+++ b/library/std/src/sys/os_str/wtf8.rs
@@ -1,5 +1,8 @@
 //! The underlying OsString/OsStr implementation on Windows is a
 //! wrapper around the "WTF-8" encoding; see the `wtf8` module for more.
+use core::clone::CloneToUninit;
+use core::ptr::addr_of_mut;
+
 use crate::borrow::Cow;
 use crate::collections::TryReserveError;
 use crate::rc::Rc;
@@ -268,3 +271,12 @@ impl Slice {
         self.inner.eq_ignore_ascii_case(&other.inner)
     }
 }
+
+#[unstable(feature = "clone_to_uninit", issue = "126799")]
+unsafe impl CloneToUninit for Slice {
+    #[cfg_attr(debug_assertions, track_caller)]
+    unsafe fn clone_to_uninit(&self, dst: *mut Self) {
+        // SAFETY: we're just a wrapper around Wtf8
+        unsafe { self.inner.clone_to_uninit(addr_of_mut!((*dst).inner)) }
+    }
+}
diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs
index 277c9506febbb..2bdeff78ddfd6 100644
--- a/library/std/src/sys_common/wtf8.rs
+++ b/library/std/src/sys_common/wtf8.rs
@@ -19,12 +19,14 @@
 mod tests;
 
 use core::char::{encode_utf16_raw, encode_utf8_raw};
+use core::clone::CloneToUninit;
 use core::str::next_code_point;
 
 use crate::borrow::Cow;
 use crate::collections::TryReserveError;
 use crate::hash::{Hash, Hasher};
 use crate::iter::FusedIterator;
+use crate::ptr::addr_of_mut;
 use crate::rc::Rc;
 use crate::sync::Arc;
 use crate::sys_common::AsInner;
@@ -1046,3 +1048,12 @@ impl Hash for Wtf8 {
         0xfeu8.hash(state)
     }
 }
+
+#[unstable(feature = "clone_to_uninit", issue = "126799")]
+unsafe impl CloneToUninit for Wtf8 {
+    #[cfg_attr(debug_assertions, track_caller)]
+    unsafe fn clone_to_uninit(&self, dst: *mut Self) {
+        // SAFETY: we're just a wrapper around [u8]
+        unsafe { self.bytes.clone_to_uninit(addr_of_mut!((*dst).bytes)) }
+    }
+}

From dbc13fb309f3a1539e8bb1cdeeb5fbb2e3eaaa43 Mon Sep 17 00:00:00 2001
From: Pavel Grigorenko <GrigorenkoPV@ya.ru>
Date: Mon, 24 Jun 2024 18:09:27 +0300
Subject: [PATCH 3/7] Sparkle some attributes over `CloneToUninit` stuff

---
 library/core/src/clone.rs           | 7 +++++++
 library/std/src/ffi/os_str.rs       | 1 +
 library/std/src/path.rs             | 1 +
 library/std/src/sys/os_str/bytes.rs | 1 +
 library/std/src/sys/os_str/wtf8.rs  | 1 +
 library/std/src/sys_common/wtf8.rs  | 1 +
 6 files changed, 12 insertions(+)

diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs
index 409fd2746f588..88f7990c017df 100644
--- a/library/core/src/clone.rs
+++ b/library/core/src/clone.rs
@@ -272,6 +272,7 @@ pub unsafe trait CloneToUninit {
 
 #[unstable(feature = "clone_to_uninit", issue = "126799")]
 unsafe impl<T: Clone> CloneToUninit for T {
+    #[inline]
     default unsafe fn clone_to_uninit(&self, dst: *mut Self) {
         // SAFETY: The safety conditions of clone_to_uninit() are a superset of those of
         // ptr::write().
@@ -285,8 +286,10 @@ unsafe impl<T: Clone> CloneToUninit for T {
 
 // Specialized implementation for types that are [`Copy`], not just [`Clone`],
 // and can therefore be copied bitwise.
+#[doc(hidden)]
 #[unstable(feature = "clone_to_uninit", issue = "126799")]
 unsafe impl<T: Copy> CloneToUninit for T {
+    #[inline]
     unsafe fn clone_to_uninit(&self, dst: *mut Self) {
         // SAFETY: The safety conditions of clone_to_uninit() are a superset of those of
         // ptr::copy_nonoverlapping().
@@ -298,6 +301,7 @@ unsafe impl<T: Copy> CloneToUninit for T {
 
 #[unstable(feature = "clone_to_uninit", issue = "126799")]
 unsafe impl<T: Clone> CloneToUninit for [T] {
+    #[inline]
     #[cfg_attr(debug_assertions, track_caller)]
     default unsafe fn clone_to_uninit(&self, dst: *mut Self) {
         let len = self.len();
@@ -326,8 +330,10 @@ unsafe impl<T: Clone> CloneToUninit for [T] {
     }
 }
 
+#[doc(hidden)]
 #[unstable(feature = "clone_to_uninit", issue = "126799")]
 unsafe impl<T: Copy> CloneToUninit for [T] {
+    #[inline]
     #[cfg_attr(debug_assertions, track_caller)]
     unsafe fn clone_to_uninit(&self, dst: *mut Self) {
         let len = self.len();
@@ -348,6 +354,7 @@ unsafe impl<T: Copy> CloneToUninit for [T] {
 
 #[unstable(feature = "clone_to_uninit", issue = "126799")]
 unsafe impl CloneToUninit for str {
+    #[inline]
     #[cfg_attr(debug_assertions, track_caller)]
     unsafe fn clone_to_uninit(&self, dst: *mut Self) {
         // SAFETY: str is just a [u8] with UTF-8 invariant
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index f68ea3c562a5e..918eec2d0d8ef 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -1266,6 +1266,7 @@ impl Clone for Box<OsStr> {
 
 #[unstable(feature = "clone_to_uninit", issue = "126799")]
 unsafe impl CloneToUninit for OsStr {
+    #[inline]
     #[cfg_attr(debug_assertions, track_caller)]
     unsafe fn clone_to_uninit(&self, dst: *mut Self) {
         // SAFETY: we're just a wrapper around a platform-specific Slice
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index d6c78883f2804..9eaa0e01c2c00 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -3113,6 +3113,7 @@ impl Path {
 
 #[unstable(feature = "clone_to_uninit", issue = "126799")]
 unsafe impl CloneToUninit for Path {
+    #[inline]
     #[cfg_attr(debug_assertions, track_caller)]
     unsafe fn clone_to_uninit(&self, dst: *mut Self) {
         // SAFETY: Path is just a wrapper around OsStr
diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs
index 8529207366e93..992767211d083 100644
--- a/library/std/src/sys/os_str/bytes.rs
+++ b/library/std/src/sys/os_str/bytes.rs
@@ -351,6 +351,7 @@ impl Slice {
 
 #[unstable(feature = "clone_to_uninit", issue = "126799")]
 unsafe impl CloneToUninit for Slice {
+    #[inline]
     #[cfg_attr(debug_assertions, track_caller)]
     unsafe fn clone_to_uninit(&self, dst: *mut Self) {
         // SAFETY: we're just a wrapper around [u8]
diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs
index e5755a4b87443..433237aa6e7bf 100644
--- a/library/std/src/sys/os_str/wtf8.rs
+++ b/library/std/src/sys/os_str/wtf8.rs
@@ -274,6 +274,7 @@ impl Slice {
 
 #[unstable(feature = "clone_to_uninit", issue = "126799")]
 unsafe impl CloneToUninit for Slice {
+    #[inline]
     #[cfg_attr(debug_assertions, track_caller)]
     unsafe fn clone_to_uninit(&self, dst: *mut Self) {
         // SAFETY: we're just a wrapper around Wtf8
diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs
index 2bdeff78ddfd6..063451ad54e1c 100644
--- a/library/std/src/sys_common/wtf8.rs
+++ b/library/std/src/sys_common/wtf8.rs
@@ -1051,6 +1051,7 @@ impl Hash for Wtf8 {
 
 #[unstable(feature = "clone_to_uninit", issue = "126799")]
 unsafe impl CloneToUninit for Wtf8 {
+    #[inline]
     #[cfg_attr(debug_assertions, track_caller)]
     unsafe fn clone_to_uninit(&self, dst: *mut Self) {
         // SAFETY: we're just a wrapper around [u8]

From 110c273f4fb40c318be59a557ba90314fbbc42a6 Mon Sep 17 00:00:00 2001
From: Pavel Grigorenko <GrigorenkoPV@ya.ru>
Date: Wed, 26 Jun 2024 02:22:07 +0300
Subject: [PATCH 4/7] CloneToUninit: use a private specialization trait

and move implementation details into a submodule
---
 library/core/src/clone.rs        | 123 ++---------------------------
 library/core/src/clone/uninit.rs | 128 +++++++++++++++++++++++++++++++
 2 files changed, 134 insertions(+), 117 deletions(-)
 create mode 100644 library/core/src/clone/uninit.rs

diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs
index 88f7990c017df..2150463067205 100644
--- a/library/core/src/clone.rs
+++ b/library/core/src/clone.rs
@@ -36,8 +36,7 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use crate::mem::{self, MaybeUninit};
-use crate::ptr;
+mod uninit;
 
 /// A common trait for the ability to explicitly duplicate an object.
 ///
@@ -248,7 +247,7 @@ pub unsafe trait CloneToUninit {
     /// * `dst` must be properly aligned.
     /// * `dst` must have the same [pointer metadata] (slice length or `dyn` vtable) as `self`.
     ///
-    /// [valid]: ptr#safety
+    /// [valid]: crate::ptr#safety
     /// [pointer metadata]: crate::ptr::metadata()
     ///
     /// # Panics
@@ -272,83 +271,20 @@ pub unsafe trait CloneToUninit {
 
 #[unstable(feature = "clone_to_uninit", issue = "126799")]
 unsafe impl<T: Clone> CloneToUninit for T {
-    #[inline]
-    default unsafe fn clone_to_uninit(&self, dst: *mut Self) {
-        // SAFETY: The safety conditions of clone_to_uninit() are a superset of those of
-        // ptr::write().
-        unsafe {
-            // We hope the optimizer will figure out to create the cloned value in-place,
-            // skipping ever storing it on the stack and the copy to the destination.
-            ptr::write(dst, self.clone());
-        }
-    }
-}
-
-// Specialized implementation for types that are [`Copy`], not just [`Clone`],
-// and can therefore be copied bitwise.
-#[doc(hidden)]
-#[unstable(feature = "clone_to_uninit", issue = "126799")]
-unsafe impl<T: Copy> CloneToUninit for T {
     #[inline]
     unsafe fn clone_to_uninit(&self, dst: *mut Self) {
-        // SAFETY: The safety conditions of clone_to_uninit() are a superset of those of
-        // ptr::copy_nonoverlapping().
-        unsafe {
-            ptr::copy_nonoverlapping(self, dst, 1);
-        }
+        // SAFETY: we're calling a specialization with the same contract
+        unsafe { <T as self::uninit::CopySpec>::clone_one(self, dst) }
     }
 }
 
 #[unstable(feature = "clone_to_uninit", issue = "126799")]
 unsafe impl<T: Clone> CloneToUninit for [T] {
-    #[inline]
-    #[cfg_attr(debug_assertions, track_caller)]
-    default unsafe fn clone_to_uninit(&self, dst: *mut Self) {
-        let len = self.len();
-        // This is the most likely mistake to make, so check it as a debug assertion.
-        debug_assert_eq!(
-            len,
-            dst.len(),
-            "clone_to_uninit() source and destination must have equal lengths",
-        );
-
-        // SAFETY: The produced `&mut` is valid because:
-        // * The caller is obligated to provide a pointer which is valid for writes.
-        // * All bytes pointed to are in MaybeUninit, so we don't care about the memory's
-        //   initialization status.
-        let uninit_ref = unsafe { &mut *(dst as *mut [MaybeUninit<T>]) };
-
-        // Copy the elements
-        let mut initializing = InitializingSlice::from_fully_uninit(uninit_ref);
-        for element_ref in self.iter() {
-            // If the clone() panics, `initializing` will take care of the cleanup.
-            initializing.push(element_ref.clone());
-        }
-        // If we reach here, then the entire slice is initialized, and we've satisfied our
-        // responsibilities to the caller. Disarm the cleanup guard by forgetting it.
-        mem::forget(initializing);
-    }
-}
-
-#[doc(hidden)]
-#[unstable(feature = "clone_to_uninit", issue = "126799")]
-unsafe impl<T: Copy> CloneToUninit for [T] {
     #[inline]
     #[cfg_attr(debug_assertions, track_caller)]
     unsafe fn clone_to_uninit(&self, dst: *mut Self) {
-        let len = self.len();
-        // This is the most likely mistake to make, so check it as a debug assertion.
-        debug_assert_eq!(
-            len,
-            dst.len(),
-            "clone_to_uninit() source and destination must have equal lengths",
-        );
-
-        // SAFETY: The safety conditions of clone_to_uninit() are a superset of those of
-        // ptr::copy_nonoverlapping().
-        unsafe {
-            ptr::copy_nonoverlapping(self.as_ptr(), dst.as_mut_ptr(), len);
-        }
+        // SAFETY: we're calling a specialization with the same contract
+        unsafe { <T as self::uninit::CopySpec>::clone_slice(self, dst) }
     }
 }
 
@@ -374,53 +310,6 @@ unsafe impl CloneToUninit for crate::ffi::CStr {
     }
 }
 
-/// Ownership of a collection of values stored in a non-owned `[MaybeUninit<T>]`, some of which
-/// are not yet initialized. This is sort of like a `Vec` that doesn't own its allocation.
-/// Its responsibility is to provide cleanup on unwind by dropping the values that *are*
-/// initialized, unless disarmed by forgetting.
-///
-/// This is a helper for `impl<T: Clone> CloneToUninit for [T]`.
-struct InitializingSlice<'a, T> {
-    data: &'a mut [MaybeUninit<T>],
-    /// Number of elements of `*self.data` that are initialized.
-    initialized_len: usize,
-}
-
-impl<'a, T> InitializingSlice<'a, T> {
-    #[inline]
-    fn from_fully_uninit(data: &'a mut [MaybeUninit<T>]) -> Self {
-        Self { data, initialized_len: 0 }
-    }
-
-    /// Push a value onto the end of the initialized part of the slice.
-    ///
-    /// # Panics
-    ///
-    /// Panics if the slice is already fully initialized.
-    #[inline]
-    fn push(&mut self, value: T) {
-        MaybeUninit::write(&mut self.data[self.initialized_len], value);
-        self.initialized_len += 1;
-    }
-}
-
-impl<'a, T> Drop for InitializingSlice<'a, T> {
-    #[cold] // will only be invoked on unwind
-    fn drop(&mut self) {
-        let initialized_slice = ptr::slice_from_raw_parts_mut(
-            MaybeUninit::slice_as_mut_ptr(self.data),
-            self.initialized_len,
-        );
-        // SAFETY:
-        // * the pointer is valid because it was made from a mutable reference
-        // * `initialized_len` counts the initialized elements as an invariant of this type,
-        //   so each of the pointed-to elements is initialized and may be dropped.
-        unsafe {
-            ptr::drop_in_place::<[T]>(initialized_slice);
-        }
-    }
-}
-
 /// Implementations of `Clone` for primitive types.
 ///
 /// Implementations that cannot be described in Rust
diff --git a/library/core/src/clone/uninit.rs b/library/core/src/clone/uninit.rs
new file mode 100644
index 0000000000000..8b738bec796de
--- /dev/null
+++ b/library/core/src/clone/uninit.rs
@@ -0,0 +1,128 @@
+use crate::mem::{self, MaybeUninit};
+use crate::ptr;
+
+/// Private specialization trait used by CloneToUninit, as per
+/// [the dev guide](https://std-dev-guide.rust-lang.org/policy/specialization.html).
+pub(super) unsafe trait CopySpec: Clone {
+    unsafe fn clone_one(src: &Self, dst: *mut Self);
+    unsafe fn clone_slice(src: &[Self], dst: *mut [Self]);
+}
+
+unsafe impl<T: Clone> CopySpec for T {
+    #[inline]
+    default unsafe fn clone_one(src: &Self, dst: *mut Self) {
+        // SAFETY: The safety conditions of clone_to_uninit() are a superset of those of
+        // ptr::write().
+        unsafe {
+            // We hope the optimizer will figure out to create the cloned value in-place,
+            // skipping ever storing it on the stack and the copy to the destination.
+            ptr::write(dst, src.clone());
+        }
+    }
+
+    #[inline]
+    #[cfg_attr(debug_assertions, track_caller)]
+    default unsafe fn clone_slice(src: &[Self], dst: *mut [Self]) {
+        let len = src.len();
+        // This is the most likely mistake to make, so check it as a debug assertion.
+        debug_assert_eq!(
+            len,
+            dst.len(),
+            "clone_to_uninit() source and destination must have equal lengths",
+        );
+
+        // SAFETY: The produced `&mut` is valid because:
+        // * The caller is obligated to provide a pointer which is valid for writes.
+        // * All bytes pointed to are in MaybeUninit, so we don't care about the memory's
+        //   initialization status.
+        let uninit_ref = unsafe { &mut *(dst as *mut [MaybeUninit<T>]) };
+
+        // Copy the elements
+        let mut initializing = InitializingSlice::from_fully_uninit(uninit_ref);
+        for element_ref in src {
+            // If the clone() panics, `initializing` will take care of the cleanup.
+            initializing.push(element_ref.clone());
+        }
+        // If we reach here, then the entire slice is initialized, and we've satisfied our
+        // responsibilities to the caller. Disarm the cleanup guard by forgetting it.
+        mem::forget(initializing);
+    }
+}
+
+// Specialized implementation for types that are [`Copy`], not just [`Clone`],
+// and can therefore be copied bitwise.
+unsafe impl<T: Copy> CopySpec for T {
+    #[inline]
+    unsafe fn clone_one(src: &Self, dst: *mut Self) {
+        // SAFETY: The safety conditions of clone_to_uninit() are a superset of those of
+        // ptr::copy_nonoverlapping().
+        unsafe {
+            ptr::copy_nonoverlapping(src, dst, 1);
+        }
+    }
+
+    #[inline]
+    #[cfg_attr(debug_assertions, track_caller)]
+    unsafe fn clone_slice(src: &[Self], dst: *mut [Self]) {
+        let len = src.len();
+        // This is the most likely mistake to make, so check it as a debug assertion.
+        debug_assert_eq!(
+            len,
+            dst.len(),
+            "clone_to_uninit() source and destination must have equal lengths",
+        );
+
+        // SAFETY: The safety conditions of clone_to_uninit() are a superset of those of
+        // ptr::copy_nonoverlapping().
+        unsafe {
+            ptr::copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr(), len);
+        }
+    }
+}
+
+/// Ownership of a collection of values stored in a non-owned `[MaybeUninit<T>]`, some of which
+/// are not yet initialized. This is sort of like a `Vec` that doesn't own its allocation.
+/// Its responsibility is to provide cleanup on unwind by dropping the values that *are*
+/// initialized, unless disarmed by forgetting.
+///
+/// This is a helper for `impl<T: Clone> CloneToUninit for [T]`.
+struct InitializingSlice<'a, T> {
+    data: &'a mut [MaybeUninit<T>],
+    /// Number of elements of `*self.data` that are initialized.
+    initialized_len: usize,
+}
+
+impl<'a, T> InitializingSlice<'a, T> {
+    #[inline]
+    fn from_fully_uninit(data: &'a mut [MaybeUninit<T>]) -> Self {
+        Self { data, initialized_len: 0 }
+    }
+
+    /// Push a value onto the end of the initialized part of the slice.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the slice is already fully initialized.
+    #[inline]
+    fn push(&mut self, value: T) {
+        MaybeUninit::write(&mut self.data[self.initialized_len], value);
+        self.initialized_len += 1;
+    }
+}
+
+impl<'a, T> Drop for InitializingSlice<'a, T> {
+    #[cold] // will only be invoked on unwind
+    fn drop(&mut self) {
+        let initialized_slice = ptr::slice_from_raw_parts_mut(
+            MaybeUninit::slice_as_mut_ptr(self.data),
+            self.initialized_len,
+        );
+        // SAFETY:
+        // * the pointer is valid because it was made from a mutable reference
+        // * `initialized_len` counts the initialized elements as an invariant of this type,
+        //   so each of the pointed-to elements is initialized and may be dropped.
+        unsafe {
+            ptr::drop_in_place::<[T]>(initialized_slice);
+        }
+    }
+}

From 0732f7d5e1ea2b735db98d53b628e512f8d5a372 Mon Sep 17 00:00:00 2001
From: daxpedda <daxpedda@gmail.com>
Date: Sun, 8 Oct 2023 10:54:15 +0200
Subject: [PATCH 5/7] Stabilize `Ready::into_inner()`

---
 library/core/src/future/ready.rs | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/library/core/src/future/ready.rs b/library/core/src/future/ready.rs
index a07b63fb62b90..6f6da8ce51ddf 100644
--- a/library/core/src/future/ready.rs
+++ b/library/core/src/future/ready.rs
@@ -34,13 +34,12 @@ impl<T> Ready<T> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(ready_into_inner)]
     /// use std::future;
     ///
     /// let a = future::ready(1);
     /// assert_eq!(a.into_inner(), 1);
     /// ```
-    #[unstable(feature = "ready_into_inner", issue = "101196")]
+    #[stable(feature = "ready_into_inner", since = "CURRENT_RUSTC_VERSION")]
     #[must_use]
     #[inline]
     pub fn into_inner(self) -> T {

From 29017e45a1c85afe457765a5d4c77e4fcdebb4f6 Mon Sep 17 00:00:00 2001
From: Josh Stone <jistone@redhat.com>
Date: Fri, 16 Aug 2024 12:42:02 -0700
Subject: [PATCH 6/7] mir/pretty: use `Option` instead of `Either<Once, Empty>`

`Either` is wasteful for a one-or-none iterator, especially since `Once`
is already an `option::IntoIter` internally. We don't really need any of
the iterator mechanisms in this case, just a single conditional insert.
---
 compiler/rustc_middle/src/mir/pretty.rs | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index f2d8781413096..5dd0e69cf1fe6 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -1418,21 +1418,19 @@ pub fn write_allocations<'tcx>(
         alloc.inner().provenance().ptrs().values().map(|p| p.alloc_id())
     }
 
-    fn alloc_ids_from_const_val(val: ConstValue<'_>) -> impl Iterator<Item = AllocId> + '_ {
+    fn alloc_id_from_const_val(val: ConstValue<'_>) -> Option<AllocId> {
         match val {
-            ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _)) => {
-                Either::Left(std::iter::once(ptr.provenance.alloc_id()))
-            }
-            ConstValue::Scalar(interpret::Scalar::Int { .. }) => Either::Right(std::iter::empty()),
-            ConstValue::ZeroSized => Either::Right(std::iter::empty()),
+            ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _)) => Some(ptr.provenance.alloc_id()),
+            ConstValue::Scalar(interpret::Scalar::Int { .. }) => None,
+            ConstValue::ZeroSized => None,
             ConstValue::Slice { .. } => {
                 // `u8`/`str` slices, shouldn't contain pointers that we want to print.
-                Either::Right(std::iter::empty())
+                None
             }
             ConstValue::Indirect { alloc_id, .. } => {
                 // FIXME: we don't actually want to print all of these, since some are printed nicely directly as values inline in MIR.
                 // Really we'd want `pretty_print_const_value` to decide which allocations to print, instead of having a separate visitor.
-                Either::Left(std::iter::once(alloc_id))
+                Some(alloc_id)
             }
         }
     }
@@ -1443,7 +1441,9 @@ pub fn write_allocations<'tcx>(
             match c.const_ {
                 Const::Ty(_, _) | Const::Unevaluated(..) => {}
                 Const::Val(val, _) => {
-                    self.0.extend(alloc_ids_from_const_val(val));
+                    if let Some(id) = alloc_id_from_const_val(val) {
+                        self.0.insert(id);
+                    }
                 }
             }
         }

From ed6315b3fef4ebd9aee053d407eb746c3b1d58bf Mon Sep 17 00:00:00 2001
From: Boxy <rust@boxyuwu.dev>
Date: Fri, 16 Aug 2024 20:53:02 +0100
Subject: [PATCH 7/7] Rewrite `get_fn_id_for_return_block`

---
 compiler/rustc_middle/src/hir/map/mod.rs      |  64 +++++-----
 tests/crashes/128810.rs                       |  25 ----
 ..._body_owner_parent_found_in_diagnostics.rs |  34 ++++++
 ...y_owner_parent_found_in_diagnostics.stderr | 113 ++++++++++++++++++
 tests/ui/typeck/const-in-fn-call-generics.rs  |  16 +++
 .../typeck/const-in-fn-call-generics.stderr   |   9 ++
 6 files changed, 199 insertions(+), 62 deletions(-)
 delete mode 100644 tests/crashes/128810.rs
 create mode 100644 tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.rs
 create mode 100644 tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr
 create mode 100644 tests/ui/typeck/const-in-fn-call-generics.rs
 create mode 100644 tests/ui/typeck/const-in-fn-call-generics.stderr

diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index edab6b5ebde84..da08027d66b19 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -554,53 +554,43 @@ impl<'hir> Map<'hir> {
     /// }
     /// ```
     pub fn get_fn_id_for_return_block(self, id: HirId) -> Option<HirId> {
-        let mut iter = self.parent_iter(id).peekable();
-        let mut ignore_tail = false;
-        if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = self.tcx.hir_node(id) {
-            // When dealing with `return` statements, we don't care about climbing only tail
-            // expressions.
-            ignore_tail = true;
-        }
+        let enclosing_body_owner = self.tcx.local_def_id_to_hir_id(self.enclosing_body_owner(id));
+
+        // Return `None` if the `id` expression is not the returned value of the enclosing body
+        let mut iter = [id].into_iter().chain(self.parent_id_iter(id)).peekable();
+        while let Some(cur_id) = iter.next() {
+            if enclosing_body_owner == cur_id {
+                break;
+            }
+
+            // A return statement is always the value returned from the enclosing body regardless of
+            // what the parent expressions are.
+            if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = self.tcx.hir_node(cur_id) {
+                break;
+            }
 
-        let mut prev_hir_id = None;
-        while let Some((hir_id, node)) = iter.next() {
-            if let (Some((_, next_node)), false) = (iter.peek(), ignore_tail) {
-                match next_node {
-                    Node::Block(Block { expr: None, .. }) => return None,
-                    // The current node is not the tail expression of its parent.
-                    Node::Block(Block { expr: Some(e), .. }) if hir_id != e.hir_id => return None,
+            // If the current expression's value doesnt get used as the parent expressions value then return `None`
+            if let Some(&parent_id) = iter.peek() {
+                match self.tcx.hir_node(parent_id) {
+                    // The current node is not the tail expression of the block expression parent expr.
+                    Node::Block(Block { expr: Some(e), .. }) if cur_id != e.hir_id => return None,
                     Node::Block(Block { expr: Some(e), .. })
                         if matches!(e.kind, ExprKind::If(_, _, None)) =>
                     {
                         return None;
                     }
+
+                    // The current expression's value does not pass up through these parent expressions
+                    Node::Block(Block { expr: None, .. })
+                    | Node::Expr(Expr { kind: ExprKind::Loop(..), .. })
+                    | Node::LetStmt(..) => return None,
+
                     _ => {}
                 }
             }
-            match node {
-                Node::Item(_)
-                | Node::ForeignItem(_)
-                | Node::TraitItem(_)
-                | Node::Expr(Expr { kind: ExprKind::Closure(_), .. })
-                | Node::ImplItem(_)
-                    // The input node `id` must be enclosed in the method's body as opposed
-                    // to some other place such as its return type (fixes #114918).
-                    // We verify that indirectly by checking that the previous node is the
-                    // current node's body
-                    if node.body_id().map(|b| b.hir_id) == prev_hir_id =>  {
-                        return Some(hir_id)
-                }
-                // Ignore `return`s on the first iteration
-                Node::Expr(Expr { kind: ExprKind::Loop(..) | ExprKind::Ret(..), .. })
-                | Node::LetStmt(_) => {
-                    return None;
-                }
-                _ => {}
-            }
-
-            prev_hir_id = Some(hir_id);
         }
-        None
+
+        Some(enclosing_body_owner)
     }
 
     /// Retrieves the `OwnerId` for `id`'s parent item, or `id` itself if no
diff --git a/tests/crashes/128810.rs b/tests/crashes/128810.rs
deleted file mode 100644
index 68214ff010c99..0000000000000
--- a/tests/crashes/128810.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-//@ known-bug: rust-lang/rust#128810
-
-#![feature(fn_delegation)]
-
-use std::marker::PhantomData;
-
-pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
-
-impl<'a> InvariantRef<'a, ()> {
-    pub const NEW: Self = InvariantRef::new(&());
-}
-
-trait Trait {
-    fn foo(&self) -> u8 { 0 }
-    fn bar(&self) -> u8 { 1 }
-    fn meh(&self) -> u8 { 2 }
-}
-
-struct Z(u8);
-
-impl Trait for Z {
-    reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
-}
-
-fn main() { }
diff --git a/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.rs b/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.rs
new file mode 100644
index 0000000000000..0a7ec5ab5c1be
--- /dev/null
+++ b/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.rs
@@ -0,0 +1,34 @@
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+use std::marker::PhantomData;
+
+pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
+
+impl<'a> InvariantRef<'a, ()> {
+    pub const NEW: Self = InvariantRef::new(&());
+    //~^ ERROR: no function or associated item named `new` found
+}
+
+trait Trait {
+    fn foo(&self) -> u8 { 0 }
+    fn bar(&self) -> u8 { 1 }
+    fn meh(&self) -> u8 { 2 }
+}
+
+struct Z(u8);
+
+impl Trait for Z {
+    reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+    //~^ ERROR: use of undeclared lifetime name `'a`
+    //~| ERROR: use of undeclared lifetime name `'a`
+    //~| ERROR: use of undeclared lifetime name `'a`
+    //~| ERROR: the trait bound `u8: Trait` is not satisfied
+    //~| ERROR: the trait bound `u8: Trait` is not satisfied
+    //~| ERROR: the trait bound `u8: Trait` is not satisfied
+    //~| ERROR: mismatched types
+    //~| ERROR: mismatched types
+    //~| ERROR: mismatched types
+}
+
+fn main() { }
diff --git a/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr b/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr
new file mode 100644
index 0000000000000..2ce3b388073c4
--- /dev/null
+++ b/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr
@@ -0,0 +1,113 @@
+error[E0261]: use of undeclared lifetime name `'a`
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:68
+   |
+LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+   |                                                                    ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'a` here
+   |
+LL |     reuse <u8 as Trait>::{foo'a, , bar, meh} { &const { InvariantRef::<'a>::NEW } }
+   |                              +++
+help: consider introducing lifetime `'a` here
+   |
+LL | impl<'a> Trait for Z {
+   |     ++++
+
+error[E0261]: use of undeclared lifetime name `'a`
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:68
+   |
+LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+   |                                                                    ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'a` here
+   |
+LL |     reuse <u8 as Trait>::{foo, bar'a, , meh} { &const { InvariantRef::<'a>::NEW } }
+   |                                   +++
+help: consider introducing lifetime `'a` here
+   |
+LL | impl<'a> Trait for Z {
+   |     ++++
+
+error[E0261]: use of undeclared lifetime name `'a`
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:68
+   |
+LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+   |                                                                    ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'a` here
+   |
+LL |     reuse <u8 as Trait>::{foo, bar, meh'a, } { &const { InvariantRef::<'a>::NEW } }
+   |                                        +++
+help: consider introducing lifetime `'a` here
+   |
+LL | impl<'a> Trait for Z {
+   |     ++++
+
+error[E0599]: no function or associated item named `new` found for struct `InvariantRef` in the current scope
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:9:41
+   |
+LL | pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
+   | -------------------------------------- function or associated item `new` not found for this struct
+...
+LL |     pub const NEW: Self = InvariantRef::new(&());
+   |                                         ^^^ function or associated item not found in `InvariantRef<'_, _>`
+
+error[E0308]: mismatched types
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:53
+   |
+LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+   |                                                     ^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `InvariantRef<'_, ()>`
+   |
+   = note: expected type `u8`
+            found struct `InvariantRef<'_, ()>`
+
+error[E0277]: the trait bound `u8: Trait` is not satisfied
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12
+   |
+LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+   |            ^^ the trait `Trait` is not implemented for `u8`
+   |
+   = help: the trait `Trait` is implemented for `Z`
+
+error[E0308]: mismatched types
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:53
+   |
+LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+   |                                                     ^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `InvariantRef<'_, ()>`
+   |
+   = note: expected type `u8`
+            found struct `InvariantRef<'_, ()>`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0277]: the trait bound `u8: Trait` is not satisfied
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12
+   |
+LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+   |            ^^ the trait `Trait` is not implemented for `u8`
+   |
+   = help: the trait `Trait` is implemented for `Z`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0308]: mismatched types
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:53
+   |
+LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+   |                                                     ^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `InvariantRef<'_, ()>`
+   |
+   = note: expected type `u8`
+            found struct `InvariantRef<'_, ()>`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0277]: the trait bound `u8: Trait` is not satisfied
+  --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12
+   |
+LL |     reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+   |            ^^ the trait `Trait` is not implemented for `u8`
+   |
+   = help: the trait `Trait` is implemented for `Z`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 10 previous errors
+
+Some errors have detailed explanations: E0261, E0277, E0308, E0599.
+For more information about an error, try `rustc --explain E0261`.
diff --git a/tests/ui/typeck/const-in-fn-call-generics.rs b/tests/ui/typeck/const-in-fn-call-generics.rs
new file mode 100644
index 0000000000000..675dbcc305475
--- /dev/null
+++ b/tests/ui/typeck/const-in-fn-call-generics.rs
@@ -0,0 +1,16 @@
+fn generic<const N: u32>() {}
+
+trait Collate<const A: u32> {
+    type Pass;
+    fn collate(self) -> Self::Pass;
+}
+
+impl<const B: u32> Collate<B> for i32 {
+    type Pass = ();
+    fn collate(self) -> Self::Pass {
+        generic::<{ true }>()
+        //~^ ERROR: mismatched types
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/typeck/const-in-fn-call-generics.stderr b/tests/ui/typeck/const-in-fn-call-generics.stderr
new file mode 100644
index 0000000000000..12dd454188cac
--- /dev/null
+++ b/tests/ui/typeck/const-in-fn-call-generics.stderr
@@ -0,0 +1,9 @@
+error[E0308]: mismatched types
+  --> $DIR/const-in-fn-call-generics.rs:11:21
+   |
+LL |         generic::<{ true }>()
+   |                     ^^^^ expected `u32`, found `bool`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.