Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 58 additions & 1 deletion library/core/src/pin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1689,9 +1689,66 @@ impl<Ptr: [const] Deref> const Deref for Pin<Ptr> {
}
}

mod helper {
/// Helper that prevents downstream crates from implementing `DerefMut` for `Pin`.
///
/// This type is not `#[fundamental]`, so it's possible to relax its `DerefMut` impl bounds in
/// the future, so the orphan rules reject downstream impls of `DerefMut` of `Pin`.
#[repr(transparent)]
#[unstable(feature = "pin_derefmut_internals", issue = "none")]
#[allow(missing_debug_implementations)]
pub struct Pin<Ptr> {
pointer: Ptr,
}

#[unstable(feature = "pin_derefmut_internals", issue = "none")]
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
pub const trait DerefMut {
type Target: ?Sized;
fn deref_mut(&mut self) -> &mut Self::Target;
}

#[unstable(feature = "pin_derefmut_internals", issue = "none")]
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
impl<Ptr: [const] super::DerefMut> const DerefMut for Pin<Ptr>
where
Ptr::Target: crate::marker::Unpin,
{
type Target = Ptr::Target;

#[inline(always)]
fn deref_mut(&mut self) -> &mut Ptr::Target {
&mut self.pointer
}
}
}

#[stable(feature = "pin", since = "1.33.0")]
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
impl<Ptr: [const] DerefMut<Target: Unpin>> const DerefMut for Pin<Ptr> {
#[cfg(not(doc))]
impl<Ptr> const DerefMut for Pin<Ptr>
where
Ptr: [const] Deref,
helper::Pin<Ptr>: [const] helper::DerefMut<Target = Self::Target>,
{
#[inline]
fn deref_mut(&mut self) -> &mut Ptr::Target {
// SAFETY: Pin and helper::Pin have the same layout, so this is equivalent to
// `&mut self.pointer` which is safe because `Target: Unpin`.
helper::DerefMut::deref_mut(unsafe {
&mut *(self as *mut Pin<Ptr> as *mut helper::Pin<Ptr>)
})
}
}

#[stable(feature = "pin", since = "1.33.0")]
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
#[cfg(doc)]
impl<Ptr> const DerefMut for Pin<Ptr>
where
Ptr: [const] DerefMut,
Ptr::Target: Unpin,
{
fn deref_mut(&mut self) -> &mut Ptr::Target {
Pin::get_mut(Pin::as_mut(self))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,27 +63,25 @@
+ let mut _44: &mut std::future::Ready<()>;
+ let mut _45: &mut std::pin::Pin<&mut std::future::Ready<()>>;
+ scope 14 (inlined <Pin<&mut std::future::Ready<()>> as DerefMut>::deref_mut) {
+ scope 15 (inlined Pin::<&mut std::future::Ready<()>>::as_mut) {
+ let mut _46: &mut &mut std::future::Ready<()>;
+ scope 16 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) {
+ let mut _46: *mut std::pin::helper::Pin<&mut std::future::Ready<()>>;
+ let mut _47: *mut std::pin::Pin<&mut std::future::Ready<()>>;
+ scope 15 (inlined <pin::helper::Pin<&mut std::future::Ready<()>> as pin::helper::DerefMut>::deref_mut) {
+ let mut _48: &mut &mut std::future::Ready<()>;
+ scope 16 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) {
+ }
+ scope 18 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) {
+ }
+ }
+ scope 17 (inlined Pin::<&mut std::future::Ready<()>>::get_mut) {
+ }
+ }
+ scope 19 (inlined Option::<()>::take) {
+ let mut _47: std::option::Option<()>;
+ scope 20 (inlined std::mem::replace::<Option<()>>) {
+ scope 21 {
+ scope 17 (inlined Option::<()>::take) {
+ let mut _49: std::option::Option<()>;
+ scope 18 (inlined std::mem::replace::<Option<()>>) {
+ scope 19 {
+ }
+ }
+ }
+ scope 22 (inlined #[track_caller] Option::<()>::expect) {
+ let mut _48: isize;
+ let mut _49: !;
+ scope 23 {
+ scope 20 (inlined #[track_caller] Option::<()>::expect) {
+ let mut _50: isize;
+ let mut _51: !;
+ scope 21 {
+ }
+ }
+ }
Expand Down Expand Up @@ -223,26 +221,32 @@
+ _22 = &mut (*_23);
+ StorageDead(_24);
+ StorageLive(_44);
+ StorageLive(_45);
+ StorageLive(_49);
+ StorageLive(_46);
+ StorageLive(_51);
+ StorageLive(_41);
+ StorageLive(_42);
+ StorageLive(_43);
+ StorageLive(_45);
+ _45 = &mut _19;
+ StorageLive(_46);
+ _46 = &mut (_19.0: &mut std::future::Ready<()>);
+ _44 = copy (_19.0: &mut std::future::Ready<()>);
+ StorageDead(_46);
+ _43 = &mut ((*_44).0: std::option::Option<()>);
+ StorageLive(_47);
+ _47 = Option::<()>::None;
+ _42 = copy ((*_44).0: std::option::Option<()>);
+ ((*_44).0: std::option::Option<()>) = copy _47;
+ _47 = &raw mut _19;
+ _46 = copy _47 as *mut std::pin::helper::Pin<&mut std::future::Ready<()>> (PtrToPtr);
+ StorageDead(_47);
+ StorageDead(_43);
+ StorageLive(_48);
+ _48 = discriminant(_42);
+ switchInt(move _48) -> [0: bb11, 1: bb12, otherwise: bb5];
+ _48 = &mut ((*_46).0: &mut std::future::Ready<()>);
+ _44 = copy ((*_46).0: &mut std::future::Ready<()>);
+ StorageDead(_48);
+ StorageDead(_45);
+ _43 = &mut ((*_44).0: std::option::Option<()>);
+ StorageLive(_49);
+ _49 = Option::<()>::None;
+ _42 = copy ((*_44).0: std::option::Option<()>);
+ ((*_44).0: std::option::Option<()>) = copy _49;
+ StorageDead(_49);
+ StorageDead(_43);
+ StorageLive(_50);
+ _50 = discriminant(_42);
+ switchInt(move _50) -> [0: bb11, 1: bb12, otherwise: bb5];
}
+
+ bb5: {
Expand Down Expand Up @@ -305,17 +309,17 @@
+ }
+
+ bb11: {
+ _49 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable;
+ _51 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable;
+ }
+
+ bb12: {
+ _41 = move ((_42 as Some).0: ());
+ StorageDead(_48);
+ StorageDead(_50);
+ StorageDead(_42);
+ _18 = Poll::<()>::Ready(move _41);
+ StorageDead(_41);
+ StorageDead(_49);
+ StorageDead(_45);
+ StorageDead(_51);
+ StorageDead(_46);
+ StorageDead(_44);
+ StorageDead(_22);
+ StorageDead(_19);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,27 +65,25 @@
+ let mut _46: &mut std::future::Ready<()>;
+ let mut _47: &mut std::pin::Pin<&mut std::future::Ready<()>>;
+ scope 14 (inlined <Pin<&mut std::future::Ready<()>> as DerefMut>::deref_mut) {
+ scope 15 (inlined Pin::<&mut std::future::Ready<()>>::as_mut) {
+ let mut _48: &mut &mut std::future::Ready<()>;
+ scope 16 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) {
+ let mut _48: *mut std::pin::helper::Pin<&mut std::future::Ready<()>>;
+ let mut _49: *mut std::pin::Pin<&mut std::future::Ready<()>>;
+ scope 15 (inlined <pin::helper::Pin<&mut std::future::Ready<()>> as pin::helper::DerefMut>::deref_mut) {
+ let mut _50: &mut &mut std::future::Ready<()>;
+ scope 16 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) {
+ }
+ scope 18 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) {
+ }
+ }
+ scope 17 (inlined Pin::<&mut std::future::Ready<()>>::get_mut) {
+ }
+ }
+ scope 19 (inlined Option::<()>::take) {
+ let mut _49: std::option::Option<()>;
+ scope 20 (inlined std::mem::replace::<Option<()>>) {
+ scope 21 {
+ scope 17 (inlined Option::<()>::take) {
+ let mut _51: std::option::Option<()>;
+ scope 18 (inlined std::mem::replace::<Option<()>>) {
+ scope 19 {
+ }
+ }
+ }
+ scope 22 (inlined #[track_caller] Option::<()>::expect) {
+ let mut _50: isize;
+ let mut _51: !;
+ scope 23 {
+ scope 20 (inlined #[track_caller] Option::<()>::expect) {
+ let mut _52: isize;
+ let mut _53: !;
+ scope 21 {
+ }
+ }
+ }
Expand Down Expand Up @@ -240,26 +238,32 @@
+ _22 = &mut (*_23);
+ StorageDead(_24);
+ StorageLive(_46);
+ StorageLive(_47);
+ StorageLive(_51);
+ StorageLive(_48);
+ StorageLive(_53);
+ StorageLive(_43);
+ StorageLive(_44);
+ StorageLive(_45);
+ StorageLive(_47);
+ _47 = &mut _19;
+ StorageLive(_48);
+ _48 = &mut (_19.0: &mut std::future::Ready<()>);
+ _46 = copy (_19.0: &mut std::future::Ready<()>);
+ StorageDead(_48);
+ _45 = &mut ((*_46).0: std::option::Option<()>);
+ StorageLive(_49);
+ _49 = Option::<()>::None;
+ _44 = copy ((*_46).0: std::option::Option<()>);
+ ((*_46).0: std::option::Option<()>) = copy _49;
+ _49 = &raw mut _19;
+ _48 = copy _49 as *mut std::pin::helper::Pin<&mut std::future::Ready<()>> (PtrToPtr);
+ StorageDead(_49);
+ StorageDead(_45);
+ StorageLive(_50);
+ _50 = discriminant(_44);
+ switchInt(move _50) -> [0: bb16, 1: bb17, otherwise: bb7];
+ _50 = &mut ((*_48).0: &mut std::future::Ready<()>);
+ _46 = copy ((*_48).0: &mut std::future::Ready<()>);
+ StorageDead(_50);
+ StorageDead(_47);
+ _45 = &mut ((*_46).0: std::option::Option<()>);
+ StorageLive(_51);
+ _51 = Option::<()>::None;
+ _44 = copy ((*_46).0: std::option::Option<()>);
+ ((*_46).0: std::option::Option<()>) = copy _51;
+ StorageDead(_51);
+ StorageDead(_45);
+ StorageLive(_52);
+ _52 = discriminant(_44);
+ switchInt(move _52) -> [0: bb16, 1: bb17, otherwise: bb7];
}

- bb6 (cleanup): {
Expand Down Expand Up @@ -346,17 +350,17 @@
+ }
+
+ bb16: {
+ _51 = option::expect_failed(const "`Ready` polled after completion") -> bb11;
+ _53 = option::expect_failed(const "`Ready` polled after completion") -> bb11;
+ }
+
+ bb17: {
+ _43 = move ((_44 as Some).0: ());
+ StorageDead(_50);
+ StorageDead(_52);
+ StorageDead(_44);
+ _18 = Poll::<()>::Ready(move _43);
+ StorageDead(_43);
+ StorageDead(_51);
+ StorageDead(_47);
+ StorageDead(_53);
+ StorageDead(_48);
+ StorageDead(_46);
+ StorageDead(_22);
+ StorageDead(_19);
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/deref/pin-impl-deref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ impl MyPinType {
fn impl_deref_mut(_: impl DerefMut) {}
fn unpin_impl_ref(r_unpin: Pin<&MyUnpinType>) {
impl_deref_mut(r_unpin)
//~^ ERROR: the trait bound `Pin<&MyUnpinType>: DerefMut` is not satisfied
//~^ ERROR: the trait bound `&MyUnpinType: DerefMut` is not satisfied
}
fn unpin_impl_mut(r_unpin: Pin<&mut MyUnpinType>) {
impl_deref_mut(r_unpin)
}
fn pin_impl_ref(r_pin: Pin<&MyPinType>) {
impl_deref_mut(r_pin)
//~^ ERROR: `PhantomPinned` cannot be unpinned
//~| ERROR: the trait bound `Pin<&MyPinType>: DerefMut` is not satisfied
//~| ERROR: the trait bound `&MyPinType: DerefMut` is not satisfied
}
fn pin_impl_mut(r_pin: Pin<&mut MyPinType>) {
impl_deref_mut(r_pin)
Expand Down
22 changes: 10 additions & 12 deletions tests/ui/deref/pin-impl-deref.stderr
Original file line number Diff line number Diff line change
@@ -1,40 +1,36 @@
error[E0277]: the trait bound `Pin<&MyUnpinType>: DerefMut` is not satisfied
error[E0277]: the trait bound `&MyUnpinType: DerefMut` is not satisfied
--> $DIR/pin-impl-deref.rs:24:20
|
LL | impl_deref_mut(r_unpin)
| -------------- ^^^^^^^ the trait `DerefMut` is not implemented for `Pin<&MyUnpinType>`
| -------------- ^^^^^^^ the trait `DerefMut` is not implemented for `&MyUnpinType`
| |
| required by a bound introduced by this call
|
= note: `DerefMut` is implemented for `&mut MyUnpinType`, but not for `&MyUnpinType`
= note: required for `pin::helper::Pin<&MyUnpinType>` to implement `pin::helper::DerefMut`
= note: required for `Pin<&MyUnpinType>` to implement `DerefMut`
note: required by a bound in `impl_deref_mut`
--> $DIR/pin-impl-deref.rs:22:27
|
LL | fn impl_deref_mut(_: impl DerefMut) {}
| ^^^^^^^^ required by this bound in `impl_deref_mut`
help: consider mutably borrowing here
|
LL | impl_deref_mut(&mut r_unpin)
| ++++

error[E0277]: the trait bound `Pin<&MyPinType>: DerefMut` is not satisfied
error[E0277]: the trait bound `&MyPinType: DerefMut` is not satisfied
--> $DIR/pin-impl-deref.rs:31:20
|
LL | impl_deref_mut(r_pin)
| -------------- ^^^^^ the trait `DerefMut` is not implemented for `Pin<&MyPinType>`
| -------------- ^^^^^ the trait `DerefMut` is not implemented for `&MyPinType`
| |
| required by a bound introduced by this call
|
= note: `DerefMut` is implemented for `&mut MyPinType`, but not for `&MyPinType`
= note: required for `pin::helper::Pin<&MyPinType>` to implement `pin::helper::DerefMut`
= note: required for `Pin<&MyPinType>` to implement `DerefMut`
note: required by a bound in `impl_deref_mut`
--> $DIR/pin-impl-deref.rs:22:27
|
LL | fn impl_deref_mut(_: impl DerefMut) {}
| ^^^^^^^^ required by this bound in `impl_deref_mut`
help: consider mutably borrowing here
|
LL | impl_deref_mut(&mut r_pin)
| ++++

error[E0277]: `PhantomPinned` cannot be unpinned
--> $DIR/pin-impl-deref.rs:31:20
Expand All @@ -51,6 +47,7 @@ note: required because it appears within the type `MyPinType`
|
LL | struct MyPinType(core::marker::PhantomPinned);
| ^^^^^^^^^
= note: required for `pin::helper::Pin<&MyPinType>` to implement `pin::helper::DerefMut`
= note: required for `Pin<&MyPinType>` to implement `DerefMut`
note: required by a bound in `impl_deref_mut`
--> $DIR/pin-impl-deref.rs:22:27
Expand All @@ -73,6 +70,7 @@ note: required because it appears within the type `MyPinType`
|
LL | struct MyPinType(core::marker::PhantomPinned);
| ^^^^^^^^^
= note: required for `pin::helper::Pin<&mut MyPinType>` to implement `pin::helper::DerefMut`
= note: required for `Pin<&mut MyPinType>` to implement `DerefMut`
note: required by a bound in `impl_deref_mut`
--> $DIR/pin-impl-deref.rs:22:27
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
//@ check-pass
//@ known-bug: #85099
//@ check-fail

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

impl<'b, 'a, Fut> DerefMut for Pin<&'b dyn SomeTrait<'a, Fut>> {
//~^ ERROR: conflicting implementations of trait `DerefMut`
fn deref_mut<'c>(
self: &'c mut Pin<&'b dyn SomeTrait<'a, Fut>>,
) -> &'c mut (dyn SomeTrait<'a, Fut> + 'b) {
Expand Down
14 changes: 14 additions & 0 deletions tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error[E0119]: conflicting implementations of trait `DerefMut` for type `Pin<&dyn SomeTrait<'_, _>>`
--> $DIR/pin-unsound-issue-85099-derefmut.rs:44:1
|
LL | impl<'b, 'a, Fut> DerefMut for Pin<&'b dyn SomeTrait<'a, Fut>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- impl<Ptr> DerefMut for Pin<Ptr>
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;
= 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

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0119`.
Loading