From c7435571ad725791494c32a48be1cd2c027af30b Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Tue, 4 Jun 2024 15:47:16 +0200 Subject: [PATCH] Actually check that the traits are the same for casting pointers to dyn _ --- compiler/rustc_hir_typeck/src/cast.rs | 13 +++++++++---- tests/ui/cast/ptr-to-trait-obj-different-args.rs | 2 +- .../ui/cast/ptr-to-trait-obj-different-args.stderr | 9 +++++---- tests/ui/cast/ptr-to-trait-obj-wrap-upcast.rs | 14 ++++++++++++++ tests/ui/cast/ptr-to-trait-obj-wrap-upcast.stderr | 11 +++++++++++ tests/ui/mismatched_types/cast-rfc0401.rs | 2 +- tests/ui/mismatched_types/cast-rfc0401.stderr | 6 +++--- 7 files changed, 44 insertions(+), 13 deletions(-) create mode 100644 tests/ui/cast/ptr-to-trait-obj-wrap-upcast.rs create mode 100644 tests/ui/cast/ptr-to-trait-obj-wrap-upcast.stderr diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 5a0e307ef6f..1809f5e4b04 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -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 -> B. 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`. - (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. diff --git a/tests/ui/cast/ptr-to-trait-obj-different-args.rs b/tests/ui/cast/ptr-to-trait-obj-different-args.rs index 41b6633d68a..88632f5506b 100644 --- a/tests/ui/cast/ptr-to-trait-obj-different-args.rs +++ b/tests/ui/cast/ptr-to-trait-obj-different-args.rs @@ -15,7 +15,7 @@ impl Trait for T {} fn main() { let a: *const dyn A = &(); - let b: *const dyn B = a as _; //~ error: the trait bound `dyn A: Unsize` 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 = &(); let y: *const dyn Trait = x as _; //~ error: the trait bound `dyn Trait: Unsize>` is not satisfied diff --git a/tests/ui/cast/ptr-to-trait-obj-different-args.stderr b/tests/ui/cast/ptr-to-trait-obj-different-args.stderr index 74a95d85d4e..65f0be8541f 100644 --- a/tests/ui/cast/ptr-to-trait-obj-different-args.stderr +++ b/tests/ui/cast/ptr-to-trait-obj-different-args.stderr @@ -1,10 +1,10 @@ -error[E0277]: the trait bound `dyn A: Unsize` 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` is not implemented for `dyn A` + | ^^^^^^ | - = note: all implementations of `Unsize` are provided automatically by the compiler, see for more information + = note: vtable kinds may not match error[E0277]: the trait bound `dyn Trait: Unsize>` 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`. diff --git a/tests/ui/cast/ptr-to-trait-obj-wrap-upcast.rs b/tests/ui/cast/ptr-to-trait-obj-wrap-upcast.rs new file mode 100644 index 00000000000..ff2c4cacfb1 --- /dev/null +++ b/tests/ui/cast/ptr-to-trait-obj-wrap-upcast.rs @@ -0,0 +1,14 @@ +trait Super {} +trait Sub: Super {} + +struct Wrapper(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 +fn cast(ptr: *const dyn Sub) -> *const Wrapper { + ptr as _ //~ error: casting `*const (dyn Sub + 'static)` as `*const Wrapper` is invalid +} + +fn main() {} diff --git a/tests/ui/cast/ptr-to-trait-obj-wrap-upcast.stderr b/tests/ui/cast/ptr-to-trait-obj-wrap-upcast.stderr new file mode 100644 index 00000000000..38c8ba96bc5 --- /dev/null +++ b/tests/ui/cast/ptr-to-trait-obj-wrap-upcast.stderr @@ -0,0 +1,11 @@ +error[E0606]: casting `*const (dyn Sub + 'static)` as `*const Wrapper` 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`. diff --git a/tests/ui/mismatched_types/cast-rfc0401.rs b/tests/ui/mismatched_types/cast-rfc0401.rs index 05e39f86cdf..b2ff5b4a0c0 100644 --- a/tests/ui/mismatched_types/cast-rfc0401.rs +++ b/tests/ui/mismatched_types/cast-rfc0401.rs @@ -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` 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::>(); //~ ERROR is invalid } diff --git a/tests/ui/mismatched_types/cast-rfc0401.stderr b/tests/ui/mismatched_types/cast-rfc0401.stderr index 9f4a7aa858e..142a52aef13 100644 --- a/tests/ui/mismatched_types/cast-rfc0401.stderr +++ b/tests/ui/mismatched_types/cast-rfc0401.stderr @@ -210,13 +210,13 @@ LL | let _ = cf as *const [u16]; | = note: vtable kinds may not match -error[E0277]: the trait bound `dyn Foo: Unsize` 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` is not implemented for `dyn Foo` + | ^^^^^^^^^^^^^^^^^^^^ | - = note: all implementations of `Unsize` are provided automatically by the compiler, see 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