Skip to content

Commit 10fd406

Browse files
committed
Prevent downstream impl DerefMut for Pin<LocalType>
1 parent ce6daf3 commit 10fd406

7 files changed

+158
-81
lines changed

library/core/src/pin.rs

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1689,9 +1689,66 @@ impl<Ptr: [const] Deref> const Deref for Pin<Ptr> {
16891689
}
16901690
}
16911691

1692+
mod helper {
1693+
/// Helper that prevents downstream crates from implementing `DerefMut` for `Pin`.
1694+
///
1695+
/// This type is not `#[fundamental]`, so it's possible to relax its `DerefMut` impl bounds in
1696+
/// the future, so the orphan rules reject downstream impls of `DerefMut` of `Pin`.
1697+
#[repr(transparent)]
1698+
#[unstable(feature = "pin_derefmut_internals", issue = "none")]
1699+
#[allow(missing_debug_implementations)]
1700+
pub struct Pin<Ptr> {
1701+
pointer: Ptr,
1702+
}
1703+
1704+
#[unstable(feature = "pin_derefmut_internals", issue = "none")]
1705+
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
1706+
pub const trait DerefMut {
1707+
type Target: ?Sized;
1708+
fn deref_mut(&mut self) -> &mut Self::Target;
1709+
}
1710+
1711+
#[unstable(feature = "pin_derefmut_internals", issue = "none")]
1712+
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
1713+
impl<Ptr: [const] super::DerefMut> const DerefMut for Pin<Ptr>
1714+
where
1715+
Ptr::Target: crate::marker::Unpin,
1716+
{
1717+
type Target = Ptr::Target;
1718+
1719+
#[inline(always)]
1720+
fn deref_mut(&mut self) -> &mut Ptr::Target {
1721+
&mut self.pointer
1722+
}
1723+
}
1724+
}
1725+
16921726
#[stable(feature = "pin", since = "1.33.0")]
16931727
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
1694-
impl<Ptr: [const] DerefMut<Target: Unpin>> const DerefMut for Pin<Ptr> {
1728+
#[cfg(not(doc))]
1729+
impl<Ptr> const DerefMut for Pin<Ptr>
1730+
where
1731+
Ptr: [const] Deref,
1732+
helper::Pin<Ptr>: [const] helper::DerefMut<Target = Self::Target>,
1733+
{
1734+
#[inline]
1735+
fn deref_mut(&mut self) -> &mut Ptr::Target {
1736+
// SAFETY: Pin and helper::Pin have the same layout, so this is equivalent to
1737+
// `&mut self.pointer` which is safe because `Target: Unpin`.
1738+
helper::DerefMut::deref_mut(unsafe {
1739+
&mut *(self as *mut Pin<Ptr> as *mut helper::Pin<Ptr>)
1740+
})
1741+
}
1742+
}
1743+
1744+
#[stable(feature = "pin", since = "1.33.0")]
1745+
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
1746+
#[cfg(doc)]
1747+
impl<Ptr> const DerefMut for Pin<Ptr>
1748+
where
1749+
Ptr: [const] DerefMut,
1750+
Ptr::Target: Unpin,
1751+
{
16951752
fn deref_mut(&mut self) -> &mut Ptr::Target {
16961753
Pin::get_mut(Pin::as_mut(self))
16971754
}

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
@@ -63,27 +63,25 @@
6363
+ let mut _44: &mut std::future::Ready<()>;
6464
+ let mut _45: &mut std::pin::Pin<&mut std::future::Ready<()>>;
6565
+ scope 14 (inlined <Pin<&mut std::future::Ready<()>> as DerefMut>::deref_mut) {
66-
+ scope 15 (inlined Pin::<&mut std::future::Ready<()>>::as_mut) {
67-
+ let mut _46: &mut &mut std::future::Ready<()>;
68-
+ scope 16 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) {
66+
+ let mut _46: *mut std::pin::helper::Pin<&mut std::future::Ready<()>>;
67+
+ let mut _47: *mut std::pin::Pin<&mut std::future::Ready<()>>;
68+
+ scope 15 (inlined <pin::helper::Pin<&mut std::future::Ready<()>> as pin::helper::DerefMut>::deref_mut) {
69+
+ let mut _48: &mut &mut std::future::Ready<()>;
70+
+ scope 16 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) {
6971
+ }
70-
+ scope 18 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) {
71-
+ }
72-
+ }
73-
+ scope 17 (inlined Pin::<&mut std::future::Ready<()>>::get_mut) {
7472
+ }
7573
+ }
76-
+ scope 19 (inlined Option::<()>::take) {
77-
+ let mut _47: std::option::Option<()>;
78-
+ scope 20 (inlined std::mem::replace::<Option<()>>) {
79-
+ scope 21 {
74+
+ scope 17 (inlined Option::<()>::take) {
75+
+ let mut _49: std::option::Option<()>;
76+
+ scope 18 (inlined std::mem::replace::<Option<()>>) {
77+
+ scope 19 {
8078
+ }
8179
+ }
8280
+ }
83-
+ scope 22 (inlined #[track_caller] Option::<()>::expect) {
84-
+ let mut _48: isize;
85-
+ let mut _49: !;
86-
+ scope 23 {
81+
+ scope 20 (inlined #[track_caller] Option::<()>::expect) {
82+
+ let mut _50: isize;
83+
+ let mut _51: !;
84+
+ scope 21 {
8785
+ }
8886
+ }
8987
+ }
@@ -223,26 +221,32 @@
223221
+ _22 = &mut (*_23);
224222
+ StorageDead(_24);
225223
+ StorageLive(_44);
226-
+ StorageLive(_45);
227-
+ StorageLive(_49);
224+
+ StorageLive(_46);
225+
+ StorageLive(_51);
228226
+ StorageLive(_41);
229227
+ StorageLive(_42);
230228
+ StorageLive(_43);
229+
+ StorageLive(_45);
231230
+ _45 = &mut _19;
232-
+ StorageLive(_46);
233-
+ _46 = &mut (_19.0: &mut std::future::Ready<()>);
234-
+ _44 = copy (_19.0: &mut std::future::Ready<()>);
235-
+ StorageDead(_46);
236-
+ _43 = &mut ((*_44).0: std::option::Option<()>);
237231
+ StorageLive(_47);
238-
+ _47 = Option::<()>::None;
239-
+ _42 = copy ((*_44).0: std::option::Option<()>);
240-
+ ((*_44).0: std::option::Option<()>) = copy _47;
232+
+ _47 = &raw mut _19;
233+
+ _46 = copy _47 as *mut std::pin::helper::Pin<&mut std::future::Ready<()>> (PtrToPtr);
241234
+ StorageDead(_47);
242-
+ StorageDead(_43);
243235
+ StorageLive(_48);
244-
+ _48 = discriminant(_42);
245-
+ switchInt(move _48) -> [0: bb11, 1: bb12, otherwise: bb5];
236+
+ _48 = &mut ((*_46).0: &mut std::future::Ready<()>);
237+
+ _44 = copy ((*_46).0: &mut std::future::Ready<()>);
238+
+ StorageDead(_48);
239+
+ StorageDead(_45);
240+
+ _43 = &mut ((*_44).0: std::option::Option<()>);
241+
+ StorageLive(_49);
242+
+ _49 = Option::<()>::None;
243+
+ _42 = copy ((*_44).0: std::option::Option<()>);
244+
+ ((*_44).0: std::option::Option<()>) = copy _49;
245+
+ StorageDead(_49);
246+
+ StorageDead(_43);
247+
+ StorageLive(_50);
248+
+ _50 = discriminant(_42);
249+
+ switchInt(move _50) -> [0: bb11, 1: bb12, otherwise: bb5];
246250
}
247251
+
248252
+ bb5: {
@@ -305,17 +309,17 @@
305309
+ }
306310
+
307311
+ bb11: {
308-
+ _49 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable;
312+
+ _51 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable;
309313
+ }
310314
+
311315
+ bb12: {
312316
+ _41 = move ((_42 as Some).0: ());
313-
+ StorageDead(_48);
317+
+ StorageDead(_50);
314318
+ StorageDead(_42);
315319
+ _18 = Poll::<()>::Ready(move _41);
316320
+ StorageDead(_41);
317-
+ StorageDead(_49);
318-
+ StorageDead(_45);
321+
+ StorageDead(_51);
322+
+ StorageDead(_46);
319323
+ StorageDead(_44);
320324
+ StorageDead(_22);
321325
+ 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
@@ -65,27 +65,25 @@
6565
+ let mut _46: &mut std::future::Ready<()>;
6666
+ let mut _47: &mut std::pin::Pin<&mut std::future::Ready<()>>;
6767
+ scope 14 (inlined <Pin<&mut std::future::Ready<()>> as DerefMut>::deref_mut) {
68-
+ scope 15 (inlined Pin::<&mut std::future::Ready<()>>::as_mut) {
69-
+ let mut _48: &mut &mut std::future::Ready<()>;
70-
+ scope 16 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) {
68+
+ let mut _48: *mut std::pin::helper::Pin<&mut std::future::Ready<()>>;
69+
+ let mut _49: *mut std::pin::Pin<&mut std::future::Ready<()>>;
70+
+ scope 15 (inlined <pin::helper::Pin<&mut std::future::Ready<()>> as pin::helper::DerefMut>::deref_mut) {
71+
+ let mut _50: &mut &mut std::future::Ready<()>;
72+
+ scope 16 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) {
7173
+ }
72-
+ scope 18 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) {
73-
+ }
74-
+ }
75-
+ scope 17 (inlined Pin::<&mut std::future::Ready<()>>::get_mut) {
7674
+ }
7775
+ }
78-
+ scope 19 (inlined Option::<()>::take) {
79-
+ let mut _49: std::option::Option<()>;
80-
+ scope 20 (inlined std::mem::replace::<Option<()>>) {
81-
+ scope 21 {
76+
+ scope 17 (inlined Option::<()>::take) {
77+
+ let mut _51: std::option::Option<()>;
78+
+ scope 18 (inlined std::mem::replace::<Option<()>>) {
79+
+ scope 19 {
8280
+ }
8381
+ }
8482
+ }
85-
+ scope 22 (inlined #[track_caller] Option::<()>::expect) {
86-
+ let mut _50: isize;
87-
+ let mut _51: !;
88-
+ scope 23 {
83+
+ scope 20 (inlined #[track_caller] Option::<()>::expect) {
84+
+ let mut _52: isize;
85+
+ let mut _53: !;
86+
+ scope 21 {
8987
+ }
9088
+ }
9189
+ }
@@ -240,26 +238,32 @@
240238
+ _22 = &mut (*_23);
241239
+ StorageDead(_24);
242240
+ StorageLive(_46);
243-
+ StorageLive(_47);
244-
+ StorageLive(_51);
241+
+ StorageLive(_48);
242+
+ StorageLive(_53);
245243
+ StorageLive(_43);
246244
+ StorageLive(_44);
247245
+ StorageLive(_45);
246+
+ StorageLive(_47);
248247
+ _47 = &mut _19;
249-
+ StorageLive(_48);
250-
+ _48 = &mut (_19.0: &mut std::future::Ready<()>);
251-
+ _46 = copy (_19.0: &mut std::future::Ready<()>);
252-
+ StorageDead(_48);
253-
+ _45 = &mut ((*_46).0: std::option::Option<()>);
254248
+ StorageLive(_49);
255-
+ _49 = Option::<()>::None;
256-
+ _44 = copy ((*_46).0: std::option::Option<()>);
257-
+ ((*_46).0: std::option::Option<()>) = copy _49;
249+
+ _49 = &raw mut _19;
250+
+ _48 = copy _49 as *mut std::pin::helper::Pin<&mut std::future::Ready<()>> (PtrToPtr);
258251
+ StorageDead(_49);
259-
+ StorageDead(_45);
260252
+ StorageLive(_50);
261-
+ _50 = discriminant(_44);
262-
+ switchInt(move _50) -> [0: bb16, 1: bb17, otherwise: bb7];
253+
+ _50 = &mut ((*_48).0: &mut std::future::Ready<()>);
254+
+ _46 = copy ((*_48).0: &mut std::future::Ready<()>);
255+
+ StorageDead(_50);
256+
+ StorageDead(_47);
257+
+ _45 = &mut ((*_46).0: std::option::Option<()>);
258+
+ StorageLive(_51);
259+
+ _51 = Option::<()>::None;
260+
+ _44 = copy ((*_46).0: std::option::Option<()>);
261+
+ ((*_46).0: std::option::Option<()>) = copy _51;
262+
+ StorageDead(_51);
263+
+ StorageDead(_45);
264+
+ StorageLive(_52);
265+
+ _52 = discriminant(_44);
266+
+ switchInt(move _52) -> [0: bb16, 1: bb17, otherwise: bb7];
263267
}
264268

265269
- bb6 (cleanup): {
@@ -346,17 +350,17 @@
346350
+ }
347351
+
348352
+ bb16: {
349-
+ _51 = option::expect_failed(const "`Ready` polled after completion") -> bb11;
353+
+ _53 = option::expect_failed(const "`Ready` polled after completion") -> bb11;
350354
+ }
351355
+
352356
+ bb17: {
353357
+ _43 = move ((_44 as Some).0: ());
354-
+ StorageDead(_50);
358+
+ StorageDead(_52);
355359
+ StorageDead(_44);
356360
+ _18 = Poll::<()>::Ready(move _43);
357361
+ StorageDead(_43);
358-
+ StorageDead(_51);
359-
+ StorageDead(_47);
362+
+ StorageDead(_53);
363+
+ StorageDead(_48);
360364
+ StorageDead(_46);
361365
+ StorageDead(_22);
362366
+ StorageDead(_19);

tests/ui/deref/pin-impl-deref.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@ impl MyPinType {
2222
fn impl_deref_mut(_: impl DerefMut) {}
2323
fn unpin_impl_ref(r_unpin: Pin<&MyUnpinType>) {
2424
impl_deref_mut(r_unpin)
25-
//~^ ERROR: the trait bound `Pin<&MyUnpinType>: DerefMut` is not satisfied
25+
//~^ ERROR: the trait bound `&MyUnpinType: DerefMut` is not satisfied
2626
}
2727
fn unpin_impl_mut(r_unpin: Pin<&mut MyUnpinType>) {
2828
impl_deref_mut(r_unpin)
2929
}
3030
fn pin_impl_ref(r_pin: Pin<&MyPinType>) {
3131
impl_deref_mut(r_pin)
3232
//~^ ERROR: `PhantomPinned` cannot be unpinned
33-
//~| ERROR: the trait bound `Pin<&MyPinType>: DerefMut` is not satisfied
33+
//~| ERROR: the trait bound `&MyPinType: DerefMut` is not satisfied
3434
}
3535
fn pin_impl_mut(r_pin: Pin<&mut MyPinType>) {
3636
impl_deref_mut(r_pin)

tests/ui/deref/pin-impl-deref.stderr

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,36 @@
1-
error[E0277]: the trait bound `Pin<&MyUnpinType>: DerefMut` is not satisfied
1+
error[E0277]: the trait bound `&MyUnpinType: DerefMut` is not satisfied
22
--> $DIR/pin-impl-deref.rs:24:20
33
|
44
LL | impl_deref_mut(r_unpin)
5-
| -------------- ^^^^^^^ the trait `DerefMut` is not implemented for `Pin<&MyUnpinType>`
5+
| -------------- ^^^^^^^ the trait `DerefMut` is not implemented for `&MyUnpinType`
66
| |
77
| required by a bound introduced by this call
88
|
9+
= note: `DerefMut` is implemented for `&mut MyUnpinType`, but not for `&MyUnpinType`
10+
= note: required for `pin::helper::Pin<&MyUnpinType>` to implement `pin::helper::DerefMut`
911
= note: required for `Pin<&MyUnpinType>` to implement `DerefMut`
1012
note: required by a bound in `impl_deref_mut`
1113
--> $DIR/pin-impl-deref.rs:22:27
1214
|
1315
LL | fn impl_deref_mut(_: impl DerefMut) {}
1416
| ^^^^^^^^ required by this bound in `impl_deref_mut`
15-
help: consider mutably borrowing here
16-
|
17-
LL | impl_deref_mut(&mut r_unpin)
18-
| ++++
1917

20-
error[E0277]: the trait bound `Pin<&MyPinType>: DerefMut` is not satisfied
18+
error[E0277]: the trait bound `&MyPinType: DerefMut` is not satisfied
2119
--> $DIR/pin-impl-deref.rs:31:20
2220
|
2321
LL | impl_deref_mut(r_pin)
24-
| -------------- ^^^^^ the trait `DerefMut` is not implemented for `Pin<&MyPinType>`
22+
| -------------- ^^^^^ the trait `DerefMut` is not implemented for `&MyPinType`
2523
| |
2624
| required by a bound introduced by this call
2725
|
26+
= note: `DerefMut` is implemented for `&mut MyPinType`, but not for `&MyPinType`
27+
= note: required for `pin::helper::Pin<&MyPinType>` to implement `pin::helper::DerefMut`
2828
= note: required for `Pin<&MyPinType>` to implement `DerefMut`
2929
note: required by a bound in `impl_deref_mut`
3030
--> $DIR/pin-impl-deref.rs:22:27
3131
|
3232
LL | fn impl_deref_mut(_: impl DerefMut) {}
3333
| ^^^^^^^^ required by this bound in `impl_deref_mut`
34-
help: consider mutably borrowing here
35-
|
36-
LL | impl_deref_mut(&mut r_pin)
37-
| ++++
3834

3935
error[E0277]: `PhantomPinned` cannot be unpinned
4036
--> $DIR/pin-impl-deref.rs:31:20
@@ -51,6 +47,7 @@ note: required because it appears within the type `MyPinType`
5147
|
5248
LL | struct MyPinType(core::marker::PhantomPinned);
5349
| ^^^^^^^^^
50+
= note: required for `pin::helper::Pin<&MyPinType>` to implement `pin::helper::DerefMut`
5451
= note: required for `Pin<&MyPinType>` to implement `DerefMut`
5552
note: required by a bound in `impl_deref_mut`
5653
--> $DIR/pin-impl-deref.rs:22:27
@@ -73,6 +70,7 @@ note: required because it appears within the type `MyPinType`
7370
|
7471
LL | struct MyPinType(core::marker::PhantomPinned);
7572
| ^^^^^^^^^
73+
= note: required for `pin::helper::Pin<&mut MyPinType>` to implement `pin::helper::DerefMut`
7674
= note: required for `Pin<&mut MyPinType>` to implement `DerefMut`
7775
note: required by a bound in `impl_deref_mut`
7876
--> $DIR/pin-impl-deref.rs:22:27

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::helper::Pin<Ptr> as pin::helper::DerefMut>::Target == <Pin<Ptr> as Deref>::Target, Ptr: Deref, pin::helper::Pin<Ptr>: pin::helper::DerefMut, pin::helper::Pin<Ptr>: ?Sized;
10+
= note: upstream crates may add a new impl of trait `std::pin::helper::DerefMut` for type `std::pin::helper::Pin<&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)