diff options
| author | Matthias Krüger <476013+matthiaskrgr@users.noreply.github.com> | 2025-10-04 12:31:24 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-10-04 12:31:24 +0200 |
| commit | 73309e323030f84c9e8e37996076623defcbc3ab (patch) | |
| tree | 6a6d59bb4958415d53b50f36a5f60d536a4fc174 | |
| parent | d53856fd46a269d744f55fafaa4568f8ae1d77e6 (diff) | |
| parent | 08b4641f50f6f8fa3aa222fa606a0c1a2482b72d (diff) | |
| download | rust-73309e323030f84c9e8e37996076623defcbc3ab.tar.gz rust-73309e323030f84c9e8e37996076623defcbc3ab.zip | |
Rollup merge of #145685 - Qelxiros:cell_get_cloned, r=programmerjake,tgross35
add CloneFromCell and Cell::get_cloned Tracking issue: rust-lang/rust#145329
| -rw-r--r-- | library/alloc/src/lib.rs | 1 | ||||
| -rw-r--r-- | library/alloc/src/rc.rs | 10 | ||||
| -rw-r--r-- | library/alloc/src/sync.rs | 9 | ||||
| -rw-r--r-- | library/core/src/cell.rs | 92 | ||||
| -rw-r--r-- | library/core/src/tuple.rs | 10 |
5 files changed, 119 insertions, 3 deletions
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index fc3266b7479..87ad5b0ce30 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -96,6 +96,7 @@ #![feature(bstr)] #![feature(bstr_internals)] #![feature(cast_maybe_uninit)] +#![feature(cell_get_cloned)] #![feature(char_internals)] #![feature(char_max_len)] #![feature(clone_to_uninit)] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 023238a00db..2b62b92d438 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -242,7 +242,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use core::any::Any; -use core::cell::Cell; +use core::cell::{Cell, CloneFromCell}; #[cfg(not(no_global_oom_handling))] use core::clone::CloneToUninit; use core::clone::UseCloned; @@ -340,6 +340,10 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Rc<U, A>> for #[unstable(feature = "dispatch_from_dyn", issue = "none")] impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Rc<U>> for Rc<T> {} +// SAFETY: `Rc::clone` doesn't access any `Cell`s which could contain the `Rc` being cloned. +#[unstable(feature = "cell_get_cloned", issue = "145329")] +unsafe impl<T: ?Sized> CloneFromCell for Rc<T> {} + impl<T: ?Sized> Rc<T> { #[inline] unsafe fn from_inner(ptr: NonNull<RcInner<T>>) -> Self { @@ -3013,6 +3017,10 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Weak<U, A>> f #[unstable(feature = "dispatch_from_dyn", issue = "none")] impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Weak<U>> for Weak<T> {} +// SAFETY: `Weak::clone` doesn't access any `Cell`s which could contain the `Weak` being cloned. +#[unstable(feature = "cell_get_cloned", issue = "145329")] +unsafe impl<T: ?Sized> CloneFromCell for Weak<T> {} + impl<T> Weak<T> { /// Constructs a new `Weak<T>`, without allocating any memory. /// Calling [`upgrade`] on the return value always gives [`None`]. diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 6432bdfbbed..5927d036469 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -9,6 +9,7 @@ //! `#[cfg(target_has_atomic = "ptr")]`. use core::any::Any; +use core::cell::CloneFromCell; #[cfg(not(no_global_oom_handling))] use core::clone::CloneToUninit; use core::clone::UseCloned; @@ -281,6 +282,10 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Arc<U, A>> fo #[unstable(feature = "dispatch_from_dyn", issue = "none")] impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Arc<U>> for Arc<T> {} +// SAFETY: `Arc::clone` doesn't access any `Cell`s which could contain the `Arc` being cloned. +#[unstable(feature = "cell_get_cloned", issue = "145329")] +unsafe impl<T: ?Sized> CloneFromCell for Arc<T> {} + impl<T: ?Sized> Arc<T> { unsafe fn from_inner(ptr: NonNull<ArcInner<T>>) -> Self { unsafe { Self::from_inner_in(ptr, Global) } @@ -356,6 +361,10 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Weak<U, A>> f #[unstable(feature = "dispatch_from_dyn", issue = "none")] impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Weak<U>> for Weak<T> {} +// SAFETY: `Weak::clone` doesn't access any `Cell`s which could contain the `Weak` being cloned. +#[unstable(feature = "cell_get_cloned", issue = "145329")] +unsafe impl<T: ?Sized> CloneFromCell for Weak<T> {} + #[stable(feature = "arc_weak", since = "1.4.0")] impl<T: ?Sized, A: Allocator> fmt::Debug for Weak<T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 6aadb7a86cd..aeac35e45a5 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -253,11 +253,12 @@ use crate::cmp::Ordering; use crate::fmt::{self, Debug, Display}; use crate::marker::{PhantomData, Unsize}; -use crate::mem; -use crate::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn}; +use crate::mem::{self, ManuallyDrop}; +use crate::ops::{self, CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn}; use crate::panic::const_panic; use crate::pin::PinCoerceUnsized; use crate::ptr::{self, NonNull}; +use crate::range; mod lazy; mod once; @@ -713,6 +714,93 @@ impl<T, const N: usize> Cell<[T; N]> { } } +/// Types for which cloning `Cell<Self>` is sound. +/// +/// # Safety +/// +/// Implementing this trait for a type is sound if and only if the following code is sound for T = +/// that type. +/// +/// ``` +/// #![feature(cell_get_cloned)] +/// # use std::cell::{CloneFromCell, Cell}; +/// fn clone_from_cell<T: CloneFromCell>(cell: &Cell<T>) -> T { +/// unsafe { T::clone(&*cell.as_ptr()) } +/// } +/// ``` +/// +/// Importantly, you can't just implement `CloneFromCell` for any arbitrary `Copy` type, e.g. the +/// following is unsound: +/// +/// ```rust +/// #![feature(cell_get_cloned)] +/// # use std::cell::Cell; +/// +/// #[derive(Copy, Debug)] +/// pub struct Bad<'a>(Option<&'a Cell<Bad<'a>>>, u8); +/// +/// impl Clone for Bad<'_> { +/// fn clone(&self) -> Self { +/// let a: &u8 = &self.1; +/// // when self.0 points to self, we write to self.1 while we have a live `&u8` pointing to +/// // it -- this is UB +/// self.0.unwrap().set(Self(None, 1)); +/// dbg!((a, self)); +/// Self(None, 0) +/// } +/// } +/// +/// // this is not sound +/// // unsafe impl CloneFromCell for Bad<'_> {} +/// ``` +#[unstable(feature = "cell_get_cloned", issue = "145329")] +// Allow potential overlapping implementations in user code +#[marker] +pub unsafe trait CloneFromCell: Clone {} + +// `CloneFromCell` can be implemented for types that don't have indirection and which don't access +// `Cell`s in their `Clone` implementation. A commonly-used subset is covered here. +#[unstable(feature = "cell_get_cloned", issue = "145329")] +unsafe impl<T: CloneFromCell, const N: usize> CloneFromCell for [T; N] {} +#[unstable(feature = "cell_get_cloned", issue = "145329")] +unsafe impl<T: CloneFromCell> CloneFromCell for Option<T> {} +#[unstable(feature = "cell_get_cloned", issue = "145329")] +unsafe impl<T: CloneFromCell, E: CloneFromCell> CloneFromCell for Result<T, E> {} +#[unstable(feature = "cell_get_cloned", issue = "145329")] +unsafe impl<T: ?Sized> CloneFromCell for PhantomData<T> {} +#[unstable(feature = "cell_get_cloned", issue = "145329")] +unsafe impl<T: CloneFromCell> CloneFromCell for ManuallyDrop<T> {} +#[unstable(feature = "cell_get_cloned", issue = "145329")] +unsafe impl<T: CloneFromCell> CloneFromCell for ops::Range<T> {} +#[unstable(feature = "cell_get_cloned", issue = "145329")] +unsafe impl<T: CloneFromCell> CloneFromCell for range::Range<T> {} + +#[unstable(feature = "cell_get_cloned", issue = "145329")] +impl<T: CloneFromCell> Cell<T> { + /// Get a clone of the `Cell` that contains a copy of the original value. + /// + /// This allows a cheaply `Clone`-able type like an `Rc` to be stored in a `Cell`, exposing the + /// cheaper `clone()` method. + /// + /// # Examples + /// + /// ``` + /// #![feature(cell_get_cloned)] + /// + /// use core::cell::Cell; + /// use std::rc::Rc; + /// + /// let rc = Rc::new(1usize); + /// let c1 = Cell::new(rc); + /// let c2 = c1.get_cloned(); + /// assert_eq!(*c2.into_inner(), 1); + /// ``` + pub fn get_cloned(&self) -> Self { + // SAFETY: T is CloneFromCell, which guarantees that this is sound. + Cell::new(T::clone(unsafe { &*self.as_ptr() })) + } +} + /// A mutable memory location with dynamically checked borrow rules /// /// See the [module-level documentation](self) for more. diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index c57a8d81ade..58f81372aff 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -1,5 +1,6 @@ // See core/src/primitive_docs.rs for documentation. +use crate::cell::CloneFromCell; use crate::cmp::Ordering::{self, *}; use crate::marker::{ConstParamTy_, StructuralPartialEq}; use crate::ops::ControlFlow::{self, Break, Continue}; @@ -155,6 +156,15 @@ macro_rules! tuple_impls { } } } + + maybe_tuple_doc! { + $($T)+ @ + // SAFETY: tuples introduce no additional indirection, so they can be copied whenever T + // can. + #[unstable(feature = "cell_get_cloned", issue = "145329")] + unsafe impl<$($T: CloneFromCell),+> CloneFromCell for ($($T,)+) + {} + } } } |
