Skip to content

Commit

Permalink
Don't allow DispatchFromDyn impls that transmute ZST to non-ZST
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Jan 8, 2025
1 parent 3c31861 commit 11bc805
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 13 deletions.
26 changes: 13 additions & 13 deletions compiler/rustc_hir_analysis/src/coherence/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
25 changes: 25 additions & 0 deletions tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.rs
Original file line number Diff line number Diff line change
@@ -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() {}
16 changes: 16 additions & 0 deletions tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.stderr
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit 11bc805

Please sign in to comment.