Skip to content

Commit e823a89

Browse files
committed
Initial UnsafePinned/UnsafeUnpin impl [Part 1: Libs]
1 parent ced8e65 commit e823a89

File tree

10 files changed

+261
-9
lines changed

10 files changed

+261
-9
lines changed

compiler/rustc_abi/src/layout.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
240240
repr: &ReprOptions,
241241
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
242242
is_enum: bool,
243-
is_unsafe_cell: bool,
243+
is_special_no_niche: bool,
244244
scalar_valid_range: (Bound<u128>, Bound<u128>),
245245
discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool),
246246
discriminants: impl Iterator<Item = (VariantIdx, i128)>,
@@ -273,7 +273,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
273273
repr,
274274
variants,
275275
is_enum,
276-
is_unsafe_cell,
276+
is_special_no_niche,
277277
scalar_valid_range,
278278
always_sized,
279279
present_first,
@@ -418,7 +418,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
418418
repr: &ReprOptions,
419419
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
420420
is_enum: bool,
421-
is_unsafe_cell: bool,
421+
is_special_no_niche: bool,
422422
scalar_valid_range: (Bound<u128>, Bound<u128>),
423423
always_sized: bool,
424424
present_first: VariantIdx,
@@ -437,7 +437,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
437437
let mut st = self.univariant(&variants[v], repr, kind)?;
438438
st.variants = Variants::Single { index: v };
439439

440-
if is_unsafe_cell {
440+
if is_special_no_niche {
441441
let hide_niches = |scalar: &mut _| match scalar {
442442
Scalar::Initialized { value, valid_range } => {
443443
*valid_range = WrappingRange::full(value.size(dl))

compiler/rustc_hir/src/lang_items.rs

+3
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ language_item_table! {
181181
DynMetadata, sym::dyn_metadata, dyn_metadata, Target::Struct, GenericRequirement::None;
182182

183183
Freeze, sym::freeze, freeze_trait, Target::Trait, GenericRequirement::Exact(0);
184+
UnsafeUnpin, sym::unsafe_unpin, unsafe_unpin_trait, Target::Trait, GenericRequirement::Exact(0);
184185

185186
FnPtrTrait, sym::fn_ptr_trait, fn_ptr_trait, Target::Trait, GenericRequirement::Exact(0);
186187
FnPtrAddr, sym::fn_ptr_addr, fn_ptr_addr, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
@@ -234,6 +235,8 @@ language_item_table! {
234235
IndexMut, sym::index_mut, index_mut_trait, Target::Trait, GenericRequirement::Exact(1);
235236

236237
UnsafeCell, sym::unsafe_cell, unsafe_cell_type, Target::Struct, GenericRequirement::None;
238+
UnsafePinned, sym::unsafe_pinned, unsafe_pinned_type, Target::Struct, GenericRequirement::None;
239+
237240
VaList, sym::va_list, va_list, Target::Struct, GenericRequirement::None;
238241

239242
Deref, sym::deref, deref_trait, Target::Trait, GenericRequirement::Exact(0);

compiler/rustc_lint/src/types.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -867,8 +867,8 @@ fn ty_is_known_nonnull<'tcx>(
867867
return true;
868868
}
869869

870-
// `UnsafeCell` has its niche hidden.
871-
if def.is_unsafe_cell() {
870+
// `UnsafeCell` and `UnsafePinned` have their niche hidden.
871+
if def.is_unsafe_cell() || def.is_unsafe_pinned() {
872872
return false;
873873
}
874874

compiler/rustc_middle/src/ty/adt.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,10 @@ bitflags::bitflags! {
5454
const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 8;
5555
/// Indicates whether the type is `UnsafeCell`.
5656
const IS_UNSAFE_CELL = 1 << 9;
57+
/// Indicates whether the type is `UnsafePinned`.
58+
const IS_UNSAFE_PINNED = 1 << 10;
5759
/// Indicates whether the type is anonymous.
58-
const IS_ANONYMOUS = 1 << 10;
60+
const IS_ANONYMOUS = 1 << 11;
5961
}
6062
}
6163
rustc_data_structures::external_bitflags_debug! { AdtFlags }
@@ -301,6 +303,9 @@ impl AdtDefData {
301303
if tcx.is_lang_item(did, LangItem::UnsafeCell) {
302304
flags |= AdtFlags::IS_UNSAFE_CELL;
303305
}
306+
if tcx.is_lang_item(did, LangItem::UnsafePinned) {
307+
flags |= AdtFlags::IS_UNSAFE_PINNED;
308+
}
304309

305310
AdtDefData { did, variants, flags, repr }
306311
}
@@ -393,6 +398,12 @@ impl<'tcx> AdtDef<'tcx> {
393398
self.flags().contains(AdtFlags::IS_UNSAFE_CELL)
394399
}
395400

401+
/// Returns `true` if this is `UnsafePinned<T>`.
402+
#[inline]
403+
pub fn is_unsafe_pinned(self) -> bool {
404+
self.flags().contains(AdtFlags::IS_UNSAFE_PINNED)
405+
}
406+
396407
/// Returns `true` if this is `ManuallyDrop<T>`.
397408
#[inline]
398409
pub fn is_manually_drop(self) -> bool {

compiler/rustc_span/src/symbol.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2152,6 +2152,8 @@ symbols! {
21522152
unsafe_fields,
21532153
unsafe_no_drop_flag,
21542154
unsafe_pin_internals,
2155+
unsafe_pinned,
2156+
unsafe_unpin,
21552157
unsize,
21562158
unsized_const_param_ty,
21572159
unsized_const_params,

compiler/rustc_ty_utils/src/layout.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,9 @@ fn layout_of_uncached<'tcx>(
619619
));
620620
}
621621

622+
// UnsafeCell and UnsafePinned both disable niche optimizations
623+
let is_special_no_niche = def.is_unsafe_cell() || def.is_unsafe_pinned();
624+
622625
let get_discriminant_type =
623626
|min, max| abi::Integer::repr_discr(tcx, ty, &def.repr(), min, max);
624627

@@ -647,7 +650,7 @@ fn layout_of_uncached<'tcx>(
647650
&def.repr(),
648651
&variants,
649652
def.is_enum(),
650-
def.is_unsafe_cell(),
653+
is_special_no_niche,
651654
tcx.layout_scalar_valid_range(def.did()),
652655
get_discriminant_type,
653656
discriminants_iter(),
@@ -673,7 +676,7 @@ fn layout_of_uncached<'tcx>(
673676
&def.repr(),
674677
&variants,
675678
def.is_enum(),
676-
def.is_unsafe_cell(),
679+
is_special_no_niche,
677680
tcx.layout_scalar_valid_range(def.did()),
678681
get_discriminant_type,
679682
discriminants_iter(),

library/core/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@
139139
#![feature(ub_checks)]
140140
#![feature(unchecked_neg)]
141141
#![feature(unchecked_shifts)]
142+
#![feature(unsafe_pinned)]
142143
#![feature(utf16_extra)]
143144
#![feature(variant_count)]
144145
// tidy-alphabetical-end

library/core/src/marker.rs

+27
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
///
@@ -858,6 +859,20 @@ marker_impls! {
858859
{T: ?Sized} &mut T,
859860
}
860861

862+
/// Used to determine whether a type contains any `UnsafePinned`
863+
/// (or `PhantomPinned`) internally, but not through an indirection. This
864+
/// affects, for example, whether we emit `noalias` metadata for `&mut T` or not.
865+
#[cfg_attr(not(bootstrap), lang = "unsafe_unpin")]
866+
#[cfg_attr(bootstrap, allow(dead_code))]
867+
pub(crate) unsafe auto trait UnsafeUnpin {}
868+
869+
impl<T: ?Sized> !UnsafeUnpin for UnsafePinned<T> {}
870+
unsafe impl<T: ?Sized> UnsafeUnpin for PhantomData<T> {}
871+
unsafe impl<T: ?Sized> UnsafeUnpin for *const T {}
872+
unsafe impl<T: ?Sized> UnsafeUnpin for *mut T {}
873+
unsafe impl<T: ?Sized> UnsafeUnpin for &T {}
874+
unsafe impl<T: ?Sized> UnsafeUnpin for &mut T {}
875+
861876
/// Types that do not require any pinning guarantees.
862877
///
863878
/// For information on what "pinning" is, see the [`pin` module] documentation.
@@ -933,13 +948,25 @@ pub auto trait Unpin {}
933948
/// A marker type which does not implement `Unpin`.
934949
///
935950
/// If a type contains a `PhantomPinned`, it will not implement `Unpin` by default.
951+
//
952+
// FIXME(unsafe_pinned): This is *not* a stable guarantee we want to make, at least not yet.
953+
// Note that for backwards compatibility with the new [`UnsafePinned`] wrapper
954+
// type, placing this marker in your struct acts as if you wrapped the entire
955+
// struct in an `UnsafePinned`. This type will likely eventually be deprecated,
956+
// and all new code should be using `UnsafePinned` instead.
936957
#[stable(feature = "pin", since = "1.33.0")]
937958
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
938959
pub struct PhantomPinned;
939960

940961
#[stable(feature = "pin", since = "1.33.0")]
941962
impl !Unpin for PhantomPinned {}
942963

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

library/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

0 commit comments

Comments
 (0)