diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs index 69bdccb85c5cd..7e20c097a1939 100644 --- a/compiler/rustc_attr_parsing/src/attributes/traits.rs +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -116,6 +116,14 @@ impl NoArgsAttributeParser for RustcCoinductiveParser { const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcCoinductive; } +pub(crate) struct RustcAntiFundamentalParser; +impl NoArgsAttributeParser for RustcAntiFundamentalParser { + const PATH: &[Symbol] = &[sym::rustc_anti_fundamental]; + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Trait)]); + const STABILITY: AttributeStability = unstable!(rustc_attrs); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcAntiFundamental; +} + pub(crate) struct RustcAllowIncoherentImplParser; impl NoArgsAttributeParser for RustcAllowIncoherentImplParser { const PATH: &[Symbol] = &[sym::rustc_allow_incoherent_impl]; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 6254dd73f3263..e5022df3ceba8 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -295,6 +295,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 1f6f97f1310ae..794d527bc3576 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -347,6 +347,7 @@ pub static BUILTIN_ATTRIBUTES: &[Symbol] = &[ sym::rustc_never_returns_null_ptr, sym::rustc_no_implicit_autorefs, sym::rustc_coherence_is_core, + sym::rustc_anti_fundamental, sym::rustc_coinductive, sym::rustc_comptime, sym::rustc_allow_incoherent_impl, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 165f06d2fde8b..338a94517bb16 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -1350,6 +1350,12 @@ pub enum AttributeKind { /// Represents `#[rustc_allow_incoherent_impl]`. RustcAllowIncoherentImpl(Span), + /// Represents `#[rustc_anti_fundamental]`. This marks a trait such that + /// `#[fundamental]` types (that are not local to the current crate) cannot + /// receive implementations of it. Used to reserve control over `Deref`, + /// `DispatchFromDyn`, etc. on fundamental wrappers like `Box` and `Pin`. + RustcAntiFundamental, + /// Represents `#[rustc_as_ptr]` (used by the `dangling_pointers_from_temporaries` lint). RustcAsPtr, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index dded70ccd08ef..8ede12f0663b3 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -106,6 +106,7 @@ impl AttributeKind { RustcAllocatorZeroedVariant { .. } => Yes, RustcAllowConstFnUnstable(..) => No, RustcAllowIncoherentImpl(..) => No, + RustcAntiFundamental => Yes, RustcAsPtr => Yes, RustcAutodiff(..) => Yes, RustcBodyStability { .. } => No, diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 1cf5da0522c2c..9565e691643a0 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -50,6 +50,10 @@ pub(crate) fn orphan_check_impl( OrphanCheckErr::NonLocalInputType(_) => { bug!("orphanck: shouldn't've gotten non-local input tys in compat mode") } + OrphanCheckErr::AntiFundamentalForeignType(_) => { + // Anti-fundamental violations are always hard errors. + return Err(emit_orphan_check_error(tcx, trait_ref, impl_def_id, err)); + } }, Err(err) => return Err(emit_orphan_check_error(tcx, trait_ref, impl_def_id, err)), }, @@ -378,6 +382,9 @@ fn orphan_check<'tcx>( }); OrphanCheckErr::NonLocalInputType(tys) } + OrphanCheckErr::AntiFundamentalForeignType(ty) => { + OrphanCheckErr::AntiFundamentalForeignType(infcx.resolve_vars_if_possible(ty)) + } }) } @@ -488,6 +495,14 @@ fn emit_orphan_check_error<'tcx>( } guar.unwrap() } + traits::OrphanCheckErr::AntiFundamentalForeignType(ty) => { + let span = tcx.def_span(impl_def_id); + tcx.dcx().emit_err(diagnostics::AntiFundamentalForeignImpl { + span, + trait_name: tcx.def_path_str(trait_ref.def_id), + fundamental_ty: ty, + }) + } } } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index bf17952313479..c0e1795745c01 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -979,6 +979,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { let deny_explicit_impl = find_attr!(attrs, RustcDenyExplicitImpl); let force_dyn_incompatible = find_attr!(attrs, RustcDynIncompatibleTrait(span) => *span); + let is_anti_fundamental = find_attr!(attrs, RustcAntiFundamental); ty::TraitDef { def_id: def_id.to_def_id(), @@ -996,6 +997,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { must_implement_one_of, force_dyn_incompatible, deny_explicit_impl, + is_anti_fundamental, } } diff --git a/compiler/rustc_hir_analysis/src/diagnostics.rs b/compiler/rustc_hir_analysis/src/diagnostics.rs index ab6fa34be9fbb..e09765b3dbcb4 100644 --- a/compiler/rustc_hir_analysis/src/diagnostics.rs +++ b/compiler/rustc_hir_analysis/src/diagnostics.rs @@ -2045,3 +2045,17 @@ pub(crate) struct OnlyStructsCanBeViewedAdt<'tcx> { pub article: &'static str, pub kind: &'static str, } + +#[derive(Diagnostic)] +#[diag("cannot implement `{$trait_name}` on the fundamental type `{$fundamental_ty}`")] +#[note( + "`{$trait_name}` is marked `#[rustc_anti_fundamental]`, which means it \ + cannot be implemented on `#[fundamental]` types from another crate" +)] +pub(crate) struct AntiFundamentalForeignImpl<'tcx> { + #[primary_span] + #[label("impl of `{$trait_name}` not allowed on `{$fundamental_ty}`")] + pub(crate) span: Span, + pub(crate) trait_name: String, + pub(crate) fundamental_ty: Ty<'tcx>, +} diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index 983b4afefdb5f..d6c47cb4086dd 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -613,6 +613,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.trait_def(def_id).is_fundamental } + fn trait_is_anti_fundamental(self, def_id: DefId) -> bool { + self.trait_def(def_id).is_anti_fundamental + } + fn trait_is_unsafe(self, trait_def_id: Self::DefId) -> bool { self.trait_def(trait_def_id).safety.is_unsafe() } diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 681a8793c6886..c537e4af0cea5 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -82,6 +82,11 @@ pub struct TraitDef { /// This only applies to built-in traits, and is marked via /// `#[rustc_deny_explicit_impl]`. pub deny_explicit_impl: bool, + + /// If `true`, then this trait has the `#[rustc_anti_fundamental]` attribute. + /// This prevents non-local `#[fundamental]` types from receiving impls of + /// this trait. Used for `Deref`, `DispatchFromDyn`, `CoerceUnsized`, etc. + pub is_anti_fundamental: bool, } /// Whether this trait is treated specially by the standard library diff --git a/compiler/rustc_next_trait_solver/src/coherence.rs b/compiler/rustc_next_trait_solver/src/coherence.rs index e37e69a617bbd..44e482f6fe9f1 100644 --- a/compiler/rustc_next_trait_solver/src/coherence.rs +++ b/compiler/rustc_next_trait_solver/src/coherence.rs @@ -118,6 +118,9 @@ impl From for IsFirstInputType { pub enum OrphanCheckErr { NonLocalInputType(Vec<(I::Ty, IsFirstInputType)>), UncoveredTyParams(UncoveredTyParams), + /// The trait is `#[rustc_anti_fundamental]` and the Self type's head is a + /// non-local `#[fundamental]` type. `fundamental_ty` is the offending type. + AntiFundamentalForeignType(I::Ty), } #[derive_where(Debug; I: Interner, T: Debug)] @@ -216,6 +219,13 @@ pub struct UncoveredTyParams { /// the above requirement is sufficient, and is necessary in "open world" /// cases). /// +/// In addition to the orphan rules above, this also enforces +/// `#[rustc_anti_fundamental]`: when the trait carries that attribute, an impl +/// whose `Self` type has a non-local `#[fundamental]` type at its head is +/// rejected (in `InCrate::Local` mode). This lets the standard library reserve +/// control over traits like `Deref` and `DispatchFromDyn` on fundamental +/// wrappers such as `Box` and `Pin`. +/// /// Note that this function is never called for types that have both type /// parameters and inference variables. #[instrument(level = "trace", skip(infcx, lazily_normalize_ty), ret)] @@ -234,6 +244,20 @@ where panic!("orphan check only expects inference variables: {trait_ref:?}"); } + // Anti-fundamental check: if the trait is marked `#[rustc_anti_fundamental]`, + // reject impls where the head of the Self type is a non-local fundamental type. + // This prevents downstream crates from implementing traits like `Deref` on + // fundamental wrappers like `Box` or `Pin`. + if matches!(in_crate, InCrate::Local { .. }) { + let cx = infcx.cx(); + if cx.trait_is_anti_fundamental(trait_ref.def_id) { + let self_ty = infcx.shallow_resolve(trait_ref.self_ty()); + if let Some(err_ty) = check_anti_fundamental_head::(self_ty) { + return Ok(Err(OrphanCheckErr::AntiFundamentalForeignType(err_ty))); + } + } + } + let mut checker = OrphanChecker::new(infcx, in_crate, lazily_normalize_ty); Ok(match trait_ref.visit_with(&mut checker) { ControlFlow::Continue(()) => Err(OrphanCheckErr::NonLocalInputType(checker.non_local_tys)), @@ -256,6 +280,22 @@ where }) } +/// Checks the head of the Self type for a non-local fundamental type. +/// If the head is a reference (`&`/`&mut`), unwrap and check again (references are fundamental). +/// Returns `Some(ty)` with the offending fundamental type if the check fails. +fn check_anti_fundamental_head(mut ty: I::Ty) -> Option { + // Unwrap through references (which are fundamental but undocumented as such). + while let ty::Ref(_, inner, _) = ty.kind() { + ty = inner; + } + + // The head is offending only if it is a fundamental ADT that is not local to the + // current crate. All other types are fine — they're either local, non-fundamental, + // or primitive (which can't be fundamental). + matches!(ty.kind(), ty::Adt(def, _) if def.is_fundamental() && !def.def_id().is_local()) + .then_some(ty) +} + struct OrphanChecker<'a, Infcx, I: Interner, F> { infcx: &'a Infcx, in_crate: InCrate, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index a55d38251c843..f3dabb1081c4f 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -305,6 +305,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::RustcAllocatorZeroed => (), AttributeKind::RustcAllocatorZeroedVariant { .. } => (), AttributeKind::RustcAllowIncoherentImpl(..) => (), + AttributeKind::RustcAntiFundamental => (), AttributeKind::RustcAsPtr => (), AttributeKind::RustcAutodiff(..) => (), AttributeKind::RustcBodyStability { .. } => (), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index a293e106bd914..e960de1c3d43e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -269,7 +269,6 @@ symbols! { PartialEq, PartialOrd, Pending, - PinDerefMutHelper, PinMacroHelper, Pointer, Poll, @@ -1762,6 +1761,7 @@ symbols! { rustc_allow_const_fn_unstable, rustc_allow_incoherent_impl, rustc_allowed_through_unstable_modules, + rustc_anti_fundamental, rustc_as_ptr, rustc_attrs, rustc_autodiff, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 8c72f0d90bb58..f228cd239af20 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -4168,24 +4168,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // can do about it. As far as they are concerned, `?` is compiler magic. return; } - if tcx.is_diagnostic_item(sym::PinDerefMutHelper, parent_def_id) { - let parent_predicate = - self.resolve_vars_if_possible(data.derived.parent_trait_pred); - - // Skip PinDerefMutHelper in suggestions, but still show downstream suggestions. - ensure_sufficient_stack(|| { - self.note_obligation_cause_code( - body_def_id, - err, - parent_predicate, - param_env, - &data.derived.parent_code, - obligated_types, - seen_requirements, - ) - }); - return; - } let self_ty_str = tcx.short_string(parent_trait_pred.skip_binder().self_ty(), err.long_ty_path()); let trait_name = tcx.short_string( diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 1fa698a4faeaf..9ee87bf8e68e3 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -435,6 +435,8 @@ pub trait Interner: fn trait_is_fundamental(self, def_id: Self::TraitId) -> bool; + fn trait_is_anti_fundamental(self, def_id: Self::TraitId) -> bool; + /// Returns `true` if this is an `unsafe trait`. fn trait_is_unsafe(self, trait_def_id: Self::TraitId) -> bool; diff --git a/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 931eafef61501..18d4a3447c3d7 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1687,84 +1687,17 @@ const impl Deref for Pin { } } -mod helper { - /// Helper that prevents downstream crates from implementing `DerefMut` for `Pin`. - /// - /// The `Pin` type implements the unsafe trait `PinCoerceUnsized`, which essentially requires - /// that the type does not have a malicious `Deref` or `DerefMut` impl. However, without this - /// helper module, downstream crates are able to write `impl DerefMut for Pin` as - /// long as it does not overlap with the impl provided by stdlib. This is because `Pin` is - /// `#[fundamental]`, so stdlib promises to never implement traits for `Pin` that it does not - /// implement today. - /// - /// However, this is problematic. Downstream crates could implement `DerefMut` for - /// `Pin<&LocalType>`, and they could do so maliciously. To prevent this, the implementation for - /// `Pin` delegates to this helper module. Since `helper::Pin` is not `#[fundamental]`, the - /// orphan rules assume that stdlib might implement `helper::DerefMut` for `helper::Pin<&_>` in - /// the future. Because of this, downstream crates can no longer provide an implementation of - /// `DerefMut` for `Pin<&_>`, as it might overlap with a trait impl that, according to the - /// orphan rules, the stdlib could introduce without a breaking change in a future release. - /// - /// See for the issue this fixes. - #[repr(transparent)] - #[unstable(feature = "pin_derefmut_internals", issue = "none")] - #[allow(missing_debug_implementations)] - pub struct PinHelper { - pointer: Ptr, - } - - #[unstable(feature = "pin_derefmut_internals", issue = "none")] - #[rustc_const_unstable(feature = "const_convert", issue = "143773")] - #[rustc_diagnostic_item = "PinDerefMutHelper"] - pub const trait PinDerefMutHelper { - type Target: ?Sized; - fn deref_mut(&mut self) -> &mut Self::Target; - } - - #[unstable(feature = "pin_derefmut_internals", issue = "none")] - #[rustc_const_unstable(feature = "const_convert", issue = "143773")] - const impl PinDerefMutHelper for PinHelper - where - Ptr::Target: crate::marker::Unpin, - { - type Target = Ptr::Target; - - #[inline(always)] - fn deref_mut(&mut self) -> &mut Ptr::Target { - &mut self.pointer - } - } -} - -#[stable(feature = "pin", since = "1.33.0")] -#[rustc_const_unstable(feature = "const_convert", issue = "143773")] -#[cfg(not(doc))] -const impl DerefMut for Pin -where - Ptr: [const] Deref, - helper::PinHelper: [const] helper::PinDerefMutHelper, -{ - #[inline] - fn deref_mut(&mut self) -> &mut Ptr::Target { - // SAFETY: Pin and PinHelper have the same layout, so this is equivalent to - // `&mut self.pointer` which is safe because `Target: Unpin`. - helper::PinDerefMutHelper::deref_mut(unsafe { - &mut *(self as *mut Pin as *mut helper::PinHelper) - }) - } -} - /// The `Target` type is restricted to `Unpin` types as it's not safe to obtain a mutable reference /// to a pinned value. /// /// For soundness reasons, implementations of `DerefMut` for `Pin` are rejected even when `T` is /// a local type not covered by this impl block. (Since `Pin` is [fundamental], such implementations -/// would normally be possible.) +/// would normally be possible.) This is enforced by the `#[rustc_anti_fundamental]` attribute on +/// the `DerefMut` trait. /// /// [fundamental]: ../../reference/items/implementations.html#r-items.impl.trait.fundamental #[stable(feature = "pin", since = "1.33.0")] #[rustc_const_unstable(feature = "const_convert", issue = "143773")] -#[cfg(doc)] const impl DerefMut for Pin where Ptr: [const] DerefMut, diff --git a/tests/mir-opt/inline/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff index 4b117a453c326..4ad4946c00099 100644 --- a/tests/mir-opt/inline/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff @@ -58,33 +58,35 @@ + let mut _38: &mut std::future::Ready<()>; + let mut _39: &mut std::pin::Pin<&mut std::future::Ready<()>>; + scope 13 (inlined > as DerefMut>::deref_mut) { -+ let mut _40: *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>>; -+ let mut _41: *mut std::pin::Pin<&mut std::future::Ready<()>>; -+ scope 14 (inlined > as pin::helper::PinDerefMutHelper>::deref_mut) { -+ let mut _42: &mut &mut std::future::Ready<()>; -+ scope 15 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) { ++ scope 14 (inlined Pin::<&mut std::future::Ready<()>>::as_mut) { ++ let mut _40: &mut &mut std::future::Ready<()>; ++ scope 15 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) { + } ++ scope 17 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) { ++ } ++ } ++ scope 16 (inlined Pin::<&mut std::future::Ready<()>>::get_mut) { + } + } -+ scope 16 (inlined Option::<()>::take) { -+ let mut _43: std::option::Option<()>; -+ scope 17 (inlined std::mem::replace::>) { -+ scope 18 { ++ scope 18 (inlined Option::<()>::take) { ++ let mut _41: std::option::Option<()>; ++ scope 19 (inlined std::mem::replace::>) { ++ scope 20 { + } + } + } -+ scope 19 (inlined #[track_caller] Option::<()>::expect) { -+ let mut _44: isize; -+ let mut _45: !; -+ scope 20 { ++ scope 21 (inlined #[track_caller] Option::<()>::expect) { ++ let mut _42: isize; ++ let mut _43: !; ++ scope 22 { + } + } + } + } + scope 10 (inlined as IntoFuture>::into_future) { + } -+ scope 21 (inlined ready::<()>) { -+ let mut _46: std::option::Option<()>; ++ scope 23 (inlined ready::<()>) { ++ let mut _44: std::option::Option<()>; + } + } + } @@ -179,23 +181,18 @@ + _22 = &mut (*_23); + StorageDead(_24); + StorageLive(_38); -+ StorageLive(_40); -+ StorageLive(_45); ++ StorageLive(_43); + StorageLive(_35); + StorageLive(_36); ++ _38 = no_retag copy (_19.0: &mut std::future::Ready<()>); + StorageLive(_41); -+ _41 = &raw mut _19; -+ _40 = copy _41 as *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>> (PtrToPtr); -+ StorageDead(_41); -+ _38 = no_retag copy ((*_40).0: &mut std::future::Ready<()>); -+ StorageLive(_43); -+ _43 = Option::<()>::None; ++ _41 = Option::<()>::None; + _36 = copy ((*_38).0: std::option::Option<()>); -+ ((*_38).0: std::option::Option<()>) = move _43; -+ StorageDead(_43); -+ StorageLive(_44); -+ _44 = discriminant(_36); -+ switchInt(move _44) -> [0: bb11, 1: bb12, otherwise: bb4]; ++ ((*_38).0: std::option::Option<()>) = move _41; ++ StorageDead(_41); ++ StorageLive(_42); ++ _42 = discriminant(_36); ++ switchInt(move _42) -> [0: bb11, 1: bb12, otherwise: bb4]; + } + bb4: { @@ -262,10 +259,10 @@ + StorageLive(_13); + StorageLive(_14); + _14 = (); -+ StorageLive(_46); -+ _46 = Option::<()>::Some(copy _14); -+ _13 = std::future::Ready::<()>(move _46); -+ StorageDead(_46); ++ StorageLive(_44); ++ _44 = Option::<()>::Some(copy _14); ++ _13 = std::future::Ready::<()>(move _44); ++ StorageDead(_44); + StorageDead(_14); + _12 = move _13; + StorageDead(_13); @@ -274,17 +271,16 @@ + } + + bb11: { -+ _45 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable; ++ _43 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable; + } + + bb12: { + _35 = move ((_36 as Some).0: ()); -+ StorageDead(_44); ++ StorageDead(_42); + StorageDead(_36); + _18 = Poll::<()>::Ready(move _35); + StorageDead(_35); -+ StorageDead(_45); -+ StorageDead(_40); ++ StorageDead(_43); + StorageDead(_38); + StorageDead(_22); + StorageDead(_19); diff --git a/tests/mir-opt/inline/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff index c365aee05f4ec..09c6199fff29e 100644 --- a/tests/mir-opt/inline/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff @@ -58,33 +58,35 @@ + let mut _38: &mut std::future::Ready<()>; + let mut _39: &mut std::pin::Pin<&mut std::future::Ready<()>>; + scope 13 (inlined > as DerefMut>::deref_mut) { -+ let mut _40: *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>>; -+ let mut _41: *mut std::pin::Pin<&mut std::future::Ready<()>>; -+ scope 14 (inlined > as pin::helper::PinDerefMutHelper>::deref_mut) { -+ let mut _42: &mut &mut std::future::Ready<()>; -+ scope 15 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) { ++ scope 14 (inlined Pin::<&mut std::future::Ready<()>>::as_mut) { ++ let mut _40: &mut &mut std::future::Ready<()>; ++ scope 15 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) { + } ++ scope 17 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) { ++ } ++ } ++ scope 16 (inlined Pin::<&mut std::future::Ready<()>>::get_mut) { + } + } -+ scope 16 (inlined Option::<()>::take) { -+ let mut _43: std::option::Option<()>; -+ scope 17 (inlined std::mem::replace::>) { -+ scope 18 { ++ scope 18 (inlined Option::<()>::take) { ++ let mut _41: std::option::Option<()>; ++ scope 19 (inlined std::mem::replace::>) { ++ scope 20 { + } + } + } -+ scope 19 (inlined #[track_caller] Option::<()>::expect) { -+ let mut _44: isize; -+ let mut _45: !; -+ scope 20 { ++ scope 21 (inlined #[track_caller] Option::<()>::expect) { ++ let mut _42: isize; ++ let mut _43: !; ++ scope 22 { + } + } + } + } + scope 10 (inlined as IntoFuture>::into_future) { + } -+ scope 21 (inlined ready::<()>) { -+ let mut _46: std::option::Option<()>; ++ scope 23 (inlined ready::<()>) { ++ let mut _44: std::option::Option<()>; + } + } + } @@ -190,23 +192,18 @@ + _22 = &mut (*_23); + StorageDead(_24); + StorageLive(_38); -+ StorageLive(_40); -+ StorageLive(_45); ++ StorageLive(_43); + StorageLive(_35); + StorageLive(_36); ++ _38 = no_retag copy (_19.0: &mut std::future::Ready<()>); + StorageLive(_41); -+ _41 = &raw mut _19; -+ _40 = copy _41 as *mut std::pin::helper::PinHelper<&mut std::future::Ready<()>> (PtrToPtr); -+ StorageDead(_41); -+ _38 = no_retag copy ((*_40).0: &mut std::future::Ready<()>); -+ StorageLive(_43); -+ _43 = Option::<()>::None; ++ _41 = Option::<()>::None; + _36 = copy ((*_38).0: std::option::Option<()>); -+ ((*_38).0: std::option::Option<()>) = move _43; -+ StorageDead(_43); -+ StorageLive(_44); -+ _44 = discriminant(_36); -+ switchInt(move _44) -> [0: bb16, 1: bb17, otherwise: bb6]; ++ ((*_38).0: std::option::Option<()>) = move _41; ++ StorageDead(_41); ++ StorageLive(_42); ++ _42 = discriminant(_36); ++ switchInt(move _42) -> [0: bb16, 1: bb17, otherwise: bb6]; } - bb5 (cleanup): { @@ -295,10 +292,10 @@ + StorageLive(_13); + StorageLive(_14); + _14 = (); -+ StorageLive(_46); -+ _46 = Option::<()>::Some(copy _14); -+ _13 = std::future::Ready::<()>(move _46); -+ StorageDead(_46); ++ StorageLive(_44); ++ _44 = Option::<()>::Some(copy _14); ++ _13 = std::future::Ready::<()>(move _44); ++ StorageDead(_44); + StorageDead(_14); + _12 = move _13; + StorageDead(_13); @@ -307,17 +304,16 @@ + } + + bb16: { -+ _45 = option::expect_failed(const "`Ready` polled after completion") -> bb10; ++ _43 = option::expect_failed(const "`Ready` polled after completion") -> bb10; + } + + bb17: { + _35 = move ((_36 as Some).0: ()); -+ StorageDead(_44); ++ StorageDead(_42); + StorageDead(_36); + _18 = Poll::<()>::Ready(move _35); + StorageDead(_35); -+ StorageDead(_45); -+ StorageDead(_40); ++ StorageDead(_43); + StorageDead(_38); + StorageDead(_22); + StorageDead(_19); diff --git a/tests/ui/coherence/anti-fundamental-foreign-type.rs b/tests/ui/coherence/anti-fundamental-foreign-type.rs new file mode 100644 index 0000000000000..5b09f3023fbc1 --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-foreign-type.rs @@ -0,0 +1,30 @@ +//@ aux-build: anti_fundamental_trait_lib.rs + +// Test that `#[rustc_anti_fundamental]` prevents implementing the trait +// on non-local `#[fundamental]` types. + +extern crate anti_fundamental_trait_lib; + +use anti_fundamental_trait_lib::{ + AntiFundamentalTrait, FundamentalWrapper, NonFundamentalWrapper, +}; + +struct LocalType; + +// OK: implementing on a local type. +impl AntiFundamentalTrait for LocalType {} + +// ERROR: implementing on a non-fundamental foreign type wrapping a local type +// (standard orphan check - not covered). +impl AntiFundamentalTrait for NonFundamentalWrapper {} +//~^ ERROR only traits defined in the current crate + +// ERROR: implementing on a foreign fundamental type. +impl AntiFundamentalTrait for FundamentalWrapper {} +//~^ ERROR cannot implement `AntiFundamentalTrait` on the fundamental type + +// ERROR: implementing on a reference to a foreign fundamental type. +impl AntiFundamentalTrait for &FundamentalWrapper {} +//~^ ERROR cannot implement `AntiFundamentalTrait` on the fundamental type + +fn main() {} diff --git a/tests/ui/coherence/anti-fundamental-foreign-type.stderr b/tests/ui/coherence/anti-fundamental-foreign-type.stderr new file mode 100644 index 0000000000000..a6f8f7e3db5d8 --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-foreign-type.stderr @@ -0,0 +1,31 @@ +error[E0117]: only traits defined in the current crate can be implemented for types defined outside of the crate + --> $DIR/anti-fundamental-foreign-type.rs:19:1 + | +LL | impl AntiFundamentalTrait for NonFundamentalWrapper {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------------------------- + | | + | `NonFundamentalWrapper` is not defined in the current crate + | + = note: impl doesn't have any local type before any uncovered type parameters + = note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules + = note: define and implement a trait or new type instead + +error: cannot implement `AntiFundamentalTrait` on the fundamental type `FundamentalWrapper` + --> $DIR/anti-fundamental-foreign-type.rs:23:1 + | +LL | impl AntiFundamentalTrait for FundamentalWrapper {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `AntiFundamentalTrait` not allowed on `FundamentalWrapper` + | + = note: `AntiFundamentalTrait` is marked `#[rustc_anti_fundamental]`, which means it cannot be implemented on `#[fundamental]` types from another crate + +error: cannot implement `AntiFundamentalTrait` on the fundamental type `FundamentalWrapper` + --> $DIR/anti-fundamental-foreign-type.rs:27:1 + | +LL | impl AntiFundamentalTrait for &FundamentalWrapper {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `AntiFundamentalTrait` not allowed on `FundamentalWrapper` + | + = note: `AntiFundamentalTrait` is marked `#[rustc_anti_fundamental]`, which means it cannot be implemented on `#[fundamental]` types from another crate + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0117`. diff --git a/tests/ui/coherence/anti-fundamental-invalid-target.rs b/tests/ui/coherence/anti-fundamental-invalid-target.rs new file mode 100644 index 0000000000000..49f7f7508ac7d --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-invalid-target.rs @@ -0,0 +1,18 @@ +// Test that `#[rustc_anti_fundamental]` can only be applied to traits. +// The target restriction is enforced declaratively by `ALLOWED_TARGETS` +// in the attribute parser, so applying it to a non-trait is an error. + +#![feature(rustc_attrs)] + +#[rustc_anti_fundamental] +//~^ ERROR attribute cannot be used on +struct NotATrait; + +#[rustc_anti_fundamental] +//~^ ERROR attribute cannot be used on +fn also_not_a_trait() {} + +#[rustc_anti_fundamental] +trait Ok {} + +fn main() {} diff --git a/tests/ui/coherence/anti-fundamental-invalid-target.stderr b/tests/ui/coherence/anti-fundamental-invalid-target.stderr new file mode 100644 index 0000000000000..26438d465a81a --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-invalid-target.stderr @@ -0,0 +1,18 @@ +error: the `rustc_anti_fundamental` attribute cannot be used on structs + --> $DIR/anti-fundamental-invalid-target.rs:7:3 + | +LL | #[rustc_anti_fundamental] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: the `rustc_anti_fundamental` attribute can only be applied to traits + +error: the `rustc_anti_fundamental` attribute cannot be used on functions + --> $DIR/anti-fundamental-invalid-target.rs:11:3 + | +LL | #[rustc_anti_fundamental] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: the `rustc_anti_fundamental` attribute can only be applied to traits + +error: aborting due to 2 previous errors + diff --git a/tests/ui/coherence/anti-fundamental-local-trait.rs b/tests/ui/coherence/anti-fundamental-local-trait.rs new file mode 100644 index 0000000000000..33c81e50494f8 --- /dev/null +++ b/tests/ui/coherence/anti-fundamental-local-trait.rs @@ -0,0 +1,23 @@ +//@ check-pass + +// Test that `#[rustc_anti_fundamental]` does NOT block local traits. +// If the trait itself is local, orphan rules pass even on fundamental types. + +#![feature(fundamental)] +#![feature(rustc_attrs)] + +#[fundamental] +struct LocalFundamental(T); + +#[rustc_anti_fundamental] +trait AntiFundamentalTrait {} + +struct LocalType; + +// OK: both trait and fundamental type are local. +impl AntiFundamentalTrait for LocalFundamental {} + +// OK: implementing on a local non-fundamental type. +impl AntiFundamentalTrait for LocalType {} + +fn main() {} diff --git a/tests/ui/coherence/auxiliary/anti_fundamental_trait_lib.rs b/tests/ui/coherence/auxiliary/anti_fundamental_trait_lib.rs new file mode 100644 index 0000000000000..e5aa617b0e53c --- /dev/null +++ b/tests/ui/coherence/auxiliary/anti_fundamental_trait_lib.rs @@ -0,0 +1,12 @@ +// Auxiliary crate for anti-fundamental coherence tests. + +#![feature(fundamental)] +#![feature(rustc_attrs)] + +#[fundamental] +pub struct FundamentalWrapper(pub T); + +pub struct NonFundamentalWrapper(pub T); + +#[rustc_anti_fundamental] +pub trait AntiFundamentalTrait {} 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..1a1820a3702e0 100644 --- a/tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs +++ b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs @@ -42,7 +42,7 @@ impl<'a, Fut: Future> SomeTrait<'a, Fut> for Fut { } impl<'b, 'a, Fut> DerefMut for Pin<&'b dyn SomeTrait<'a, Fut>> { -//~^ ERROR: conflicting implementations of trait `DerefMut` +//~^ ERROR: cannot implement `DerefMut` on the fundamental type fn deref_mut<'c>( self: &'c mut Pin<&'b dyn SomeTrait<'a, Fut>>, ) -> &'c mut (dyn SomeTrait<'a, Fut> + 'b) { diff --git a/tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr index 2bcd92b76a09d..6e7436cdc9a59 100644 --- a/tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr +++ b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr @@ -1,14 +1,10 @@ -error[E0119]: conflicting implementations of trait `DerefMut` for type `Pin<&dyn SomeTrait<'_, _>>` +error: cannot implement `DerefMut` on the fundamental type `Pin<&dyn SomeTrait<'_, _>>` --> $DIR/pin-unsound-issue-85099-derefmut.rs:44:1 | LL | impl<'b, 'a, Fut> DerefMut for Pin<&'b dyn SomeTrait<'a, Fut>> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `DerefMut` not allowed on `Pin<&dyn SomeTrait<'_, _>>` | - = note: conflicting implementation in crate `core`: - - impl DerefMut for Pin - where as pin::helper::PinDerefMutHelper>::Target == as Deref>::Target, Ptr: Deref, pin::helper::PinHelper: pin::helper::PinDerefMutHelper, pin::helper::PinHelper: ?Sized; - = note: upstream crates may add a new impl of trait `std::pin::helper::PinDerefMutHelper` for type `std::pin::helper::PinHelper<&dyn SomeTrait<'_, _>>` in future versions + = note: `DerefMut` is marked `#[rustc_anti_fundamental]`, which means it cannot be implemented on `#[fundamental]` types from another crate error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0119`.