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..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, @@ -1782,6 +1781,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_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/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/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/library/core/src/pin.rs b/library/core/src/pin.rs index 58e63ff04af15..76d16adda7852 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)) } 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/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/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/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 {} 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 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`.