Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions library/alloc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,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)]
Expand Down
10 changes: 9 additions & 1 deletion library/alloc/src/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -338,6 +338,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 {
Expand Down Expand Up @@ -3011,6 +3015,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`].
Expand Down
9 changes: 9 additions & 0 deletions library/alloc/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) }
Expand Down Expand Up @@ -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 {
Expand Down
92 changes: 90 additions & 2 deletions library/core/src/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be directly on the function instead? idk

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.
Expand Down
10 changes: 10 additions & 0 deletions library/core/src/tuple.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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,)+)
{}
}
}
}

Expand Down
Loading