From ad5f912d966cc26c17d64a87796d55c5c51bb2d4 Mon Sep 17 00:00:00 2001
From: Scott McMurray <scottmcm@users.noreply.github.com>
Date: Fri, 15 Nov 2024 00:35:46 -0800
Subject: [PATCH] Transmute from NonNull to pointer when elaborating a box
 deref (MCP807)

---
 .../src/elaborate_box_derefs.rs               | 27 ++++++++++---------
 tests/mir-opt/box_expr.rs                     |  2 +-
 .../boxes.main.GVN.panic-abort.diff           |  4 +--
 .../boxes.main.GVN.panic-unwind.diff          |  4 +--
 .../transmute.unreachable_box.GVN.32bit.diff  |  4 +--
 .../transmute.unreachable_box.GVN.64bit.diff  |  4 +--
 ...reachable_box.DataflowConstProp.32bit.diff |  2 +-
 ...reachable_box.DataflowConstProp.64bit.diff |  2 +-
 ...inhabited.LowerIntrinsics.panic-abort.diff |  2 +-
 ...nhabited.LowerIntrinsics.panic-unwind.diff |  2 +-
 ...fg-pre-optimizations.after.panic-abort.mir |  2 +-
 ...g-pre-optimizations.after.panic-unwind.mir |  2 +-
 12 files changed, 29 insertions(+), 28 deletions(-)

diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
index b909dfa132052..d6ecadbfe29c1 100644
--- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
@@ -29,13 +29,8 @@ fn build_ptr_tys<'tcx>(
 pub(super) fn build_projection<'tcx>(
     unique_ty: Ty<'tcx>,
     nonnull_ty: Ty<'tcx>,
-    ptr_ty: Ty<'tcx>,
-) -> [PlaceElem<'tcx>; 3] {
-    [
-        PlaceElem::Field(FieldIdx::ZERO, unique_ty),
-        PlaceElem::Field(FieldIdx::ZERO, nonnull_ty),
-        PlaceElem::Field(FieldIdx::ZERO, ptr_ty),
-    ]
+) -> [PlaceElem<'tcx>; 2] {
+    [PlaceElem::Field(FieldIdx::ZERO, unique_ty), PlaceElem::Field(FieldIdx::ZERO, nonnull_ty)]
 }
 
 struct ElaborateBoxDerefVisitor<'a, 'tcx> {
@@ -75,10 +70,14 @@ impl<'a, 'tcx> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'a, 'tcx> {
             self.patch.add_assign(
                 location,
                 Place::from(ptr_local),
-                Rvalue::Use(Operand::Copy(
-                    Place::from(place.local)
-                        .project_deeper(&build_projection(unique_ty, nonnull_ty, ptr_ty), tcx),
-                )),
+                Rvalue::Cast(
+                    CastKind::Transmute,
+                    Operand::Copy(
+                        Place::from(place.local)
+                            .project_deeper(&build_projection(unique_ty, nonnull_ty), tcx),
+                    ),
+                    ptr_ty,
+                ),
             );
 
             place.local = ptr_local;
@@ -133,8 +132,10 @@ impl<'tcx> crate::MirPass<'tcx> for ElaborateBoxDerefs {
                         let (unique_ty, nonnull_ty, ptr_ty) =
                             build_ptr_tys(tcx, boxed_ty, unique_did, nonnull_did);
 
-                        new_projections
-                            .extend_from_slice(&build_projection(unique_ty, nonnull_ty, ptr_ty));
+                        new_projections.extend_from_slice(&build_projection(unique_ty, nonnull_ty));
+                        // While we can't project into `NonNull<_>` in a basic block
+                        // due to MCP#807, this is debug info where it's fine.
+                        new_projections.push(PlaceElem::Field(FieldIdx::ZERO, ptr_ty));
                         new_projections.push(PlaceElem::Deref);
                     } else if let Some(new_projections) = new_projections.as_mut() {
                         // Keep building up our projections list once we've started it.
diff --git a/tests/mir-opt/box_expr.rs b/tests/mir-opt/box_expr.rs
index 233946e713ce4..009a5ae54e089 100644
--- a/tests/mir-opt/box_expr.rs
+++ b/tests/mir-opt/box_expr.rs
@@ -7,7 +7,7 @@
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK:   [[box:_.*]] = ShallowInitBox(
-    // CHECK:   [[ptr:_.*]] = copy ((([[box]].0: std::ptr::Unique<S>).0: std::ptr::NonNull<S>).0: *const S);
+    // CHECK:   [[ptr:_.*]] = copy (([[box]].0: std::ptr::Unique<S>).0: std::ptr::NonNull<S>) as *const S (Transmute);
     // CHECK:   (*[[ptr]]) = S::new() -> [return: [[ret:bb.*]], unwind: [[unwind:bb.*]]];
     // CHECK: [[ret]]: {
     // CHECK:   [[box2:_.*]] = move [[box]];
diff --git a/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff
index d5f15b750d4ba..f43c0cca9ad28 100644
--- a/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff
+++ b/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff
@@ -32,11 +32,11 @@
       bb1: {
           StorageLive(_7);
           _7 = ShallowInitBox(move _6, i32);
-          _8 = copy (((_7.0: std::ptr::Unique<i32>).0: std::ptr::NonNull<i32>).0: *const i32);
+          _8 = copy ((_7.0: std::ptr::Unique<i32>).0: std::ptr::NonNull<i32>) as *const i32 (Transmute);
           (*_8) = const 42_i32;
           _3 = move _7;
           StorageDead(_7);
-          _9 = copy (((_3.0: std::ptr::Unique<i32>).0: std::ptr::NonNull<i32>).0: *const i32);
+          _9 = copy ((_3.0: std::ptr::Unique<i32>).0: std::ptr::NonNull<i32>) as *const i32 (Transmute);
           _2 = copy (*_9);
 -         _1 = Add(move _2, const 0_i32);
 -         StorageDead(_2);
diff --git a/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff
index d4d4f21be6e02..2c903b6d85349 100644
--- a/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff
@@ -32,11 +32,11 @@
       bb1: {
           StorageLive(_7);
           _7 = ShallowInitBox(move _6, i32);
-          _8 = copy (((_7.0: std::ptr::Unique<i32>).0: std::ptr::NonNull<i32>).0: *const i32);
+          _8 = copy ((_7.0: std::ptr::Unique<i32>).0: std::ptr::NonNull<i32>) as *const i32 (Transmute);
           (*_8) = const 42_i32;
           _3 = move _7;
           StorageDead(_7);
-          _9 = copy (((_3.0: std::ptr::Unique<i32>).0: std::ptr::NonNull<i32>).0: *const i32);
+          _9 = copy ((_3.0: std::ptr::Unique<i32>).0: std::ptr::NonNull<i32>) as *const i32 (Transmute);
           _2 = copy (*_9);
 -         _1 = Add(move _2, const 0_i32);
 -         StorageDead(_2);
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.32bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.32bit.diff
index de0b1a57f8080..b698d8f373575 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.32bit.diff
@@ -12,9 +12,9 @@
       bb0: {
           StorageLive(_1);
 -         _1 = const 1_usize as std::boxed::Box<Never> (Transmute);
--         _2 = copy (((_1.0: std::ptr::Unique<Never>).0: std::ptr::NonNull<Never>).0: *const Never);
+-         _2 = copy ((_1.0: std::ptr::Unique<Never>).0: std::ptr::NonNull<Never>) as *const Never (Transmute);
 +         _1 = const Box::<Never>(Unique::<Never> {{ pointer: NonNull::<Never> {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData::<Never> }}, std::alloc::Global);
-+         _2 = const {0x1 as *const Never};
++         _2 = const std::ptr::NonNull::<Never> {{ pointer: {0x1 as *const Never} }} as *const Never (Transmute);
           unreachable;
       }
   }
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.64bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.64bit.diff
index de0b1a57f8080..b698d8f373575 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.64bit.diff
@@ -12,9 +12,9 @@
       bb0: {
           StorageLive(_1);
 -         _1 = const 1_usize as std::boxed::Box<Never> (Transmute);
--         _2 = copy (((_1.0: std::ptr::Unique<Never>).0: std::ptr::NonNull<Never>).0: *const Never);
+-         _2 = copy ((_1.0: std::ptr::Unique<Never>).0: std::ptr::NonNull<Never>) as *const Never (Transmute);
 +         _1 = const Box::<Never>(Unique::<Never> {{ pointer: NonNull::<Never> {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData::<Never> }}, std::alloc::Global);
-+         _2 = const {0x1 as *const Never};
++         _2 = const std::ptr::NonNull::<Never> {{ pointer: {0x1 as *const Never} }} as *const Never (Transmute);
           unreachable;
       }
   }
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff
index 2d67ac92209b3..fa6c2e29e072e 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.32bit.diff
@@ -13,7 +13,7 @@
           StorageLive(_1);
 -         _1 = const 1_usize as std::boxed::Box<Never> (Transmute);
 +         _1 = const Box::<Never>(Unique::<Never> {{ pointer: NonNull::<Never> {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData::<Never> }}, std::alloc::Global);
-          _2 = copy (((_1.0: std::ptr::Unique<Never>).0: std::ptr::NonNull<Never>).0: *const Never);
+          _2 = copy ((_1.0: std::ptr::Unique<Never>).0: std::ptr::NonNull<Never>) as *const Never (Transmute);
           unreachable;
       }
   }
diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff
index 2d67ac92209b3..fa6c2e29e072e 100644
--- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff
+++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_box.DataflowConstProp.64bit.diff
@@ -13,7 +13,7 @@
           StorageLive(_1);
 -         _1 = const 1_usize as std::boxed::Box<Never> (Transmute);
 +         _1 = const Box::<Never>(Unique::<Never> {{ pointer: NonNull::<Never> {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData::<Never> }}, std::alloc::Global);
-          _2 = copy (((_1.0: std::ptr::Unique<Never>).0: std::ptr::NonNull<Never>).0: *const Never);
+          _2 = copy ((_1.0: std::ptr::Unique<Never>).0: std::ptr::NonNull<Never>) as *const Never (Transmute);
           unreachable;
       }
   }
diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.panic-abort.diff
index 7098b4d316882..4f8b7c4160f99 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.panic-abort.diff
@@ -17,7 +17,7 @@
       }
   
       bb1: {
-          _2 = copy (((_1.0: std::ptr::Unique<Never>).0: std::ptr::NonNull<Never>).0: *const Never);
+          _2 = copy ((_1.0: std::ptr::Unique<Never>).0: std::ptr::NonNull<Never>) as *const Never (Transmute);
           PlaceMention((*_2));
           unreachable;
       }
diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.panic-unwind.diff
index 7098b4d316882..4f8b7c4160f99 100644
--- a/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.panic-unwind.diff
@@ -17,7 +17,7 @@
       }
   
       bb1: {
-          _2 = copy (((_1.0: std::ptr::Unique<Never>).0: std::ptr::NonNull<Never>).0: *const Never);
+          _2 = copy ((_1.0: std::ptr::Unique<Never>).0: std::ptr::NonNull<Never>) as *const Never (Transmute);
           PlaceMention((*_2));
           unreachable;
       }
diff --git a/tests/mir-opt/retag.box_to_raw_mut.SimplifyCfg-pre-optimizations.after.panic-abort.mir b/tests/mir-opt/retag.box_to_raw_mut.SimplifyCfg-pre-optimizations.after.panic-abort.mir
index ca02e7b49cccd..da005d552e2bf 100644
--- a/tests/mir-opt/retag.box_to_raw_mut.SimplifyCfg-pre-optimizations.after.panic-abort.mir
+++ b/tests/mir-opt/retag.box_to_raw_mut.SimplifyCfg-pre-optimizations.after.panic-abort.mir
@@ -9,7 +9,7 @@ fn box_to_raw_mut(_1: &mut Box<i32>) -> *mut i32 {
     bb0: {
         Retag([fn entry] _1);
         _2 = deref_copy (*_1);
-        _3 = copy (((_2.0: std::ptr::Unique<i32>).0: std::ptr::NonNull<i32>).0: *const i32);
+        _3 = copy ((_2.0: std::ptr::Unique<i32>).0: std::ptr::NonNull<i32>) as *const i32 (Transmute);
         _0 = &raw mut (*_3);
         Retag([raw] _0);
         return;
diff --git a/tests/mir-opt/retag.box_to_raw_mut.SimplifyCfg-pre-optimizations.after.panic-unwind.mir b/tests/mir-opt/retag.box_to_raw_mut.SimplifyCfg-pre-optimizations.after.panic-unwind.mir
index ca02e7b49cccd..da005d552e2bf 100644
--- a/tests/mir-opt/retag.box_to_raw_mut.SimplifyCfg-pre-optimizations.after.panic-unwind.mir
+++ b/tests/mir-opt/retag.box_to_raw_mut.SimplifyCfg-pre-optimizations.after.panic-unwind.mir
@@ -9,7 +9,7 @@ fn box_to_raw_mut(_1: &mut Box<i32>) -> *mut i32 {
     bb0: {
         Retag([fn entry] _1);
         _2 = deref_copy (*_1);
-        _3 = copy (((_2.0: std::ptr::Unique<i32>).0: std::ptr::NonNull<i32>).0: *const i32);
+        _3 = copy ((_2.0: std::ptr::Unique<i32>).0: std::ptr::NonNull<i32>) as *const i32 (Transmute);
         _0 = &raw mut (*_3);
         Retag([raw] _0);
         return;