Skip to content

Commit

Permalink
Don't allow transmuting ZSTs in dispatch_from_dyn impl
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Jan 8, 2025
1 parent ad211ce commit 3c31861
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 7 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
17 changes: 13 additions & 4 deletions compiler/rustc_hir_analysis/src/coherence/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/invalid_dispatch_from_dyn_impls.stderr
Original file line number Diff line number Diff line change
@@ -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>
Expand Down Expand Up @@ -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>
Expand Down
34 changes: 34 additions & 0 deletions tests/ui/self/dispatch-from-dyn-zst-transmute.rs
Original file line number Diff line number Diff line change
@@ -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() {}
16 changes: 16 additions & 0 deletions tests/ui/self/dispatch-from-dyn-zst-transmute.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.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`.

0 comments on commit 3c31861

Please sign in to comment.