From 9fca04db59c1198347ad4dd897d55ac1e31b1488 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 28 Oct 2026 21:55:38 +0000 Subject: [PATCH] Unelaborate deref temps in reverse postorder unelaborate_derefs visited blocks in index order, recording a deref temp's replacement only when it reached the defining statement. Drop elaboration can number a cleanup block that uses a box-deref temp before the cleanup block that defines it (the unwind path dropping a box's contents after `*b` is moved out). That use was left in place while its definition became a Nop, so the temp's `*const T` type was live up to the function entry and building block templates panicked with `unrefined_ty: *const T`. Visit blocks in reverse postorder, where a temp's defining block, which dominates its uses, always comes first. Fixes #357 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Hw71PvwhBTUpfmvDdSGkXL --- src/analyze/local_def.rs | 8 ++++++-- tests/ui/fail/box_move_out_after_call.rs | 12 ++++++++++++ tests/ui/pass/box_move_out_after_call.rs | 12 ++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 tests/ui/fail/box_move_out_after_call.rs create mode 100644 tests/ui/pass/box_move_out_after_call.rs diff --git a/src/analyze/local_def.rs b/src/analyze/local_def.rs index 6a9cdf1b5..7f0b8beb7 100644 --- a/src/analyze/local_def.rs +++ b/src/analyze/local_def.rs @@ -461,8 +461,12 @@ impl<'tcx, 'ctx> Analyzer<'tcx, 'ctx> { fn unelaborate_derefs(&mut self) { let mut v = analyze::ReplacePlacesVisitor::new(self.tcx); - for (block, data) in self.body.basic_blocks.clone().iter_enumerated() { - for (idx, _stmt) in data.statements.iter().enumerate() { + // A deref temp must be replaced in every block that uses it, and block indices do not + // follow dominance: drop elaboration can number a cleanup block before the one that + // defines the temp it uses. + for block in self.body.basic_blocks.reverse_postorder().to_vec() { + let statement_count = self.body.basic_blocks[block].statements.len(); + for idx in 0..statement_count { let stmt = &mut self.body.basic_blocks.as_mut().as_mut_slice()[block].statements[idx]; v.visit_statement(stmt); diff --git a/tests/ui/fail/box_move_out_after_call.rs b/tests/ui/fail/box_move_out_after_call.rs new file mode 100644 index 000000000..a3830ad59 --- /dev/null +++ b/tests/ui/fail/box_move_out_after_call.rs @@ -0,0 +1,12 @@ +//@error-in-other-file: Unsat +//@compile-flags: -C debug-assertions=off + +fn add(bb: Box>, x: i64) -> i64 { + let c = Box::new(x); + let inner = *bb; + *inner + *c +} + +fn main() { + assert!(add(Box::new(Box::new(1)), 2) == 4); +} diff --git a/tests/ui/pass/box_move_out_after_call.rs b/tests/ui/pass/box_move_out_after_call.rs new file mode 100644 index 000000000..66bb2d8fe --- /dev/null +++ b/tests/ui/pass/box_move_out_after_call.rs @@ -0,0 +1,12 @@ +//@check-pass +//@compile-flags: -C debug-assertions=off + +fn add(bb: Box>, x: i64) -> i64 { + let c = Box::new(x); + let inner = *bb; + *inner + *c +} + +fn main() { + assert!(add(Box::new(Box::new(1)), 2) == 3); +}