Skip to content

Commit a9ea5ef

Browse files
authored
Unrolled build for #151365
Rollup merge of #151365 - RalfJung:unsafe-unpin-opsem, r=BoxyUwU UnsafePinned: implement opsem effects of UnsafeUnpin This implements the next step for #125735: actually making `UnsafePinned` have special opsem effects by suppressing the `noalias` *even if* the type is wrapped in an `Unpin` wrapper. For backwards compatibility we also still keep the `Unpin` hack, i.e. a type must be both `Unpin` and `UnsafeUnpin` to get `noalias`.
2 parents a33907a + 0cbe1cc commit a9ea5ef

16 files changed

Lines changed: 121 additions & 34 deletions

File tree

compiler/rustc_middle/src/queries.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1693,6 +1693,10 @@ rustc_queries! {
16931693
query is_freeze_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
16941694
desc { "computing whether `{}` is freeze", env.value }
16951695
}
1696+
/// Query backing `Ty::is_unsafe_unpin`.
1697+
query is_unsafe_unpin_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
1698+
desc { "computing whether `{}` is `UnsafeUnpin`", env.value }
1699+
}
16961700
/// Query backing `Ty::is_unpin`.
16971701
query is_unpin_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
16981702
desc { "computing whether `{}` is `Unpin`", env.value }

compiler/rustc_middle/src/ty/layout.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,9 +1046,11 @@ where
10461046
hir::Mutability::Not => {
10471047
PointerKind::SharedRef { frozen: optimize && ty.is_freeze(tcx, typing_env) }
10481048
}
1049-
hir::Mutability::Mut => {
1050-
PointerKind::MutableRef { unpin: optimize && ty.is_unpin(tcx, typing_env) }
1051-
}
1049+
hir::Mutability::Mut => PointerKind::MutableRef {
1050+
unpin: optimize
1051+
&& ty.is_unpin(tcx, typing_env)
1052+
&& ty.is_unsafe_unpin(tcx, typing_env),
1053+
},
10521054
};
10531055

10541056
tcx.layout_of(typing_env.as_query_input(ty)).ok().map(|layout| PointeeInfo {
@@ -1143,7 +1145,9 @@ where
11431145
debug_assert!(pointee.safe.is_none());
11441146
let optimize = tcx.sess.opts.optimize != OptLevel::No;
11451147
pointee.safe = Some(PointerKind::Box {
1146-
unpin: optimize && boxed_ty.is_unpin(tcx, typing_env),
1148+
unpin: optimize
1149+
&& boxed_ty.is_unpin(tcx, typing_env)
1150+
&& boxed_ty.is_unsafe_unpin(tcx, typing_env),
11471151
global: this.ty.is_box_global(tcx),
11481152
});
11491153
}

compiler/rustc_middle/src/ty/util.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,14 +1189,23 @@ impl<'tcx> Ty<'tcx> {
11891189
}
11901190
}
11911191

1192+
/// Checks whether values of this type `T` implement the `UnsafeUnpin` trait.
1193+
pub fn is_unsafe_unpin(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool {
1194+
self.is_trivially_unpin() || tcx.is_unsafe_unpin_raw(typing_env.as_query_input(self))
1195+
}
1196+
11921197
/// Checks whether values of this type `T` implement the `Unpin` trait.
1198+
///
1199+
/// Note that this is a safe trait, so it cannot be very semantically meaningful.
1200+
/// However, as a hack to mitigate <https://github.com/rust-lang/rust/issues/63818> until a
1201+
/// proper solution is implemented, we do give special semantics to the `Unpin` trait.
11931202
pub fn is_unpin(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool {
11941203
self.is_trivially_unpin() || tcx.is_unpin_raw(typing_env.as_query_input(self))
11951204
}
11961205

1197-
/// Fast path helper for testing if a type is `Unpin`.
1206+
/// Fast path helper for testing if a type is `Unpin` *and* `UnsafeUnpin`.
11981207
///
1199-
/// Returning true means the type is known to be `Unpin`. Returning
1208+
/// Returning true means the type is known to be `Unpin` and `UnsafeUnpin`. Returning
12001209
/// `false` means nothing -- could be `Unpin`, might not be.
12011210
fn is_trivially_unpin(self) -> bool {
12021211
match self.kind() {

compiler/rustc_ty_utils/src/abi.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,8 +306,12 @@ fn arg_attrs_for_rust_scalar<'tcx>(
306306
let kind = if let Some(kind) = pointee.safe {
307307
Some(kind)
308308
} else if let Some(pointee) = drop_target_pointee {
309+
assert_eq!(pointee, layout.ty.builtin_deref(true).unwrap());
310+
assert_eq!(offset, Size::ZERO);
309311
// The argument to `drop_in_place` is semantically equivalent to a mutable reference.
310-
Some(PointerKind::MutableRef { unpin: pointee.is_unpin(tcx, cx.typing_env) })
312+
let mutref = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, pointee);
313+
let layout = cx.layout_of(mutref).unwrap();
314+
layout.pointee_info_at(&cx, offset).and_then(|pi| pi.safe)
311315
} else {
312316
None
313317
};

compiler/rustc_ty_utils/src/common_traits.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,36 +8,43 @@ use rustc_span::DUMMY_SP;
88
use rustc_trait_selection::traits;
99

1010
fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
11-
is_item_raw(tcx, query, LangItem::Copy)
11+
is_trait_raw(tcx, query, LangItem::Copy)
1212
}
1313

1414
fn is_use_cloned_raw<'tcx>(
1515
tcx: TyCtxt<'tcx>,
1616
query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>,
1717
) -> bool {
18-
is_item_raw(tcx, query, LangItem::UseCloned)
18+
is_trait_raw(tcx, query, LangItem::UseCloned)
1919
}
2020

2121
fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
22-
is_item_raw(tcx, query, LangItem::Sized)
22+
is_trait_raw(tcx, query, LangItem::Sized)
2323
}
2424

2525
fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
26-
is_item_raw(tcx, query, LangItem::Freeze)
26+
is_trait_raw(tcx, query, LangItem::Freeze)
27+
}
28+
29+
fn is_unsafe_unpin_raw<'tcx>(
30+
tcx: TyCtxt<'tcx>,
31+
query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>,
32+
) -> bool {
33+
is_trait_raw(tcx, query, LangItem::UnsafeUnpin)
2734
}
2835

2936
fn is_unpin_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
30-
is_item_raw(tcx, query, LangItem::Unpin)
37+
is_trait_raw(tcx, query, LangItem::Unpin)
3138
}
3239

3340
fn is_async_drop_raw<'tcx>(
3441
tcx: TyCtxt<'tcx>,
3542
query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>,
3643
) -> bool {
37-
is_item_raw(tcx, query, LangItem::AsyncDrop)
44+
is_trait_raw(tcx, query, LangItem::AsyncDrop)
3845
}
3946

40-
fn is_item_raw<'tcx>(
47+
fn is_trait_raw<'tcx>(
4148
tcx: TyCtxt<'tcx>,
4249
query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>,
4350
item: LangItem,
@@ -53,6 +60,7 @@ pub(crate) fn provide(providers: &mut Providers) {
5360
is_use_cloned_raw,
5461
is_sized_raw,
5562
is_freeze_raw,
63+
is_unsafe_unpin_raw,
5664
is_unpin_raw,
5765
is_async_drop_raw,
5866
..*providers

library/core/src/marker.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -927,14 +927,20 @@ marker_impls! {
927927
/// This is part of [RFC 3467](https://rust-lang.github.io/rfcs/3467-unsafe-pinned.html), and is
928928
/// tracked by [#125735](https://github.com/rust-lang/rust/issues/125735).
929929
#[lang = "unsafe_unpin"]
930-
pub(crate) unsafe auto trait UnsafeUnpin {}
930+
#[unstable(feature = "unsafe_unpin", issue = "125735")]
931+
pub unsafe auto trait UnsafeUnpin {}
931932

933+
#[unstable(feature = "unsafe_unpin", issue = "125735")]
932934
impl<T: ?Sized> !UnsafeUnpin for UnsafePinned<T> {}
933-
unsafe impl<T: ?Sized> UnsafeUnpin for PhantomData<T> {}
934-
unsafe impl<T: ?Sized> UnsafeUnpin for *const T {}
935-
unsafe impl<T: ?Sized> UnsafeUnpin for *mut T {}
936-
unsafe impl<T: ?Sized> UnsafeUnpin for &T {}
937-
unsafe impl<T: ?Sized> UnsafeUnpin for &mut T {}
935+
marker_impls! {
936+
#[unstable(feature = "unsafe_unpin", issue = "125735")]
937+
unsafe UnsafeUnpin for
938+
{T: ?Sized} PhantomData<T>,
939+
{T: ?Sized} *const T,
940+
{T: ?Sized} *mut T,
941+
{T: ?Sized} &T,
942+
{T: ?Sized} &mut T,
943+
}
938944

939945
/// Types that do not require any pinning guarantees.
940946
///
@@ -1027,6 +1033,7 @@ impl !Unpin for PhantomPinned {}
10271033
// continue working. Ideally PhantomPinned could just wrap an `UnsafePinned<()>` to get the same
10281034
// effect, but we can't add a new field to an already stable unit struct -- that would be a breaking
10291035
// change.
1036+
#[unstable(feature = "unsafe_unpin", issue = "125735")]
10301037
impl !UnsafeUnpin for PhantomPinned {}
10311038

10321039
marker_impls! {

library/core/src/num/nonzero.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use crate::{fmt, intrinsics, ptr, ub_checks};
3131
issue = "none"
3232
)]
3333
pub unsafe trait ZeroablePrimitive: Sized + Copy + private::Sealed {
34-
#[doc(hidden)]
34+
/// A type like `Self` but with a niche that includes zero.
3535
type NonZeroInner: Sized + Copy;
3636
}
3737

src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,9 @@ impl NewPermission {
7171
access: None,
7272
protector: None,
7373
}
74-
} else if pointee.is_unpin(*cx.tcx, cx.typing_env()) {
74+
} else if pointee.is_unpin(*cx.tcx, cx.typing_env())
75+
&& pointee.is_unsafe_unpin(*cx.tcx, cx.typing_env())
76+
{
7577
// A regular full mutable reference. On `FnEntry` this is `noalias` and `dereferenceable`.
7678
NewPermission::Uniform {
7779
perm: Permission::Unique,
@@ -129,7 +131,9 @@ impl NewPermission {
129131
fn from_box_ty<'tcx>(ty: Ty<'tcx>, kind: RetagKind, cx: &crate::MiriInterpCx<'tcx>) -> Self {
130132
// `ty` is not the `Box` but the field of the Box with this pointer (due to allocator handling).
131133
let pointee = ty.builtin_deref(true).unwrap();
132-
if pointee.is_unpin(*cx.tcx, cx.typing_env()) {
134+
if pointee.is_unpin(*cx.tcx, cx.typing_env())
135+
&& pointee.is_unsafe_unpin(*cx.tcx, cx.typing_env())
136+
{
133137
// A regular box. On `FnEntry` this is `noalias`, but not `dereferenceable` (hence only
134138
// a weak protector).
135139
NewPermission::Uniform {

src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,8 @@ impl<'tcx> NewPermission {
133133
retag_kind: RetagKind,
134134
cx: &crate::MiriInterpCx<'tcx>,
135135
) -> Option<Self> {
136-
let ty_is_unpin = pointee.is_unpin(*cx.tcx, cx.typing_env());
136+
let ty_is_unpin = pointee.is_unpin(*cx.tcx, cx.typing_env())
137+
&& pointee.is_unsafe_unpin(*cx.tcx, cx.typing_env());
137138
let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.typing_env());
138139
let is_protected = retag_kind == RetagKind::FnEntry;
139140

src/tools/miri/tests/pass/both_borrows/unsafe_pinned.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,36 @@ fn mutate(x: &UnsafePinned<i32>) {
99
unsafe { ptr.write(42) };
1010
}
1111

12+
fn mut_alias(x: &mut UnsafePinned<i32>, y: &mut UnsafePinned<i32>) {
13+
unsafe {
14+
x.get().write(0);
15+
y.get().write(0);
16+
x.get().write(0);
17+
y.get().write(0);
18+
}
19+
}
20+
21+
// Also try this with a type for which we implement `Unpin`, just to be extra mean.
22+
struct MyUnsafePinned<T>(UnsafePinned<T>);
23+
impl<T> Unpin for MyUnsafePinned<T> {}
24+
25+
fn my_mut_alias(x: &mut MyUnsafePinned<i32>, y: &mut MyUnsafePinned<i32>) {
26+
unsafe {
27+
x.0.get().write(0);
28+
y.0.get().write(0);
29+
x.0.get().write(0);
30+
y.0.get().write(0);
31+
}
32+
}
33+
1234
fn main() {
13-
let x = UnsafePinned::new(0);
35+
let mut x = UnsafePinned::new(0i32);
1436
mutate(&x);
15-
assert_eq!(x.into_inner(), 42);
37+
assert_eq!(unsafe { x.get().read() }, 42);
38+
39+
let ptr = &raw mut x;
40+
unsafe { mut_alias(&mut *ptr, &mut *ptr) };
41+
42+
let ptr = ptr.cast::<MyUnsafePinned<i32>>();
43+
unsafe { my_mut_alias(&mut *ptr, &mut *ptr) };
1644
}

0 commit comments

Comments
 (0)