From 7e1c00dbce512b260c396b4425527b00891168a7 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Wed, 17 Sep 2025 17:06:14 +0000 Subject: [PATCH 1/4] Prevent downstream impl DerefMut for Pin --- library/core/src/pin.rs | 59 ++++++++++++++++++- ...y.run2-{closure#0}.Inline.panic-abort.diff | 56 ++++++++++-------- ....run2-{closure#0}.Inline.panic-unwind.diff | 56 ++++++++++-------- tests/ui/deref/pin-impl-deref.rs | 4 +- tests/ui/deref/pin-impl-deref.stderr | 22 ++++--- .../pin-unsound-issue-85099-derefmut.rs | 4 +- .../pin-unsound-issue-85099-derefmut.stderr | 14 +++++ 7 files changed, 146 insertions(+), 69 deletions(-) create mode 100644 tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 535830f2e749f..d7e348b71e1d0 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1689,9 +1689,66 @@ impl const Deref for Pin { } } +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 { + 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 const DerefMut for Pin + 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> const DerefMut for Pin { +#[cfg(not(doc))] +impl const DerefMut for Pin +where + Ptr: [const] Deref, + helper::Pin: [const] helper::DerefMut, +{ + #[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 as *mut helper::Pin) + }) + } +} + +#[stable(feature = "pin", since = "1.33.0")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +#[cfg(doc)] +impl const DerefMut for Pin +where + Ptr: [const] DerefMut, + Ptr::Target: Unpin, +{ fn deref_mut(&mut self) -> &mut Ptr::Target { Pin::get_mut(Pin::as_mut(self)) } diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff index 0acb33febe52b..226a16d6eec39 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff @@ -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 > 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 > 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::>) { -+ scope 21 { ++ scope 17 (inlined Option::<()>::take) { ++ let mut _49: std::option::Option<()>; ++ scope 18 (inlined std::mem::replace::>) { ++ 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 { + } + } + } @@ -217,18 +215,23 @@ + _22 = &mut (*_23); + StorageDead(_24); + StorageLive(_44); -+ StorageLive(_49); ++ StorageLive(_46); ++ StorageLive(_51); + StorageLive(_41); + StorageLive(_42); -+ _44 = copy (_19.0: &mut std::future::Ready<()>); + 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); -+ StorageLive(_48); -+ _48 = discriminant(_42); -+ switchInt(move _48) -> [0: bb11, 1: bb12, otherwise: bb5]; ++ _44 = copy ((*_46).0: &mut std::future::Ready<()>); ++ StorageLive(_49); ++ _49 = Option::<()>::None; ++ _42 = copy ((*_44).0: std::option::Option<()>); ++ ((*_44).0: std::option::Option<()>) = copy _49; ++ StorageDead(_49); ++ StorageLive(_50); ++ _50 = discriminant(_42); ++ switchInt(move _50) -> [0: bb11, 1: bb12, otherwise: bb5]; } + + bb5: { @@ -291,16 +294,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(_51); ++ StorageDead(_46); + StorageDead(_44); + StorageDead(_22); + StorageDead(_19); diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff index 98ee46c29b1be..770b6e471ff8b 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff @@ -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 > 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 > 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::>) { -+ scope 21 { ++ scope 17 (inlined Option::<()>::take) { ++ let mut _51: std::option::Option<()>; ++ scope 18 (inlined std::mem::replace::>) { ++ 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 { + } + } + } @@ -234,18 +232,23 @@ + _22 = &mut (*_23); + StorageDead(_24); + StorageLive(_46); -+ StorageLive(_51); ++ StorageLive(_48); ++ StorageLive(_53); + StorageLive(_43); + StorageLive(_44); -+ _46 = copy (_19.0: &mut std::future::Ready<()>); + 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); -+ StorageLive(_50); -+ _50 = discriminant(_44); -+ switchInt(move _50) -> [0: bb16, 1: bb17, otherwise: bb7]; ++ _46 = copy ((*_48).0: &mut std::future::Ready<()>); ++ StorageLive(_51); ++ _51 = Option::<()>::None; ++ _44 = copy ((*_46).0: std::option::Option<()>); ++ ((*_46).0: std::option::Option<()>) = copy _51; ++ StorageDead(_51); ++ StorageLive(_52); ++ _52 = discriminant(_44); ++ switchInt(move _52) -> [0: bb16, 1: bb17, otherwise: bb7]; } - bb6 (cleanup): { @@ -332,16 +335,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(_53); ++ StorageDead(_48); + StorageDead(_46); + StorageDead(_22); + StorageDead(_19); diff --git a/tests/ui/deref/pin-impl-deref.rs b/tests/ui/deref/pin-impl-deref.rs index b1dc8dea3f248..ccd8d0dfc72ae 100644 --- a/tests/ui/deref/pin-impl-deref.rs +++ b/tests/ui/deref/pin-impl-deref.rs @@ -22,7 +22,7 @@ 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) @@ -30,7 +30,7 @@ fn unpin_impl_mut(r_unpin: Pin<&mut MyUnpinType>) { 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) diff --git a/tests/ui/deref/pin-impl-deref.stderr b/tests/ui/deref/pin-impl-deref.stderr index 106654641a117..918ff7ca91218 100644 --- a/tests/ui/deref/pin-impl-deref.stderr +++ b/tests/ui/deref/pin-impl-deref.stderr @@ -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 @@ -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 @@ -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 diff --git a/tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs index f3ece563f5403..e8c3bbba1e458 100644 --- a/tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs +++ b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs @@ -1,5 +1,4 @@ -//@ check-pass -//@ known-bug: #85099 +//@ check-fail // Should fail. Can coerce `Pin` into `Pin` where // `T: Deref` and `U: Deref`, using the @@ -43,6 +42,7 @@ impl<'a, Fut: Future> 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) { diff --git a/tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr new file mode 100644 index 0000000000000..cc56c77809eaa --- /dev/null +++ b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr @@ -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 DerefMut for Pin + where as pin::helper::DerefMut>::Target == as Deref>::Target, Ptr: Deref, pin::helper::Pin: pin::helper::DerefMut, pin::helper::Pin: ?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`. From cd44cd0f63a7e67dcfc3618aa7bf6e2e70643561 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Thu, 25 Sep 2025 08:39:35 +0000 Subject: [PATCH 2/4] Improve docs for module --- library/core/src/pin.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index d7e348b71e1d0..fdbeaea464194 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1692,8 +1692,22 @@ impl const Deref for Pin { 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`. + /// The `Pin` type implements the unsafe trait `PinCoerceUnsized`, which essentially requires + /// that the type does not have a malicious `Deref` or `DerefMut` impl. However, without this + /// helper module, downstream crates are able to write `impl DerefMut for Pin` as + /// long as it does not overlap with the impl provided by stdlib. This is because `Pin` is + /// `#[fundamental]`, so stdlib promises to never implement traits for `Pin` that it does not + /// implement today. + /// + /// However, this is problematic. Downstream crates could implement `DerefMut` for + /// `Pin<&LocalType>`, and they could do so maliciously. To prevent this, the implementation for + /// `Pin` delegates to this helper module. Since `helper::Pin` is not `#[fundamental]`, the + /// orphan rules assume that stdlib might implement `helper::DerefMut` for `helper::Pin<&_>` in + /// the future. Because of this, downstream crates can no longer provide an implementation of + /// `DerefMut` for `Pin<&_>`, as it might overlap with a trait impl that, according to the + /// orphan rules, the stdlib could introduce without a breaking change in a future release. + /// + /// See for the issue this fixes. #[repr(transparent)] #[unstable(feature = "pin_derefmut_internals", issue = "none")] #[allow(missing_debug_implementations)] From f65250b3dd0eada1ab25ad4f766048f2ebe24623 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Mon, 29 Sep 2025 09:34:18 +0000 Subject: [PATCH 3/4] Document workaround in docs --- library/core/src/pin.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index fdbeaea464194..23950acd97610 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1755,13 +1755,21 @@ where } } +/// The `Target` type is restricted to `Unpin` types as it's not safe to obtain a mutable reference +/// to a pinned value. +/// +/// For soundness reasons, implementations of `DerefMut` for `Pin` are rejected even when `T` is +/// a local type not covered by this impl block. (Since `Pin` is [fundamental], such implementations +/// would normally be possible.) +/// +/// [fundamental]: ../../reference/items/implementations.html#r-items.impl.trait.fundamental #[stable(feature = "pin", since = "1.33.0")] #[rustc_const_unstable(feature = "const_convert", issue = "143773")] #[cfg(doc)] impl const DerefMut for Pin where Ptr: [const] DerefMut, - Ptr::Target: Unpin, + ::Target: Unpin, { fn deref_mut(&mut self) -> &mut Ptr::Target { Pin::get_mut(Pin::as_mut(self)) From 76dcb39c240382a7d62cc8ee475e0c3866ad8025 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Wed, 1 Oct 2025 11:14:08 +0000 Subject: [PATCH 4/4] Adjust error messages --- compiler/rustc_span/src/symbol.rs | 1 + .../src/error_reporting/traits/suggestions.rs | 18 ++++++++++++++++++ library/core/src/pin.rs | 15 ++++++++------- ...dy.run2-{closure#0}.Inline.panic-abort.diff | 6 +++--- ...y.run2-{closure#0}.Inline.panic-unwind.diff | 6 +++--- tests/ui/deref/pin-impl-deref.stderr | 4 ---- .../pin-unsound-issue-85099-derefmut.stderr | 4 ++-- 7 files changed, 35 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 083e04730bc37..7f1ca96b2a75b 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -309,6 +309,7 @@ symbols! { PathBuf, Pending, PinCoerceUnsized, + PinDerefMutHelper, Pointer, Poll, ProcMacro, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 37e622102e70f..5665229a4cbe6 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3476,6 +3476,24 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // can do about it. As far as they are concerned, `?` is compiler magic. return; } + if tcx.is_diagnostic_item(sym::PinDerefMutHelper, parent_def_id) { + let parent_predicate = + self.resolve_vars_if_possible(data.derived.parent_trait_pred); + + // Skip PinDerefMutHelper in suggestions, but still show downstream suggestions. + ensure_sufficient_stack(|| { + self.note_obligation_cause_code( + body_id, + err, + parent_predicate, + param_env, + &data.derived.parent_code, + obligated_types, + seen_requirements, + ) + }); + return; + } let self_ty_str = tcx.short_string(parent_trait_pred.skip_binder().self_ty(), err.long_ty_path()); let trait_name = tcx.short_string( diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 23950acd97610..81c2dabf0d1d8 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1711,20 +1711,21 @@ mod helper { #[repr(transparent)] #[unstable(feature = "pin_derefmut_internals", issue = "none")] #[allow(missing_debug_implementations)] - pub struct Pin { + pub struct PinHelper { pointer: Ptr, } #[unstable(feature = "pin_derefmut_internals", issue = "none")] #[rustc_const_unstable(feature = "const_convert", issue = "143773")] - pub const trait DerefMut { + #[rustc_diagnostic_item = "PinDerefMutHelper"] + pub const trait PinDerefMutHelper { 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 const DerefMut for Pin + impl const PinDerefMutHelper for PinHelper where Ptr::Target: crate::marker::Unpin, { @@ -1743,14 +1744,14 @@ mod helper { impl const DerefMut for Pin where Ptr: [const] Deref, - helper::Pin: [const] helper::DerefMut, + helper::PinHelper: [const] helper::PinDerefMutHelper, { #[inline] fn deref_mut(&mut self) -> &mut Ptr::Target { - // SAFETY: Pin and helper::Pin have the same layout, so this is equivalent to + // SAFETY: Pin and PinHelper 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 as *mut helper::Pin) + helper::PinDerefMutHelper::deref_mut(unsafe { + &mut *(self as *mut Pin as *mut helper::PinHelper) }) } } diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff index 226a16d6eec39..0203ff52d63f8 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff @@ -63,9 +63,9 @@ + let mut _44: &mut std::future::Ready<()>; + let mut _45: &mut std::pin::Pin<&mut std::future::Ready<()>>; + scope 14 (inlined > as DerefMut>::deref_mut) { -+ let mut _46: *mut std::pin::helper::Pin<&mut std::future::Ready<()>>; ++ let mut _46: *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>>; + let mut _47: *mut std::pin::Pin<&mut std::future::Ready<()>>; -+ scope 15 (inlined > as pin::helper::DerefMut>::deref_mut) { ++ scope 15 (inlined > as pin::helper::PinDerefMutHelper>::deref_mut) { + let mut _48: &mut &mut std::future::Ready<()>; + scope 16 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) { + } @@ -221,7 +221,7 @@ + StorageLive(_42); + StorageLive(_47); + _47 = &raw mut _19; -+ _46 = copy _47 as *mut std::pin::helper::Pin<&mut std::future::Ready<()>> (PtrToPtr); ++ _46 = copy _47 as *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>> (PtrToPtr); + StorageDead(_47); + _44 = copy ((*_46).0: &mut std::future::Ready<()>); + StorageLive(_49); diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff index 770b6e471ff8b..6c8cad3e992e7 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff @@ -65,9 +65,9 @@ + let mut _46: &mut std::future::Ready<()>; + let mut _47: &mut std::pin::Pin<&mut std::future::Ready<()>>; + scope 14 (inlined > as DerefMut>::deref_mut) { -+ let mut _48: *mut std::pin::helper::Pin<&mut std::future::Ready<()>>; ++ let mut _48: *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>>; + let mut _49: *mut std::pin::Pin<&mut std::future::Ready<()>>; -+ scope 15 (inlined > as pin::helper::DerefMut>::deref_mut) { ++ scope 15 (inlined > as pin::helper::PinDerefMutHelper>::deref_mut) { + let mut _50: &mut &mut std::future::Ready<()>; + scope 16 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) { + } @@ -238,7 +238,7 @@ + StorageLive(_44); + StorageLive(_49); + _49 = &raw mut _19; -+ _48 = copy _49 as *mut std::pin::helper::Pin<&mut std::future::Ready<()>> (PtrToPtr); ++ _48 = copy _49 as *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>> (PtrToPtr); + StorageDead(_49); + _46 = copy ((*_48).0: &mut std::future::Ready<()>); + StorageLive(_51); diff --git a/tests/ui/deref/pin-impl-deref.stderr b/tests/ui/deref/pin-impl-deref.stderr index 918ff7ca91218..4143d66f42723 100644 --- a/tests/ui/deref/pin-impl-deref.stderr +++ b/tests/ui/deref/pin-impl-deref.stderr @@ -7,7 +7,6 @@ LL | impl_deref_mut(r_unpin) | 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 @@ -24,7 +23,6 @@ LL | impl_deref_mut(r_pin) | 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 @@ -47,7 +45,6 @@ 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 @@ -70,7 +67,6 @@ 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 diff --git a/tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr index cc56c77809eaa..2bcd92b76a09d 100644 --- a/tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr +++ b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr @@ -6,8 +6,8 @@ LL | impl<'b, 'a, Fut> DerefMut for Pin<&'b dyn SomeTrait<'a, Fut>> { | = note: conflicting implementation in crate `core`: - impl DerefMut for Pin - where as pin::helper::DerefMut>::Target == as Deref>::Target, Ptr: Deref, pin::helper::Pin: pin::helper::DerefMut, pin::helper::Pin: ?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 + where as pin::helper::PinDerefMutHelper>::Target == as Deref>::Target, Ptr: Deref, pin::helper::PinHelper: pin::helper::PinDerefMutHelper, pin::helper::PinHelper: ?Sized; + = note: upstream crates may add a new impl of trait `std::pin::helper::PinDerefMutHelper` for type `std::pin::helper::PinHelper<&dyn SomeTrait<'_, _>>` in future versions error: aborting due to 1 previous error