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
+