From bafe406711a4e7e9e2683d9245fcc13f306e1d83 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 7 Jun 2025 15:42:19 +0200 Subject: [PATCH 1/2] UnsafePinned: update get() docs and signature to allow shared mutation --- library/core/src/cell.rs | 2 +- library/core/src/pin/unsafe_pinned.rs | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index ed523920e42b5..0656ab98ee3c1 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -2170,7 +2170,7 @@ impl UnsafeCell { /// This can be cast to a pointer of any kind. /// Ensure that the access is unique (no active references, mutable or not) /// when casting to `&mut T`, and ensure that there are no mutations - /// or mutable aliases going on when casting to `&T` + /// or mutable aliases going on when casting to `&T`. /// /// # Examples /// diff --git a/library/core/src/pin/unsafe_pinned.rs b/library/core/src/pin/unsafe_pinned.rs index dbcceb807aba8..f3d5e07983827 100644 --- a/library/core/src/pin/unsafe_pinned.rs +++ b/library/core/src/pin/unsafe_pinned.rs @@ -86,11 +86,14 @@ impl UnsafePinned { ptr::from_mut(self) as *mut T } - /// Get read-only access to the contents of a shared `UnsafePinned`. + /// Get mutable access to the contents of a shared `UnsafePinned`. /// - /// Note that `&UnsafePinned` is read-only if `&T` is read-only. This means that if there is - /// mutation of the `T`, future reads from the `*const T` returned here are UB! Use - /// [`UnsafeCell`] if you also need interior mutability. + /// This can be cast to a pointer of any kind. + /// Ensure that the access is unique (no active references, mutable or not) + /// when casting to `&mut T`, and ensure that there are no mutations + /// or mutable aliases going on when casting to `&T`. + /// + /// All the usual caveats around mutation shared state apply, see [`UnsafeCell`]. /// /// [`UnsafeCell`]: crate::cell::UnsafeCell /// @@ -100,16 +103,16 @@ impl UnsafePinned { /// /// unsafe { /// let mut x = UnsafePinned::new(0); - /// let ptr = x.get(); // read-only pointer, assumes immutability + /// let ptr = x.get(); /// x.get_mut_unchecked().write(1); - /// ptr.read(); // UB! + /// assert_eq!(ptr.read(), 1); /// } /// ``` #[inline(always)] #[must_use] #[unstable(feature = "unsafe_pinned", issue = "125735")] - pub const fn get(&self) -> *const T { - ptr::from_ref(self) as *const T + pub const fn get(&self) -> *mut T { + self.value.get() } /// Gets an immutable pointer to the wrapped value. From bd0a81ee82bbc9e7e163bab648c86170cf816c5e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 7 Jun 2025 21:57:45 +0200 Subject: [PATCH 2/2] centralize aliasing rules discussion in UnsafeCell docs --- library/core/src/cell.rs | 16 ++++++++-------- library/core/src/pin/unsafe_pinned.rs | 10 +++------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 0656ab98ee3c1..a4b6efe35fc14 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1914,6 +1914,8 @@ impl fmt::Display for RefMut<'_, T> { /// [`.get()`]: `UnsafeCell::get` /// [concurrent memory model]: ../sync/atomic/index.html#memory-model-for-atomic-accesses /// +/// # Aliasing rules +/// /// The precise Rust aliasing rules are somewhat in flux, but the main points are not contentious: /// /// - If you create a safe reference with lifetime `'a` (either a `&T` or `&mut T` reference), then @@ -2167,10 +2169,9 @@ impl UnsafeCell { /// Gets a mutable pointer to the wrapped value. /// - /// This can be cast to a pointer of any kind. - /// Ensure that the access is unique (no active references, mutable or not) - /// when casting to `&mut T`, and ensure that there are no mutations - /// or mutable aliases going on when casting to `&T`. + /// This can be cast to a pointer of any kind. When creating references, you must uphold the + /// aliasing rules; see [the type-level docs][UnsafeCell#aliasing-rules] for more discussion and + /// caveats. /// /// # Examples /// @@ -2219,10 +2220,9 @@ impl UnsafeCell { /// The difference from [`get`] is that this function accepts a raw pointer, /// which is useful to avoid the creation of temporary references. /// - /// The result can be cast to a pointer of any kind. - /// Ensure that the access is unique (no active references, mutable or not) - /// when casting to `&mut T`, and ensure that there are no mutations - /// or mutable aliases going on when casting to `&T`. + /// This can be cast to a pointer of any kind. When creating references, you must uphold the + /// aliasing rules; see [the type-level docs][UnsafeCell#aliasing-rules] for more discussion and + /// caveats. /// /// [`get`]: UnsafeCell::get() /// diff --git a/library/core/src/pin/unsafe_pinned.rs b/library/core/src/pin/unsafe_pinned.rs index f3d5e07983827..17f7bcd306b05 100644 --- a/library/core/src/pin/unsafe_pinned.rs +++ b/library/core/src/pin/unsafe_pinned.rs @@ -88,14 +88,10 @@ impl UnsafePinned { /// Get mutable access to the contents of a shared `UnsafePinned`. /// - /// This can be cast to a pointer of any kind. - /// Ensure that the access is unique (no active references, mutable or not) - /// when casting to `&mut T`, and ensure that there are no mutations - /// or mutable aliases going on when casting to `&T`. + /// This can be cast to a pointer of any kind. When creating references, you must uphold the + /// aliasing rules; see [`UnsafeCell`] for more discussion and caveats. /// - /// All the usual caveats around mutation shared state apply, see [`UnsafeCell`]. - /// - /// [`UnsafeCell`]: crate::cell::UnsafeCell + /// [`UnsafeCell`]: crate::cell::UnsafeCell#aliasing-rules /// /// ```rust,no_run /// #![feature(unsafe_pinned)]