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
56 changes: 54 additions & 2 deletions library/core/src/pin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1676,8 +1676,60 @@ impl<Ptr: Deref> Deref for Pin<Ptr> {
}
}

mod hidden {
use super::*;

/// 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 PinHelper<Ptr> {
pointer: Ptr,
}

#[unstable(feature = "pin_derefmut_internals", issue = "none")]
impl<Ptr: Deref> Deref for PinHelper<Ptr> {
type Target = Ptr::Target;
fn deref(&self) -> &Ptr::Target {
&self.pointer
}
}

#[unstable(feature = "pin_derefmut_internals", issue = "none")]
impl<Ptr: DerefMut<Target: Unpin>> DerefMut for PinHelper<Ptr> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Ptr::Target {
&mut self.pointer
}
}
}

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

// This impl is only used during documentation, but it is fully equivalent to the above impl with
// the exception of how the orphan rule treats it.
#[stable(feature = "pin", since = "1.33.0")]
#[cfg(doc)]
impl<Ptr> DerefMut for Pin<Ptr>
where
Ptr: DerefMut,
Ptr::Target: Unpin,
{
fn deref_mut(&mut self) -> &mut Ptr::Target {
Pin::get_mut(Pin::as_mut(self))
}
Expand Down Expand Up @@ -1759,7 +1811,7 @@ unsafe impl<'a, T: ?Sized> PinCoerceUnsized for &'a T {}
unsafe impl<'a, T: ?Sized> PinCoerceUnsized for &'a mut T {}

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

#[stable(feature = "pin", since = "1.33.0")]
unsafe impl<T: ?Sized> PinCoerceUnsized for *const T {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,27 +64,25 @@
+ let mut _45: &mut std::future::Ready<()>;
+ let mut _46: &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 _47: &mut &mut std::future::Ready<()>;
+ scope 16 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) {
+ let mut _47: *mut std::pin::hidden::PinHelper<&mut std::future::Ready<()>>;
+ let mut _48: *mut std::pin::Pin<&mut std::future::Ready<()>>;
+ scope 15 (inlined <pin::hidden::PinHelper<&mut std::future::Ready<()>> as DerefMut>::deref_mut) {
+ let mut _49: &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 _48: std::option::Option<()>;
+ scope 20 (inlined std::mem::replace::<Option<()>>) {
+ scope 21 {
+ scope 17 (inlined Option::<()>::take) {
+ let mut _50: std::option::Option<()>;
+ scope 18 (inlined std::mem::replace::<Option<()>>) {
+ scope 19 {
+ }
+ }
+ }
+ scope 22 (inlined #[track_caller] Option::<()>::expect) {
+ let mut _49: isize;
+ let mut _50: !;
+ scope 23 {
+ scope 20 (inlined #[track_caller] Option::<()>::expect) {
+ let mut _51: isize;
+ let mut _52: !;
+ scope 21 {
+ }
+ }
+ }
Expand Down Expand Up @@ -227,26 +225,32 @@
+ _22 = &mut (*_23);
+ StorageDead(_24);
+ StorageLive(_45);
+ StorageLive(_46);
+ StorageLive(_50);
+ StorageLive(_47);
+ StorageLive(_52);
+ StorageLive(_42);
+ StorageLive(_43);
+ StorageLive(_44);
+ StorageLive(_46);
+ _46 = &mut _19;
+ StorageLive(_47);
+ _47 = &mut (_19.0: &mut std::future::Ready<()>);
+ _45 = copy (_19.0: &mut std::future::Ready<()>);
+ StorageDead(_47);
+ _44 = &mut ((*_45).0: std::option::Option<()>);
+ StorageLive(_48);
+ _48 = Option::<()>::None;
+ _43 = copy ((*_45).0: std::option::Option<()>);
+ ((*_45).0: std::option::Option<()>) = copy _48;
+ _48 = &raw mut _19;
+ _47 = move _48 as *mut std::pin::hidden::PinHelper<&mut std::future::Ready<()>> (PtrToPtr);
+ StorageDead(_48);
+ StorageDead(_44);
+ StorageLive(_49);
+ _49 = discriminant(_43);
+ switchInt(move _49) -> [0: bb11, 1: bb12, otherwise: bb5];
+ _49 = &mut ((*_47).0: &mut std::future::Ready<()>);
+ _45 = copy ((*_47).0: &mut std::future::Ready<()>);
+ StorageDead(_49);
+ StorageDead(_46);
+ _44 = &mut ((*_45).0: std::option::Option<()>);
+ StorageLive(_50);
+ _50 = Option::<()>::None;
+ _43 = copy ((*_45).0: std::option::Option<()>);
+ ((*_45).0: std::option::Option<()>) = copy _50;
+ StorageDead(_50);
+ StorageDead(_44);
+ StorageLive(_51);
+ _51 = discriminant(_43);
+ switchInt(move _51) -> [0: bb11, 1: bb12, otherwise: bb5];
}
+
+ bb5: {
Expand Down Expand Up @@ -309,17 +313,17 @@
+ }
+
+ bb11: {
+ _50 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable;
+ _52 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable;
+ }
+
+ bb12: {
+ _42 = move ((_43 as Some).0: ());
+ StorageDead(_49);
+ StorageDead(_51);
+ StorageDead(_43);
+ _18 = Poll::<()>::Ready(move _42);
+ StorageDead(_42);
+ StorageDead(_50);
+ StorageDead(_46);
+ StorageDead(_52);
+ StorageDead(_47);
+ StorageDead(_45);
+ StorageDead(_22);
+ StorageDead(_19);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,27 +66,25 @@
+ let mut _47: &mut std::future::Ready<()>;
+ let mut _48: &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 _49: &mut &mut std::future::Ready<()>;
+ scope 16 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) {
+ let mut _49: *mut std::pin::hidden::PinHelper<&mut std::future::Ready<()>>;
+ let mut _50: *mut std::pin::Pin<&mut std::future::Ready<()>>;
+ scope 15 (inlined <pin::hidden::PinHelper<&mut std::future::Ready<()>> as DerefMut>::deref_mut) {
+ let mut _51: &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 _50: std::option::Option<()>;
+ scope 20 (inlined std::mem::replace::<Option<()>>) {
+ scope 21 {
+ scope 17 (inlined Option::<()>::take) {
+ let mut _52: std::option::Option<()>;
+ scope 18 (inlined std::mem::replace::<Option<()>>) {
+ scope 19 {
+ }
+ }
+ }
+ scope 22 (inlined #[track_caller] Option::<()>::expect) {
+ let mut _51: isize;
+ let mut _52: !;
+ scope 23 {
+ scope 20 (inlined #[track_caller] Option::<()>::expect) {
+ let mut _53: isize;
+ let mut _54: !;
+ scope 21 {
+ }
+ }
+ }
Expand Down Expand Up @@ -244,26 +242,32 @@
+ _22 = &mut (*_23);
+ StorageDead(_24);
+ StorageLive(_47);
+ StorageLive(_48);
+ StorageLive(_52);
+ StorageLive(_49);
+ StorageLive(_54);
+ StorageLive(_44);
+ StorageLive(_45);
+ StorageLive(_46);
+ StorageLive(_48);
+ _48 = &mut _19;
+ StorageLive(_49);
+ _49 = &mut (_19.0: &mut std::future::Ready<()>);
+ _47 = copy (_19.0: &mut std::future::Ready<()>);
+ StorageDead(_49);
+ _46 = &mut ((*_47).0: std::option::Option<()>);
+ StorageLive(_50);
+ _50 = Option::<()>::None;
+ _45 = copy ((*_47).0: std::option::Option<()>);
+ ((*_47).0: std::option::Option<()>) = copy _50;
+ _50 = &raw mut _19;
+ _49 = move _50 as *mut std::pin::hidden::PinHelper<&mut std::future::Ready<()>> (PtrToPtr);
+ StorageDead(_50);
+ StorageDead(_46);
+ StorageLive(_51);
+ _51 = discriminant(_45);
+ switchInt(move _51) -> [0: bb16, 1: bb17, otherwise: bb7];
+ _51 = &mut ((*_49).0: &mut std::future::Ready<()>);
+ _47 = copy ((*_49).0: &mut std::future::Ready<()>);
+ StorageDead(_51);
+ StorageDead(_48);
+ _46 = &mut ((*_47).0: std::option::Option<()>);
+ StorageLive(_52);
+ _52 = Option::<()>::None;
+ _45 = copy ((*_47).0: std::option::Option<()>);
+ ((*_47).0: std::option::Option<()>) = copy _52;
+ StorageDead(_52);
+ StorageDead(_46);
+ StorageLive(_53);
+ _53 = discriminant(_45);
+ switchInt(move _53) -> [0: bb16, 1: bb17, otherwise: bb7];
}

- bb6 (cleanup): {
Expand Down Expand Up @@ -350,17 +354,17 @@
+ }
+
+ bb16: {
+ _52 = option::expect_failed(const "`Ready` polled after completion") -> bb11;
+ _54 = option::expect_failed(const "`Ready` polled after completion") -> bb11;
+ }
+
+ bb17: {
+ _44 = move ((_45 as Some).0: ());
+ StorageDead(_51);
+ StorageDead(_53);
+ StorageDead(_45);
+ _18 = Poll::<()>::Ready(move _44);
+ StorageDead(_44);
+ StorageDead(_52);
+ StorageDead(_48);
+ StorageDead(_54);
+ StorageDead(_49);
+ StorageDead(_47);
+ StorageDead(_22);
+ StorageDead(_19);
Expand Down
74 changes: 74 additions & 0 deletions tests/ui/deref/pin-deref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// The purpose of this file is to track the error messages from Pin and DerefMut interacting.

//@ check-fail

use std::ops::DerefMut;
use std::pin::Pin;

struct MyUnpinType {}

impl MyUnpinType {
fn at_self(&self) {}
fn at_mut_self(&mut self) {}
}

struct MyPinType(core::marker::PhantomPinned);

impl MyPinType {
fn at_self(&self) {}
fn at_mut_self(&mut self) {}
}

fn call_mut_ref_unpin(mut r_unpin: Pin<&mut MyUnpinType>) {
r_unpin.at_self();
r_unpin.at_mut_self();
}

fn call_ref_unpin(mut r_unpin: Pin<&MyUnpinType>) {
r_unpin.at_self();
r_unpin.at_mut_self(); //~ ERROR: cannot borrow data in dereference of `Pin<&MyUnpinType>` as mutable
}

fn call_mut_ref_pin(mut r_pin: Pin<&mut MyPinType>) {
r_pin.at_self();
r_pin.at_mut_self(); //~ ERROR: cannot borrow data in dereference of `Pin<&mut MyPinType>` as mutable
}

fn call_ref_pin(mut r_pin: Pin<&MyPinType>) {
r_pin.at_self();
r_pin.at_mut_self(); //~ ERROR: cannot borrow data in dereference of `Pin<&MyPinType>` as mutable
}

fn coerce_unpin_rr<'a>(mut r_unpin: &'a mut Pin<&MyUnpinType>) -> &'a MyUnpinType {
r_unpin
}

fn coerce_unpin_rm<'a>(mut r_unpin: &'a mut Pin<&MyUnpinType>) -> &'a mut MyUnpinType {
r_unpin //~ ERROR: cannot borrow data in dereference of `Pin<&MyUnpinType>` as mutable
}

fn coerce_unpin_mr<'a>(mut r_unpin: &'a mut Pin<&mut MyUnpinType>) -> &'a MyUnpinType {
r_unpin
}

fn coerce_unpin_mm<'a>(mut r_unpin: &'a mut Pin<&mut MyUnpinType>) -> &'a mut MyUnpinType {
r_unpin
}

fn coerce_pin_rr<'a>(mut r_pin: &'a mut Pin<&MyPinType>) -> &'a MyPinType {
r_pin
}

fn coerce_pin_rm<'a>(mut r_pin: &'a mut Pin<&MyPinType>) -> &'a mut MyPinType {
r_pin //~ ERROR: cannot borrow data in dereference of `Pin<&MyPinType>` as mutable
}

fn coerce_pin_mr<'a>(mut r_pin: &'a mut Pin<&mut MyPinType>) -> &'a MyPinType {
r_pin
}

fn coerce_pin_mm<'a>(mut r_pin: &'a mut Pin<&mut MyPinType>) -> &'a mut MyPinType {
r_pin //~ ERROR: cannot borrow data in dereference of `Pin<&mut MyPinType>` as mutable
}

fn main() {}
Loading
Loading