Skip to content

Commit 3b9a4b0

Browse files
committed
Initial UnsafePinned/UnsafeUnpin impl [Part 1: Libs]
1 parent d1d4180 commit 3b9a4b0

File tree

4 files changed

+232
-0
lines changed

4 files changed

+232
-0
lines changed

Diff for: core/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@
127127
#![feature(ub_checks)]
128128
#![feature(unchecked_neg)]
129129
#![feature(unchecked_shifts)]
130+
#![feature(unsafe_pinned)]
130131
#![feature(utf16_extra)]
131132
#![feature(variant_count)]
132133
// tidy-alphabetical-end

Diff for: core/src/marker.rs

+29
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use crate::cell::UnsafeCell;
1717
use crate::cmp;
1818
use crate::fmt::Debug;
1919
use crate::hash::{Hash, Hasher};
20+
use crate::pin::UnsafePinned;
2021

2122
/// Implements a given marker trait for multiple types at the same time.
2223
///
@@ -878,6 +879,23 @@ marker_impls! {
878879
{T: ?Sized} &mut T,
879880
}
880881

882+
/// Used to determine whether a type contains any `UnsafePinned` (or `PhantomPinned`) internally,
883+
/// but not through an indirection. This affects, for example, whether we emit `noalias` metadata
884+
/// for `&mut T` or not.
885+
///
886+
/// This is part of [RFC 3467](https://rust-lang.github.io/rfcs/3467-unsafe-pinned.html), and is
887+
/// tracked by [#125735](https://github.com/rust-lang/rust/issues/125735).
888+
#[cfg_attr(not(bootstrap), lang = "unsafe_unpin")]
889+
#[cfg_attr(bootstrap, allow(dead_code))]
890+
pub(crate) unsafe auto trait UnsafeUnpin {}
891+
892+
impl<T: ?Sized> !UnsafeUnpin for UnsafePinned<T> {}
893+
unsafe impl<T: ?Sized> UnsafeUnpin for PhantomData<T> {}
894+
unsafe impl<T: ?Sized> UnsafeUnpin for *const T {}
895+
unsafe impl<T: ?Sized> UnsafeUnpin for *mut T {}
896+
unsafe impl<T: ?Sized> UnsafeUnpin for &T {}
897+
unsafe impl<T: ?Sized> UnsafeUnpin for &mut T {}
898+
881899
/// Types that do not require any pinning guarantees.
882900
///
883901
/// For information on what "pinning" is, see the [`pin` module] documentation.
@@ -953,13 +971,24 @@ pub auto trait Unpin {}
953971
/// A marker type which does not implement `Unpin`.
954972
///
955973
/// If a type contains a `PhantomPinned`, it will not implement `Unpin` by default.
974+
//
975+
// FIXME(unsafe_pinned): This is *not* a stable guarantee we want to make, at least not yet.
976+
// Note that for backwards compatibility with the new [`UnsafePinned`] wrapper type, placing this
977+
// marker in your struct acts as if you wrapped the entire struct in an `UnsafePinned`. This type
978+
// will likely eventually be deprecated, and all new code should be using `UnsafePinned` instead.
956979
#[stable(feature = "pin", since = "1.33.0")]
957980
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
958981
pub struct PhantomPinned;
959982

960983
#[stable(feature = "pin", since = "1.33.0")]
961984
impl !Unpin for PhantomPinned {}
962985

986+
// This is a small hack to allow existing code which uses PhantomPinned to opt-out of noalias to
987+
// continue working. Ideally PhantomPinned could just wrap an `UnsafePinned<()>` to get the same
988+
// effect, but we can't add a new field to an already stable unit struct -- that would be a breaking
989+
// change.
990+
impl !UnsafeUnpin for PhantomPinned {}
991+
963992
marker_impls! {
964993
#[stable(feature = "pin", since = "1.33.0")]
965994
Unpin for

Diff for: core/src/pin.rs

+5
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,11 @@ use crate::{
931931
};
932932
use crate::{cmp, fmt};
933933

934+
mod unsafe_pinned;
935+
936+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
937+
pub use self::unsafe_pinned::UnsafePinned;
938+
934939
/// A pointer which pins its pointee in place.
935940
///
936941
/// [`Pin`] is a wrapper around some kind of pointer `Ptr` which makes that pointer "pin" its

Diff for: core/src/pin/unsafe_pinned.rs

+197
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
use crate::marker::{PointerLike, Unpin};
2+
use crate::ops::{CoerceUnsized, DispatchFromDyn};
3+
use crate::pin::Pin;
4+
use crate::{fmt, ptr};
5+
6+
/// This type provides a way to opt-out of typical aliasing rules;
7+
/// specifically, `&mut UnsafePinned<T>` is not guaranteed to be a unique pointer.
8+
///
9+
/// However, even if you define your type like `pub struct Wrapper(UnsafePinned<...>)`, it is still
10+
/// very risky to have an `&mut Wrapper` that aliases anything else. Many functions that work
11+
/// generically on `&mut T` assume that the memory that stores `T` is uniquely owned (such as
12+
/// `mem::swap`). In other words, while having aliasing with `&mut Wrapper` is not immediate
13+
/// Undefined Behavior, it is still unsound to expose such a mutable reference to code you do not
14+
/// control! Techniques such as pinning via [`Pin`] are needed to ensure soundness.
15+
///
16+
/// Similar to [`UnsafeCell`](crate::cell::UnsafeCell), `UnsafePinned` will not usually show up in
17+
/// the public API of a library. It is an internal implementation detail of libraries that need to
18+
/// support aliasing mutable references.
19+
///
20+
/// Further note that this does *not* lift the requirement that shared references must be read-only!
21+
/// Use `UnsafeCell` for that.
22+
///
23+
/// This type blocks niches the same way `UnsafeCell` does.
24+
#[cfg_attr(not(bootstrap), lang = "unsafe_pinned")]
25+
#[repr(transparent)]
26+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
27+
pub struct UnsafePinned<T: ?Sized> {
28+
value: T,
29+
}
30+
31+
/// When this type is used, that almost certainly means safe APIs need to use pinning to avoid the
32+
/// aliases from becoming invalidated. Therefore let's mark this as `!Unpin`. You can always opt
33+
/// back in to `Unpin` with an `impl` block, provided your API is still sound while unpinned.
34+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
35+
impl<T: ?Sized> !Unpin for UnsafePinned<T> {}
36+
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+
52+
// `Send` and `Sync` are inherited from `T`. This is similar to `SyncUnsafeCell`, since
53+
// we eventually concluded that `UnsafeCell` implicitly making things `!Sync` is sometimes
54+
// unergonomic. A type that needs to be `!Send`/`!Sync` should really have an explicit
55+
// opt-out itself, e.g. via an `PhantomData<*mut T>` or (one day) via `impl !Send`/`impl !Sync`.
56+
57+
impl<T> UnsafePinned<T> {
58+
/// Constructs a new instance of `UnsafePinned` which will wrap the specified value.
59+
///
60+
/// All access to the inner value through `&UnsafePinned<T>` or `&mut UnsafePinned<T>` or
61+
/// `Pin<&mut UnsafePinned<T>>` requires `unsafe` code.
62+
#[inline(always)]
63+
#[must_use]
64+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
65+
pub const fn new(value: T) -> Self {
66+
UnsafePinned { value }
67+
}
68+
69+
/// Unwraps the value, consuming this `UnsafePinned`.
70+
#[inline(always)]
71+
#[must_use]
72+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
73+
#[rustc_allow_const_fn_unstable(const_precise_live_drops)]
74+
pub const fn into_inner(self) -> T {
75+
self.value
76+
}
77+
}
78+
79+
impl<T: ?Sized> UnsafePinned<T> {
80+
/// Get read-write access to the contents of a pinned `UnsafePinned`.
81+
#[inline(always)]
82+
#[must_use]
83+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
84+
pub const fn get_mut_pinned(self: Pin<&mut Self>) -> *mut T {
85+
// SAFETY: we're not using `get_unchecked_mut` to unpin anything
86+
unsafe { self.get_unchecked_mut() }.get_mut_unchecked()
87+
}
88+
89+
/// Get read-write access to the contents of an `UnsafePinned`.
90+
///
91+
/// You should usually be using `get_mut_pinned` instead to explicitly track the fact that this
92+
/// memory is "pinned" due to there being aliases.
93+
#[inline(always)]
94+
#[must_use]
95+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
96+
pub const fn get_mut_unchecked(&mut self) -> *mut T {
97+
ptr::from_mut(self) as *mut T
98+
}
99+
100+
/// Get read-only access to the contents of a shared `UnsafePinned`.
101+
///
102+
/// Note that `&UnsafePinned<T>` is read-only if `&T` is read-only. This means that if there is
103+
/// mutation of the `T`, future reads from the `*const T` returned here are UB! Use
104+
/// [`UnsafeCell`] if you also need interior mutability.
105+
///
106+
/// [`UnsafeCell`]: crate::cell::UnsafeCell
107+
///
108+
/// ```rust,no_run
109+
/// #![feature(unsafe_pinned)]
110+
/// use std::pin::UnsafePinned;
111+
///
112+
/// unsafe {
113+
/// let mut x = UnsafePinned::new(0);
114+
/// let ptr = x.get(); // read-only pointer, assumes immutability
115+
/// x.get_mut_unchecked().write(1);
116+
/// ptr.read(); // UB!
117+
/// }
118+
/// ```
119+
#[inline(always)]
120+
#[must_use]
121+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
122+
pub const fn get(&self) -> *const T {
123+
ptr::from_ref(self) as *const T
124+
}
125+
126+
/// Gets an immutable pointer to the wrapped value.
127+
///
128+
/// The difference from [`get`] is that this function accepts a raw pointer, which is useful to
129+
/// avoid the creation of temporary references.
130+
///
131+
/// [`get`]: UnsafePinned::get
132+
#[inline(always)]
133+
#[must_use]
134+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
135+
pub const fn raw_get(this: *const Self) -> *const T {
136+
this as *const T
137+
}
138+
139+
/// Gets a mutable pointer to the wrapped value.
140+
///
141+
/// The difference from [`get_mut_pinned`] and [`get_mut_unchecked`] is that this function
142+
/// accepts a raw pointer, which is useful to avoid the creation of temporary references.
143+
///
144+
/// [`get_mut_pinned`]: UnsafePinned::get_mut_pinned
145+
/// [`get_mut_unchecked`]: UnsafePinned::get_mut_unchecked
146+
#[inline(always)]
147+
#[must_use]
148+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
149+
pub const fn raw_get_mut(this: *mut Self) -> *mut T {
150+
this as *mut T
151+
}
152+
}
153+
154+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
155+
impl<T: Default> Default for UnsafePinned<T> {
156+
/// Creates an `UnsafePinned`, with the `Default` value for T.
157+
fn default() -> Self {
158+
UnsafePinned::new(T::default())
159+
}
160+
}
161+
162+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
163+
impl<T> From<T> for UnsafePinned<T> {
164+
/// Creates a new `UnsafePinned<T>` containing the given value.
165+
fn from(value: T) -> Self {
166+
UnsafePinned::new(value)
167+
}
168+
}
169+
170+
#[unstable(feature = "unsafe_pinned", issue = "125735")]
171+
impl<T: ?Sized> fmt::Debug for UnsafePinned<T> {
172+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173+
f.debug_struct("UnsafePinned").finish_non_exhaustive()
174+
}
175+
}
176+
177+
#[unstable(feature = "coerce_unsized", issue = "18598")]
178+
// #[unstable(feature = "unsafe_pinned", issue = "125735")]
179+
impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafePinned<U>> for UnsafePinned<T> {}
180+
181+
// Allow types that wrap `UnsafePinned` to also implement `DispatchFromDyn`
182+
// and become dyn-compatible method receivers.
183+
// Note that currently `UnsafePinned` itself cannot be a method receiver
184+
// because it does not implement Deref.
185+
// In other words:
186+
// `self: UnsafePinned<&Self>` won't work
187+
// `self: UnsafePinned<Self>` becomes possible
188+
// FIXME(unsafe_pinned) this logic is copied from UnsafeCell, is it still sound?
189+
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
190+
// #[unstable(feature = "unsafe_pinned", issue = "125735")]
191+
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<UnsafePinned<U>> for UnsafePinned<T> {}
192+
193+
#[unstable(feature = "pointer_like_trait", issue = "none")]
194+
// #[unstable(feature = "unsafe_pinned", issue = "125735")]
195+
impl<T: PointerLike> PointerLike for UnsafePinned<T> {}
196+
197+
// FIXME(unsafe_pinned): impl PinCoerceUnsized for UnsafePinned<T>?

0 commit comments

Comments
 (0)