From 7a3622448fbade0e57cf5bc0cdf23281cf32a012 Mon Sep 17 00:00:00 2001 From: piorr Date: Fri, 17 Jul 2026 08:30:24 +0000 Subject: [PATCH 1/3] Add #[rustc_anti_fundamental] attribute infrastructure This adds a new compiler attribute that prevents non-local #[fundamental] types from receiving implementations of the marked trait. This is the infrastructure for fixing soundness problems with DerefMut and DispatchFromDyn on fundamental wrappers like Box and Pin. The attribute is parsed, cross-crate encoded, stored in TraitDef, and checked during the orphan check in coherence. --- .../src/attributes/traits.rs | 8 ++++ compiler/rustc_attr_parsing/src/context.rs | 1 + compiler/rustc_feature/src/builtin_attrs.rs | 1 + .../rustc_hir/src/attrs/data_structures.rs | 6 +++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + .../src/coherence/orphan.rs | 15 +++++++ compiler/rustc_hir_analysis/src/collect.rs | 2 + .../rustc_hir_analysis/src/diagnostics.rs | 14 +++++++ .../src/ty/context/impl_interner.rs | 4 ++ compiler/rustc_middle/src/ty/trait_def.rs | 5 +++ .../rustc_next_trait_solver/src/coherence.rs | 40 +++++++++++++++++++ compiler/rustc_passes/src/check_attr.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_type_ir/src/interner.rs | 2 + .../anti-fundamental-foreign-type.rs | 30 ++++++++++++++ .../anti-fundamental-foreign-type.stderr | 31 ++++++++++++++ .../anti-fundamental-invalid-target.rs | 18 +++++++++ .../anti-fundamental-invalid-target.stderr | 18 +++++++++ .../coherence/anti-fundamental-local-trait.rs | 23 +++++++++++ .../auxiliary/anti_fundamental_trait_lib.rs | 12 ++++++ 20 files changed, 233 insertions(+) create mode 100644 tests/ui/coherence/anti-fundamental-foreign-type.rs create mode 100644 tests/ui/coherence/anti-fundamental-foreign-type.stderr create mode 100644 tests/ui/coherence/anti-fundamental-invalid-target.rs create mode 100644 tests/ui/coherence/anti-fundamental-invalid-target.stderr create mode 100644 tests/ui/coherence/anti-fundamental-local-trait.rs create mode 100644 tests/ui/coherence/auxiliary/anti_fundamental_trait_lib.rs diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs index 69bdccb85c5cd..7e20c097a1939 100644 --- a/compiler/rustc_attr_parsing/src/attributes/traits.rs +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -116,6 +116,14 @@ impl NoArgsAttributeParser for RustcCoinductiveParser { const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcCoinductive; } +pub(crate) struct RustcAntiFundamentalParser; +impl NoArgsAttributeParser for RustcAntiFundamentalParser { + const PATH: &[Symbol] = &[sym::rustc_anti_fundamental]; + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Trait)]); + const STABILITY: AttributeStability = unstable!(rustc_attrs); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcAntiFundamental; +} + pub(crate) struct RustcAllowIncoherentImplParser; impl NoArgsAttributeParser for RustcAllowIncoherentImplParser { const PATH: &[Symbol] = &[sym::rustc_allow_incoherent_impl]; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 6254dd73f3263..e5022df3ceba8 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -295,6 +295,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 1f6f97f1310ae..794d527bc3576 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -347,6 +347,7 @@ pub static BUILTIN_ATTRIBUTES: &[Symbol] = &[ sym::rustc_never_returns_null_ptr, sym::rustc_no_implicit_autorefs, sym::rustc_coherence_is_core, + sym::rustc_anti_fundamental, sym::rustc_coinductive, sym::rustc_comptime, sym::rustc_allow_incoherent_impl, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 165f06d2fde8b..338a94517bb16 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -1350,6 +1350,12 @@ pub enum AttributeKind { /// Represents `#[rustc_allow_incoherent_impl]`. RustcAllowIncoherentImpl(Span), + /// Represents `#[rustc_anti_fundamental]`. This marks a trait such that + /// `#[fundamental]` types (that are not local to the current crate) cannot + /// receive implementations of it. Used to reserve control over `Deref`, + /// `DispatchFromDyn`, etc. on fundamental wrappers like `Box` and `Pin`. + RustcAntiFundamental, + /// Represents `#[rustc_as_ptr]` (used by the `dangling_pointers_from_temporaries` lint). RustcAsPtr, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index dded70ccd08ef..8ede12f0663b3 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -106,6 +106,7 @@ impl AttributeKind { RustcAllocatorZeroedVariant { .. } => Yes, RustcAllowConstFnUnstable(..) => No, RustcAllowIncoherentImpl(..) => No, + RustcAntiFundamental => Yes, RustcAsPtr => Yes, RustcAutodiff(..) => Yes, RustcBodyStability { .. } => No, diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 1cf5da0522c2c..9565e691643a0 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -50,6 +50,10 @@ pub(crate) fn orphan_check_impl( OrphanCheckErr::NonLocalInputType(_) => { bug!("orphanck: shouldn't've gotten non-local input tys in compat mode") } + OrphanCheckErr::AntiFundamentalForeignType(_) => { + // Anti-fundamental violations are always hard errors. + return Err(emit_orphan_check_error(tcx, trait_ref, impl_def_id, err)); + } }, Err(err) => return Err(emit_orphan_check_error(tcx, trait_ref, impl_def_id, err)), }, @@ -378,6 +382,9 @@ fn orphan_check<'tcx>( }); OrphanCheckErr::NonLocalInputType(tys) } + OrphanCheckErr::AntiFundamentalForeignType(ty) => { + OrphanCheckErr::AntiFundamentalForeignType(infcx.resolve_vars_if_possible(ty)) + } }) } @@ -488,6 +495,14 @@ fn emit_orphan_check_error<'tcx>( } guar.unwrap() } + traits::OrphanCheckErr::AntiFundamentalForeignType(ty) => { + let span = tcx.def_span(impl_def_id); + tcx.dcx().emit_err(diagnostics::AntiFundamentalForeignImpl { + span, + trait_name: tcx.def_path_str(trait_ref.def_id), + fundamental_ty: ty, + }) + } } } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index bf17952313479..c0e1795745c01 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -979,6 +979,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { let deny_explicit_impl = find_attr!(attrs, RustcDenyExplicitImpl); let force_dyn_incompatible = find_attr!(attrs, RustcDynIncompatibleTrait(span) => *span); + let is_anti_fundamental = find_attr!(attrs, RustcAntiFundamental); ty::TraitDef { def_id: def_id.to_def_id(), @@ -996,6 +997,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { must_implement_one_of, force_dyn_incompatible, deny_explicit_impl, + is_anti_fundamental, } } diff --git a/compiler/rustc_hir_analysis/src/diagnostics.rs b/compiler/rustc_hir_analysis/src/diagnostics.rs index ab6fa34be9fbb..e09765b3dbcb4 100644 --- a/compiler/rustc_hir_analysis/src/diagnostics.rs +++ b/compiler/rustc_hir_analysis/src/diagnostics.rs @@ -2045,3 +2045,17 @@ pub(crate) struct OnlyStructsCanBeViewedAdt<'tcx> { pub article: &'static str, pub kind: &'static str, } + +#[derive(Diagnostic)] +#[diag("cannot implement `{$trait_name}` on the fundamental type `{$fundamental_ty}`")] +#[note( + "`{$trait_name}` is marked `#[rustc_anti_fundamental]`, which means it \ + cannot be implemented on `#[fundamental]` types from another crate" +)] +pub(crate) struct AntiFundamentalForeignImpl<'tcx> { + #[primary_span] + #[label("impl of `{$trait_name}` not allowed on `{$fundamental_ty}`")] + pub(crate) span: Span, + pub(crate) trait_name: String, + pub(crate) fundamental_ty: Ty<'tcx>, +} diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index 983b4afefdb5f..d6c47cb4086dd 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -613,6 +613,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.trait_def(def_id).is_fundamental } + fn trait_is_anti_fundamental(self, def_id: DefId) -> bool { + self.trait_def(def_id).is_anti_fundamental + } + fn trait_is_unsafe(self, trait_def_id: Self::DefId) -> bool { self.trait_def(trait_def_id).safety.is_unsafe() } diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 681a8793c6886..c537e4af0cea5 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -82,6 +82,11 @@ pub struct TraitDef { /// This only applies to built-in traits, and is marked via /// `#[rustc_deny_explicit_impl]`. pub deny_explicit_impl: bool, + + /// If `true`, then this trait has the `#[rustc_anti_fundamental]` attribute. + /// This prevents non-local `#[fundamental]` types from receiving impls of + /// this trait. Used for `Deref`, `DispatchFromDyn`, `CoerceUnsized`, etc. + pub is_anti_fundamental: bool, } /// Whether this trait is treated specially by the standard library diff --git a/compiler/rustc_next_trait_solver/src/coherence.rs b/compiler/rustc_next_trait_solver/src/coherence.rs index e37e69a617bbd..44e482f6fe9f1 100644 --- a/compiler/rustc_next_trait_solver/src/coherence.rs +++ b/compiler/rustc_next_trait_solver/src/coherence.rs @@ -118,6 +118,9 @@ impl From for IsFirstInputType { pub enum OrphanCheckErr { NonLocalInputType(Vec<(I::Ty, IsFirstInputType)>), UncoveredTyParams(UncoveredTyParams), + /// The trait is `#[rustc_anti_fundamental]` and the Self type's head is a + /// non-local `#[fundamental]` type. `fundamental_ty` is the offending type. + AntiFundamentalForeignType(I::Ty), } #[derive_where(Debug; I: Interner, T: Debug)] @@ -216,6 +219,13 @@ pub struct UncoveredTyParams { /// the above requirement is sufficient, and is necessary in "open world" /// cases). /// +/// In addition to the orphan rules above, this also enforces +/// `#[rustc_anti_fundamental]`: when the trait carries that attribute, an impl +/// whose `Self` type has a non-local `#[fundamental]` type at its head is +/// rejected (in `InCrate::Local` mode). This lets the standard library reserve +/// control over traits like `Deref` and `DispatchFromDyn` on fundamental +/// wrappers such as `Box` and `Pin`. +/// /// Note that this function is never called for types that have both type /// parameters and inference variables. #[instrument(level = "trace", skip(infcx, lazily_normalize_ty), ret)] @@ -234,6 +244,20 @@ where panic!("orphan check only expects inference variables: {trait_ref:?}"); } + // Anti-fundamental check: if the trait is marked `#[rustc_anti_fundamental]`, + // reject impls where the head of the Self type is a non-local fundamental type. + // This prevents downstream crates from implementing traits like `Deref` on + // fundamental wrappers like `Box` or `Pin`. + if matches!(in_crate, InCrate::Local { .. }) { + let cx = infcx.cx(); + if cx.trait_is_anti_fundamental(trait_ref.def_id) { + let self_ty = infcx.shallow_resolve(trait_ref.self_ty()); + if let Some(err_ty) = check_anti_fundamental_head::(self_ty) { + return Ok(Err(OrphanCheckErr::AntiFundamentalForeignType(err_ty))); + } + } + } + let mut checker = OrphanChecker::new(infcx, in_crate, lazily_normalize_ty); Ok(match trait_ref.visit_with(&mut checker) { ControlFlow::Continue(()) => Err(OrphanCheckErr::NonLocalInputType(checker.non_local_tys)), @@ -256,6 +280,22 @@ where }) } +/// Checks the head of the Self type for a non-local fundamental type. +/// If the head is a reference (`&`/`&mut`), unwrap and check again (references are fundamental). +/// Returns `Some(ty)` with the offending fundamental type if the check fails. +fn check_anti_fundamental_head(mut ty: I::Ty) -> Option { + // Unwrap through references (which are fundamental but undocumented as such). + while let ty::Ref(_, inner, _) = ty.kind() { + ty = inner; + } + + // The head is offending only if it is a fundamental ADT that is not local to the + // current crate. All other types are fine — they're either local, non-fundamental, + // or primitive (which can't be fundamental). + matches!(ty.kind(), ty::Adt(def, _) if def.is_fundamental() && !def.def_id().is_local()) + .then_some(ty) +} + struct OrphanChecker<'a, Infcx, I: Interner, F> { infcx: &'a Infcx, in_crate: InCrate, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index a55d38251c843..f3dabb1081c4f 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -305,6 +305,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::RustcAllocatorZeroed => (), AttributeKind::RustcAllocatorZeroedVariant { .. } => (), AttributeKind::RustcAllowIncoherentImpl(..) => (), + AttributeKind::RustcAntiFundamental => (), AttributeKind::RustcAsPtr => (), AttributeKind::RustcAutodiff(..) => (), AttributeKind::RustcBodyStability { .. } => (), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index a293e106bd914..41c35bc1bebea 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1762,6 +1762,7 @@ symbols! { rustc_allow_const_fn_unstable, rustc_allow_incoherent_impl, rustc_allowed_through_unstable_modules, + rustc_anti_fundamental, rustc_as_ptr, rustc_attrs, rustc_autodiff, diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 1fa698a4faeaf..9ee87bf8e68e3 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -435,6 +435,8 @@ pub trait Interner: fn trait_is_fundamental(self, def_id: Self::TraitId) -> bool; + fn trait_is_anti_fundamental(self, def_id: Self::TraitId) -> bool; + /// Returns `true` if this is an `unsafe trait`. fn trait_is_unsafe(self, trait_def_id: Self::TraitId) -> bool; diff --git a/tests/ui/coherence/anti-fundamental-foreign-type.rs b/tests/ui/coherence/anti-fundamental-foreign-type.rs new file mode 100644 index 0000000000000..5b09f3023fbc1 --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-foreign-type.rs @@ -0,0 +1,30 @@ +//@ aux-build: anti_fundamental_trait_lib.rs + +// Test that `#[rustc_anti_fundamental]` prevents implementing the trait +// on non-local `#[fundamental]` types. + +extern crate anti_fundamental_trait_lib; + +use anti_fundamental_trait_lib::{ + AntiFundamentalTrait, FundamentalWrapper, NonFundamentalWrapper, +}; + +struct LocalType; + +// OK: implementing on a local type. +impl AntiFundamentalTrait for LocalType {} + +// ERROR: implementing on a non-fundamental foreign type wrapping a local type +// (standard orphan check - not covered). +impl AntiFundamentalTrait for NonFundamentalWrapper {} +//~^ ERROR only traits defined in the current crate + +// ERROR: implementing on a foreign fundamental type. +impl AntiFundamentalTrait for FundamentalWrapper {} +//~^ ERROR cannot implement `AntiFundamentalTrait` on the fundamental type + +// ERROR: implementing on a reference to a foreign fundamental type. +impl AntiFundamentalTrait for &FundamentalWrapper {} +//~^ ERROR cannot implement `AntiFundamentalTrait` on the fundamental type + +fn main() {} diff --git a/tests/ui/coherence/anti-fundamental-foreign-type.stderr b/tests/ui/coherence/anti-fundamental-foreign-type.stderr new file mode 100644 index 0000000000000..a6f8f7e3db5d8 --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-foreign-type.stderr @@ -0,0 +1,31 @@ +error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate + --> $DIR/anti-fundamental-foreign-type.rs:19:1 + | +LL | impl AntiFundamentalTrait for NonFundamentalWrapper {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------------------------- + | | + | `NonFundamentalWrapper` is not defined in the current crate + | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + = note: define and implement a trait or new type instead + +error: cannot implement `AntiFundamentalTrait` on the fundamental type `FundamentalWrapper` + --> $DIR/anti-fundamental-foreign-type.rs:23:1 + | +LL | impl AntiFundamentalTrait for FundamentalWrapper {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `AntiFundamentalTrait` not allowed on `FundamentalWrapper` + | + = note: `AntiFundamentalTrait` is marked `#[rustc_anti_fundamental]`, which means it cannot be implemented on `#[fundamental]` types from another crate + +error: cannot implement `AntiFundamentalTrait` on the fundamental type `FundamentalWrapper` + --> $DIR/anti-fundamental-foreign-type.rs:27:1 + | +LL | impl AntiFundamentalTrait for &FundamentalWrapper {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `AntiFundamentalTrait` not allowed on `FundamentalWrapper` + | + = note: `AntiFundamentalTrait` is marked `#[rustc_anti_fundamental]`, which means it cannot be implemented on `#[fundamental]` types from another crate + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0117`. diff --git a/tests/ui/coherence/anti-fundamental-invalid-target.rs b/tests/ui/coherence/anti-fundamental-invalid-target.rs new file mode 100644 index 0000000000000..49f7f7508ac7d --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-invalid-target.rs @@ -0,0 +1,18 @@ +// Test that `#[rustc_anti_fundamental]` can only be applied to traits. +// The target restriction is enforced declaratively by `ALLOWED_TARGETS` +// in the attribute parser, so applying it to a non-trait is an error. + +#![feature(rustc_attrs)] + +#[rustc_anti_fundamental] +//~^ ERROR attribute cannot be used on +struct NotATrait; + +#[rustc_anti_fundamental] +//~^ ERROR attribute cannot be used on +fn also_not_a_trait() {} + +#[rustc_anti_fundamental] +trait Ok {} + +fn main() {} diff --git a/tests/ui/coherence/anti-fundamental-invalid-target.stderr b/tests/ui/coherence/anti-fundamental-invalid-target.stderr new file mode 100644 index 0000000000000..26438d465a81a --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-invalid-target.stderr @@ -0,0 +1,18 @@ +error: the `rustc_anti_fundamental` attribute cannot be used on structs + --> $DIR/anti-fundamental-invalid-target.rs:7:3 + | +LL | #[rustc_anti_fundamental] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: the `rustc_anti_fundamental` attribute can only be applied to traits + +error: the `rustc_anti_fundamental` attribute cannot be used on functions + --> $DIR/anti-fundamental-invalid-target.rs:11:3 + | +LL | #[rustc_anti_fundamental] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: the `rustc_anti_fundamental` attribute can only be applied to traits + +error: aborting due to 2 previous errors + diff --git a/tests/ui/coherence/anti-fundamental-local-trait.rs b/tests/ui/coherence/anti-fundamental-local-trait.rs new file mode 100644 index 0000000000000..33c81e50494f8 --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-local-trait.rs @@ -0,0 +1,23 @@ +//@ check-pass + +// Test that `#[rustc_anti_fundamental]` does NOT block local traits. +// If the trait itself is local, orphan rules pass even on fundamental types. + +#![feature(fundamental)] +#![feature(rustc_attrs)] + +#[fundamental] +struct LocalFundamental(T); + +#[rustc_anti_fundamental] +trait AntiFundamentalTrait {} + +struct LocalType; + +// OK: both trait and fundamental type are local. +impl AntiFundamentalTrait for LocalFundamental {} + +// OK: implementing on a local non-fundamental type. +impl AntiFundamentalTrait for LocalType {} + +fn main() {} diff --git a/tests/ui/coherence/auxiliary/anti_fundamental_trait_lib.rs b/tests/ui/coherence/auxiliary/anti_fundamental_trait_lib.rs new file mode 100644 index 0000000000000..e5aa617b0e53c --- /dev/null +++ b/tests/ui/coherence/auxiliary/anti_fundamental_trait_lib.rs @@ -0,0 +1,12 @@ +// Auxiliary crate for anti-fundamental coherence tests. + +#![feature(fundamental)] +#![feature(rustc_attrs)] + +#[fundamental] +pub struct FundamentalWrapper(pub T); + +pub struct NonFundamentalWrapper(pub T); + +#[rustc_anti_fundamental] +pub trait AntiFundamentalTrait {} From a6a3053900097d6cd807283c45d029e4e9524d47 Mon Sep 17 00:00:00 2001 From: piorr Date: Fri, 17 Jul 2026 08:49:23 +0000 Subject: [PATCH 2/3] Annotate std traits with #[rustc_anti_fundamental] Mark Deref, DerefMut, DispatchFromDyn, CoerceUnsized, and Receiver with #[rustc_anti_fundamental] to prevent downstream crates from implementing these traits on #[fundamental] types like Box and Pin. --- library/core/src/ops/deref.rs | 3 +++ library/core/src/ops/unsize.rs | 2 ++ tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs | 2 +- .../ui/typeck/pin-unsound-issue-85099-derefmut.stderr | 10 +++------- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index 58bf0e2d73b97..fffbf1210103d 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -136,6 +136,7 @@ use crate::marker::PointeeSized; #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "Deref"] #[rustc_const_unstable(feature = "const_convert", issue = "143773")] +#[rustc_anti_fundamental] pub const trait Deref: PointeeSized { /// The resulting type after dereferencing. #[stable(feature = "rust1", since = "1.0.0")] @@ -267,6 +268,7 @@ const impl Deref for &mut T { #[doc(alias = "*")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_convert", issue = "143773")] +#[rustc_anti_fundamental] pub const trait DerefMut: [const] Deref + PointeeSized { /// Mutably dereferences the value. #[stable(feature = "rust1", since = "1.0.0")] @@ -367,6 +369,7 @@ unsafe impl DerefPure for &mut T {} /// ``` #[lang = "receiver"] #[unstable(feature = "arbitrary_self_types", issue = "44874")] +#[rustc_anti_fundamental] pub trait Receiver: PointeeSized { /// The target type on which the method may be called. #[rustc_diagnostic_item = "receiver_target"] diff --git a/library/core/src/ops/unsize.rs b/library/core/src/ops/unsize.rs index aade68df2b6ce..9179c1761215d 100644 --- a/library/core/src/ops/unsize.rs +++ b/library/core/src/ops/unsize.rs @@ -33,6 +33,7 @@ use crate::marker::{PointeeSized, Unsize}; /// [nomicon-coerce]: ../../nomicon/coercions.html #[unstable(feature = "coerce_unsized", issue = "18598")] #[lang = "coerce_unsized"] +#[rustc_anti_fundamental] pub trait CoerceUnsized: Sized { // Empty. } @@ -119,6 +120,7 @@ impl, U: PointeeSized> CoerceUnsized<*const U> for * /// [^1]: Formerly known as *object safety*. #[unstable(feature = "dispatch_from_dyn", issue = "none")] #[lang = "dispatch_from_dyn"] +#[rustc_anti_fundamental] pub trait DispatchFromDyn: Sized { // Empty. } diff --git a/tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs index e8c3bbba1e458..1a1820a3702e0 100644 --- a/tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs +++ b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs @@ -42,7 +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` +//~^ ERROR: cannot implement `DerefMut` on the fundamental type 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 index 2bcd92b76a09d..6e7436cdc9a59 100644 --- a/tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr +++ b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr @@ -1,14 +1,10 @@ -error[E0119]: conflicting implementations of trait `DerefMut` for type `Pin<&dyn SomeTrait<'_, _>>` +error: cannot implement `DerefMut` on the fundamental 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>> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `DerefMut` not allowed on `Pin<&dyn SomeTrait<'_, _>>` | - = note: conflicting implementation in crate `core`: - - impl DerefMut for Pin - 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 + = note: `DerefMut` is marked `#[rustc_anti_fundamental]`, which means it cannot be implemented on `#[fundamental]` types from another crate error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0119`. From 8bc0866a08b18ad7726e0d479042871442ea18cf Mon Sep 17 00:00:00 2001 From: piorr Date: Fri, 17 Jul 2026 09:32:12 +0000 Subject: [PATCH 3/3] Remove PinDerefMutHelper With DerefMut now marked #[rustc_anti_fundamental], the PinHelper/ PinDerefMutHelper indirection is no longer needed to prevent downstream crates from implementing DerefMut on Pin. Replace it with a direct DerefMut impl for Pin and remove the helper module, its diagnostic item, and the special-casing in trait suggestion rendering. --- compiler/rustc_span/src/symbol.rs | 1 - .../src/error_reporting/traits/suggestions.rs | 18 ----- library/core/src/pin.rs | 71 +------------------ ...y.run2-{closure#0}.Inline.panic-abort.diff | 68 +++++++++--------- ....run2-{closure#0}.Inline.panic-unwind.diff | 68 +++++++++--------- tests/ui/deref/pin-impl-deref.rs | 4 +- tests/ui/deref/pin-impl-deref.stderr | 18 +++-- 7 files changed, 80 insertions(+), 168 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 41c35bc1bebea..e960de1c3d43e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -269,7 +269,6 @@ symbols! { PartialEq, PartialOrd, Pending, - PinDerefMutHelper, PinMacroHelper, Pointer, Poll, 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 8c72f0d90bb58..f228cd239af20 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -4168,24 +4168,6 @@ 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_def_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 931eafef61501..18d4a3447c3d7 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1687,84 +1687,17 @@ const impl Deref for Pin { } } -mod helper { - /// Helper that prevents downstream crates from implementing `DerefMut` for `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)] - pub struct PinHelper { - pointer: Ptr, - } - - #[unstable(feature = "pin_derefmut_internals", issue = "none")] - #[rustc_const_unstable(feature = "const_convert", issue = "143773")] - #[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")] - const impl PinDerefMutHelper for PinHelper - 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")] -#[cfg(not(doc))] -const impl DerefMut for Pin -where - Ptr: [const] Deref, - helper::PinHelper: [const] helper::PinDerefMutHelper, -{ - #[inline] - 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`. - helper::PinDerefMutHelper::deref_mut(unsafe { - &mut *(self as *mut Pin as *mut helper::PinHelper) - }) - } -} - /// 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.) +/// would normally be possible.) This is enforced by the `#[rustc_anti_fundamental]` attribute on +/// the `DerefMut` trait. /// /// [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)] const impl DerefMut for Pin where Ptr: [const] DerefMut, diff --git a/tests/mir-opt/inline/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff index 4b117a453c326..4ad4946c00099 100644 --- a/tests/mir-opt/inline/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff @@ -58,33 +58,35 @@ + let mut _38: &mut std::future::Ready<()>; + let mut _39: &mut std::pin::Pin<&mut std::future::Ready<()>>; + scope 13 (inlined > as DerefMut>::deref_mut) { -+ let mut _40: *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>>; -+ let mut _41: *mut std::pin::Pin<&mut std::future::Ready<()>>; -+ scope 14 (inlined > as pin::helper::PinDerefMutHelper>::deref_mut) { -+ let mut _42: &mut &mut std::future::Ready<()>; -+ scope 15 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) { ++ scope 14 (inlined Pin::<&mut std::future::Ready<()>>::as_mut) { ++ let mut _40: &mut &mut std::future::Ready<()>; ++ scope 15 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) { + } ++ scope 17 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) { ++ } ++ } ++ scope 16 (inlined Pin::<&mut std::future::Ready<()>>::get_mut) { + } + } -+ scope 16 (inlined Option::<()>::take) { -+ let mut _43: std::option::Option<()>; -+ scope 17 (inlined std::mem::replace::>) { -+ scope 18 { ++ scope 18 (inlined Option::<()>::take) { ++ let mut _41: std::option::Option<()>; ++ scope 19 (inlined std::mem::replace::>) { ++ scope 20 { + } + } + } -+ scope 19 (inlined #[track_caller] Option::<()>::expect) { -+ let mut _44: isize; -+ let mut _45: !; -+ scope 20 { ++ scope 21 (inlined #[track_caller] Option::<()>::expect) { ++ let mut _42: isize; ++ let mut _43: !; ++ scope 22 { + } + } + } + } + scope 10 (inlined as IntoFuture>::into_future) { + } -+ scope 21 (inlined ready::<()>) { -+ let mut _46: std::option::Option<()>; ++ scope 23 (inlined ready::<()>) { ++ let mut _44: std::option::Option<()>; + } + } + } @@ -179,23 +181,18 @@ + _22 = &mut (*_23); + StorageDead(_24); + StorageLive(_38); -+ StorageLive(_40); -+ StorageLive(_45); ++ StorageLive(_43); + StorageLive(_35); + StorageLive(_36); ++ _38 = no_retag copy (_19.0: &mut std::future::Ready<()>); + StorageLive(_41); -+ _41 = &raw mut _19; -+ _40 = copy _41 as *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>> (PtrToPtr); -+ StorageDead(_41); -+ _38 = no_retag copy ((*_40).0: &mut std::future::Ready<()>); -+ StorageLive(_43); -+ _43 = Option::<()>::None; ++ _41 = Option::<()>::None; + _36 = copy ((*_38).0: std::option::Option<()>); -+ ((*_38).0: std::option::Option<()>) = move _43; -+ StorageDead(_43); -+ StorageLive(_44); -+ _44 = discriminant(_36); -+ switchInt(move _44) -> [0: bb11, 1: bb12, otherwise: bb4]; ++ ((*_38).0: std::option::Option<()>) = move _41; ++ StorageDead(_41); ++ StorageLive(_42); ++ _42 = discriminant(_36); ++ switchInt(move _42) -> [0: bb11, 1: bb12, otherwise: bb4]; + } + bb4: { @@ -262,10 +259,10 @@ + StorageLive(_13); + StorageLive(_14); + _14 = (); -+ StorageLive(_46); -+ _46 = Option::<()>::Some(copy _14); -+ _13 = std::future::Ready::<()>(move _46); -+ StorageDead(_46); ++ StorageLive(_44); ++ _44 = Option::<()>::Some(copy _14); ++ _13 = std::future::Ready::<()>(move _44); ++ StorageDead(_44); + StorageDead(_14); + _12 = move _13; + StorageDead(_13); @@ -274,17 +271,16 @@ + } + + bb11: { -+ _45 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable; ++ _43 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable; + } + + bb12: { + _35 = move ((_36 as Some).0: ()); -+ StorageDead(_44); ++ StorageDead(_42); + StorageDead(_36); + _18 = Poll::<()>::Ready(move _35); + StorageDead(_35); -+ StorageDead(_45); -+ StorageDead(_40); ++ StorageDead(_43); + StorageDead(_38); + StorageDead(_22); + StorageDead(_19); diff --git a/tests/mir-opt/inline/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff index c365aee05f4ec..09c6199fff29e 100644 --- a/tests/mir-opt/inline/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff @@ -58,33 +58,35 @@ + let mut _38: &mut std::future::Ready<()>; + let mut _39: &mut std::pin::Pin<&mut std::future::Ready<()>>; + scope 13 (inlined > as DerefMut>::deref_mut) { -+ let mut _40: *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>>; -+ let mut _41: *mut std::pin::Pin<&mut std::future::Ready<()>>; -+ scope 14 (inlined > as pin::helper::PinDerefMutHelper>::deref_mut) { -+ let mut _42: &mut &mut std::future::Ready<()>; -+ scope 15 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) { ++ scope 14 (inlined Pin::<&mut std::future::Ready<()>>::as_mut) { ++ let mut _40: &mut &mut std::future::Ready<()>; ++ scope 15 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) { + } ++ scope 17 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) { ++ } ++ } ++ scope 16 (inlined Pin::<&mut std::future::Ready<()>>::get_mut) { + } + } -+ scope 16 (inlined Option::<()>::take) { -+ let mut _43: std::option::Option<()>; -+ scope 17 (inlined std::mem::replace::>) { -+ scope 18 { ++ scope 18 (inlined Option::<()>::take) { ++ let mut _41: std::option::Option<()>; ++ scope 19 (inlined std::mem::replace::>) { ++ scope 20 { + } + } + } -+ scope 19 (inlined #[track_caller] Option::<()>::expect) { -+ let mut _44: isize; -+ let mut _45: !; -+ scope 20 { ++ scope 21 (inlined #[track_caller] Option::<()>::expect) { ++ let mut _42: isize; ++ let mut _43: !; ++ scope 22 { + } + } + } + } + scope 10 (inlined as IntoFuture>::into_future) { + } -+ scope 21 (inlined ready::<()>) { -+ let mut _46: std::option::Option<()>; ++ scope 23 (inlined ready::<()>) { ++ let mut _44: std::option::Option<()>; + } + } + } @@ -190,23 +192,18 @@ + _22 = &mut (*_23); + StorageDead(_24); + StorageLive(_38); -+ StorageLive(_40); -+ StorageLive(_45); ++ StorageLive(_43); + StorageLive(_35); + StorageLive(_36); ++ _38 = no_retag copy (_19.0: &mut std::future::Ready<()>); + StorageLive(_41); -+ _41 = &raw mut _19; -+ _40 = copy _41 as *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>> (PtrToPtr); -+ StorageDead(_41); -+ _38 = no_retag copy ((*_40).0: &mut std::future::Ready<()>); -+ StorageLive(_43); -+ _43 = Option::<()>::None; ++ _41 = Option::<()>::None; + _36 = copy ((*_38).0: std::option::Option<()>); -+ ((*_38).0: std::option::Option<()>) = move _43; -+ StorageDead(_43); -+ StorageLive(_44); -+ _44 = discriminant(_36); -+ switchInt(move _44) -> [0: bb16, 1: bb17, otherwise: bb6]; ++ ((*_38).0: std::option::Option<()>) = move _41; ++ StorageDead(_41); ++ StorageLive(_42); ++ _42 = discriminant(_36); ++ switchInt(move _42) -> [0: bb16, 1: bb17, otherwise: bb6]; } - bb5 (cleanup): { @@ -295,10 +292,10 @@ + StorageLive(_13); + StorageLive(_14); + _14 = (); -+ StorageLive(_46); -+ _46 = Option::<()>::Some(copy _14); -+ _13 = std::future::Ready::<()>(move _46); -+ StorageDead(_46); ++ StorageLive(_44); ++ _44 = Option::<()>::Some(copy _14); ++ _13 = std::future::Ready::<()>(move _44); ++ StorageDead(_44); + StorageDead(_14); + _12 = move _13; + StorageDead(_13); @@ -307,17 +304,16 @@ + } + + bb16: { -+ _45 = option::expect_failed(const "`Ready` polled after completion") -> bb10; ++ _43 = option::expect_failed(const "`Ready` polled after completion") -> bb10; + } + + bb17: { + _35 = move ((_36 as Some).0: ()); -+ StorageDead(_44); ++ StorageDead(_42); + StorageDead(_36); + _18 = Poll::<()>::Ready(move _35); + StorageDead(_35); -+ StorageDead(_45); -+ StorageDead(_40); ++ StorageDead(_43); + StorageDead(_38); + StorageDead(_22); + StorageDead(_19); diff --git a/tests/ui/deref/pin-impl-deref.rs b/tests/ui/deref/pin-impl-deref.rs index ccd8d0dfc72ae..b1dc8dea3f248 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 `&MyUnpinType: DerefMut` is not satisfied + //~^ ERROR: the trait bound `Pin<&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 `&MyPinType: DerefMut` is not satisfied + //~| ERROR: the trait bound `Pin<&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 4143d66f42723..106654641a117 100644 --- a/tests/ui/deref/pin-impl-deref.stderr +++ b/tests/ui/deref/pin-impl-deref.stderr @@ -1,34 +1,40 @@ -error[E0277]: the trait bound `&MyUnpinType: DerefMut` is not satisfied +error[E0277]: the trait bound `Pin<&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 `&MyUnpinType` + | -------------- ^^^^^^^ the trait `DerefMut` is not implemented for `Pin<&MyUnpinType>` | | | required by a bound introduced by this call | - = note: `DerefMut` is implemented for `&mut MyUnpinType`, but not for `&MyUnpinType` = 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 `&MyPinType: DerefMut` is not satisfied +error[E0277]: the trait bound `Pin<&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 `&MyPinType` + | -------------- ^^^^^ the trait `DerefMut` is not implemented for `Pin<&MyPinType>` | | | required by a bound introduced by this call | - = note: `DerefMut` is implemented for `&mut MyPinType`, but not for `&MyPinType` = 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