Skip to content

Commit 11bd78c

Browse files
authored
Rollup merge of rust-lang#140638 - RalfJung:unsafe-pinned-shared-aliased, r=workingjubilee
UnsafePinned: also include the effects of UnsafeCell This tackles rust-lang#137750 by including an `UnsafeCell` in `UnsafePinned`, thus imbuing it with all the usual properties of interior mutability (no `noalias` nor `dereferenceable` on shared refs, special treatment by Miri's aliasing model). The soundness issue is not fixed yet because coroutine lowering does not use `UnsafePinned`. The RFC said that `UnsafePinned` would not permit mutability on shared references, but since then, rust-lang#137750 has demonstrated that this is not tenable. In the face of those examples, I propose that we do the "obvious" thing and permit shared mutable state inside `UnsafePinned`. This seems loosely consistent with the fact that we allow going from `Pin<&mut T>` to `&T` (where the former can be aliased with other pointers that perform mutation, and hence the same goes for the latter) -- but the `as_ref` example shows that we in fact would need to add this `UnsafeCell` even if we didn't have a safe conversion to `&T`, since for the compiler and Miri, `&T` and `Pin<&T>` are basically the same type. To make this possible, I had to remove the `Copy` and `Clone` impls for `UnsafePinned`. Tracking issue: rust-lang#125735 Cc ``@rust-lang/lang`` ``@rust-lang/opsem`` ``@Sky9x`` I don't think this needs FCP since the type is still unstable -- we'll finally decide whether we like this approach when `UnsafePinned` is moved towards stabilization (IOW, this PR is reversible). However, I'd still like to make sure that the lang team is okay with the direction I am proposing here.
2 parents 8b51863 + e014521 commit 11bd78c

File tree

1 file changed

+11
-22
lines changed

1 file changed

+11
-22
lines changed

core/src/pin/unsafe_pinned.rs

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
use crate::cell::UnsafeCell;
12
use crate::marker::{PointerLike, Unpin};
23
use crate::ops::{CoerceUnsized, DispatchFromDyn};
34
use crate::pin::Pin;
45
use crate::{fmt, ptr};
56

6-
/// This type provides a way to opt-out of typical aliasing rules;
7+
/// This type provides a way to entirely opt-out of typical aliasing rules;
78
/// specifically, `&mut UnsafePinned<T>` is not guaranteed to be a unique pointer.
9+
/// This also subsumes the effects of `UnsafeCell`, i.e., `&UnsafePinned<T>` may point to data
10+
/// that is being mutated.
811
///
912
/// However, even if you define your type like `pub struct Wrapper(UnsafePinned<...>)`, it is still
1013
/// very risky to have an `&mut Wrapper` that aliases anything else. Many functions that work
@@ -17,38 +20,24 @@ use crate::{fmt, ptr};
1720
/// the public API of a library. It is an internal implementation detail of libraries that need to
1821
/// support aliasing mutable references.
1922
///
20-
/// Further note that this does *not* lift the requirement that shared references must be read-only!
21-
/// Use `UnsafeCell` for that.
22-
///
2323
/// This type blocks niches the same way `UnsafeCell` does.
2424
#[lang = "unsafe_pinned"]
2525
#[repr(transparent)]
2626
#[unstable(feature = "unsafe_pinned", issue = "125735")]
2727
pub struct UnsafePinned<T: ?Sized> {
28-
value: T,
28+
value: UnsafeCell<T>,
2929
}
3030

31+
// Override the manual `!Sync` in `UnsafeCell`.
32+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
33+
unsafe impl<T: ?Sized + Sync> Sync for UnsafePinned<T> {}
34+
3135
/// When this type is used, that almost certainly means safe APIs need to use pinning to avoid the
3236
/// aliases from becoming invalidated. Therefore let's mark this as `!Unpin`. You can always opt
3337
/// back in to `Unpin` with an `impl` block, provided your API is still sound while unpinned.
3438
#[unstable(feature = "unsafe_pinned", issue = "125735")]
3539
impl<T: ?Sized> !Unpin for UnsafePinned<T> {}
3640

37-
/// The type is `Copy` when `T` is to avoid people assuming that `Copy` implies there is no
38-
/// `UnsafePinned` anywhere. (This is an issue with `UnsafeCell`: people use `Copy` bounds to mean
39-
/// `Freeze`.) Given that there is no `unsafe impl Copy for ...`, this is also the option that
40-
/// leaves the user more choices (as they can always wrap this in a `!Copy` type).
41-
// FIXME(unsafe_pinned): this may be unsound or a footgun?
42-
#[unstable(feature = "unsafe_pinned", issue = "125735")]
43-
impl<T: Copy> Copy for UnsafePinned<T> {}
44-
45-
#[unstable(feature = "unsafe_pinned", issue = "125735")]
46-
impl<T: Copy> Clone for UnsafePinned<T> {
47-
fn clone(&self) -> Self {
48-
*self
49-
}
50-
}
51-
5241
// `Send` and `Sync` are inherited from `T`. This is similar to `SyncUnsafeCell`, since
5342
// we eventually concluded that `UnsafeCell` implicitly making things `!Sync` is sometimes
5443
// unergonomic. A type that needs to be `!Send`/`!Sync` should really have an explicit
@@ -63,7 +52,7 @@ impl<T> UnsafePinned<T> {
6352
#[must_use]
6453
#[unstable(feature = "unsafe_pinned", issue = "125735")]
6554
pub const fn new(value: T) -> Self {
66-
UnsafePinned { value }
55+
UnsafePinned { value: UnsafeCell::new(value) }
6756
}
6857

6958
/// Unwraps the value, consuming this `UnsafePinned`.
@@ -72,7 +61,7 @@ impl<T> UnsafePinned<T> {
7261
#[unstable(feature = "unsafe_pinned", issue = "125735")]
7362
#[rustc_allow_const_fn_unstable(const_precise_live_drops)]
7463
pub const fn into_inner(self) -> T {
75-
self.value
64+
self.value.into_inner()
7665
}
7766
}
7867

0 commit comments

Comments
 (0)