From e0c1c8bc5058cd3f8831b235c5963ab89840b33b Mon Sep 17 00:00:00 2001 From: Zachary S Date: Fri, 1 Nov 2024 00:07:59 -0500 Subject: [PATCH] Make `CloneToUninit` dyn-compatible --- library/alloc/src/boxed.rs | 2 +- library/alloc/src/rc.rs | 2 +- library/alloc/src/sync.rs | 2 +- library/core/src/clone.rs | 29 +++++++++++++++-------------- library/std/src/ffi/os_str.rs | 8 ++++---- library/std/src/ffi/os_str/tests.rs | 4 ++-- library/std/src/path.rs | 8 ++++---- library/std/src/path/tests.rs | 4 ++-- library/std/src/sys/os_str/bytes.rs | 6 +++--- library/std/src/sys/os_str/wtf8.rs | 6 +++--- library/std/src/sys_common/wtf8.rs | 6 +++--- 11 files changed, 39 insertions(+), 38 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index c5024a05ed631..bb6dd1d2d30c5 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1735,7 +1735,7 @@ impl Clone for Box { // Pre-allocate memory to allow writing the cloned value directly. let mut boxed = Self::new_uninit_in(self.1.clone()); unsafe { - (**self).clone_to_uninit(boxed.as_mut_ptr()); + (**self).clone_to_uninit(boxed.as_mut_ptr().cast()); boxed.assume_init() } } diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 4718264e68590..3a9bd1b5bf119 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1876,7 +1876,7 @@ impl Rc { // Initialize with clone of this. let initialized_clone = unsafe { // Clone. If the clone panics, `in_progress` will be dropped and clean up. - this_data_ref.clone_to_uninit(in_progress.data_ptr()); + this_data_ref.clone_to_uninit(in_progress.data_ptr().cast()); // Cast type of pointer, now that it is initialized. in_progress.into_rc() }; diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 8520c3c196b1b..da2d6bb3bce24 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -2272,7 +2272,7 @@ impl Arc { let initialized_clone = unsafe { // Clone. If the clone panics, `in_progress` will be dropped and clean up. - this_data_ref.clone_to_uninit(in_progress.data_ptr()); + this_data_ref.clone_to_uninit(in_progress.data_ptr().cast()); // Cast type of pointer, now that it is initialized. in_progress.into_arc() }; diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index c5f8bd7401e5e..ec1aed53eaf72 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -232,20 +232,20 @@ pub struct AssertParamIsCopy { pub unsafe trait CloneToUninit { /// Performs copy-assignment from `self` to `dst`. /// - /// This is analogous to `std::ptr::write(dst, self.clone())`, + /// This is analogous to `std::ptr::write(dst.cast(), self.clone())`, /// except that `self` may be a dynamically-sized type ([`!Sized`](Sized)). /// /// Before this function is called, `dst` may point to uninitialized memory. /// After this function is called, `dst` will point to initialized memory; it will be - /// sound to create a `&Self` reference from the pointer. + /// sound to create a `&Self` reference from the pointer with the [pointer metadata] + /// from `self`. /// /// # Safety /// /// Behavior is undefined if any of the following conditions are violated: /// - /// * `dst` must be [valid] for writes. - /// * `dst` must be properly aligned. - /// * `dst` must have the same [pointer metadata] (slice length or `dyn` vtable) as `self`. + /// * `dst` must be [valid] for writes for `std::mem::size_of_val(self)` bytes. + /// * `dst` must be properly aligned to `std::mem::align_of_val(self)`. /// /// [valid]: crate::ptr#safety /// [pointer metadata]: crate::ptr::metadata() @@ -266,15 +266,15 @@ pub unsafe trait CloneToUninit { /// that might have already been created. (For example, if a `[Foo]` of length 3 is being /// cloned, and the second of the three calls to `Foo::clone()` unwinds, then the first `Foo` /// cloned should be dropped.) - unsafe fn clone_to_uninit(&self, dst: *mut Self); + unsafe fn clone_to_uninit(&self, dst: *mut u8); } #[unstable(feature = "clone_to_uninit", issue = "126799")] unsafe impl CloneToUninit for T { #[inline] - unsafe fn clone_to_uninit(&self, dst: *mut Self) { + unsafe fn clone_to_uninit(&self, dst: *mut u8) { // SAFETY: we're calling a specialization with the same contract - unsafe { ::clone_one(self, dst) } + unsafe { ::clone_one(self, dst.cast::()) } } } @@ -282,7 +282,8 @@ unsafe impl CloneToUninit for T { unsafe impl CloneToUninit for [T] { #[inline] #[cfg_attr(debug_assertions, track_caller)] - unsafe fn clone_to_uninit(&self, dst: *mut Self) { + unsafe fn clone_to_uninit(&self, dst: *mut u8) { + let dst: *mut [T] = dst.with_metadata_of(self); // SAFETY: we're calling a specialization with the same contract unsafe { ::clone_slice(self, dst) } } @@ -292,21 +293,21 @@ unsafe impl CloneToUninit for [T] { unsafe impl CloneToUninit for str { #[inline] #[cfg_attr(debug_assertions, track_caller)] - unsafe fn clone_to_uninit(&self, dst: *mut Self) { + unsafe fn clone_to_uninit(&self, dst: *mut u8) { // SAFETY: str is just a [u8] with UTF-8 invariant - unsafe { self.as_bytes().clone_to_uninit(dst as *mut [u8]) } + unsafe { self.as_bytes().clone_to_uninit(dst) } } } #[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) { + unsafe fn clone_to_uninit(&self, dst: *mut u8) { // 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). + // The pointer metadata properly preserves the length (so NUL is also copied). // See: `cstr_metadata_is_length_with_nul` in tests. - unsafe { self.to_bytes_with_nul().clone_to_uninit(dst as *mut [u8]) } + unsafe { self.to_bytes_with_nul().clone_to_uninit(dst) } } } diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index b19d482feaad0..79dfb47d0c499 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -112,7 +112,7 @@ impl crate::sealed::Sealed for OsString {} /// [conversions]: super#conversions #[cfg_attr(not(test), rustc_diagnostic_item = "OsStr")] #[stable(feature = "rust1", since = "1.0.0")] -// `OsStr::from_inner` current implementation relies +// `OsStr::from_inner` and `impl CloneToUninit for OsStr` current implementation relies // on `OsStr` being layout-compatible with `Slice`. // However, `OsStr` layout is considered an implementation detail and must not be relied upon. #[repr(transparent)] @@ -1278,9 +1278,9 @@ impl Clone for Box { 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 - unsafe { self.inner.clone_to_uninit(&raw mut (*dst).inner) } + unsafe fn clone_to_uninit(&self, dst: *mut u8) { + // SAFETY: we're just a transparent wrapper around a platform-specific Slice + unsafe { self.inner.clone_to_uninit(dst) } } } diff --git a/library/std/src/ffi/os_str/tests.rs b/library/std/src/ffi/os_str/tests.rs index 67147934b4db3..cbec44c862646 100644 --- a/library/std/src/ffi/os_str/tests.rs +++ b/library/std/src/ffi/os_str/tests.rs @@ -294,12 +294,12 @@ fn clone_to_uninit() { let a = OsStr::new("hello.txt"); let mut storage = vec![MaybeUninit::::uninit(); size_of_val::(a)]; - unsafe { a.clone_to_uninit(ptr::from_mut::<[_]>(storage.as_mut_slice()) as *mut OsStr) }; + unsafe { a.clone_to_uninit(ptr::from_mut::<[_]>(storage.as_mut_slice()).cast()) }; assert_eq!(a.as_encoded_bytes(), unsafe { MaybeUninit::slice_assume_init_ref(&storage) }); let mut b: Box = OsStr::new("world.exe").into(); assert_eq!(size_of_val::(a), size_of_val::(&b)); assert_ne!(a, &*b); - unsafe { a.clone_to_uninit(ptr::from_mut::(&mut b)) }; + unsafe { a.clone_to_uninit(ptr::from_mut::(&mut b).cast()) }; assert_eq!(a, &*b); } diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 5662a44d83232..b0291e3aa196f 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2128,7 +2128,7 @@ impl AsRef for PathBuf { /// ``` #[cfg_attr(not(test), rustc_diagnostic_item = "Path")] #[stable(feature = "rust1", since = "1.0.0")] -// `Path::new` current implementation relies +// `Path::new` and `impl CloneToUninit for Path` current implementation relies // on `Path` being layout-compatible with `OsStr`. // However, `Path` layout is considered an implementation detail and must not be relied upon. #[repr(transparent)] @@ -3170,9 +3170,9 @@ impl Path { 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 - unsafe { self.inner.clone_to_uninit(&raw mut (*dst).inner) } + unsafe fn clone_to_uninit(&self, dst: *mut u8) { + // SAFETY: Path is just a transparent wrapper around OsStr + unsafe { self.inner.clone_to_uninit(dst) } } } diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs index b75793d2bc990..ff3f7151bb834 100644 --- a/library/std/src/path/tests.rs +++ b/library/std/src/path/tests.rs @@ -2068,7 +2068,7 @@ fn clone_to_uninit() { let a = Path::new("hello.txt"); let mut storage = vec![MaybeUninit::::uninit(); size_of_val::(a)]; - unsafe { a.clone_to_uninit(ptr::from_mut::<[_]>(storage.as_mut_slice()) as *mut Path) }; + unsafe { a.clone_to_uninit(ptr::from_mut::<[_]>(storage.as_mut_slice()).cast()) }; assert_eq!(a.as_os_str().as_encoded_bytes(), unsafe { MaybeUninit::slice_assume_init_ref(&storage) }); @@ -2076,6 +2076,6 @@ fn clone_to_uninit() { let mut b: Box = Path::new("world.exe").into(); assert_eq!(size_of_val::(a), size_of_val::(&b)); assert_ne!(a, &*b); - unsafe { a.clone_to_uninit(ptr::from_mut::(&mut b)) }; + unsafe { a.clone_to_uninit(ptr::from_mut::(&mut b).cast()) }; 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 8e0609fe48c53..5b65d862be102 100644 --- a/library/std/src/sys/os_str/bytes.rs +++ b/library/std/src/sys/os_str/bytes.rs @@ -352,8 +352,8 @@ impl Slice { 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] - unsafe { self.inner.clone_to_uninit(&raw mut (*dst).inner) } + unsafe fn clone_to_uninit(&self, dst: *mut u8) { + // SAFETY: we're just a transparent wrapper around [u8] + unsafe { self.inner.clone_to_uninit(dst) } } } diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs index b3834388df68a..a4ad5966afe57 100644 --- a/library/std/src/sys/os_str/wtf8.rs +++ b/library/std/src/sys/os_str/wtf8.rs @@ -275,8 +275,8 @@ impl Slice { 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 - unsafe { self.inner.clone_to_uninit(&raw mut (*dst).inner) } + unsafe fn clone_to_uninit(&self, dst: *mut u8) { + // SAFETY: we're just a transparent wrapper around Wtf8 + unsafe { self.inner.clone_to_uninit(dst) } } } diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index 19d4c94f45099..666942bb8a10f 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -1052,8 +1052,8 @@ impl Hash for Wtf8 { 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] - unsafe { self.bytes.clone_to_uninit(&raw mut (*dst).bytes) } + unsafe fn clone_to_uninit(&self, dst: *mut u8) { + // SAFETY: we're just a transparent wrapper around [u8] + unsafe { self.bytes.clone_to_uninit(dst) } } }