about summary refs log tree commit diff
path: root/library/core/src/cell.rs
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-10-04 13:37:12 +0000
committerbors <bors@rust-lang.org>2025-10-04 13:37:12 +0000
commit1bd98acf0e54f1ea678c4fabb8e1b10851eb8465 (patch)
treee1e0adfca6dd8050387b45ffb09c0985cf2a32a8 /library/core/src/cell.rs
parent99b9a8850349e56247acb6ce19910c7f96db8439 (diff)
parent1ebbb3c2fd78de38d0730cf9d874295f0d5dc2f1 (diff)
downloadrust-auto.tar.gz
rust-auto.zip
Auto merge of #147330 - matthiaskrgr:rollup-h4jyzmv, r=matthiaskrgr auto
Rollup of 11 pull requests

Successful merges:

 - rust-lang/rust#142670 (Document fully-qualified syntax in `as`' keyword doc)
 - rust-lang/rust#145685 (add CloneFromCell and Cell::get_cloned)
 - rust-lang/rust#146330 (Bump unicode_data and printables to version 17.0.0)
 - rust-lang/rust#146451 (Fix atan2 inaccuracy in documentation)
 - rust-lang/rust#146479 (add mem::conjure_zst)
 - rust-lang/rust#147117 (interpret `#[used]` as `#[used(compiler)]` on illumos)
 - rust-lang/rust#147190 (std: `sys::net` cleanups)
 - rust-lang/rust#147251 (Do not assert that a change in global cache only happens when concurrent)
 - rust-lang/rust#147280 (Return to needs-llvm-components being info-only)
 - rust-lang/rust#147288 (compiletest: Make `DirectiveLine` responsible for name/value splitting)
 - rust-lang/rust#147315 (bless autodiff batching test)

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'library/core/src/cell.rs')
-rw-r--r--library/core/src/cell.rs92
1 files changed, 90 insertions, 2 deletions
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.