about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_middle/src/mir/tcx.rs14
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs28
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs19
-rw-r--r--tests/mir-opt/lower_array_len.array_bound.GVN.panic-abort.diff24
-rw-r--r--tests/mir-opt/lower_array_len.array_bound.GVN.panic-unwind.diff24
-rw-r--r--tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-abort.diff24
-rw-r--r--tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-unwind.diff24
-rw-r--r--tests/mir-opt/lower_array_len.rs12
8 files changed, 102 insertions, 67 deletions
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index 126387db1d9..412cfc1fc7a 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -289,19 +289,7 @@ impl<'tcx> UnOp {
     pub fn ty(&self, tcx: TyCtxt<'tcx>, arg_ty: Ty<'tcx>) -> Ty<'tcx> {
         match self {
             UnOp::Not | UnOp::Neg => arg_ty,
-            UnOp::PtrMetadata => {
-                let pointee_ty = arg_ty
-                    .builtin_deref(true)
-                    .unwrap_or_else(|| bug!("PtrMetadata of non-dereferenceable ty {arg_ty:?}"));
-                if pointee_ty.is_trivially_sized(tcx) {
-                    tcx.types.unit
-                } else {
-                    let Some(metadata_def_id) = tcx.lang_items().metadata_type() else {
-                        bug!("No metadata_type lang item while looking at {arg_ty:?}")
-                    };
-                    Ty::new_projection(tcx, metadata_def_id, [pointee_ty])
-                }
-            }
+            UnOp::PtrMetadata => arg_ty.pointee_metadata_ty_or_projection(tcx),
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 9c8a3484aa5..709c5fe2305 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1638,6 +1638,34 @@ impl<'tcx> Ty<'tcx> {
         }
     }
 
+    /// Given a pointer or reference type, returns the type of the *pointee*'s
+    /// metadata. If it can't be determined exactly (perhaps due to still
+    /// being generic) then a projection through `ptr::Pointee` will be returned.
+    ///
+    /// This is particularly useful for getting the type of the result of
+    /// [`UnOp::PtrMetadata`](crate::mir::UnOp::PtrMetadata).
+    ///
+    /// Panics if `self` is not dereferencable.
+    #[track_caller]
+    pub fn pointee_metadata_ty_or_projection(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
+        let Some(pointee_ty) = self.builtin_deref(true) else {
+            bug!("Type {self:?} is not a pointer or reference type")
+        };
+        if pointee_ty.is_trivially_sized(tcx) {
+            tcx.types.unit
+        } else {
+            match pointee_ty.ptr_metadata_ty_or_tail(tcx, |x| x) {
+                Ok(metadata_ty) => metadata_ty,
+                Err(tail_ty) => {
+                    let Some(metadata_def_id) = tcx.lang_items().metadata_type() else {
+                        bug!("No metadata_type lang item while looking at {self:?}")
+                    };
+                    Ty::new_projection(tcx, metadata_def_id, [tail_ty])
+                }
+            }
+        }
+    }
+
     /// When we create a closure, we record its kind (i.e., what trait
     /// it implements, constrained by how it uses its borrows) into its
     /// [`ty::ClosureArgs`] or [`ty::CoroutineClosureArgs`] using a type
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index bfdefd5a7d6..23124523f17 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -987,23 +987,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                     // `*const [T]` -> `*const T` which remove metadata.
                     // We run on potentially-generic MIR, though, so unlike codegen
                     // we can't always know exactly what the metadata are.
-                    // Thankfully, equality on `ptr_metadata_ty_or_tail` gives us
-                    // what we need: `Ok(meta_ty)` if the metadata is known, or
-                    // `Err(tail_ty)` if not. Matching metadata is ok, but if
-                    // that's not known, then matching tail types is also ok,
-                    // allowing things like `*mut (?A, ?T)` <-> `*mut (?B, ?T)`.
+                    // To allow things like `*mut (?A, ?T)` <-> `*mut (?B, ?T)`,
+                    // it's fine to get a projection as the type.
                     // FIXME: Would it be worth trying to normalize, rather than
-                    // passing the identity closure?  Or are the types in the
+                    // just accepting the projection?  Or are the types in the
                     // Cast realistically about as normalized as we can get anyway?
                     Value::Cast { kind: CastKind::PtrToPtr, value: inner, from, to }
-                        if from
-                            .builtin_deref(true)
-                            .unwrap()
-                            .ptr_metadata_ty_or_tail(self.tcx, |t| t)
-                            == to
-                                .builtin_deref(true)
-                                .unwrap()
-                                .ptr_metadata_ty_or_tail(self.tcx, |t| t) =>
+                        if from.pointee_metadata_ty_or_projection(self.tcx)
+                            == to.pointee_metadata_ty_or_projection(self.tcx) =>
                     {
                         arg_index = *inner;
                         was_updated = true;
diff --git a/tests/mir-opt/lower_array_len.array_bound.GVN.panic-abort.diff b/tests/mir-opt/lower_array_len.array_bound.GVN.panic-abort.diff
index 6c0c7a1d438..7aca2cb0007 100644
--- a/tests/mir-opt/lower_array_len.array_bound.GVN.panic-abort.diff
+++ b/tests/mir-opt/lower_array_len.array_bound.GVN.panic-abort.diff
@@ -15,10 +15,12 @@
       let mut _10: bool;
   
       bb0: {
-          StorageLive(_3);
+-         StorageLive(_3);
++         nop;
           StorageLive(_4);
           _4 = _1;
-          StorageLive(_5);
+-         StorageLive(_5);
++         nop;
           StorageLive(_6);
           StorageLive(_7);
           _7 = &(*_2);
@@ -32,12 +34,14 @@
       bb1: {
           StorageDead(_6);
 -         _3 = Lt(move _4, move _5);
-+         _3 = Lt(_1, move _5);
-          switchInt(move _3) -> [0: bb4, otherwise: bb2];
+-         switchInt(move _3) -> [0: bb4, otherwise: bb2];
++         _3 = Lt(_1, const N);
++         switchInt(_3) -> [0: bb4, otherwise: bb2];
       }
   
       bb2: {
-          StorageDead(_5);
+-         StorageDead(_5);
++         nop;
           StorageDead(_4);
           StorageLive(_8);
           _8 = _1;
@@ -45,8 +49,8 @@
 -         _10 = Lt(_8, _9);
 -         assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> [success: bb3, unwind unreachable];
 +         _9 = const N;
-+         _10 = Lt(_1, const N);
-+         assert(move _10, "index out of bounds: the length is {} but the index is {}", const N, _1) -> [success: bb3, unwind unreachable];
++         _10 = _3;
++         assert(_3, "index out of bounds: the length is {} but the index is {}", const N, _1) -> [success: bb3, unwind unreachable];
       }
   
       bb3: {
@@ -57,14 +61,16 @@
       }
   
       bb4: {
-          StorageDead(_5);
+-         StorageDead(_5);
++         nop;
           StorageDead(_4);
           _0 = const 42_u8;
           goto -> bb5;
       }
   
       bb5: {
-          StorageDead(_3);
+-         StorageDead(_3);
++         nop;
           return;
       }
   }
diff --git a/tests/mir-opt/lower_array_len.array_bound.GVN.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_bound.GVN.panic-unwind.diff
index ed41703c873..ed39c11319a 100644
--- a/tests/mir-opt/lower_array_len.array_bound.GVN.panic-unwind.diff
+++ b/tests/mir-opt/lower_array_len.array_bound.GVN.panic-unwind.diff
@@ -15,10 +15,12 @@
       let mut _10: bool;
   
       bb0: {
-          StorageLive(_3);
+-         StorageLive(_3);
++         nop;
           StorageLive(_4);
           _4 = _1;
-          StorageLive(_5);
+-         StorageLive(_5);
++         nop;
           StorageLive(_6);
           StorageLive(_7);
           _7 = &(*_2);
@@ -32,12 +34,14 @@
       bb1: {
           StorageDead(_6);
 -         _3 = Lt(move _4, move _5);
-+         _3 = Lt(_1, move _5);
-          switchInt(move _3) -> [0: bb4, otherwise: bb2];
+-         switchInt(move _3) -> [0: bb4, otherwise: bb2];
++         _3 = Lt(_1, const N);
++         switchInt(_3) -> [0: bb4, otherwise: bb2];
       }
   
       bb2: {
-          StorageDead(_5);
+-         StorageDead(_5);
++         nop;
           StorageDead(_4);
           StorageLive(_8);
           _8 = _1;
@@ -45,8 +49,8 @@
 -         _10 = Lt(_8, _9);
 -         assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> [success: bb3, unwind continue];
 +         _9 = const N;
-+         _10 = Lt(_1, const N);
-+         assert(move _10, "index out of bounds: the length is {} but the index is {}", const N, _1) -> [success: bb3, unwind continue];
++         _10 = _3;
++         assert(_3, "index out of bounds: the length is {} but the index is {}", const N, _1) -> [success: bb3, unwind continue];
       }
   
       bb3: {
@@ -57,14 +61,16 @@
       }
   
       bb4: {
-          StorageDead(_5);
+-         StorageDead(_5);
++         nop;
           StorageDead(_4);
           _0 = const 42_u8;
           goto -> bb5;
       }
   
       bb5: {
-          StorageDead(_3);
+-         StorageDead(_3);
++         nop;
           return;
       }
   }
diff --git a/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-abort.diff b/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-abort.diff
index 80e8ea37f41..734d28e9546 100644
--- a/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-abort.diff
+++ b/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-abort.diff
@@ -18,10 +18,12 @@
       let mut _13: bool;
   
       bb0: {
-          StorageLive(_3);
+-         StorageLive(_3);
++         nop;
           StorageLive(_4);
           _4 = _1;
-          StorageLive(_5);
+-         StorageLive(_5);
++         nop;
           StorageLive(_6);
           StorageLive(_7);
           _7 = &(*_2);
@@ -35,12 +37,14 @@
       bb1: {
           StorageDead(_6);
 -         _3 = Lt(move _4, move _5);
-+         _3 = Lt(_1, move _5);
-          switchInt(move _3) -> [0: bb4, otherwise: bb2];
+-         switchInt(move _3) -> [0: bb4, otherwise: bb2];
++         _3 = Lt(_1, const N);
++         switchInt(_3) -> [0: bb4, otherwise: bb2];
       }
   
       bb2: {
-          StorageDead(_5);
+-         StorageDead(_5);
++         nop;
           StorageDead(_4);
           StorageLive(_8);
           _8 = _1;
@@ -48,8 +52,8 @@
 -         _10 = Lt(_8, _9);
 -         assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> [success: bb3, unwind unreachable];
 +         _9 = const N;
-+         _10 = Lt(_1, const N);
-+         assert(move _10, "index out of bounds: the length is {} but the index is {}", const N, _1) -> [success: bb3, unwind unreachable];
++         _10 = _3;
++         assert(_3, "index out of bounds: the length is {} but the index is {}", const N, _1) -> [success: bb3, unwind unreachable];
       }
   
       bb3: {
@@ -60,7 +64,8 @@
       }
   
       bb4: {
-          StorageDead(_5);
+-         StorageDead(_5);
++         nop;
           StorageDead(_4);
           StorageLive(_11);
           _11 = const 0_usize;
@@ -81,7 +86,8 @@
       }
   
       bb6: {
-          StorageDead(_3);
+-         StorageDead(_3);
++         nop;
           return;
       }
   }
diff --git a/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-unwind.diff
index 6e67a6c17ef..ec569ab5042 100644
--- a/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-unwind.diff
+++ b/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-unwind.diff
@@ -18,10 +18,12 @@
       let mut _13: bool;
   
       bb0: {
-          StorageLive(_3);
+-         StorageLive(_3);
++         nop;
           StorageLive(_4);
           _4 = _1;
-          StorageLive(_5);
+-         StorageLive(_5);
++         nop;
           StorageLive(_6);
           StorageLive(_7);
           _7 = &(*_2);
@@ -35,12 +37,14 @@
       bb1: {
           StorageDead(_6);
 -         _3 = Lt(move _4, move _5);
-+         _3 = Lt(_1, move _5);
-          switchInt(move _3) -> [0: bb4, otherwise: bb2];
+-         switchInt(move _3) -> [0: bb4, otherwise: bb2];
++         _3 = Lt(_1, const N);
++         switchInt(_3) -> [0: bb4, otherwise: bb2];
       }
   
       bb2: {
-          StorageDead(_5);
+-         StorageDead(_5);
++         nop;
           StorageDead(_4);
           StorageLive(_8);
           _8 = _1;
@@ -48,8 +52,8 @@
 -         _10 = Lt(_8, _9);
 -         assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> [success: bb3, unwind continue];
 +         _9 = const N;
-+         _10 = Lt(_1, const N);
-+         assert(move _10, "index out of bounds: the length is {} but the index is {}", const N, _1) -> [success: bb3, unwind continue];
++         _10 = _3;
++         assert(_3, "index out of bounds: the length is {} but the index is {}", const N, _1) -> [success: bb3, unwind continue];
       }
   
       bb3: {
@@ -60,7 +64,8 @@
       }
   
       bb4: {
-          StorageDead(_5);
+-         StorageDead(_5);
++         nop;
           StorageDead(_4);
           StorageLive(_11);
           _11 = const 0_usize;
@@ -81,7 +86,8 @@
       }
   
       bb6: {
-          StorageDead(_3);
+-         StorageDead(_3);
++         nop;
           return;
       }
   }
diff --git a/tests/mir-opt/lower_array_len.rs b/tests/mir-opt/lower_array_len.rs
index caa598d067a..f7ed376726c 100644
--- a/tests/mir-opt/lower_array_len.rs
+++ b/tests/mir-opt/lower_array_len.rs
@@ -5,16 +5,20 @@
 // EMIT_MIR lower_array_len.array_bound.GVN.diff
 pub fn array_bound<const N: usize>(index: usize, slice: &[u8; N]) -> u8 {
     // CHECK-LABEL: fn array_bound(
-    // CHECK: [[len:_.*]] = const N;
-    // CHECK: Lt(_1, move [[len]]);
+    // CHECK-NOT: Lt
+    // CHECK: Lt(_1, const N);
+    // CHECK-NOT: Lt
     if index < slice.len() { slice[index] } else { 42 }
 }
 
 // EMIT_MIR lower_array_len.array_bound_mut.GVN.diff
 pub fn array_bound_mut<const N: usize>(index: usize, slice: &mut [u8; N]) -> u8 {
     // CHECK-LABEL: fn array_bound_mut(
-    // CHECK: [[len:_.*]] = const N;
-    // CHECK: Lt(_1, move [[len]]);
+    // CHECK-NOT: Lt
+    // CHECK: Lt(_1, const N);
+    // CHECK-NOT: Lt
+    // CHECK: Lt(const 0_usize, const N)
+    // CHECK-NOT: Lt
     if index < slice.len() {
         slice[index]
     } else {