Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make CloneToUninit dyn-compatible #133003

Merged
merged 2 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion library/alloc/src/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1735,7 +1735,7 @@ impl<T: Clone, A: Allocator + Clone> Clone for Box<T, A> {
// 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()
}
}
Expand Down
2 changes: 1 addition & 1 deletion library/alloc/src/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1876,7 +1876,7 @@ impl<T: ?Sized + CloneToUninit, A: Allocator + Clone> Rc<T, A> {
// 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()
};
Expand Down
2 changes: 1 addition & 1 deletion library/alloc/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2272,7 +2272,7 @@ impl<T: ?Sized + CloneToUninit, A: Allocator + Clone> Arc<T, A> {

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()
};
Expand Down
29 changes: 15 additions & 14 deletions library/core/src/clone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,20 +232,20 @@ pub struct AssertParamIsCopy<T: Copy + ?Sized> {
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()
Expand All @@ -266,23 +266,24 @@ 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<T: Clone> 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 { <T as self::uninit::CopySpec>::clone_one(self, dst) }
unsafe { <T as self::uninit::CopySpec>::clone_one(self, dst.cast::<T>()) }
}
}

#[unstable(feature = "clone_to_uninit", issue = "126799")]
unsafe impl<T: Clone> 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 { <T as self::uninit::CopySpec>::clone_slice(self, dst) }
}
Expand All @@ -292,21 +293,21 @@ unsafe impl<T: Clone> 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) }
}
}

Expand Down
8 changes: 4 additions & 4 deletions library/std/src/ffi/os_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -1278,9 +1278,9 @@ impl Clone for Box<OsStr> {
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) }
}
}

Expand Down
4 changes: 2 additions & 2 deletions library/std/src/ffi/os_str/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,12 +294,12 @@ 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) };
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> = 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)) };
unsafe { a.clone_to_uninit(ptr::from_mut::<OsStr>(&mut b).cast()) };
assert_eq!(a, &*b);
}
8 changes: 4 additions & 4 deletions library/std/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2128,7 +2128,7 @@ impl AsRef<OsStr> 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)]
Expand Down Expand Up @@ -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) }
}
}

Expand Down
4 changes: 2 additions & 2 deletions library/std/src/path/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2068,14 +2068,14 @@ 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) };
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)
});

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)) };
unsafe { a.clone_to_uninit(ptr::from_mut::<Path>(&mut b).cast()) };
assert_eq!(a, &*b);
}
6 changes: 3 additions & 3 deletions library/std/src/sys/os_str/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) }
}
}
6 changes: 3 additions & 3 deletions library/std/src/sys/os_str/wtf8.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) }
}
}
6 changes: 3 additions & 3 deletions library/std/src/sys_common/wtf8.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) }
}
}
Loading