Skip to content

Commit 1942a84

Browse files
committed
Prevent downstream impl DerefMut for Pin
1 parent 8365fcb commit 1942a84

5 files changed

+128
-69
lines changed

library/core/src/pin.rs

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1676,10 +1676,47 @@ impl<Ptr: Deref> Deref for Pin<Ptr> {
16761676
}
16771677
}
16781678

1679+
mod hidden {
1680+
use super::*;
1681+
1682+
/// Helper that prevents downstream crates from implementing `DerefMut` for `Pin`.
1683+
///
1684+
/// This type is not `#[fundamental]`, so it's possible to relax its `DerefMut` impl bounds in
1685+
/// the future, so the orphan rules reject downstream impls of `DerefMut` of `Pin`.
1686+
#[repr(transparent)]
1687+
#[unstable(feature = "pin_derefmut_internals", issue = "none")]
1688+
#[allow(missing_debug_implementations)]
1689+
pub struct PinHelper<Ptr> {
1690+
pointer: Ptr,
1691+
}
1692+
1693+
#[unstable(feature = "pin_derefmut_internals", issue = "none")]
1694+
impl<Ptr: Deref> Deref for PinHelper<Ptr> {
1695+
type Target = Ptr::Target;
1696+
fn deref(&self) -> &Ptr::Target {
1697+
&self.pointer
1698+
}
1699+
}
1700+
1701+
#[unstable(feature = "pin_derefmut_internals", issue = "none")]
1702+
impl<Ptr: DerefMut<Target: Unpin>> DerefMut for PinHelper<Ptr> {
1703+
#[inline(always)]
1704+
fn deref_mut(&mut self) -> &mut Ptr::Target {
1705+
&mut self.pointer
1706+
}
1707+
}
1708+
}
1709+
16791710
#[stable(feature = "pin", since = "1.33.0")]
1680-
impl<Ptr: DerefMut<Target: Unpin>> DerefMut for Pin<Ptr> {
1711+
impl<Ptr> DerefMut for Pin<Ptr>
1712+
where
1713+
Ptr: Deref,
1714+
hidden::PinHelper<Ptr>: DerefMut<Target = Self::Target>,
1715+
{
16811716
fn deref_mut(&mut self) -> &mut Ptr::Target {
1682-
Pin::get_mut(Pin::as_mut(self))
1717+
// SAFETY: Pin and PinHelper have the same layout, so this is equivalent to
1718+
// `&mut self.pointer` which is safe because `Target: Unpin`.
1719+
unsafe { &mut **(self as *mut Pin<Ptr> as *mut hidden::PinHelper<Ptr>) }
16831720
}
16841721
}
16851722

@@ -1759,7 +1796,7 @@ unsafe impl<'a, T: ?Sized> PinCoerceUnsized for &'a T {}
17591796
unsafe impl<'a, T: ?Sized> PinCoerceUnsized for &'a mut T {}
17601797

17611798
#[stable(feature = "pin", since = "1.33.0")]
1762-
unsafe impl<T: PinCoerceUnsized> PinCoerceUnsized for Pin<T> {}
1799+
unsafe impl<T: PinCoerceUnsized + Deref> PinCoerceUnsized for Pin<T> {}
17631800

17641801
#[stable(feature = "pin", since = "1.33.0")]
17651802
unsafe impl<T: ?Sized> PinCoerceUnsized for *const T {}

tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff

Lines changed: 36 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -64,27 +64,25 @@
6464
+ let mut _45: &mut std::future::Ready<()>;
6565
+ let mut _46: &mut std::pin::Pin<&mut std::future::Ready<()>>;
6666
+ scope 14 (inlined <Pin<&mut std::future::Ready<()>> as DerefMut>::deref_mut) {
67-
+ scope 15 (inlined Pin::<&mut std::future::Ready<()>>::as_mut) {
68-
+ let mut _47: &mut &mut std::future::Ready<()>;
69-
+ scope 16 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) {
67+
+ let mut _47: *mut std::pin::hidden::PinHelper<&mut std::future::Ready<()>>;
68+
+ let mut _48: *mut std::pin::Pin<&mut std::future::Ready<()>>;
69+
+ scope 15 (inlined <pin::hidden::PinHelper<&mut std::future::Ready<()>> as DerefMut>::deref_mut) {
70+
+ let mut _49: &mut &mut std::future::Ready<()>;
71+
+ scope 16 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) {
7072
+ }
71-
+ scope 18 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) {
72-
+ }
73-
+ }
74-
+ scope 17 (inlined Pin::<&mut std::future::Ready<()>>::get_mut) {
7573
+ }
7674
+ }
77-
+ scope 19 (inlined Option::<()>::take) {
78-
+ let mut _48: std::option::Option<()>;
79-
+ scope 20 (inlined std::mem::replace::<Option<()>>) {
80-
+ scope 21 {
75+
+ scope 17 (inlined Option::<()>::take) {
76+
+ let mut _50: std::option::Option<()>;
77+
+ scope 18 (inlined std::mem::replace::<Option<()>>) {
78+
+ scope 19 {
8179
+ }
8280
+ }
8381
+ }
84-
+ scope 22 (inlined #[track_caller] Option::<()>::expect) {
85-
+ let mut _49: isize;
86-
+ let mut _50: !;
87-
+ scope 23 {
82+
+ scope 20 (inlined #[track_caller] Option::<()>::expect) {
83+
+ let mut _51: isize;
84+
+ let mut _52: !;
85+
+ scope 21 {
8886
+ }
8987
+ }
9088
+ }
@@ -227,26 +225,32 @@
227225
+ _22 = &mut (*_23);
228226
+ StorageDead(_24);
229227
+ StorageLive(_45);
230-
+ StorageLive(_46);
231-
+ StorageLive(_50);
228+
+ StorageLive(_47);
229+
+ StorageLive(_52);
232230
+ StorageLive(_42);
233231
+ StorageLive(_43);
234232
+ StorageLive(_44);
233+
+ StorageLive(_46);
235234
+ _46 = &mut _19;
236-
+ StorageLive(_47);
237-
+ _47 = &mut (_19.0: &mut std::future::Ready<()>);
238-
+ _45 = copy (_19.0: &mut std::future::Ready<()>);
239-
+ StorageDead(_47);
240-
+ _44 = &mut ((*_45).0: std::option::Option<()>);
241235
+ StorageLive(_48);
242-
+ _48 = Option::<()>::None;
243-
+ _43 = copy ((*_45).0: std::option::Option<()>);
244-
+ ((*_45).0: std::option::Option<()>) = copy _48;
236+
+ _48 = &raw mut _19;
237+
+ _47 = move _48 as *mut std::pin::hidden::PinHelper<&mut std::future::Ready<()>> (PtrToPtr);
245238
+ StorageDead(_48);
246-
+ StorageDead(_44);
247239
+ StorageLive(_49);
248-
+ _49 = discriminant(_43);
249-
+ switchInt(move _49) -> [0: bb11, 1: bb12, otherwise: bb5];
240+
+ _49 = &mut ((*_47).0: &mut std::future::Ready<()>);
241+
+ _45 = copy ((*_47).0: &mut std::future::Ready<()>);
242+
+ StorageDead(_49);
243+
+ StorageDead(_46);
244+
+ _44 = &mut ((*_45).0: std::option::Option<()>);
245+
+ StorageLive(_50);
246+
+ _50 = Option::<()>::None;
247+
+ _43 = copy ((*_45).0: std::option::Option<()>);
248+
+ ((*_45).0: std::option::Option<()>) = copy _50;
249+
+ StorageDead(_50);
250+
+ StorageDead(_44);
251+
+ StorageLive(_51);
252+
+ _51 = discriminant(_43);
253+
+ switchInt(move _51) -> [0: bb11, 1: bb12, otherwise: bb5];
250254
}
251255
+
252256
+ bb5: {
@@ -309,17 +313,17 @@
309313
+ }
310314
+
311315
+ bb11: {
312-
+ _50 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable;
316+
+ _52 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable;
313317
+ }
314318
+
315319
+ bb12: {
316320
+ _42 = move ((_43 as Some).0: ());
317-
+ StorageDead(_49);
321+
+ StorageDead(_51);
318322
+ StorageDead(_43);
319323
+ _18 = Poll::<()>::Ready(move _42);
320324
+ StorageDead(_42);
321-
+ StorageDead(_50);
322-
+ StorageDead(_46);
325+
+ StorageDead(_52);
326+
+ StorageDead(_47);
323327
+ StorageDead(_45);
324328
+ StorageDead(_22);
325329
+ StorageDead(_19);

tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff

Lines changed: 36 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -66,27 +66,25 @@
6666
+ let mut _47: &mut std::future::Ready<()>;
6767
+ let mut _48: &mut std::pin::Pin<&mut std::future::Ready<()>>;
6868
+ scope 14 (inlined <Pin<&mut std::future::Ready<()>> as DerefMut>::deref_mut) {
69-
+ scope 15 (inlined Pin::<&mut std::future::Ready<()>>::as_mut) {
70-
+ let mut _49: &mut &mut std::future::Ready<()>;
71-
+ scope 16 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) {
69+
+ let mut _49: *mut std::pin::hidden::PinHelper<&mut std::future::Ready<()>>;
70+
+ let mut _50: *mut std::pin::Pin<&mut std::future::Ready<()>>;
71+
+ scope 15 (inlined <pin::hidden::PinHelper<&mut std::future::Ready<()>> as DerefMut>::deref_mut) {
72+
+ let mut _51: &mut &mut std::future::Ready<()>;
73+
+ scope 16 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) {
7274
+ }
73-
+ scope 18 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) {
74-
+ }
75-
+ }
76-
+ scope 17 (inlined Pin::<&mut std::future::Ready<()>>::get_mut) {
7775
+ }
7876
+ }
79-
+ scope 19 (inlined Option::<()>::take) {
80-
+ let mut _50: std::option::Option<()>;
81-
+ scope 20 (inlined std::mem::replace::<Option<()>>) {
82-
+ scope 21 {
77+
+ scope 17 (inlined Option::<()>::take) {
78+
+ let mut _52: std::option::Option<()>;
79+
+ scope 18 (inlined std::mem::replace::<Option<()>>) {
80+
+ scope 19 {
8381
+ }
8482
+ }
8583
+ }
86-
+ scope 22 (inlined #[track_caller] Option::<()>::expect) {
87-
+ let mut _51: isize;
88-
+ let mut _52: !;
89-
+ scope 23 {
84+
+ scope 20 (inlined #[track_caller] Option::<()>::expect) {
85+
+ let mut _53: isize;
86+
+ let mut _54: !;
87+
+ scope 21 {
9088
+ }
9189
+ }
9290
+ }
@@ -244,26 +242,32 @@
244242
+ _22 = &mut (*_23);
245243
+ StorageDead(_24);
246244
+ StorageLive(_47);
247-
+ StorageLive(_48);
248-
+ StorageLive(_52);
245+
+ StorageLive(_49);
246+
+ StorageLive(_54);
249247
+ StorageLive(_44);
250248
+ StorageLive(_45);
251249
+ StorageLive(_46);
250+
+ StorageLive(_48);
252251
+ _48 = &mut _19;
253-
+ StorageLive(_49);
254-
+ _49 = &mut (_19.0: &mut std::future::Ready<()>);
255-
+ _47 = copy (_19.0: &mut std::future::Ready<()>);
256-
+ StorageDead(_49);
257-
+ _46 = &mut ((*_47).0: std::option::Option<()>);
258252
+ StorageLive(_50);
259-
+ _50 = Option::<()>::None;
260-
+ _45 = copy ((*_47).0: std::option::Option<()>);
261-
+ ((*_47).0: std::option::Option<()>) = copy _50;
253+
+ _50 = &raw mut _19;
254+
+ _49 = move _50 as *mut std::pin::hidden::PinHelper<&mut std::future::Ready<()>> (PtrToPtr);
262255
+ StorageDead(_50);
263-
+ StorageDead(_46);
264256
+ StorageLive(_51);
265-
+ _51 = discriminant(_45);
266-
+ switchInt(move _51) -> [0: bb16, 1: bb17, otherwise: bb7];
257+
+ _51 = &mut ((*_49).0: &mut std::future::Ready<()>);
258+
+ _47 = copy ((*_49).0: &mut std::future::Ready<()>);
259+
+ StorageDead(_51);
260+
+ StorageDead(_48);
261+
+ _46 = &mut ((*_47).0: std::option::Option<()>);
262+
+ StorageLive(_52);
263+
+ _52 = Option::<()>::None;
264+
+ _45 = copy ((*_47).0: std::option::Option<()>);
265+
+ ((*_47).0: std::option::Option<()>) = copy _52;
266+
+ StorageDead(_52);
267+
+ StorageDead(_46);
268+
+ StorageLive(_53);
269+
+ _53 = discriminant(_45);
270+
+ switchInt(move _53) -> [0: bb16, 1: bb17, otherwise: bb7];
267271
}
268272

269273
- bb6 (cleanup): {
@@ -350,17 +354,17 @@
350354
+ }
351355
+
352356
+ bb16: {
353-
+ _52 = option::expect_failed(const "`Ready` polled after completion") -> bb11;
357+
+ _54 = option::expect_failed(const "`Ready` polled after completion") -> bb11;
354358
+ }
355359
+
356360
+ bb17: {
357361
+ _44 = move ((_45 as Some).0: ());
358-
+ StorageDead(_51);
362+
+ StorageDead(_53);
359363
+ StorageDead(_45);
360364
+ _18 = Poll::<()>::Ready(move _44);
361365
+ StorageDead(_44);
362-
+ StorageDead(_52);
363-
+ StorageDead(_48);
366+
+ StorageDead(_54);
367+
+ StorageDead(_49);
364368
+ StorageDead(_47);
365369
+ StorageDead(_22);
366370
+ StorageDead(_19);

tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
//@ check-pass
2-
//@ known-bug: #85099
1+
//@ check-fail
32

43
// Should fail. Can coerce `Pin<T>` into `Pin<U>` where
54
// `T: Deref<Target: Unpin>` and `U: Deref<Target: !Unpin>`, using the
@@ -43,6 +42,7 @@ impl<'a, Fut: Future<Output = ()>> SomeTrait<'a, Fut> for Fut {
4342
}
4443

4544
impl<'b, 'a, Fut> DerefMut for Pin<&'b dyn SomeTrait<'a, Fut>> {
45+
//~^ ERROR: conflicting implementations of trait `DerefMut`
4646
fn deref_mut<'c>(
4747
self: &'c mut Pin<&'b dyn SomeTrait<'a, Fut>>,
4848
) -> &'c mut (dyn SomeTrait<'a, Fut> + 'b) {
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0119]: conflicting implementations of trait `DerefMut` for type `Pin<&dyn SomeTrait<'_, _>>`
2+
--> $DIR/pin-unsound-issue-85099-derefmut.rs:44:1
3+
|
4+
LL | impl<'b, 'a, Fut> DerefMut for Pin<&'b dyn SomeTrait<'a, Fut>> {
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: conflicting implementation in crate `core`:
8+
- impl<Ptr> DerefMut for Pin<Ptr>
9+
where <pin::hidden::PinHelper<Ptr> as Deref>::Target == <Pin<Ptr> as Deref>::Target, Ptr: Deref, pin::hidden::PinHelper<Ptr>: DerefMut, pin::hidden::PinHelper<Ptr>: ?Sized;
10+
= note: upstream crates may add a new impl of trait `std::ops::DerefMut` for type `std::pin::hidden::PinHelper<&dyn SomeTrait<'_, _>>` in future versions
11+
12+
error: aborting due to 1 previous error
13+
14+
For more information about this error, try `rustc --explain E0119`.

0 commit comments

Comments
 (0)