Skip to content

Commit 1c5930e

Browse files
authored
Rollup merge of rust-lang#145685 - Qelxiros:cell_get_cloned, r=programmerjake,tgross35
add CloneFromCell and Cell::get_cloned Tracking issue: rust-lang#145329
2 parents 6ec439d + 08b4641 commit 1c5930e

File tree

5 files changed

+119
-3
lines changed

5 files changed

+119
-3
lines changed

library/alloc/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
#![feature(bstr)]
9797
#![feature(bstr_internals)]
9898
#![feature(cast_maybe_uninit)]
99+
#![feature(cell_get_cloned)]
99100
#![feature(char_internals)]
100101
#![feature(char_max_len)]
101102
#![feature(clone_to_uninit)]

library/alloc/src/rc.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@
242242
#![stable(feature = "rust1", since = "1.0.0")]
243243

244244
use core::any::Any;
245-
use core::cell::Cell;
245+
use core::cell::{Cell, CloneFromCell};
246246
#[cfg(not(no_global_oom_handling))]
247247
use core::clone::CloneToUninit;
248248
use core::clone::UseCloned;
@@ -340,6 +340,10 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Rc<U, A>> for
340340
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
341341
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Rc<U>> for Rc<T> {}
342342

343+
// SAFETY: `Rc::clone` doesn't access any `Cell`s which could contain the `Rc` being cloned.
344+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
345+
unsafe impl<T: ?Sized> CloneFromCell for Rc<T> {}
346+
343347
impl<T: ?Sized> Rc<T> {
344348
#[inline]
345349
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
30133017
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
30143018
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Weak<U>> for Weak<T> {}
30153019

3020+
// SAFETY: `Weak::clone` doesn't access any `Cell`s which could contain the `Weak` being cloned.
3021+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
3022+
unsafe impl<T: ?Sized> CloneFromCell for Weak<T> {}
3023+
30163024
impl<T> Weak<T> {
30173025
/// Constructs a new `Weak<T>`, without allocating any memory.
30183026
/// Calling [`upgrade`] on the return value always gives [`None`].

library/alloc/src/sync.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
//! `#[cfg(target_has_atomic = "ptr")]`.
1010
1111
use core::any::Any;
12+
use core::cell::CloneFromCell;
1213
#[cfg(not(no_global_oom_handling))]
1314
use core::clone::CloneToUninit;
1415
use core::clone::UseCloned;
@@ -281,6 +282,10 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Arc<U, A>> fo
281282
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
282283
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Arc<U>> for Arc<T> {}
283284

285+
// SAFETY: `Arc::clone` doesn't access any `Cell`s which could contain the `Arc` being cloned.
286+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
287+
unsafe impl<T: ?Sized> CloneFromCell for Arc<T> {}
288+
284289
impl<T: ?Sized> Arc<T> {
285290
unsafe fn from_inner(ptr: NonNull<ArcInner<T>>) -> Self {
286291
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
356361
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
357362
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Weak<U>> for Weak<T> {}
358363

364+
// SAFETY: `Weak::clone` doesn't access any `Cell`s which could contain the `Weak` being cloned.
365+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
366+
unsafe impl<T: ?Sized> CloneFromCell for Weak<T> {}
367+
359368
#[stable(feature = "arc_weak", since = "1.4.0")]
360369
impl<T: ?Sized, A: Allocator> fmt::Debug for Weak<T, A> {
361370
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

library/core/src/cell.rs

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,11 +253,12 @@
253253
use crate::cmp::Ordering;
254254
use crate::fmt::{self, Debug, Display};
255255
use crate::marker::{PhantomData, Unsize};
256-
use crate::mem;
257-
use crate::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn};
256+
use crate::mem::{self, ManuallyDrop};
257+
use crate::ops::{self, CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn};
258258
use crate::panic::const_panic;
259259
use crate::pin::PinCoerceUnsized;
260260
use crate::ptr::{self, NonNull};
261+
use crate::range;
261262

262263
mod lazy;
263264
mod once;
@@ -713,6 +714,93 @@ impl<T, const N: usize> Cell<[T; N]> {
713714
}
714715
}
715716

717+
/// Types for which cloning `Cell<Self>` is sound.
718+
///
719+
/// # Safety
720+
///
721+
/// Implementing this trait for a type is sound if and only if the following code is sound for T =
722+
/// that type.
723+
///
724+
/// ```
725+
/// #![feature(cell_get_cloned)]
726+
/// # use std::cell::{CloneFromCell, Cell};
727+
/// fn clone_from_cell<T: CloneFromCell>(cell: &Cell<T>) -> T {
728+
/// unsafe { T::clone(&*cell.as_ptr()) }
729+
/// }
730+
/// ```
731+
///
732+
/// Importantly, you can't just implement `CloneFromCell` for any arbitrary `Copy` type, e.g. the
733+
/// following is unsound:
734+
///
735+
/// ```rust
736+
/// #![feature(cell_get_cloned)]
737+
/// # use std::cell::Cell;
738+
///
739+
/// #[derive(Copy, Debug)]
740+
/// pub struct Bad<'a>(Option<&'a Cell<Bad<'a>>>, u8);
741+
///
742+
/// impl Clone for Bad<'_> {
743+
/// fn clone(&self) -> Self {
744+
/// let a: &u8 = &self.1;
745+
/// // when self.0 points to self, we write to self.1 while we have a live `&u8` pointing to
746+
/// // it -- this is UB
747+
/// self.0.unwrap().set(Self(None, 1));
748+
/// dbg!((a, self));
749+
/// Self(None, 0)
750+
/// }
751+
/// }
752+
///
753+
/// // this is not sound
754+
/// // unsafe impl CloneFromCell for Bad<'_> {}
755+
/// ```
756+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
757+
// Allow potential overlapping implementations in user code
758+
#[marker]
759+
pub unsafe trait CloneFromCell: Clone {}
760+
761+
// `CloneFromCell` can be implemented for types that don't have indirection and which don't access
762+
// `Cell`s in their `Clone` implementation. A commonly-used subset is covered here.
763+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
764+
unsafe impl<T: CloneFromCell, const N: usize> CloneFromCell for [T; N] {}
765+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
766+
unsafe impl<T: CloneFromCell> CloneFromCell for Option<T> {}
767+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
768+
unsafe impl<T: CloneFromCell, E: CloneFromCell> CloneFromCell for Result<T, E> {}
769+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
770+
unsafe impl<T: ?Sized> CloneFromCell for PhantomData<T> {}
771+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
772+
unsafe impl<T: CloneFromCell> CloneFromCell for ManuallyDrop<T> {}
773+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
774+
unsafe impl<T: CloneFromCell> CloneFromCell for ops::Range<T> {}
775+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
776+
unsafe impl<T: CloneFromCell> CloneFromCell for range::Range<T> {}
777+
778+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
779+
impl<T: CloneFromCell> Cell<T> {
780+
/// Get a clone of the `Cell` that contains a copy of the original value.
781+
///
782+
/// This allows a cheaply `Clone`-able type like an `Rc` to be stored in a `Cell`, exposing the
783+
/// cheaper `clone()` method.
784+
///
785+
/// # Examples
786+
///
787+
/// ```
788+
/// #![feature(cell_get_cloned)]
789+
///
790+
/// use core::cell::Cell;
791+
/// use std::rc::Rc;
792+
///
793+
/// let rc = Rc::new(1usize);
794+
/// let c1 = Cell::new(rc);
795+
/// let c2 = c1.get_cloned();
796+
/// assert_eq!(*c2.into_inner(), 1);
797+
/// ```
798+
pub fn get_cloned(&self) -> Self {
799+
// SAFETY: T is CloneFromCell, which guarantees that this is sound.
800+
Cell::new(T::clone(unsafe { &*self.as_ptr() }))
801+
}
802+
}
803+
716804
/// A mutable memory location with dynamically checked borrow rules
717805
///
718806
/// See the [module-level documentation](self) for more.

library/core/src/tuple.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// See core/src/primitive_docs.rs for documentation.
22

3+
use crate::cell::CloneFromCell;
34
use crate::cmp::Ordering::{self, *};
45
use crate::marker::{ConstParamTy_, StructuralPartialEq};
56
use crate::ops::ControlFlow::{self, Break, Continue};
@@ -155,6 +156,15 @@ macro_rules! tuple_impls {
155156
}
156157
}
157158
}
159+
160+
maybe_tuple_doc! {
161+
$($T)+ @
162+
// SAFETY: tuples introduce no additional indirection, so they can be copied whenever T
163+
// can.
164+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
165+
unsafe impl<$($T: CloneFromCell),+> CloneFromCell for ($($T,)+)
166+
{}
167+
}
158168
}
159169
}
160170

0 commit comments

Comments
 (0)