about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2025-01-08 00:29:22 +0000
committerMichael Goulet <michael@errs.io>2025-01-08 00:45:47 +0000
commit11bc805369b7e2aa641e885c137b2c86ce701e2c (patch)
tree89a7727d32909c991dcc90b366b287bc8affcf1a
parent3c3186148e4a66a507e606f191c35ed49d873b08 (diff)
downloadrust-11bc805369b7e2aa641e885c137b2c86ce701e2c.tar.gz
rust-11bc805369b7e2aa641e885c137b2c86ce701e2c.zip
Don't allow DispatchFromDyn impls that transmute ZST to non-ZST
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs26
-rw-r--r--tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.rs25
-rw-r--r--tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.stderr16
3 files changed, 54 insertions, 13 deletions
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 760c09a1e72..a661e588b95 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -267,20 +267,20 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
                     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()
-                    {
-                        // ignore 1-ZST fields
-                        return false;
-                    }
-
                     if ty_a == ty_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()
+                        {
+                            // ignore 1-ZST fields
+                            return false;
+                        }
+
                         res = Err(tcx.dcx().emit_err(errors::DispatchFromDynZST {
                             span,
                             name: field.name,
diff --git a/tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.rs b/tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.rs
new file mode 100644
index 00000000000..71f198f7dc7
--- /dev/null
+++ b/tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.rs
@@ -0,0 +1,25 @@
+// We used to allow erroneous `DispatchFromDyn` impls whose RHS type contained
+// fields that weren't ZSTs. I don't believe this was possible to abuse, but
+// it's at least nice to give users better errors.
+
+#![feature(arbitrary_self_types)]
+#![feature(unsize)]
+#![feature(dispatch_from_dyn)]
+
+use std::marker::Unsize;
+use std::ops::DispatchFromDyn;
+
+struct Dispatchable<T: ?Sized, Z> {
+    _ptr: Box<T>,
+    z: Z,
+}
+
+impl<T, U> DispatchFromDyn<Dispatchable<U, i32>> for Dispatchable<T, ()>
+//~^ ERROR implementing the `DispatchFromDyn` trait requires multiple coercions
+where
+    T: Unsize<U> + ?Sized,
+    U: ?Sized,
+{
+}
+
+fn main() {}
diff --git a/tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.stderr b/tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.stderr
new file mode 100644
index 00000000000..1f13c51f679
--- /dev/null
+++ b/tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.stderr
@@ -0,0 +1,16 @@
+error[E0378]: implementing the `DispatchFromDyn` trait requires multiple coercions
+  --> $DIR/dispatch-from-dyn-zst-transmute-zst-nonzst.rs:17:1
+   |
+LL | / impl<T, U> DispatchFromDyn<Dispatchable<U, i32>> for Dispatchable<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: `_ptr` (`Box<T>` to `Box<U>`), `z` (`()` to `i32`)
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0378`.