Rollup merge of #135228 - compiler-errors:normalizes-ur-dispatch, r=BoxyUwU
Improve `DispatchFromDyn` and `CoerceUnsized` impl validation * Disallow arbitrary 1-ZST fields in `DispatchFromDyn` -- only `PhantomData`, and 1-ZSTs that mention no params (which is needed to support, e.g., the `Global` alloctor in `Box<T, U = Global>`). * Don't allow coercing between non-ZSTs to ZSTs (since the previous check wasn't actually checking the field tys were the same before checking the layout...) * Normalize the field before checking it's `PhantomData`. Fixes #135215 Fixes #135214 Fixes #135220 r? ```@BoxyUwU``` or reassign
This commit is contained in:
commit
f256f9ef22
8 changed files with 153 additions and 11 deletions
|
@ -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_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
|
.note = extra field `{$name}` of type `{$ty}` is not allowed
|
||||||
|
|
||||||
hir_analysis_drop_impl_negative = negative `Drop` impls are not supported
|
hir_analysis_drop_impl_negative = negative `Drop` impls are not supported
|
||||||
|
|
|
@ -259,19 +259,37 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
|
||||||
let coerced_fields = fields
|
let coerced_fields = fields
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|field| {
|
.filter(|field| {
|
||||||
|
// Ignore PhantomData fields
|
||||||
|
let unnormalized_ty = tcx.type_of(field.did).instantiate_identity();
|
||||||
|
if tcx
|
||||||
|
.try_normalize_erasing_regions(
|
||||||
|
ty::TypingEnv::non_body_analysis(tcx, def_a.did()),
|
||||||
|
unnormalized_ty,
|
||||||
|
)
|
||||||
|
.unwrap_or(unnormalized_ty)
|
||||||
|
.is_phantom_data()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
let ty_a = field.ty(tcx, args_a);
|
let ty_a = field.ty(tcx, args_a);
|
||||||
let ty_b = field.ty(tcx, args_b);
|
let ty_b = field.ty(tcx, args_b);
|
||||||
|
|
||||||
|
// FIXME: We could do normalization here, but is it really worth it?
|
||||||
|
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) =
|
if let Ok(layout) =
|
||||||
tcx.layout_of(infcx.typing_env(param_env).as_query_input(ty_a))
|
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
|
// ignore 1-ZST fields
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ty_a == ty_b {
|
|
||||||
res = Err(tcx.dcx().emit_err(errors::DispatchFromDynZST {
|
res = Err(tcx.dcx().emit_err(errors::DispatchFromDynZST {
|
||||||
span,
|
span,
|
||||||
name: field.name,
|
name: field.name,
|
||||||
|
@ -460,8 +478,16 @@ pub(crate) fn coerce_unsized_info<'tcx>(
|
||||||
.filter_map(|(i, f)| {
|
.filter_map(|(i, f)| {
|
||||||
let (a, b) = (f.ty(tcx, args_a), f.ty(tcx, args_b));
|
let (a, b) = (f.ty(tcx, args_a), f.ty(tcx, args_b));
|
||||||
|
|
||||||
if tcx.type_of(f.did).instantiate_identity().is_phantom_data() {
|
|
||||||
// Ignore PhantomData fields
|
// Ignore PhantomData fields
|
||||||
|
let unnormalized_ty = tcx.type_of(f.did).instantiate_identity();
|
||||||
|
if tcx
|
||||||
|
.try_normalize_erasing_regions(
|
||||||
|
ty::TypingEnv::non_body_analysis(tcx, def_a.did()),
|
||||||
|
unnormalized_ty,
|
||||||
|
)
|
||||||
|
.unwrap_or(unnormalized_ty)
|
||||||
|
.is_phantom_data()
|
||||||
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
--> $DIR/invalid_dispatch_from_dyn_impls.rs:10:1
|
||||||
|
|
|
|
||||||
LL | / impl<T, U> DispatchFromDyn<WrapperWithExtraField<U>> for WrapperWithExtraField<T>
|
LL | / impl<T, U> DispatchFromDyn<WrapperWithExtraField<U>> for WrapperWithExtraField<T>
|
||||||
|
@ -35,7 +35,7 @@ LL | | where
|
||||||
LL | | T: Unsize<U>,
|
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
|
--> $DIR/invalid_dispatch_from_dyn_impls.rs:46:1
|
||||||
|
|
|
|
||||||
LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<OverAligned<U>> for OverAligned<T>
|
LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<OverAligned<U>> for OverAligned<T>
|
||||||
|
|
25
tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.rs
Normal file
25
tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.rs
Normal file
|
@ -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() {}
|
|
@ -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`.
|
34
tests/ui/self/dispatch-from-dyn-zst-transmute.rs
Normal file
34
tests/ui/self/dispatch-from-dyn-zst-transmute.rs
Normal file
|
@ -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
tests/ui/self/dispatch-from-dyn-zst-transmute.stderr
Normal file
16
tests/ui/self/dispatch-from-dyn-zst-transmute.stderr
Normal file
|
@ -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`.
|
25
tests/ui/self/phantomdata-in-coerce-and-dispatch-impls.rs
Normal file
25
tests/ui/self/phantomdata-in-coerce-and-dispatch-impls.rs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
//@ check-pass
|
||||||
|
|
||||||
|
#![feature(coerce_unsized, dispatch_from_dyn, unsize)]
|
||||||
|
|
||||||
|
use std::marker::Unsize;
|
||||||
|
use std::ops::{CoerceUnsized, DispatchFromDyn};
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
trait Mirror {
|
||||||
|
type Assoc;
|
||||||
|
}
|
||||||
|
impl<T> Mirror for T {
|
||||||
|
type Assoc = T;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct W<T: 'static> {
|
||||||
|
t: &'static T,
|
||||||
|
f: <PhantomData<T> as Mirror>::Assoc,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, U> CoerceUnsized<W<U>> for W<T> where T: Unsize<U> {}
|
||||||
|
|
||||||
|
impl<T, U> DispatchFromDyn<W<U>> for W<T> where T: Unsize<U> {}
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue