From a9c60fe26d760608ad5b99da6794225173a61e88 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 This adds a new compiler attribute that prevents non-local fundamental types from receiving implementations of marked traits. This allows addressing soundness problems with traits like DerefMut on Pin and similar wrapper types. The attribute is checked during the orphan check in coherence. --- compiler/rustc_attr_ir/src/data_structures.rs | 6 ++ .../rustc_attr_ir/src/encode_cross_crate.rs | 1 + .../src/attributes/traits.rs | 8 ++ compiler/rustc_attr_parsing/src/context.rs | 1 + compiler/rustc_feature/src/builtin_attrs.rs | 1 + .../src/coherence/orphan.rs | 86 ++++++++++++----- compiler/rustc_hir_analysis/src/collect.rs | 2 + .../rustc_hir_analysis/src/diagnostics.rs | 16 +++- .../src/ty/context/impl_interner.rs | 4 + compiler/rustc_middle/src/ty/trait_def.rs | 5 + .../rustc_next_trait_solver/src/coherence.rs | 77 +++++++++++++-- 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 | 85 +++++++++++++++++ .../anti-fundamental-foreign-type.stderr | 95 +++++++++++++++++++ .../anti-fundamental-generic-projection.rs | 77 +++++++++++++++ ...anti-fundamental-generic-projection.stderr | 50 ++++++++++ .../anti-fundamental-invalid-target.rs | 18 ++++ .../anti-fundamental-invalid-target.stderr | 18 ++++ .../coherence/anti-fundamental-local-trait.rs | 23 +++++ .../ui/coherence/anti-fundamental-overlap.rs | 19 ++++ .../coherence/anti-fundamental-overlap.stderr | 13 +++ .../auxiliary/anti_fundamental_trait_lib.rs | 15 +++ 24 files changed, 593 insertions(+), 31 deletions(-) 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-generic-projection.rs create mode 100644 tests/ui/coherence/anti-fundamental-generic-projection.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/anti-fundamental-overlap.rs create mode 100644 tests/ui/coherence/anti-fundamental-overlap.stderr create mode 100644 tests/ui/coherence/auxiliary/anti_fundamental_trait_lib.rs diff --git a/compiler/rustc_attr_ir/src/data_structures.rs b/compiler/rustc_attr_ir/src/data_structures.rs index beb4ba8fabef7..b1d74e86eb3c9 100644 --- a/compiler/rustc_attr_ir/src/data_structures.rs +++ b/compiler/rustc_attr_ir/src/data_structures.rs @@ -1137,6 +1137,12 @@ pub enum AttributeKind { /// Represents `#[rustc_allow_lifetime_dependent_specialization]`. RustcAllowLifetimeDependentSpecialization, + /// Represents `#[rustc_anti_fundamental]`. This marks a trait so that it + /// cannot be implemented for non-local `#[fundamental]` types. This in particular + /// prevents the implementation of `Deref`, `DerefMut`, and `DispatchFromDyn` on + /// fundamental wrappers like `Pin` and `Box`. + RustcAntiFundamental, + /// Represents `#[rustc_as_ptr]` (used by the `dangling_pointers_from_temporaries` lint). RustcAsPtr, diff --git a/compiler/rustc_attr_ir/src/encode_cross_crate.rs b/compiler/rustc_attr_ir/src/encode_cross_crate.rs index 270ec0399799e..7bb75e54440b1 100644 --- a/compiler/rustc_attr_ir/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_ir/src/encode_cross_crate.rs @@ -107,6 +107,7 @@ impl AttributeKind { RustcAllowConstFnUnstable(..) => No, RustcAllowIncoherentImpl(..) => No, RustcAllowLifetimeDependentSpecialization => No, + RustcAntiFundamental => No, RustcAsPtr => Yes, RustcAutodiff(..) => Yes, RustcBodyStability { .. } => No, diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs index 1d0d26ea62cb3..5968efa2d815f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/traits.rs +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -123,6 +123,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 cf99311cc0cfc..7e4b0149a0c70 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 92f77e76e83b3..09c120d7648db 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_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index c970799d318fe..b7730551ae03a 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -28,31 +28,41 @@ pub(crate) fn orphan_check_impl( match orphan_check(tcx, impl_def_id, OrphanCheckMode::Proper) { Ok(()) => {} - Err(err) => match orphan_check(tcx, impl_def_id, OrphanCheckMode::Compat) { - Ok(()) => match err { - OrphanCheckErr::UncoveredTyParams(uncovered_ty_params) => { - let hir_id = tcx.local_def_id_to_hir_id(impl_def_id); - - for param_def_id in uncovered_ty_params.uncovered { - let ident = tcx.item_ident(param_def_id); - - tcx.emit_node_span_lint( - UNCOVERED_PARAM_IN_PROJECTION, - hir_id, - ident.span, - diagnostics::UncoveredTyParam { - param: ident, - local_ty: uncovered_ty_params.local_ty, - }, - ); + Err(err) => { + if tcx.trait_def(trait_ref.def_id).is_anti_fundamental { + return Err(emit_orphan_check_error(tcx, trait_ref, impl_def_id, err)); + } + + match orphan_check(tcx, impl_def_id, OrphanCheckMode::Compat) { + Ok(()) => match err { + OrphanCheckErr::UncoveredTyParams(uncovered_ty_params) => { + let hir_id = tcx.local_def_id_to_hir_id(impl_def_id); + + for param_def_id in uncovered_ty_params.uncovered { + let ident = tcx.item_ident(param_def_id); + + tcx.emit_node_span_lint( + UNCOVERED_PARAM_IN_PROJECTION, + hir_id, + ident.span, + diagnostics::UncoveredTyParam { + param: ident, + local_ty: uncovered_ty_params.local_ty, + }, + ); + } } - } - OrphanCheckErr::NonLocalInputType(_) => { - bug!("orphanck: shouldn't've gotten non-local input tys in compat mode") - } - }, - Err(err) => return Err(emit_orphan_check_error(tcx, trait_ref, impl_def_id, err)), - }, + OrphanCheckErr::NonLocalInputType(_) => { + bug!("orphanck: shouldn't've gotten non-local input tys in compat mode") + } + OrphanCheckErr::AntiFundamentalForeignType { .. } => { + // An anti-fundamental trait should return early above and never enter compat mode. + bug!("anti-fundamental traits never enter compat mode") + } + }, + Err(err) => return Err(emit_orphan_check_error(tcx, trait_ref, impl_def_id, err)), + } + } } let trait_def_id = trait_ref.def_id; @@ -381,6 +391,24 @@ fn orphan_check<'tcx>( }); OrphanCheckErr::NonLocalInputType(tys) } + OrphanCheckErr::AntiFundamentalForeignType { self_ty, fundamental_ty } => { + let (self_ty, fundamental_ty) = infcx.probe(|_| { + for (arg, id_arg) in + std::iter::zip(args, ty::GenericArgs::identity_for_item(tcx, impl_def_id)) + { + let _ = infcx.at(&cause, ty::ParamEnv::empty()).eq( + DefineOpaqueTypes::No, + arg, + id_arg, + ); + } + ( + infcx.resolve_vars_if_possible(self_ty), + infcx.resolve_vars_if_possible(fundamental_ty), + ) + }); + OrphanCheckErr::AntiFundamentalForeignType { self_ty, fundamental_ty } + } }) } @@ -499,6 +527,16 @@ fn emit_orphan_check_error<'tcx>( } guar.unwrap() } + traits::OrphanCheckErr::AntiFundamentalForeignType { self_ty, fundamental_ty } => { + let item = tcx.hir_expect_item(impl_def_id); + let impl_ = item.expect_impl(); + tcx.dcx().emit_err(diagnostics::AntiFundamentalForeignImpl { + span: impl_.self_ty.span, + trait_name: tcx.def_path_str(trait_ref.def_id), + self_ty, + fundamental_ty, + }) + } } } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 65fd562a4ebf6..775200988c1c6 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1122,6 +1122,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(), @@ -1139,6 +1140,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 a50aefd016059..f7b05dafc3bed 100644 --- a/compiler/rustc_hir_analysis/src/diagnostics.rs +++ b/compiler/rustc_hir_analysis/src/diagnostics.rs @@ -2144,7 +2144,6 @@ pub(crate) struct OnlyStructsCanBeViewedAdt<'tcx> { pub article: &'static str, pub kind: &'static str, } - #[derive(Diagnostic)] #[diag("the type of const parameters must not depend on other generic parameters", code = E0770)] pub(crate) struct ParamInTyOfConstParam<'tcx> { @@ -2153,3 +2152,18 @@ pub(crate) struct ParamInTyOfConstParam<'tcx> { pub(crate) span: Span, pub(crate) ty: Ty<'tcx>, } + +#[derive(Diagnostic)] +#[diag("cannot implement `{$trait_name}` for the fundamental type `{$fundamental_ty}`")] +#[note( + "`{$trait_name}` is `#[rustc_anti_fundamental]` and \ + cannot be implemented for `#[fundamental]` types from another crate" +)] +pub(crate) struct AntiFundamentalForeignImpl<'tcx> { + #[primary_span] + #[label("impl of `{$trait_name}` not allowed for `{$self_ty}`")] + pub(crate) span: Span, + pub(crate) trait_name: String, + pub(crate) self_ty: Ty<'tcx>, + 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 048e509ec88e0..eec36d3b7eb99 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -603,6 +603,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 5309e35b1073c..eb0c293938f66 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -80,6 +80,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 + /// and cannot be implemented for `#[fundamental]` types from another crate. + /// Used for `Deref`, `DerefMut`, `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..d64eef889a251 100644 --- a/compiler/rustc_next_trait_solver/src/coherence.rs +++ b/compiler/rustc_next_trait_solver/src/coherence.rs @@ -17,6 +17,12 @@ pub enum InCrate { Remote, } +impl InCrate { + pub fn def_id_is_local(self, def_id: impl DefId) -> bool { + matches!(self, InCrate::Local { .. }) && def_id.is_local() + } +} + #[derive(Copy, Clone, Debug)] pub enum OrphanCheckMode { /// Proper orphan check. @@ -118,6 +124,7 @@ impl From for IsFirstInputType { pub enum OrphanCheckErr { NonLocalInputType(Vec<(I::Ty, IsFirstInputType)>), UncoveredTyParams(UncoveredTyParams), + AntiFundamentalForeignType { self_ty: I::Ty, fundamental_ty: I::Ty }, } #[derive_where(Debug; I: Interner, T: Debug)] @@ -160,6 +167,13 @@ pub struct UncoveredTyParams { /// - however, `LocalType>` is OK, because `T` is a subtree of /// `LocalType>`, which is local and has no types between it and /// the type parameter. +/// 5. If the trait is marked `#[rustc_anti_fundamental]`, the `Self` type +/// must not have a non-local `#[fundamental]` type at its head (even if +/// it wraps a local type as in (2)). +/// - e.g., `Box` or `&Pin` is rejected if the trait +/// is `#[rustc_anti_fundamental]`. +/// - This lets the standard library reserve control over traits like `Deref` +/// and `DispatchFromDyn` on fundamental wrappers such as `Box` and `Pin`. /// /// The orphan rules actually serve several different purposes: /// @@ -223,7 +237,7 @@ pub fn orphan_check_trait_ref( infcx: &Infcx, trait_ref: ty::TraitRef, in_crate: InCrate, - lazily_normalize_ty: impl FnMut(I::Ty) -> Result, + mut lazily_normalize_ty: impl FnMut(I::Ty) -> Result, ) -> Result>, E> where Infcx: InferCtxtLike, @@ -234,6 +248,20 @@ where panic!("orphan check only expects inference variables: {trait_ref:?}"); } + // Anti-fundamental check: if the trait is marked `#[rustc_anti_fundamental]`, + // we do not allow 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`. + let cx = infcx.cx(); + if cx.trait_is_anti_fundamental(trait_ref.def_id) { + let self_ty = trait_ref.self_ty(); + if let Some(fundamental_ty) = + check_anti_fundamental_head(infcx, in_crate, &mut lazily_normalize_ty, self_ty)? + { + return Ok(Err(OrphanCheckErr::AntiFundamentalForeignType { self_ty, fundamental_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 +284,46 @@ where }) } +/// Checks the head of the Self type for a non-local fundamental type. +/// +/// If the head is a reference (`&` / `&mut`), we unwrap it and inspect the pointee type. +/// This ensures that wrapping a fundamental type in a reference (such as `&Pin`) +/// cannot be used to bypass the anti-fundamental restriction. +/// +/// Returns `Some(ty)` with the offending fundamental type if the check fails. +fn check_anti_fundamental_head( + infcx: &Infcx, + in_crate: InCrate, + mut lazily_normalize_ty: impl FnMut(I::Ty) -> Result, + mut ty: I::Ty, +) -> Result, E> +where + Infcx: InferCtxtLike, + I: Interner, +{ + loop { + ty = infcx.shallow_resolve(ty); + let norm_ty = match lazily_normalize_ty(ty)? { + norm if norm.is_ty_var() => ty, + norm => norm, + }; + + if let ty::Ref(_, inner, _) = norm_ty.kind() { + ty = inner; + continue; + } + + ty = norm_ty; + break; + } + + Ok(matches!( + ty.kind(), + ty::Adt(def, _) if def.is_fundamental() && !in_crate.def_id_is_local(def.def_id()) + ) + .then_some(ty)) +} + struct OrphanChecker<'a, Infcx, I: Interner, F> { infcx: &'a Infcx, in_crate: InCrate, @@ -296,11 +364,8 @@ where ControlFlow::Break(OrphanCheckEarlyExit::UncoveredTyParam(ty)) } - fn def_id_is_local(&mut self, def_id: impl DefId) -> bool { - match self.in_crate { - InCrate::Local { .. } => def_id.is_local(), - InCrate::Remote => false, - } + fn def_id_is_local(&self, def_id: impl DefId) -> bool { + self.in_crate.def_id_is_local(def_id) } } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index b0271a1ae993a..59b56eb93bc4f 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -316,6 +316,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::RustcAllocatorZeroedVariant { .. } => (), AttributeKind::RustcAllowIncoherentImpl(..) => (), AttributeKind::RustcAllowLifetimeDependentSpecialization => (), + 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 057ea6bd3d0a2..18cc71731bf3d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1782,6 +1782,7 @@ symbols! { rustc_allow_incoherent_impl, rustc_allow_lifetime_dependent_specialization, 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 d230791304527..e6219a35be650 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -468,6 +468,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..bd9ca9542f939 --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-foreign-type.rs @@ -0,0 +1,85 @@ +//@ aux-build: anti_fundamental_trait_lib.rs + +// Test that `#[rustc_anti_fundamental]` prevents implementing the trait +// on non-local `#[fundamental]` types. + +#![feature(fundamental)] + +extern crate anti_fundamental_trait_lib; + +use anti_fundamental_trait_lib::{ + AntiFundamentalTrait, AntiFundamentalWithParam, FundamentalWrapper, NonFundamentalWrapper, +}; + +struct LocalType; + +#[fundamental] +struct LocalFundamental(T); + +// OK: implementing on a local type. +impl AntiFundamentalTrait for LocalType {} + +// ERROR: implementing on a non-fundamental foreign type wrapping a local type +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` for the fundamental type + +// ERROR: implementing on a reference to a foreign fundamental type. +impl AntiFundamentalTrait for &FundamentalWrapper {} +//~^ ERROR cannot implement `AntiFundamentalTrait` for the fundamental type + +// ERROR: implementing on a mutable double-reference to a foreign fundamental type. +impl AntiFundamentalTrait for &mut &FundamentalWrapper {} +//~^ ERROR cannot implement `AntiFundamentalTrait` for the fundamental type + +// OK: outer type is local fundamental, so the Self type is local. +impl AntiFundamentalTrait for LocalFundamental> {} + +// ERROR: outer type is foreign fundamental. +impl AntiFundamentalTrait for FundamentalWrapper> {} +//~^ ERROR cannot implement `AntiFundamentalTrait` for the fundamental type + +// OK: Self is a local type, even if the trait parameter is a foreign fundamental type. +impl AntiFundamentalWithParam> for LocalType {} + +// ERROR: Self is a foreign fundamental type. +impl AntiFundamentalWithParam for FundamentalWrapper {} +//~^ ERROR cannot implement `AntiFundamentalWithParam` for the fundamental type + +// ERROR: projection normalizes to a foreign fundamental type. +struct LocalType2; +trait AssocHelper { + type Assoc; +} + +impl AssocHelper for LocalType2 { + type Assoc = FundamentalWrapper; +} + +impl AntiFundamentalTrait for ::Assoc {} +//~^ ERROR cannot implement `AntiFundamentalTrait` for the fundamental type + +// ERROR: foreign fundamental type wrapping a generic local type. +struct LocalGeneric(T); + +impl AntiFundamentalTrait for FundamentalWrapper> {} +//~^ ERROR cannot implement `AntiFundamentalTrait` for the fundamental type + +// ERROR: reference to a foreign fundamental type wrapping a generic local type. +impl AntiFundamentalTrait for &FundamentalWrapper> {} +//~^ ERROR cannot implement `AntiFundamentalTrait` for the fundamental type + +// ERROR: single mutable reference to a foreign fundamental type. +impl AntiFundamentalTrait for &mut FundamentalWrapper {} +//~^ ERROR cannot implement `AntiFundamentalTrait` for the fundamental type + +// ERROR: type alias expanding to a foreign fundamental type. +struct LocalType3; +type LocalAlias = FundamentalWrapper; +impl AntiFundamentalTrait for LocalAlias {} +//~^ ERROR cannot implement `AntiFundamentalTrait` for 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..f61788390510b --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-foreign-type.stderr @@ -0,0 +1,95 @@ +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:23: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` for the fundamental type `FundamentalWrapper` + --> $DIR/anti-fundamental-foreign-type.rs:27:31 + | +LL | impl AntiFundamentalTrait for FundamentalWrapper {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `AntiFundamentalTrait` not allowed for `FundamentalWrapper` + | + = note: `AntiFundamentalTrait` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `AntiFundamentalTrait` for the fundamental type `FundamentalWrapper` + --> $DIR/anti-fundamental-foreign-type.rs:31:31 + | +LL | impl AntiFundamentalTrait for &FundamentalWrapper {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `AntiFundamentalTrait` not allowed for `&FundamentalWrapper` + | + = note: `AntiFundamentalTrait` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `AntiFundamentalTrait` for the fundamental type `FundamentalWrapper` + --> $DIR/anti-fundamental-foreign-type.rs:35:31 + | +LL | impl AntiFundamentalTrait for &mut &FundamentalWrapper {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `AntiFundamentalTrait` not allowed for `&mut &FundamentalWrapper` + | + = note: `AntiFundamentalTrait` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `AntiFundamentalTrait` for the fundamental type `FundamentalWrapper>` + --> $DIR/anti-fundamental-foreign-type.rs:42:31 + | +LL | impl AntiFundamentalTrait for FundamentalWrapper> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `AntiFundamentalTrait` not allowed for `FundamentalWrapper>` + | + = note: `AntiFundamentalTrait` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `AntiFundamentalTrait` for the fundamental type `FundamentalWrapper` + --> $DIR/anti-fundamental-foreign-type.rs:62:31 + | +LL | impl AntiFundamentalTrait for ::Assoc {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `AntiFundamentalTrait` not allowed for `::Assoc` + | + = note: `AntiFundamentalTrait` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `AntiFundamentalTrait` for the fundamental type `FundamentalWrapper>` + --> $DIR/anti-fundamental-foreign-type.rs:68:34 + | +LL | impl AntiFundamentalTrait for FundamentalWrapper> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `AntiFundamentalTrait` not allowed for `FundamentalWrapper>` + | + = note: `AntiFundamentalTrait` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `AntiFundamentalTrait` for the fundamental type `FundamentalWrapper>` + --> $DIR/anti-fundamental-foreign-type.rs:72:34 + | +LL | impl AntiFundamentalTrait for &FundamentalWrapper> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `AntiFundamentalTrait` not allowed for `&FundamentalWrapper>` + | + = note: `AntiFundamentalTrait` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `AntiFundamentalTrait` for the fundamental type `FundamentalWrapper` + --> $DIR/anti-fundamental-foreign-type.rs:76:31 + | +LL | impl AntiFundamentalTrait for &mut FundamentalWrapper {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `AntiFundamentalTrait` not allowed for `&mut FundamentalWrapper` + | + = note: `AntiFundamentalTrait` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `AntiFundamentalTrait` for the fundamental type `FundamentalWrapper` + --> $DIR/anti-fundamental-foreign-type.rs:82:31 + | +LL | impl AntiFundamentalTrait for LocalAlias {} + | ^^^^^^^^^^ impl of `AntiFundamentalTrait` not allowed for `FundamentalWrapper` + | + = note: `AntiFundamentalTrait` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `AntiFundamentalWithParam` for the fundamental type `FundamentalWrapper` + --> $DIR/anti-fundamental-foreign-type.rs:49:46 + | +LL | impl AntiFundamentalWithParam for FundamentalWrapper {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `AntiFundamentalWithParam` not allowed for `FundamentalWrapper` + | + = note: `AntiFundamentalWithParam` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: aborting due to 11 previous errors + +For more information about this error, try `rustc --explain E0117`. diff --git a/tests/ui/coherence/anti-fundamental-generic-projection.rs b/tests/ui/coherence/anti-fundamental-generic-projection.rs new file mode 100644 index 0000000000000..26e22f771d3e4 --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-generic-projection.rs @@ -0,0 +1,77 @@ +//@ aux-build: anti_fundamental_trait_lib.rs + +// Test that generic projections cannot bypass #[rustc_anti_fundamental] +// due to normalization failure or compat mode. + +extern crate anti_fundamental_trait_lib; + +use anti_fundamental_trait_lib::{ + AntiFundamentalTrait, AntiFundamentalWithParam, FundamentalWrapper, +}; + +struct LocalGeneric(T); +struct LocalGeneric2(T); + +trait GenericAssocHelper { + type Assoc; +} + +impl GenericAssocHelper for LocalGeneric { + type Assoc = FundamentalWrapper>; +} + +// ERROR: Generic projections normalize at coherence time, but +// we reject as a hard error because Compat mode is disallowed for anti-fundamental traits. +impl AntiFundamentalWithParam> +//~^ ERROR type parameter `T` must be covered by another type + for as GenericAssocHelper>::Assoc +{ +} + +// ERROR: Generic projection with bounds is similarly hard rejected. +trait BoundedHelper { + type Assoc; +} + +impl BoundedHelper for LocalGeneric2 { + type Assoc = FundamentalWrapper>; +} + +impl AntiFundamentalWithParam> +//~^ ERROR type parameter `T` must be covered by another type + for as BoundedHelper>::Assoc +{ +} + +// Blanket implementation attempting to implement an anti-fundamental trait +// on a projection where the type parameter is constrained by the trait: +// rejected by the orphan rule (E0210) because T is not behind a local type. +trait Helper2 { + type T; +} + +impl AntiFundamentalWithParam for ::T { + //~^ ERROR type parameter `T` must be used as an argument to some local type +} + +impl Helper2 for FundamentalWrapper { + type T = T; +} + +// Blanket implementation of a parameterless anti-fundamental trait (like `Deref`) +// on an associated type projection: rejected both by the orphan rule (E0210) +// and because T is unconstrained (E0207). +trait Helper3 { + type T; +} + +impl AntiFundamentalTrait for ::T { + //~^ ERROR type parameter `T` must be used as an argument to some local type + //~| ERROR the type parameter `T` is not constrained +} + +impl Helper3 for FundamentalWrapper { + type T = T; +} + +fn main() {} diff --git a/tests/ui/coherence/anti-fundamental-generic-projection.stderr b/tests/ui/coherence/anti-fundamental-generic-projection.stderr new file mode 100644 index 0000000000000..b91ae4307149c --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-generic-projection.stderr @@ -0,0 +1,50 @@ +error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`LocalGeneric<_>`) + --> $DIR/anti-fundamental-generic-projection.rs:25:6 + | +LL | impl AntiFundamentalWithParam> + | ^ uncovered type parameter + | + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, + and no uncovered type parameters appear before that first local type + = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, + where `T0` is the first and `Tn` is the last + +error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`LocalGeneric2<_>`) + --> $DIR/anti-fundamental-generic-projection.rs:40:6 + | +LL | impl AntiFundamentalWithParam> + | ^ uncovered type parameter + | + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, + and no uncovered type parameters appear before that first local type + = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, + where `T0` is the first and `Tn` is the last + +error[E0210]: type parameter `T` must be used as an argument to some local type (e.g., `MyStruct`) + --> $DIR/anti-fundamental-generic-projection.rs:53:6 + | +LL | impl AntiFundamentalWithParam for ::T { + | ^ uncovered type parameter + | + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local + = note: only traits defined in the current crate can be implemented for a type parameter + +error[E0210]: type parameter `T` must be used as an argument to some local type (e.g., `MyStruct`) + --> $DIR/anti-fundamental-generic-projection.rs:68:6 + | +LL | impl AntiFundamentalTrait for ::T { + | ^ uncovered type parameter + | + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local + = note: only traits defined in the current crate can be implemented for a type parameter + +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/anti-fundamental-generic-projection.rs:68:6 + | +LL | impl AntiFundamentalTrait for ::T { + | ^ unconstrained type parameter + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0207, E0210. +For more information about an error, try `rustc --explain E0207`. 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/anti-fundamental-overlap.rs b/tests/ui/coherence/anti-fundamental-overlap.rs new file mode 100644 index 0000000000000..08e983fba9802 --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-overlap.rs @@ -0,0 +1,19 @@ +//@ aux-build: anti_fundamental_trait_lib.rs +//@ dont-require-annotations: NOTE + +// Test that `#[rustc_anti_fundamental]` prevents reporting +// "downstream crates may implement trait" ambiguity notes, +// and instead reports that only upstream crates can add such an impl. + +extern crate anti_fundamental_trait_lib; + +use anti_fundamental_trait_lib::{AntiFundamentalTrait, FundamentalWrapper}; + +trait Trait1 {} +impl Trait1 for T {} +impl Trait1 for FundamentalWrapper { + //~^ ERROR conflicting implementations of trait `Trait1` for type `FundamentalWrapper<_>` + //~| NOTE upstream crates may add a new impl of trait `anti_fundamental_trait_lib::AntiFundamentalTrait` for type `anti_fundamental_trait_lib::FundamentalWrapper<_>` in future versions +} + +fn main() {} diff --git a/tests/ui/coherence/anti-fundamental-overlap.stderr b/tests/ui/coherence/anti-fundamental-overlap.stderr new file mode 100644 index 0000000000000..8d35e7a17d932 --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-overlap.stderr @@ -0,0 +1,13 @@ +error[E0119]: conflicting implementations of trait `Trait1` for type `FundamentalWrapper<_>` + --> $DIR/anti-fundamental-overlap.rs:14:1 + | +LL | impl Trait1 for T {} + | ------------------------------------------ first implementation here +LL | impl Trait1 for FundamentalWrapper { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `FundamentalWrapper<_>` + | + = note: upstream crates may add a new impl of trait `anti_fundamental_trait_lib::AntiFundamentalTrait` for type `anti_fundamental_trait_lib::FundamentalWrapper<_>` in future versions + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. 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..177874d30432b --- /dev/null +++ b/tests/ui/coherence/auxiliary/anti_fundamental_trait_lib.rs @@ -0,0 +1,15 @@ +// 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 {} + +#[rustc_anti_fundamental] +pub trait AntiFundamentalWithParam {} From aa2681c0d5912d571836e6c8fca0ed3d4021684f 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 + .../coherence/anti-fundamental-std-traits.rs | 81 +++++++++++++++++ .../anti-fundamental-std-traits.stderr | 87 +++++++++++++++++++ .../pin-unsound-issue-85099-derefmut.rs | 2 +- .../pin-unsound-issue-85099-derefmut.stderr | 12 +-- 6 files changed, 178 insertions(+), 9 deletions(-) create mode 100644 tests/ui/coherence/anti-fundamental-std-traits.rs create mode 100644 tests/ui/coherence/anti-fundamental-std-traits.stderr 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/coherence/anti-fundamental-std-traits.rs b/tests/ui/coherence/anti-fundamental-std-traits.rs new file mode 100644 index 0000000000000..20d0c0b219b9e --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-std-traits.rs @@ -0,0 +1,81 @@ +//@ check-fail + +// Test that `#[rustc_anti_fundamental]` on std traits (Deref, Receiver, +// CoerceUnsized, DispatchFromDyn) prevents implementing them for foreign +// fundamental types like `Pin`. + +#![feature(arbitrary_self_types, coerce_unsized, dispatch_from_dyn)] + +use std::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Receiver}; +use std::pin::Pin; + +struct LocalType; +struct LocalType2; + +// ERROR: cannot implement Deref for Pin +impl Deref for Pin { + type Target = LocalType; + fn deref(&self) -> &LocalType { + unimplemented!() + } +} +//~^^^^^^ ERROR cannot implement `Deref` for the fundamental type + +// ERROR: cannot implement DerefMut for Pin +impl DerefMut for Pin { + fn deref_mut(&mut self) -> &mut LocalType { + unimplemented!() + } +} +//~^^^^^ ERROR cannot implement `DerefMut` for the fundamental type + +// ERROR: cannot implement Receiver for Pin +impl Receiver for Pin { + type Target = LocalType; +} +//~^^^ ERROR cannot implement `std::ops::Receiver` for the fundamental type + +// ERROR: cannot implement CoerceUnsized for Pin +impl CoerceUnsized> for Pin {} +//~^ ERROR cannot implement `CoerceUnsized` for the fundamental type +//~| ERROR the trait bound `LocalType: CoerceUnsized` is not satisfied + +// ERROR: cannot implement DispatchFromDyn for Pin +impl DispatchFromDyn> for Pin {} +//~^ ERROR cannot implement `DispatchFromDyn` for the fundamental type + +struct LocalBoxType; + +// ERROR: cannot implement Deref for Box +impl Deref for Box { + type Target = LocalBoxType; + fn deref(&self) -> &LocalBoxType { + unimplemented!() + } +} +//~^^^^^^ ERROR cannot implement `Deref` for the fundamental type + +// ERROR: cannot implement DerefMut for Box +impl DerefMut for Box { + fn deref_mut(&mut self) -> &mut LocalBoxType { + unimplemented!() + } +} +//~^^^^^ ERROR cannot implement `DerefMut` for the fundamental type + +// ERROR: cannot implement Deref for &Pin +impl Deref for &Pin { + type Target = LocalType; + fn deref(&self) -> &LocalType { + unimplemented!() + } +} +//~^^^^^^ ERROR cannot implement `Deref` for the fundamental type + +// ERROR: cannot implement Receiver for Box +impl Receiver for Box { + type Target = LocalBoxType; +} +//~^^^ ERROR cannot implement `std::ops::Receiver` for the fundamental type + +fn main() {} diff --git a/tests/ui/coherence/anti-fundamental-std-traits.stderr b/tests/ui/coherence/anti-fundamental-std-traits.stderr new file mode 100644 index 0000000000000..3aa6ad742b7bc --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-std-traits.stderr @@ -0,0 +1,87 @@ +error: cannot implement `Deref` for the fundamental type `Box` + --> $DIR/anti-fundamental-std-traits.rs:50:16 + | +LL | impl Deref for Box { + | ^^^^^^^^^^^^^^^^^ impl of `Deref` not allowed for `Box` + | + = note: `Deref` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `Deref` for the fundamental type `Pin` + --> $DIR/anti-fundamental-std-traits.rs:67:16 + | +LL | impl Deref for &Pin { + | ^^^^^^^^^^^^^^^ impl of `Deref` not allowed for `&Pin` + | + = note: `Deref` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `Deref` for the fundamental type `Pin` + --> $DIR/anti-fundamental-std-traits.rs:16:16 + | +LL | impl Deref for Pin { + | ^^^^^^^^^^^^^^ impl of `Deref` not allowed for `Pin` + | + = note: `Deref` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `DerefMut` for the fundamental type `Box` + --> $DIR/anti-fundamental-std-traits.rs:59:19 + | +LL | impl DerefMut for Box { + | ^^^^^^^^^^^^^^^^^ impl of `DerefMut` not allowed for `Box` + | + = note: `DerefMut` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `DerefMut` for the fundamental type `Pin` + --> $DIR/anti-fundamental-std-traits.rs:25:19 + | +LL | impl DerefMut for Pin { + | ^^^^^^^^^^^^^^ impl of `DerefMut` not allowed for `Pin` + | + = note: `DerefMut` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `std::ops::Receiver` for the fundamental type `Pin` + --> $DIR/anti-fundamental-std-traits.rs:33:19 + | +LL | impl Receiver for Pin { + | ^^^^^^^^^^^^^^ impl of `std::ops::Receiver` not allowed for `Pin` + | + = note: `std::ops::Receiver` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `std::ops::Receiver` for the fundamental type `Box` + --> $DIR/anti-fundamental-std-traits.rs:76:19 + | +LL | impl Receiver for Box { + | ^^^^^^^^^^^^^^^^^ impl of `std::ops::Receiver` not allowed for `Box` + | + = note: `std::ops::Receiver` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: cannot implement `CoerceUnsized` for the fundamental type `Pin` + --> $DIR/anti-fundamental-std-traits.rs:39:41 + | +LL | impl CoerceUnsized> for Pin {} + | ^^^^^^^^^^^^^^ impl of `CoerceUnsized` not allowed for `Pin` + | + = note: `CoerceUnsized` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error[E0277]: the trait bound `LocalType: CoerceUnsized` is not satisfied + --> $DIR/anti-fundamental-std-traits.rs:39:1 + | +LL | impl CoerceUnsized> for Pin {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound + | +help: the nightly-only, unstable trait `CoerceUnsized` is not implemented for `LocalType` + --> $DIR/anti-fundamental-std-traits.rs:12:1 + | +LL | struct LocalType; + | ^^^^^^^^^^^^^^^^ + +error: cannot implement `DispatchFromDyn` for the fundamental type `Pin` + --> $DIR/anti-fundamental-std-traits.rs:44:43 + | +LL | impl DispatchFromDyn> for Pin {} + | ^^^^^^^^^^^^^^ impl of `DispatchFromDyn` not allowed for `Pin` + | + = note: `DispatchFromDyn` is `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate + +error: aborting due to 10 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs index e8c3bbba1e458..a32a61b767d4e 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` for 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..3e413d9ef9e1b 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<'_, _>>` - --> $DIR/pin-unsound-issue-85099-derefmut.rs:44:1 +error: cannot implement `DerefMut` for the fundamental type `Pin<&dyn SomeTrait<'_, Fut>>` + --> $DIR/pin-unsound-issue-85099-derefmut.rs:44:32 | LL | impl<'b, 'a, Fut> DerefMut for Pin<&'b dyn SomeTrait<'a, Fut>> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `DerefMut` not allowed for `Pin<&dyn SomeTrait<'_, Fut>>` | - = 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 `#[rustc_anti_fundamental]` and cannot be implemented for `#[fundamental]` types from another crate error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0119`. From b6158f7a5d0a0856a395c105eec17594be42fd31 Mon Sep 17 00:00:00 2001 From: piorr Date: Fri, 17 Jul 2026 09:32:12 +0000 Subject: [PATCH 3/3] Remove PinDerefMutHelper We marked DerefMut anti-fundamental, so the PinHelper indirection is no longer needed to prevent downstream users from implementing DerefMut on Pin. --- compiler/rustc_span/src/symbol.rs | 1 - .../src/error_reporting/traits/suggestions.rs | 16 ---- library/core/src/pin.rs | 80 ++----------------- ...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, 85 insertions(+), 170 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 18cc71731bf3d..d08b57556f2bf 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -271,7 +271,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 7921250a85a9e..9ffb043934274 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -4432,23 +4432,7 @@ 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. - - 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 58e63ff04af15..bb5b0fd50c2dc 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1691,89 +1691,23 @@ const impl Deref for Pin { } } -mod helper { - /// Helper that prevents downstream crates from implementing `DerefMut` for `Pin`. - /// - /// The `Pin` type implements the unsafe trait `PinSafePointer`, 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, - ::Target: Unpin, + Ptr::Target: Unpin, { + #[inline] fn deref_mut(&mut self) -> &mut Ptr::Target { Pin::get_mut(Pin::as_mut(self)) } @@ -1953,9 +1887,9 @@ unsafe impl<'a, T: ?Sized> PinSafePointer for &'a mut T {} // The `Pin

` type only implements `DerefMut` when `P: DerefMut` and // `P::Target: Unpin`, so normally downstream crates would be able to provide // an implementation of `DerefMut` for `Pin` when `LocalType` does -// not satisfy those conditions. However, a special hack is used to prevent -// such downstream implementations, so this is not a problem. See -// [#145608](https://github.com/rust-lang/rust/pull/145608) for details. +// not satisfy those conditions. However, `#[rustc_anti_fundamental]` is used to +// prevent such downstream implementations, so this is not a problem. See +// [#160391](https://github.com/rust-lang/rust/pull/160391) for details. // // Conversely, downstream crates are able to implement `Clone`, `Debug` and // `Display` for `Pin` as long as `LocalType` does not implement 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