Actually check that the traits are the same for casting pointers to dyn _

This commit is contained in:
Waffle Lapkin 2024-06-04 15:47:16 +02:00 committed by Maybe Lapkin
parent e85295c321
commit c7435571ad
7 changed files with 44 additions and 13 deletions

View File

@ -828,13 +828,18 @@ fn check_ptr_ptr_cast(
(Some(PointerKind::VTable(src_tty)), Some(PointerKind::VTable(dst_tty))) => {
match (src_tty.principal(), dst_tty.principal()) {
// A<dyn Trait + Auto> -> B<dyn Trait' + Auto'>. need to make sure
// - traits are the same & have the same generic arguments
// - traits are the same
// - traits have the same generic arguments
// - Auto' is a subset of Auto
//
// This is checked by checking `dyn Trait + Auto + 'erased: Unsize<dyn Trait' + Auto' + 'erased>`.
(Some(_), Some(_)) => {
(Some(src_principal), Some(dst_principal)) => {
let tcx = fcx.tcx;
// Check that the traits are actually the same
// (this is required as the `Unsize` check below would allow upcasting, etc)
if src_principal.def_id() != dst_principal.def_id() {
return Err(CastError::DifferingKinds);
}
// We need to reconstruct trait object types.
// `m_src` and `m_dst` won't work for us here because they will potentially
// contain wrappers, which we do not care about.

View File

@ -15,7 +15,7 @@ impl<T> Trait<Y> for T {}
fn main() {
let a: *const dyn A = &();
let b: *const dyn B = a as _; //~ error: the trait bound `dyn A: Unsize<dyn B>` is not satisfied
let b: *const dyn B = a as _; //~ error: casting `*const dyn A` as `*const dyn B` is invalid
let x: *const dyn Trait<X> = &();
let y: *const dyn Trait<Y> = x as _; //~ error: the trait bound `dyn Trait<X>: Unsize<dyn Trait<Y>>` is not satisfied

View File

@ -1,10 +1,10 @@
error[E0277]: the trait bound `dyn A: Unsize<dyn B>` is not satisfied
error[E0606]: casting `*const dyn A` as `*const dyn B` is invalid
--> $DIR/ptr-to-trait-obj-different-args.rs:18:27
|
LL | let b: *const dyn B = a as _;
| ^^^^^^ the trait `Unsize<dyn B>` is not implemented for `dyn A`
| ^^^^^^
|
= note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information
= note: vtable kinds may not match
error[E0277]: the trait bound `dyn Trait<X>: Unsize<dyn Trait<Y>>` is not satisfied
--> $DIR/ptr-to-trait-obj-different-args.rs:21:34
@ -48,4 +48,5 @@ LL | x as _
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0277`.
Some errors have detailed explanations: E0277, E0606.
For more information about an error, try `rustc --explain E0277`.

View File

@ -0,0 +1,14 @@
trait Super {}
trait Sub: Super {}
struct Wrapper<T: ?Sized>(T);
// This cast should not compile.
// Upcasting can't work here, because we are also changing the type (`Wrapper`),
// and reinterpreting would be confusing/surprising.
// See <https://github.com/rust-lang/rust/pull/120248#discussion_r1487739518>
fn cast(ptr: *const dyn Sub) -> *const Wrapper<dyn Super> {
ptr as _ //~ error: casting `*const (dyn Sub + 'static)` as `*const Wrapper<dyn Super>` is invalid
}
fn main() {}

View File

@ -0,0 +1,11 @@
error[E0606]: casting `*const (dyn Sub + 'static)` as `*const Wrapper<dyn Super>` is invalid
--> $DIR/ptr-to-trait-obj-wrap-upcast.rs:11:5
|
LL | ptr as _
| ^^^^^^^^
|
= note: vtable kinds may not match
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0606`.

View File

@ -66,7 +66,7 @@ fn main()
let cf: *const dyn Foo = &0;
let _ = cf as *const [u16]; //~ ERROR is invalid
let _ = cf as *const dyn Bar; //~ ERROR the trait bound `dyn Foo: Unsize<dyn Bar>` is not satisfied
let _ = cf as *const dyn Bar; //~ ERROR casting `*const dyn Foo` as `*const dyn Bar` is invalid
vec![0.0].iter().map(|s| s as f32).collect::<Vec<f32>>(); //~ ERROR is invalid
}

View File

@ -210,13 +210,13 @@ LL | let _ = cf as *const [u16];
|
= note: vtable kinds may not match
error[E0277]: the trait bound `dyn Foo: Unsize<dyn Bar>` is not satisfied
error[E0606]: casting `*const dyn Foo` as `*const dyn Bar` is invalid
--> $DIR/cast-rfc0401.rs:69:13
|
LL | let _ = cf as *const dyn Bar;
| ^^^^^^^^^^^^^^^^^^^^ the trait `Unsize<dyn Bar>` is not implemented for `dyn Foo`
| ^^^^^^^^^^^^^^^^^^^^
|
= note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information
= note: vtable kinds may not match
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
--> $DIR/cast-rfc0401.rs:53:13