Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/analyze/local_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Comment on lines +421 to +422

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Restrict copy unelaboration to actual deref temps

Projected copies are not exclusive to GVN-generated deref temps: rustc also emits them for ordinary mutable bindings such as let mut r = &mut *w.a. If r is later reassigned from w.b, ReplacePlacesVisitor retains the permanent r -> w.a replacement, so the reassignment's destination is rewritten into w.a itself. For a borrowed aggregate this makes Thrust analyze the function as changing the caller's reference field even though the real program only reassigns a local, which can corrupt post-state constraints and accept an invalid assertion or reject a valid one. Check that lhs_local is marked as a DerefTemp rather than classifying every projected &mut copy.

Useful? React with 👍 / 👎.

}
}

let unique_did = self.ctx.def_ids.unique()?;
let nonnull_did = self.ctx.def_ids.nonnull()?;

Expand Down
13 changes: 13 additions & 0 deletions tests/ui/fail/mut_ref_deref_optimized.rs
Original file line number Diff line number Diff line change
@@ -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);
}
13 changes: 13 additions & 0 deletions tests/ui/pass/mut_ref_deref_optimized.rs
Original file line number Diff line number Diff line change
@@ -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);
}
Loading