From e3cbb4c1543402740c4378b69c9cca0aa94e0449 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 21:55:29 +0000 Subject: [PATCH] Borrow a pointer-typed field itself when replacing it ReborrowVisitor picked the Ref/Box arms from the type of the assigned place whenever it did not end in a Deref. For a Box- or &mut-typed struct or tuple field, that borrowed the field's pointee and rewrote `c.page = Box::new(5)` as a write through the old box, leaving the field typed as its pointee (and producing ill-sorted `mut>` terms for `c.r = r`). Take those arms only when a trailing Deref was stripped, so a field replacement borrows the field itself. Refs #267 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Q3oq9H8cDHT88svt78yAmn --- src/analyze/basic_block/visitor/reborrow.rs | 7 ++++--- tests/ui/fail/assign_box_field.rs | 16 ++++++++++++++++ tests/ui/pass/assign_box_field.rs | 16 ++++++++++++++++ 3 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 tests/ui/fail/assign_box_field.rs create mode 100644 tests/ui/pass/assign_box_field.rs diff --git a/src/analyze/basic_block/visitor/reborrow.rs b/src/analyze/basic_block/visitor/reborrow.rs index aa51bae2..ee8dcd5e 100644 --- a/src/analyze/basic_block/visitor/reborrow.rs +++ b/src/analyze/basic_block/visitor/reborrow.rs @@ -59,7 +59,8 @@ impl<'a, 'tcx, 'ctx> mir::visit::MutVisitor<'tcx> for ReborrowVisitor<'a, 'tcx, return; } - let inner_place = if place.projection.last() == Some(&mir::PlaceElem::Deref) { + let assigns_through_deref = place.projection.last() == Some(&mir::PlaceElem::Deref); + let inner_place = if assigns_through_deref { // *m = *m + 1 => m1 = &mut m; *m1 = *m + 1 let mut projection = place.projection.as_ref().to_vec(); projection.pop(); @@ -74,11 +75,11 @@ impl<'a, 'tcx, 'ctx> mir::visit::MutVisitor<'tcx> for ReborrowVisitor<'a, 'tcx, let ty = inner_place.ty(&self.analyzer.local_decls, self.tcx).ty; let (new_local, new_place) = match ty.kind() { - mir_ty::TyKind::Ref(_, inner_ty, m) if m.is_mut() => { + mir_ty::TyKind::Ref(_, inner_ty, m) if assigns_through_deref && m.is_mut() => { let new_local = self.insert_reborrow(*place, *inner_ty); (new_local, new_local.into()) } - mir_ty::TyKind::Adt(adt, args) if adt.is_box() => { + mir_ty::TyKind::Adt(adt, args) if assigns_through_deref && adt.is_box() => { let inner_ty = args.type_at(0); let new_local = self.insert_borrow(*place, inner_ty); (new_local, new_local.into()) diff --git a/tests/ui/fail/assign_box_field.rs b/tests/ui/fail/assign_box_field.rs new file mode 100644 index 00000000..742cef6d --- /dev/null +++ b/tests/ui/fail/assign_box_field.rs @@ -0,0 +1,16 @@ +//@error-in-other-file: Unsat +//@compile-flags: -C debug-assertions=off + +struct Cache { + page: Box, +} + +impl thrust_models::Model for Cache { + type Ty = Self; +} + +fn main() { + let mut c = Cache { page: Box::new(1) }; + c.page = Box::new(5); + assert!(*c.page == 1); +} diff --git a/tests/ui/pass/assign_box_field.rs b/tests/ui/pass/assign_box_field.rs new file mode 100644 index 00000000..4f9bd756 --- /dev/null +++ b/tests/ui/pass/assign_box_field.rs @@ -0,0 +1,16 @@ +//@check-pass +//@compile-flags: -C debug-assertions=off + +struct Cache { + page: Box, +} + +impl thrust_models::Model for Cache { + type Ty = Self; +} + +fn main() { + let mut c = Cache { page: Box::new(1) }; + c.page = Box::new(5); + assert!(*c.page == 5); +}