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(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(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 {