about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl2
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs17
-rw-r--r--tests/ui/invalid_dispatch_from_dyn_impls.stderr4
-rw-r--r--tests/ui/self/dispatch-from-dyn-zst-transmute.rs34
-rw-r--r--tests/ui/self/dispatch-from-dyn-zst-transmute.stderr16
5 files changed, 66 insertions, 7 deletions
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 0c3ed9b5c60..d7ab6eca84b 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -135,7 +135,7 @@ hir_analysis_dispatch_from_dyn_multi = implementing the `DispatchFromDyn` trait
 
 hir_analysis_dispatch_from_dyn_repr = structs implementing `DispatchFromDyn` may not have `#[repr(packed)]` or `#[repr(C)]`
 
-hir_analysis_dispatch_from_dyn_zst = the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment, and nothing else
+hir_analysis_dispatch_from_dyn_zst = the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment that don't mention type/const generics, and nothing else
     .note = extra field `{$name}` of type `{$ty}` is not allowed
 
 hir_analysis_drop_impl_negative = negative `Drop` impls are not supported
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 3b98f358b1e..760c09a1e72 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -259,16 +259,25 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
             let coerced_fields = fields
                 .iter()
                 .filter(|field| {
+                    // Ignore PhantomData fields
+                    if tcx.type_of(field.did).instantiate_identity().is_phantom_data() {
+                        return false;
+                    }
+
                     let ty_a = field.ty(tcx, args_a);
                     let ty_b = field.ty(tcx, args_b);
 
+                    // Allow 1-ZSTs that don't mention type params.
+                    //
+                    // Allowing type params here would allow us to possibly transmute
+                    // between ZSTs, which may be used to create library unsoundness.
                     if let Ok(layout) =
                         tcx.layout_of(infcx.typing_env(param_env).as_query_input(ty_a))
+                        && layout.is_1zst()
+                        && !ty_a.has_non_region_param()
                     {
-                        if layout.is_1zst() {
-                            // ignore 1-ZST fields
-                            return false;
-                        }
+                        // ignore 1-ZST fields
+                        return false;
                     }
 
                     if ty_a == ty_b {
diff --git a/tests/ui/invalid_dispatch_from_dyn_impls.stderr b/tests/ui/invalid_dispatch_from_dyn_impls.stderr
index 168ed37d0e6..02718334c73 100644
--- a/tests/ui/invalid_dispatch_from_dyn_impls.stderr
+++ b/tests/ui/invalid_dispatch_from_dyn_impls.stderr
@@ -1,4 +1,4 @@
-error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment, and nothing else
+error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment that don't mention type/const generics, and nothing else
   --> $DIR/invalid_dispatch_from_dyn_impls.rs:10:1
    |
 LL | / impl<T, U> DispatchFromDyn<WrapperWithExtraField<U>> for WrapperWithExtraField<T>
@@ -35,7 +35,7 @@ LL | | where
 LL | |     T: Unsize<U>,
    | |_________________^
 
-error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment, and nothing else
+error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment that don't mention type/const generics, and nothing else
   --> $DIR/invalid_dispatch_from_dyn_impls.rs:46:1
    |
 LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<OverAligned<U>> for OverAligned<T>
diff --git a/tests/ui/self/dispatch-from-dyn-zst-transmute.rs b/tests/ui/self/dispatch-from-dyn-zst-transmute.rs
new file mode 100644
index 00000000000..57c255b4d7b
--- /dev/null
+++ b/tests/ui/self/dispatch-from-dyn-zst-transmute.rs
@@ -0,0 +1,34 @@
+#![feature(arbitrary_self_types)]
+#![feature(unsize)]
+#![feature(dispatch_from_dyn)]
+
+use std::marker::PhantomData;
+use std::marker::Unsize;
+use std::ops::DispatchFromDyn;
+use std::ops::Deref;
+
+struct IsSendToken<T: ?Sized>(PhantomData<fn(T) -> T>);
+
+struct Foo<'a, U: ?Sized> {
+    token: IsSendToken<U>,
+    ptr: &'a U,
+}
+
+impl<'a, T, U> DispatchFromDyn<Foo<'a, U>> for Foo<'a, T>
+//~^ ERROR implementing the `DispatchFromDyn` trait requires multiple coercions
+where
+    T: Unsize<U> + ?Sized,
+    U: ?Sized {}
+
+trait Bar {
+    fn f(self: Foo<'_, Self>);
+}
+
+impl<U: ?Sized> Deref for Foo<'_, U> {
+    type Target = U;
+    fn deref(&self) -> &U {
+        self.ptr
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/self/dispatch-from-dyn-zst-transmute.stderr b/tests/ui/self/dispatch-from-dyn-zst-transmute.stderr
new file mode 100644
index 00000000000..5a8ae88b5f1
--- /dev/null
+++ b/tests/ui/self/dispatch-from-dyn-zst-transmute.stderr
@@ -0,0 +1,16 @@
+error[E0378]: implementing the `DispatchFromDyn` trait requires multiple coercions
+  --> $DIR/dispatch-from-dyn-zst-transmute.rs:17:1
+   |
+LL | / impl<'a, T, U> DispatchFromDyn<Foo<'a, U>> for Foo<'a, T>
+LL | |
+LL | | where
+LL | |     T: Unsize<U> + ?Sized,
+LL | |     U: ?Sized {}
+   | |_____________^
+   |
+   = note: the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced
+   = note: currently, 2 fields need coercions: `token` (`IsSendToken<T>` to `IsSendToken<U>`), `ptr` (`&'a T` to `&'a U`)
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0378`.