From 9cff29ed39a2236d4bd2f83b7cf3c293d833b919 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 13 Oct 2023 19:52:53 +0000 Subject: [PATCH] WIP --- compiler/rustc_feature/src/builtin_attrs.rs | 5 +++++ compiler/rustc_span/src/symbol.rs | 1 + .../rustc_trait_selection/src/traits/coherence.rs | 5 ++++- library/core/src/pin.rs | 12 +++++++++++- tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs | 4 +--- .../typeck/pin-unsound-issue-85099-derefmut.stderr | 13 +++++++++++++ 6 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 65e697c8f3b80..7e95e2b7e88b1 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -714,6 +714,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_coinductive, AttributeType::Normal, template!(Word), WarnFollowing, @only_local: true, "#![rustc_coinductive] changes a trait to be coinductive, allowing cycles in the trait solver." ), + rustc_attr!( + rustc_no_implicit_negative_coherence, AttributeType::Normal, template!(Word), WarnFollowing, @only_local: false, + "#![rustc_no_implicit_negative_coherence] makes the implementation overlap \ + with other implementations even if where clauses are known to never hold" + ), rustc_attr!( rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing, @only_local: true, "#[rustc_allow_incoherent_impl] has to be added to all impl items of an incoherent inherent impl." diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index ea261923c6541..cc174a455c7b9 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1383,6 +1383,7 @@ symbols! { rustc_mir, rustc_must_implement_one_of, rustc_never_returns_null_ptr, + rustc_no_implicit_negative_coherence, rustc_nonnull_optimization_guaranteed, rustc_nounwind, rustc_object_lifetime_default, diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index acab4498a0985..0ad88a7889fe2 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -220,7 +220,10 @@ fn overlap<'tcx>( ), ); - if overlap_mode.use_implicit_negative() { + if overlap_mode.use_implicit_negative() + && !tcx.has_attr(impl1_def_id, sym::rustc_no_implicit_negative_coherence) + && !tcx.has_attr(impl2_def_id, sym::rustc_no_implicit_negative_coherence) + { for mode in [TreatInductiveCycleAs::Ambig, TreatInductiveCycleAs::Recur] { if let Some(failing_obligation) = selcx.with_treat_inductive_cycle_as(mode, |selcx| { impl_intersection_has_impossible_obligation(selcx, &obligations) diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 94c682b615ad4..5de708659c8f1 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -406,7 +406,7 @@ use crate::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Receiver}; #[lang = "pin"] #[fundamental] #[repr(transparent)] -#[derive(Copy, Clone)] +#[derive(Copy)] pub struct Pin

{ // FIXME(#93176): this field is made `#[unstable] #[doc(hidden)] pub` to: // - deter downstream users from accessing it (which would be unsound!), @@ -418,6 +418,15 @@ pub struct Pin

{ pub pointer: P, } +// N.B. manual implementation exists to add `rustc_no_implicit_negative_coherence` +#[stable(feature = "pin", since = "1.33.0")] +#[cfg_attr(not(bootstrap), rustc_no_implicit_negative_coherence)] +impl Clone for Pin

{ + fn clone(&self) -> Self { + Pin { pointer: self.pointer.clone() } + } +} + // The following implementations aren't derived in order to avoid soundness // issues. `&self.pointer` should not be accessible to untrusted trait // implementations. @@ -967,6 +976,7 @@ impl Deref for Pin

{ } #[stable(feature = "pin", since = "1.33.0")] +#[cfg_attr(not(bootstrap), rustc_no_implicit_negative_coherence)] impl> DerefMut for Pin

{ fn deref_mut(&mut self) -> &mut P::Target { Pin::get_mut(Pin::as_mut(self)) diff --git a/tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs index 03602144e5001..7ca85fca9ac23 100644 --- a/tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs +++ b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.rs @@ -1,6 +1,3 @@ -// check-pass -// known-bug: #85099 - // Should fail. Can coerce `Pin` into `Pin` where // `T: Deref` and `U: Deref`, using the // `CoerceUnsized` impl on `Pin` and an unorthodox `DerefMut` impl for @@ -43,6 +40,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` for type `Pin<&dyn SomeTrait<'_, _>>` fn deref_mut<'c>( self: &'c mut Pin<&'b dyn SomeTrait<'a, Fut>>, ) -> &'c mut (dyn SomeTrait<'a, Fut> + 'b) { diff --git a/tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr new file mode 100644 index 0000000000000..8f5127c9d3780 --- /dev/null +++ b/tests/ui/typeck/pin-unsound-issue-85099-derefmut.stderr @@ -0,0 +1,13 @@ +error[E0119]: conflicting implementations of trait `DerefMut` for type `Pin<&dyn SomeTrait<'_, _>>` + --> $DIR/pin-unsound-issue-85099-derefmut.rs:42:1 + | +LL | impl<'b, 'a, Fut> DerefMut for Pin<&'b dyn SomeTrait<'a, Fut>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `core`: + - impl

DerefMut for Pin

+ where P: DerefMut,

::Target: Unpin; + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`.