Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit c743557

Browse files
committed
Actually check that the traits are the same for casting pointers to dyn _
1 parent e85295c commit c743557

File tree

7 files changed

+44
-13
lines changed

7 files changed

+44
-13
lines changed

compiler/rustc_hir_typeck/src/cast.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -828,13 +828,18 @@ impl<'a, 'tcx> CastCheck<'tcx> {
828828
(Some(PointerKind::VTable(src_tty)), Some(PointerKind::VTable(dst_tty))) => {
829829
match (src_tty.principal(), dst_tty.principal()) {
830830
// A<dyn Trait + Auto> -> B<dyn Trait' + Auto'>. need to make sure
831-
// - traits are the same & have the same generic arguments
831+
// - traits are the same
832+
// - traits have the same generic arguments
832833
// - Auto' is a subset of Auto
833-
//
834-
// This is checked by checking `dyn Trait + Auto + 'erased: Unsize<dyn Trait' + Auto' + 'erased>`.
835-
(Some(_), Some(_)) => {
834+
(Some(src_principal), Some(dst_principal)) => {
836835
let tcx = fcx.tcx;
837836

837+
// Check that the traits are actually the same
838+
// (this is required as the `Unsize` check below would allow upcasting, etc)
839+
if src_principal.def_id() != dst_principal.def_id() {
840+
return Err(CastError::DifferingKinds);
841+
}
842+
838843
// We need to reconstruct trait object types.
839844
// `m_src` and `m_dst` won't work for us here because they will potentially
840845
// contain wrappers, which we do not care about.

tests/ui/cast/ptr-to-trait-obj-different-args.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ impl<T> Trait<Y> for T {}
1515

1616
fn main() {
1717
let a: *const dyn A = &();
18-
let b: *const dyn B = a as _; //~ error: the trait bound `dyn A: Unsize<dyn B>` is not satisfied
18+
let b: *const dyn B = a as _; //~ error: casting `*const dyn A` as `*const dyn B` is invalid
1919

2020
let x: *const dyn Trait<X> = &();
2121
let y: *const dyn Trait<Y> = x as _; //~ error: the trait bound `dyn Trait<X>: Unsize<dyn Trait<Y>>` is not satisfied

tests/ui/cast/ptr-to-trait-obj-different-args.stderr

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
error[E0277]: the trait bound `dyn A: Unsize<dyn B>` is not satisfied
1+
error[E0606]: casting `*const dyn A` as `*const dyn B` is invalid
22
--> $DIR/ptr-to-trait-obj-different-args.rs:18:27
33
|
44
LL | let b: *const dyn B = a as _;
5-
| ^^^^^^ the trait `Unsize<dyn B>` is not implemented for `dyn A`
5+
| ^^^^^^
66
|
7-
= 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
7+
= note: vtable kinds may not match
88

99
error[E0277]: the trait bound `dyn Trait<X>: Unsize<dyn Trait<Y>>` is not satisfied
1010
--> $DIR/ptr-to-trait-obj-different-args.rs:21:34
@@ -48,4 +48,5 @@ LL | x as _
4848

4949
error: aborting due to 5 previous errors
5050

51-
For more information about this error, try `rustc --explain E0277`.
51+
Some errors have detailed explanations: E0277, E0606.
52+
For more information about an error, try `rustc --explain E0277`.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
trait Super {}
2+
trait Sub: Super {}
3+
4+
struct Wrapper<T: ?Sized>(T);
5+
6+
// This cast should not compile.
7+
// Upcasting can't work here, because we are also changing the type (`Wrapper`),
8+
// and reinterpreting would be confusing/surprising.
9+
// See <https://github.com/rust-lang/rust/pull/120248#discussion_r1487739518>
10+
fn cast(ptr: *const dyn Sub) -> *const Wrapper<dyn Super> {
11+
ptr as _ //~ error: casting `*const (dyn Sub + 'static)` as `*const Wrapper<dyn Super>` is invalid
12+
}
13+
14+
fn main() {}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0606]: casting `*const (dyn Sub + 'static)` as `*const Wrapper<dyn Super>` is invalid
2+
--> $DIR/ptr-to-trait-obj-wrap-upcast.rs:11:5
3+
|
4+
LL | ptr as _
5+
| ^^^^^^^^
6+
|
7+
= note: vtable kinds may not match
8+
9+
error: aborting due to 1 previous error
10+
11+
For more information about this error, try `rustc --explain E0606`.

tests/ui/mismatched_types/cast-rfc0401.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ fn main()
6666

6767
let cf: *const dyn Foo = &0;
6868
let _ = cf as *const [u16]; //~ ERROR is invalid
69-
let _ = cf as *const dyn Bar; //~ ERROR the trait bound `dyn Foo: Unsize<dyn Bar>` is not satisfied
69+
let _ = cf as *const dyn Bar; //~ ERROR casting `*const dyn Foo` as `*const dyn Bar` is invalid
7070

7171
vec![0.0].iter().map(|s| s as f32).collect::<Vec<f32>>(); //~ ERROR is invalid
7272
}

tests/ui/mismatched_types/cast-rfc0401.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -210,13 +210,13 @@ LL | let _ = cf as *const [u16];
210210
|
211211
= note: vtable kinds may not match
212212

213-
error[E0277]: the trait bound `dyn Foo: Unsize<dyn Bar>` is not satisfied
213+
error[E0606]: casting `*const dyn Foo` as `*const dyn Bar` is invalid
214214
--> $DIR/cast-rfc0401.rs:69:13
215215
|
216216
LL | let _ = cf as *const dyn Bar;
217-
| ^^^^^^^^^^^^^^^^^^^^ the trait `Unsize<dyn Bar>` is not implemented for `dyn Foo`
217+
| ^^^^^^^^^^^^^^^^^^^^
218218
|
219-
= 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
219+
= note: vtable kinds may not match
220220

221221
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
222222
--> $DIR/cast-rfc0401.rs:53:13

0 commit comments

Comments
 (0)