From a1f20f17c86a7a0a51728be48afd121d5ae2df64 Mon Sep 17 00:00:00 2001 From: Maybe Lapkin <waffle.lapkin@gmail.com> Date: Thu, 4 Jul 2024 17:53:37 +0200 Subject: [PATCH] Properly normalize types in bck when checking pointer casts --- compiler/rustc_borrowck/src/type_check/mod.rs | 7 +++-- ...to-trait-obj-different-regions-id-trait.rs | 27 +++++++++++++++++++ ...rait-obj-different-regions-id-trait.stderr | 15 +++++++++++ 3 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.rs create mode 100644 tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.stderr diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 81ce7418852..6fd49c8027b 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -2320,8 +2320,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let cast_ty_to = CastTy::from_ty(*ty); match (cast_ty_from, cast_ty_to) { (Some(CastTy::Ptr(src)), Some(CastTy::Ptr(dst))) => { - let src_tail = tcx.struct_tail_without_normalization(src.ty); - let dst_tail = tcx.struct_tail_without_normalization(dst.ty); + let mut normalize = |t| self.normalize(t, location); + let src_tail = + tcx.struct_tail_with_normalize(src.ty, &mut normalize, || ()); + let dst_tail = + tcx.struct_tail_with_normalize(dst.ty, &mut normalize, || ()); // This checks (lifetime part of) vtable validity for pointer casts, // which is irrelevant when there are aren't principal traits on both sides (aka only auto traits). diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.rs b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.rs new file mode 100644 index 00000000000..cdd55e24392 --- /dev/null +++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.rs @@ -0,0 +1,27 @@ +//@ check-fail +// +// Make sure we can't trick the compiler by using a projection. + +trait Cat<'a> {} +impl Cat<'_> for () {} + +trait Id { + type Id: ?Sized; +} +impl<T: ?Sized> Id for T { + type Id = T; +} + +struct S<T: ?Sized> { + tail: <T as Id>::Id, +} + +fn m<'a>() { + let unsend: *const dyn Cat<'a> = &(); + let _send = unsend as *const S<dyn Cat<'static>>; + //~^ error: lifetime may not live long enough +} + +fn main() { + m(); +} diff --git a/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.stderr b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.stderr new file mode 100644 index 00000000000..d1d598e603f --- /dev/null +++ b/tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.stderr @@ -0,0 +1,15 @@ +error: lifetime may not live long enough + --> $DIR/ptr-to-trait-obj-different-regions-id-trait.rs:21:17 + | +LL | fn m<'a>() { + | -- lifetime `'a` defined here +LL | let unsend: *const dyn Cat<'a> = &(); +LL | let _send = unsend as *const S<dyn Cat<'static>>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + | + = note: requirement occurs because of the type `S<dyn Cat<'_>>`, which makes the generic argument `dyn Cat<'_>` invariant + = note: the struct `S<T>` is invariant over the parameter `T` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: aborting due to 1 previous error +