diff --git a/src/analyze/local_def.rs b/src/analyze/local_def.rs index 6a9cdf1b..6e9acc38 100644 --- a/src/analyze/local_def.rs +++ b/src/analyze/local_def.rs @@ -415,6 +415,14 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> { return Some((lhs_local, *place)); } + // GVN rewrites the deref temp of a `&mut` from `deref_copy` into a plain `copy`. + if let mir::Rvalue::Use(mir::Operand::Copy(place)) = &rvalue { + let ty = place.ty(&self.body.local_decls, self.tcx).ty; + if !place.projection.is_empty() && ty.ref_mutability() == Some(mir::Mutability::Mut) { + return Some((lhs_local, *place)); + } + } + let unique_did = self.ctx.def_ids.unique()?; let nonnull_did = self.ctx.def_ids.nonnull()?; diff --git a/tests/ui/fail/mut_ref_deref_optimized.rs b/tests/ui/fail/mut_ref_deref_optimized.rs new file mode 100644 index 00000000..8b092d39 --- /dev/null +++ b/tests/ui/fail/mut_ref_deref_optimized.rs @@ -0,0 +1,13 @@ +//@error-in-other-file: Unsat +//@compile-flags: -C debug-assertions=off -C opt-level=1 + +fn bump(w: &mut &mut i64) { + **w += 3; +} + +fn main() { + let mut a = 0; + let mut r = &mut a; + bump(&mut r); + assert!(a == 0); +} diff --git a/tests/ui/pass/mut_ref_deref_optimized.rs b/tests/ui/pass/mut_ref_deref_optimized.rs new file mode 100644 index 00000000..1fe48759 --- /dev/null +++ b/tests/ui/pass/mut_ref_deref_optimized.rs @@ -0,0 +1,13 @@ +//@check-pass +//@compile-flags: -C debug-assertions=off -C opt-level=1 + +fn bump(w: &mut &mut i64) { + **w += 3; +} + +fn main() { + let mut a = 0; + let mut r = &mut a; + bump(&mut r); + assert!(a == 3); +}