about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs31
-rw-r--r--src/test/ui/coherence/issue-99663-2.rs22
-rw-r--r--src/test/ui/coherence/issue-99663.rs22
-rw-r--r--src/test/ui/impl-trait/negative-reasoning.stderr2
4 files changed, 75 insertions, 2 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 9983438233e..fa94aa19abd 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -703,13 +703,42 @@ impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> {
                 }
             }
             ty::Error(_) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
-            ty::Opaque(..) | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => {
+            ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => {
                 self.tcx.sess.delay_span_bug(
                     DUMMY_SP,
                     format!("ty_is_local invoked on closure or generator: {:?}", ty),
                 );
                 ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
             }
+            ty::Opaque(..) => {
+                // This merits some explanation.
+                // Normally, opaque types are not involved when performing
+                // coherence checking, since it is illegal to directly
+                // implement a trait on an opaque type. However, we might
+                // end up looking at an opaque type during coherence checking
+                // if an opaque type gets used within another type (e.g. as
+                // the type of a field) when checking for auto trait or `Sized`
+                // impls. This requires us to decide whether or not an opaque
+                // type should be considered 'local' or not.
+                //
+                // We choose to treat all opaque types as non-local, even
+                // those that appear within the same crate. This seems
+                // somewhat surprising at first, but makes sense when
+                // you consider that opaque types are supposed to hide
+                // the underlying type *within the same crate*. When an
+                // opaque type is used from outside the module
+                // where it is declared, it should be impossible to observe
+                // anything about it other than the traits that it implements.
+                //
+                // The alternative would be to look at the underlying type
+                // to determine whether or not the opaque type itself should
+                // be considered local. However, this could make it a breaking change
+                // to switch the underlying ('defining') type from a local type
+                // to a remote type. This would violate the rule that opaque
+                // types should be completely opaque apart from the traits
+                // that they implement, so we don't use this behavior.
+                self.found_non_local_ty(ty)
+            }
         };
         // A bit of a hack, the `OrphanChecker` is only used to visit a `TraitRef`, so
         // the first type we visit is always the self type.
diff --git a/src/test/ui/coherence/issue-99663-2.rs b/src/test/ui/coherence/issue-99663-2.rs
new file mode 100644
index 00000000000..10a0a568849
--- /dev/null
+++ b/src/test/ui/coherence/issue-99663-2.rs
@@ -0,0 +1,22 @@
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+
+struct Outer<T: ?Sized> {
+    i: InnerSend<T>,
+}
+
+type InnerSend<T: ?Sized> = impl Send;
+
+fn constrain<T: ?Sized>() -> InnerSend<T> {
+    ()
+}
+
+trait SendMustNotImplDrop {}
+
+#[allow(drop_bounds)]
+impl<T: ?Sized + Send + Drop> SendMustNotImplDrop for T {}
+
+impl<T: ?Sized> SendMustNotImplDrop for Outer<T> {}
+
+fn main() {}
diff --git a/src/test/ui/coherence/issue-99663.rs b/src/test/ui/coherence/issue-99663.rs
new file mode 100644
index 00000000000..a2d4d398ce1
--- /dev/null
+++ b/src/test/ui/coherence/issue-99663.rs
@@ -0,0 +1,22 @@
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+
+struct Send<T> {
+    i: InnerSend<T>,
+}
+
+type InnerSend<T> = impl Sized;
+
+fn constrain<T>() -> InnerSend<T> {
+    ()
+}
+
+trait SendMustNotImplDrop {}
+
+#[allow(drop_bounds)]
+impl<T: Drop> SendMustNotImplDrop for T {}
+
+impl<T> SendMustNotImplDrop for Send<T> {}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/negative-reasoning.stderr b/src/test/ui/impl-trait/negative-reasoning.stderr
index 2eea726a19c..479b451855d 100644
--- a/src/test/ui/impl-trait/negative-reasoning.stderr
+++ b/src/test/ui/impl-trait/negative-reasoning.stderr
@@ -7,7 +7,7 @@ LL | impl<T: std::fmt::Debug> AnotherTrait for T {}
 LL | impl AnotherTrait for D<OpaqueType> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>`
    |
-   = note: downstream crates may implement trait `std::fmt::Debug` for type `OpaqueType`
+   = note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `OpaqueType` in future versions
 
 error: cannot implement trait on type alias impl trait
   --> $DIR/negative-reasoning.rs:19:25