diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 936a7e2d9dedd..3dbdeb615cfe2 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1074,11 +1074,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { { lhs = *lhs_value; rhs = *rhs_value; - if let Some(op) = self.try_as_operand(lhs, location) { - *lhs_operand = op; - } - if let Some(op) = self.try_as_operand(rhs, location) { - *rhs_operand = op; + if let Some(lhs_op) = self.try_as_operand(lhs, location) + && let Some(rhs_op) = self.try_as_operand(rhs, location) + { + *lhs_operand = lhs_op; + *rhs_operand = rhs_op; } } diff --git a/tests/mir-opt/gvn.remove_casts_must_change_both_sides.GVN.panic-abort.diff b/tests/mir-opt/gvn.remove_casts_must_change_both_sides.GVN.panic-abort.diff new file mode 100644 index 0000000000000..8b4bfb70401b3 --- /dev/null +++ b/tests/mir-opt/gvn.remove_casts_must_change_both_sides.GVN.panic-abort.diff @@ -0,0 +1,16 @@ +- // MIR for `remove_casts_must_change_both_sides` before GVN ++ // MIR for `remove_casts_must_change_both_sides` after GVN + + fn remove_casts_must_change_both_sides(_1: &*mut u8, _2: *mut u8) -> bool { + let mut _0: bool; + let mut _3: *const u8; + let mut _4: *const u8; + + bb0: { + _3 = (*_1) as *const u8 (PtrToPtr); + _4 = _2 as *const u8 (PtrToPtr); + _0 = Eq(_3, _4); + return; + } + } + diff --git a/tests/mir-opt/gvn.remove_casts_must_change_both_sides.GVN.panic-unwind.diff b/tests/mir-opt/gvn.remove_casts_must_change_both_sides.GVN.panic-unwind.diff new file mode 100644 index 0000000000000..8b4bfb70401b3 --- /dev/null +++ b/tests/mir-opt/gvn.remove_casts_must_change_both_sides.GVN.panic-unwind.diff @@ -0,0 +1,16 @@ +- // MIR for `remove_casts_must_change_both_sides` before GVN ++ // MIR for `remove_casts_must_change_both_sides` after GVN + + fn remove_casts_must_change_both_sides(_1: &*mut u8, _2: *mut u8) -> bool { + let mut _0: bool; + let mut _3: *const u8; + let mut _4: *const u8; + + bb0: { + _3 = (*_1) as *const u8 (PtrToPtr); + _4 = _2 as *const u8 (PtrToPtr); + _0 = Eq(_3, _4); + return; + } + } + diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs index 86f42d23f3835..c7fae0bd08108 100644 --- a/tests/mir-opt/gvn.rs +++ b/tests/mir-opt/gvn.rs @@ -926,6 +926,25 @@ unsafe fn cast_pointer_then_transmute(thin: *mut u32, fat: *mut [u8]) { let fat_addr: usize = std::intrinsics::transmute(fat as *const ()); } +#[custom_mir(dialect = "analysis")] +fn remove_casts_must_change_both_sides(mut_a: &*mut u8, mut_b: *mut u8) -> bool { + // CHECK-LABEL: fn remove_casts_must_change_both_sides( + mir! { + // We'd like to remove these casts, but we can't change *both* of them + // to be locals, so make sure we don't change one without the other, as + // that would be a type error. + { + // CHECK: [[A:_.+]] = (*_1) as *const u8 (PtrToPtr); + let a = *mut_a as *const u8; + // CHECK: [[B:_.+]] = _2 as *const u8 (PtrToPtr); + let b = mut_b as *const u8; + // CHECK: _0 = Eq([[A]], [[B]]); + RET = a == b; + Return() + } + } +} + fn main() { subexpression_elimination(2, 4, 5); wrap_unwrap(5); @@ -995,3 +1014,4 @@ fn identity(x: T) -> T { // EMIT_MIR gvn.generic_cast_metadata.GVN.diff // EMIT_MIR gvn.cast_pointer_eq.GVN.diff // EMIT_MIR gvn.cast_pointer_then_transmute.GVN.diff +// EMIT_MIR gvn.remove_casts_must_change_both_sides.GVN.diff diff --git a/tests/mir-opt/gvn_ptr_eq_with_constant.main.GVN.diff b/tests/mir-opt/gvn_ptr_eq_with_constant.main.GVN.diff new file mode 100644 index 0000000000000..3af78d9b6ce98 --- /dev/null +++ b/tests/mir-opt/gvn_ptr_eq_with_constant.main.GVN.diff @@ -0,0 +1,52 @@ +- // MIR for `main` before GVN ++ // MIR for `main` after GVN + + fn main() -> () { + let mut _0: (); + let _1: bool; + let mut _2: *mut u8; + scope 1 (inlined dangling_mut::) { + let mut _3: usize; + scope 2 (inlined align_of::) { + } + scope 3 (inlined without_provenance_mut::) { + } + } + scope 4 (inlined Foo::::cmp_ptr) { + let mut _4: *const u8; + let mut _5: *mut u8; + let mut _6: *const u8; + scope 5 (inlined std::ptr::eq::) { + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + StorageLive(_3); +- _3 = AlignOf(u8); +- _2 = _3 as *mut u8 (Transmute); ++ _3 = const 1_usize; ++ _2 = const {0x1 as *mut u8}; + StorageDead(_3); + StorageLive(_4); + StorageLive(_5); +- _5 = _2; +- _4 = _2 as *const u8 (PtrToPtr); ++ _5 = const {0x1 as *mut u8}; ++ _4 = const {0x1 as *const u8}; + StorageDead(_5); + StorageLive(_6); +- _6 = const Foo::::SENTINEL as *const u8 (PtrToPtr); +- _1 = Eq(_4, _6); ++ _6 = const {0x1 as *const u8}; ++ _1 = const true; + StorageDead(_6); + StorageDead(_4); + StorageDead(_2); + StorageDead(_1); + _0 = const (); + return; + } + } + diff --git a/tests/mir-opt/gvn_ptr_eq_with_constant.rs b/tests/mir-opt/gvn_ptr_eq_with_constant.rs new file mode 100644 index 0000000000000..d8025072ee3d3 --- /dev/null +++ b/tests/mir-opt/gvn_ptr_eq_with_constant.rs @@ -0,0 +1,23 @@ +// skip-filecheck +//@ test-mir-pass: GVN +//@ only-64bit +//@ compile-flags: -Z mir-enable-passes=+Inline + +// Regression for + +#![feature(strict_provenance)] + +struct Foo(std::marker::PhantomData); + +impl Foo { + const SENTINEL: *mut T = std::ptr::dangling_mut(); + + fn cmp_ptr(a: *mut T) -> bool { + std::ptr::eq(a, Self::SENTINEL) + } +} + +// EMIT_MIR gvn_ptr_eq_with_constant.main.GVN.diff +pub fn main() { + Foo::::cmp_ptr(std::ptr::dangling_mut()); +}