From f6fc2bbe558e1a3b8838f0f541cba1e45b153049 Mon Sep 17 00:00:00 2001 From: beepster4096 <19316085+beepster4096@users.noreply.github.com> Date: Wed, 13 Aug 2025 02:09:20 -0700 Subject: [PATCH 1/2] remove DerefTemp and CopyFromDeref from runtime mir --- compiler/rustc_borrowck/src/lib.rs | 20 +------ .../src/polonius/legacy/loan_invalidations.rs | 7 +-- compiler/rustc_codegen_cranelift/src/base.rs | 6 +-- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 4 +- .../src/check_consts/qualifs.rs | 2 +- .../rustc_const_eval/src/interpret/step.rs | 5 +- compiler/rustc_middle/src/mir/syntax.rs | 2 + compiler/rustc_mir_transform/src/copy_prop.rs | 9 ++-- .../src/dataflow_const_prop.rs | 11 +--- compiler/rustc_mir_transform/src/dest_prop.rs | 5 +- .../src/erase_deref_temps.rs | 41 ++++++++++++++ compiler/rustc_mir_transform/src/gvn.rs | 7 +-- .../rustc_mir_transform/src/jump_threading.rs | 1 - compiler/rustc_mir_transform/src/lib.rs | 3 ++ compiler/rustc_mir_transform/src/ref_prop.rs | 3 +- .../src/shim/async_destructor_ctor.rs | 8 +-- compiler/rustc_mir_transform/src/ssa.rs | 4 +- compiler/rustc_mir_transform/src/validate.rs | 53 +++++++++++++++---- 18 files changed, 112 insertions(+), 79 deletions(-) create mode 100644 compiler/rustc_mir_transform/src/erase_deref_temps.rs diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index d76d6a04e6e03..7900f1b0cd877 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1473,24 +1473,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { self.consume_operand(location, (operand, span), state) } - &Rvalue::CopyForDeref(place) => { - self.access_place( - location, - (place, span), - (Deep, Read(ReadKind::Copy)), - LocalMutationIsAllowed::No, - state, - ); - - // Finally, check if path was already moved. - self.check_if_path_or_subpath_is_moved( - location, - InitializationRequiringAction::Use, - (place.as_ref(), span), - state, - ); - } - &(Rvalue::Len(place) | Rvalue::Discriminant(place)) => { let af = match *rvalue { Rvalue::Len(..) => Some(ArtificialField::ArrayLength), @@ -1553,6 +1535,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { Rvalue::WrapUnsafeBinder(op, _) => { self.consume_operand(location, (op, span), state); } + + Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in borrowck"), } } diff --git a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs index 99dd0b2dd4664..7d9c90ef9a04b 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs @@ -301,11 +301,6 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> { | Rvalue::Cast(_ /*cast_kind*/, operand, _ /*ty*/) | Rvalue::ShallowInitBox(operand, _ /*ty*/) => self.consume_operand(location, operand), - &Rvalue::CopyForDeref(place) => { - let op = &Operand::Copy(place); - self.consume_operand(location, op); - } - &(Rvalue::Len(place) | Rvalue::Discriminant(place)) => { let af = match rvalue { Rvalue::Len(..) => Some(ArtificialField::ArrayLength), @@ -336,6 +331,8 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> { Rvalue::WrapUnsafeBinder(op, _) => { self.consume_operand(location, op); } + + Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in borrowck"), } } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index bc0a0f034b236..b50315a0f2c3f 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -601,11 +601,6 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt: let val = codegen_operand(fx, operand); lval.write_cvalue(fx, val); } - Rvalue::CopyForDeref(place) => { - let cplace = codegen_place(fx, place); - let val = cplace.to_cvalue(fx); - lval.write_cvalue(fx, val) - } Rvalue::Ref(_, _, place) | Rvalue::RawPtr(_, place) => { let place = codegen_place(fx, place); let ref_ = place.place_ref(fx, lval.layout()); @@ -935,6 +930,7 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt: let operand = codegen_operand(fx, operand); lval.write_cvalue_transmute(fx, operand); } + Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in codegen"), } } StatementKind::StorageLive(_) diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 8a67b8d6e5f13..29c344fa6d9d2 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -494,9 +494,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.codegen_place_to_pointer(bx, place, mk_ref) } - mir::Rvalue::CopyForDeref(place) => { - self.codegen_operand(bx, &mir::Operand::Copy(place)) - } mir::Rvalue::RawPtr(kind, place) => { let mk_ptr = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| { Ty::new_ptr(tcx, ty, kind.to_mutbl_lossy()) @@ -740,6 +737,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let layout = bx.cx().layout_of(binder_ty); OperandRef { val: operand.val, layout } } + mir::Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in codegen"), } } diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index faf41f1658b70..1fcb13a076572 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -236,7 +236,7 @@ where in_place::(cx, in_local, place.as_ref()) } - Rvalue::CopyForDeref(place) => in_place::(cx, in_local, place.as_ref()), + Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in runtime MIR"), Rvalue::Use(operand) | Rvalue::Repeat(operand, _) diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 76e470b69dce3..cb25b04975913 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -185,10 +185,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.copy_op(&op, &dest)?; } - CopyForDeref(place) => { - let op = self.eval_place_to_op(place, Some(dest.layout))?; - self.copy_op(&op, &dest)?; - } + CopyForDeref(_) => bug!("`CopyForDeref` in runtime MIR"), BinaryOp(bin_op, box (ref left, ref right)) => { let layout = util::binop_left_homogeneous(bin_op).then_some(dest.layout); diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 6039a03aa29de..778f0b7d6b10e 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -130,7 +130,9 @@ pub enum RuntimePhase { /// * [`TerminatorKind::Yield`] /// * [`TerminatorKind::CoroutineDrop`] /// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array` + /// * [`Rvalue::CopyForDeref`] /// * [`PlaceElem::OpaqueCast`] + /// * [`LocalInfo::DerefTemp`] /// /// And the following variants are allowed: /// * [`StatementKind::Retag`] diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs index cddeefca68174..e3b47611e7413 100644 --- a/compiler/rustc_mir_transform/src/copy_prop.rs +++ b/compiler/rustc_mir_transform/src/copy_prop.rs @@ -74,9 +74,7 @@ fn fully_moved_locals(ssa: &SsaLocals, body: &Body<'_>) -> DenseBitSet { let mut fully_moved = DenseBitSet::new_filled(body.local_decls.len()); for (_, rvalue, _) in ssa.assignments(body) { - let (Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) - | Rvalue::CopyForDeref(place)) = rvalue - else { + let Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) = rvalue else { continue; }; @@ -85,7 +83,7 @@ fn fully_moved_locals(ssa: &SsaLocals, body: &Body<'_>) -> DenseBitSet { continue; } - if let Rvalue::Use(Operand::Copy(_)) | Rvalue::CopyForDeref(_) = rvalue { + if let Rvalue::Use(Operand::Copy(_)) = rvalue { fully_moved.remove(rhs); } } @@ -146,8 +144,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { // Do not leave tautological assignments around. if let StatementKind::Assign(box (lhs, ref rhs)) = stmt.kind - && let Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)) | Rvalue::CopyForDeref(rhs) = - *rhs + && let Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)) = *rhs && lhs == rhs { stmt.make_nop(); diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index fe53de31f7583..e17c7e3ca015b 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -309,12 +309,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { self.assign_operand(state, target, operand); } } - Rvalue::CopyForDeref(rhs) => { - state.flood(target.as_ref(), &self.map); - if let Some(target) = self.map.find(target.as_ref()) { - self.assign_operand(state, target, &Operand::Copy(*rhs)); - } - } + Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in runtime MIR"), Rvalue::Aggregate(kind, operands) => { // If we assign `target = Enum::Variant#0(operand)`, // we must make sure that all `target as Variant#i` are `Top`. @@ -492,9 +487,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { } Rvalue::Discriminant(place) => state.get_discr(place.as_ref(), &self.map), Rvalue::Use(operand) => return self.handle_operand(operand, state), - Rvalue::CopyForDeref(place) => { - return self.handle_operand(&Operand::Copy(*place), state); - } + Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in runtime MIR"), Rvalue::Ref(..) | Rvalue::RawPtr(..) => { // We don't track such places. return ValueOrPlace::TOP; diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 4c94a6c524e00..445ac595d79de 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -317,8 +317,7 @@ impl<'tcx> MutVisitor<'tcx> for Merger<'tcx> { match &statement.kind { StatementKind::Assign(box (dest, rvalue)) => { match rvalue { - Rvalue::CopyForDeref(place) - | Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) => { + Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) => { // These might've been turned into self-assignments by the replacement // (this includes the original statement we wanted to eliminate). if dest == place { @@ -751,7 +750,7 @@ impl<'tcx> Visitor<'tcx> for FindAssignments<'_, 'tcx> { fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) { if let StatementKind::Assign(box ( lhs, - Rvalue::CopyForDeref(rhs) | Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)), + Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)), )) = &statement.kind { let Some((src, dest)) = places_to_candidate_pair(*lhs, *rhs, self.body) else { diff --git a/compiler/rustc_mir_transform/src/erase_deref_temps.rs b/compiler/rustc_mir_transform/src/erase_deref_temps.rs new file mode 100644 index 0000000000000..ee0c7715c3cb5 --- /dev/null +++ b/compiler/rustc_mir_transform/src/erase_deref_temps.rs @@ -0,0 +1,41 @@ +//! This pass converts all `DerefTemp` locals into normal temporaries +//! and turns their `CopyForDeref` rvalues into normal copies. + +use rustc_middle::mir::visit::MutVisitor; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; + +struct EraseDerefTempsVisitor<'tcx> { + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> MutVisitor<'tcx> for EraseDerefTempsVisitor<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, _: Location) { + if let &mut Rvalue::CopyForDeref(place) = rvalue { + *rvalue = Rvalue::Use(Operand::Copy(place)) + } + } + + fn visit_local_decl(&mut self, _: Local, local_decl: &mut LocalDecl<'tcx>) { + if local_decl.is_deref_temp() { + let info = local_decl.local_info.as_mut().unwrap_crate_local(); + **info = LocalInfo::Boring; + } + } +} + +pub(super) struct EraseDerefTemps; + +impl<'tcx> crate::MirPass<'tcx> for EraseDerefTemps { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + EraseDerefTempsVisitor { tcx }.visit_body_preserves_cfg(body); + } + + fn is_required(&self) -> bool { + true + } +} diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 952da2cdf7253..fe4ae5ee6ab6f 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -831,12 +831,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let value = match *rvalue { // Forward values. Rvalue::Use(ref mut operand) => return self.simplify_operand(operand, location), - Rvalue::CopyForDeref(place) => { - let mut operand = Operand::Copy(place); - let val = self.simplify_operand(&mut operand, location); - *rvalue = Rvalue::Use(operand); - return val; - } // Roots. Rvalue::Repeat(ref mut op, amount) => { @@ -879,6 +873,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // Unsupported values. Rvalue::ThreadLocalRef(..) | Rvalue::ShallowInitBox(..) => return None, + Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in runtime MIR"), }; let ty = rvalue.ty(self.local_decls, self.tcx); Some(self.insert(ty, value)) diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index f9e642e28ebd7..61363d9489ecf 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -455,7 +455,6 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { match rhs { Rvalue::Use(operand) => self.process_operand(bb, lhs, operand, state), // Transfer the conditions on the copy rhs. - Rvalue::CopyForDeref(rhs) => self.process_operand(bb, lhs, &Operand::Copy(*rhs), state), Rvalue::Discriminant(rhs) => { let Some(rhs) = self.map.find_discr(rhs.as_ref()) else { return }; state.insert_place_idx(rhs, lhs, &self.map); diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 08f25276cecc1..9b6bc39b46a94 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -137,6 +137,7 @@ declare_passes! { mod dest_prop : DestinationPropagation; pub mod dump_mir : Marker; mod early_otherwise_branch : EarlyOtherwiseBranch; + mod erase_deref_temps : EraseDerefTemps; mod elaborate_box_derefs : ElaborateBoxDerefs; mod elaborate_drops : ElaborateDrops; mod function_item_references : FunctionItemReferences; @@ -616,6 +617,8 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // Otherwise it should run fairly late, but before optimizations begin. &add_retag::AddRetag, &elaborate_box_derefs::ElaborateBoxDerefs, + // `EraseDerefTemps` needs to run before `StateTransform`. + &erase_deref_temps::EraseDerefTemps, &coroutine::StateTransform, &Lint(known_panics_lint::KnownPanicsLint), ]; diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs index d1c2d6b508f2f..9826b263c31b9 100644 --- a/compiler/rustc_mir_transform/src/ref_prop.rs +++ b/compiler/rustc_mir_transform/src/ref_prop.rs @@ -214,8 +214,7 @@ fn compute_replacement<'tcx>( // This is a copy, just use the value we have in store for the previous one. // As we are visiting in `assignment_order`, ie. reverse postorder, `rhs` should // have been visited before. - Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) - | Rvalue::CopyForDeref(place) => { + Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) => { if let Some(rhs) = place.as_local() && ssa.is_ssa(rhs) { diff --git a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs index 18d09473c191e..a0f1260cd986d 100644 --- a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs +++ b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs @@ -240,7 +240,7 @@ fn build_adrop_for_coroutine_shim<'tcx>( source_info, StatementKind::Assign(Box::new(( Place::from(proxy_ref_local), - Rvalue::CopyForDeref(proxy_ref_place), + Rvalue::Use(Operand::Copy(proxy_ref_place)), ))), ), ); @@ -261,7 +261,7 @@ fn build_adrop_for_coroutine_shim<'tcx>( source_info, StatementKind::Assign(Box::new(( Place::from(cor_ptr_local), - Rvalue::CopyForDeref(impl_ptr_place), + Rvalue::Use(Operand::Copy(impl_ptr_place)), ))), ), ); @@ -334,7 +334,7 @@ fn build_adrop_for_adrop_shim<'tcx>( source_info, StatementKind::Assign(Box::new(( Place::from(proxy_ref_local), - Rvalue::CopyForDeref(proxy_ref_place), + Rvalue::Use(Operand::Copy(proxy_ref_place)), ))), )); @@ -350,7 +350,7 @@ fn build_adrop_for_adrop_shim<'tcx>( source_info, StatementKind::Assign(Box::new(( Place::from(cor_ptr_local), - Rvalue::CopyForDeref(impl_ptr_place), + Rvalue::Use(Operand::Copy(impl_ptr_place)), ))), )); } diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs index cd9a7f4a39dfe..3902eeac9b65a 100644 --- a/compiler/rustc_mir_transform/src/ssa.rs +++ b/compiler/rustc_mir_transform/src/ssa.rs @@ -295,9 +295,7 @@ fn compute_copy_classes(ssa: &mut SsaLocals, body: &Body<'_>) { let mut copies = IndexVec::from_fn_n(|l| l, body.local_decls.len()); for (local, rvalue, _) in ssa.assignments(body) { - let (Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) - | Rvalue::CopyForDeref(place)) = rvalue - else { + let Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) = rvalue else { continue; }; diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 99e4782e4700c..c667848d7eadb 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -9,7 +9,7 @@ use rustc_index::bit_set::DenseBitSet; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::{Obligation, ObligationCause}; use rustc_middle::mir::coverage::CoverageKind; -use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor}; +use rustc_middle::mir::visit::{MutatingUseContext, NonUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::print::with_no_trimmed_paths; @@ -922,6 +922,19 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } + if self.body.local_decls[place.local].is_deref_temp() + && !place.is_indirect_first_projection() + { + if cntxt != PlaceContext::MutatingUse(MutatingUseContext::Store) + || place.as_local().is_none() + { + self.fail( + location, + format!("`DerefTemp` locals must only be dereferenced or directly assigned to"), + ); + } + } + self.super_place(place, cntxt, location); } @@ -934,7 +947,12 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { }; } match rvalue { - Rvalue::Use(_) | Rvalue::CopyForDeref(_) => {} + Rvalue::Use(_) => {} + Rvalue::CopyForDeref(_) => { + if self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial) { + self.fail(location, "`CopyForDeref` should have been removed in runtime MIR"); + } + } Rvalue::Aggregate(kind, fields) => match **kind { AggregateKind::Tuple => {} AggregateKind::Array(dest) => { @@ -1432,13 +1450,12 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ), ); } - if let Rvalue::CopyForDeref(place) = rvalue { - if place.ty(&self.body.local_decls, self.tcx).ty.builtin_deref(true).is_none() { - self.fail( - location, - "`CopyForDeref` should only be used for dereferenceable types", - ) - } + + if let Some(local) = dest.as_local() + && self.body.local_decls[local].is_deref_temp() + && !matches!(rvalue, Rvalue::CopyForDeref(_)) + { + self.fail(location, "assignment to a `DerefTemp` must use `CopyForDeref`") } } StatementKind::AscribeUserType(..) => { @@ -1610,4 +1627,22 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.super_terminator(terminator, location); } + + fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) { + if local_decl.is_deref_temp() { + if self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial) { + self.fail( + START_BLOCK.start_location(), + "`DerefTemp` should have been removed in runtime MIR", + ); + } else if local_decl.ty.builtin_deref(true).is_none() { + self.fail( + START_BLOCK.start_location(), + "`DerefTemp` should only be used for dereferenceable types", + ) + } + } + + self.super_local_decl(local, local_decl); + } } From 37a752961beb94086b8c9ddb558634cdeb52e4ef Mon Sep 17 00:00:00 2001 From: beepster4096 <19316085+beepster4096@users.noreply.github.com> Date: Wed, 13 Aug 2025 02:23:35 -0700 Subject: [PATCH 2/2] store underefer info in dereftemp --- compiler/rustc_borrowck/src/def_use.rs | 3 +- compiler/rustc_middle/src/mir/mod.rs | 4 +- compiler/rustc_middle/src/mir/visit.rs | 21 +++++++- .../src/move_paths/builder.rs | 13 ++--- compiler/rustc_mir_dataflow/src/un_derefer.rs | 13 +++++ .../src/deref_separator.rs | 11 ++-- compiler/rustc_mir_transform/src/validate.rs | 51 +++++++++++++++---- 7 files changed, 89 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_borrowck/src/def_use.rs b/compiler/rustc_borrowck/src/def_use.rs index b9ced81c46c19..20301a1a93e17 100644 --- a/compiler/rustc_borrowck/src/def_use.rs +++ b/compiler/rustc_borrowck/src/def_use.rs @@ -80,7 +80,8 @@ pub(crate) fn categorize(context: PlaceContext) -> Option { // Backwards incompatible drop hint is not a use, just a marker for linting. PlaceContext::NonUse(NonUseContext::BackwardIncompatibleDropHint) => None, - PlaceContext::MutatingUse(MutatingUseContext::Deinit | MutatingUseContext::SetDiscriminant) => { + PlaceContext::MutatingUse(MutatingUseContext::Deinit | MutatingUseContext::SetDiscriminant) | + PlaceContext::NonUse(NonUseContext::DerefTempDecl) => { bug!("These statements are not allowed in this MIR phase") } } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index c55c7fc6002c7..2d75d09dd6d03 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1110,7 +1110,7 @@ pub enum LocalInfo<'tcx> { /// and subject to Edition 2024 temporary lifetime rules IfThenRescopeTemp { if_then: HirId }, /// A temporary created during the pass `Derefer` to avoid it's retagging - DerefTemp, + DerefTemp { alias_for: Place<'tcx> }, /// A temporary created for borrow checking. FakeBorrow, /// A local without anything interesting about it. @@ -1191,7 +1191,7 @@ impl<'tcx> LocalDecl<'tcx> { /// Returns `true` if this is a DerefTemp pub fn is_deref_temp(&self) -> bool { match self.local_info() { - LocalInfo::DerefTemp => true, + LocalInfo::DerefTemp { .. } => true, _ => false, } } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 42a68b29ec754..25d0f9cede71e 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -864,7 +864,7 @@ macro_rules! make_mir_visitor { ty, user_ty, source_info, - local_info: _, + local_info, } = local_decl; self.visit_source_info(source_info); @@ -878,6 +878,17 @@ macro_rules! make_mir_visitor { self.visit_user_type_projection(user_ty); } } + + let location = Location::START; + + // FIXME: ? + if let ClearCrossCrate::Set(box LocalInfo::DerefTemp { alias_for }) = local_info { + self.visit_place( + alias_for, + PlaceContext::NonUse(NonUseContext::DerefTempDecl), + location + ); + } } fn super_local( @@ -1373,6 +1384,8 @@ pub enum NonUseContext { VarDebugInfo, /// A `BackwardIncompatibleDropHint` statement, meant for edition 2024 lints. BackwardIncompatibleDropHint, + /// `LocalInfo::DerefTemp` + DerefTempDecl, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -1448,7 +1461,11 @@ impl PlaceContext { match self { PlaceContext::MutatingUse(_) => ty::Invariant, PlaceContext::NonUse( - StorageDead | StorageLive | VarDebugInfo | BackwardIncompatibleDropHint, + StorageDead + | StorageLive + | VarDebugInfo + | BackwardIncompatibleDropHint + | DerefTempDecl, ) => ty::Invariant, PlaceContext::NonMutatingUse( Inspect | Copy | Move | PlaceMention | SharedBorrow | FakeBorrow | RawBorrow diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 8bbc89fdcecb7..89a1995f42faf 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -12,6 +12,7 @@ use super::{ Init, InitIndex, InitKind, InitLocation, LocationMap, LookupResult, MoveData, MoveOut, MoveOutIndex, MovePath, MovePathIndex, MovePathLookup, }; +use crate::un_derefer::UnDerefer; struct MoveDataBuilder<'a, 'tcx, F> { body: &'a Body<'tcx>, @@ -58,7 +59,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { rev_lookup: MovePathLookup { locals, projections: Default::default(), - un_derefer: Default::default(), + un_derefer: UnDerefer::from_local_decls(&body.local_decls), }, move_paths, path_map, @@ -342,15 +343,15 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { fn gather_statement(&mut self, stmt: &Statement<'tcx>) { debug!("gather_statement({:?}, {:?})", self.loc, stmt); match &stmt.kind { - StatementKind::Assign(box (place, Rvalue::CopyForDeref(reffed))) => { + StatementKind::Assign(box (place, Rvalue::CopyForDeref(_reffed))) => { let local = place.as_local().unwrap(); assert!(self.body.local_decls[local].is_deref_temp()); - let rev_lookup = &mut self.data.rev_lookup; + //let rev_lookup = &mut self.data.rev_lookup; - rev_lookup.un_derefer.insert(local, reffed.as_ref()); - let base_local = rev_lookup.un_derefer.deref_chain(local).first().unwrap().local; - rev_lookup.locals[local] = rev_lookup.locals[base_local]; + //rev_lookup.un_derefer.insert(local, reffed.as_ref()); + //let base_local = rev_lookup.un_derefer.deref_chain(local).first().unwrap().local; + //rev_lookup.locals[local] = rev_lookup.locals[base_local]; } StatementKind::Assign(box (place, rval)) => { self.create_move_path(*place); diff --git a/compiler/rustc_mir_dataflow/src/un_derefer.rs b/compiler/rustc_mir_dataflow/src/un_derefer.rs index b38dd9d40f521..fc11f7d77e525 100644 --- a/compiler/rustc_mir_dataflow/src/un_derefer.rs +++ b/compiler/rustc_mir_dataflow/src/un_derefer.rs @@ -8,6 +8,19 @@ pub(crate) struct UnDerefer<'tcx> { } impl<'tcx> UnDerefer<'tcx> { + #[inline] + pub(crate) fn from_local_decls(local_decls: &LocalDecls<'tcx>) -> Self { + let mut this = Self::default(); + + for (local, decl) in local_decls.iter_enumerated() { + if let LocalInfo::DerefTemp { alias_for } = decl.local_info() { + this.insert(local, alias_for.as_ref()); + } + } + + this + } + #[inline] pub(crate) fn insert(&mut self, local: Local, reffed: PlaceRef<'tcx>) { let mut chain = self.deref_chains.remove(&reffed.local).unwrap_or_default(); diff --git a/compiler/rustc_mir_transform/src/deref_separator.rs b/compiler/rustc_mir_transform/src/deref_separator.rs index bc914ea656415..f8d58a4071d52 100644 --- a/compiler/rustc_mir_transform/src/deref_separator.rs +++ b/compiler/rustc_mir_transform/src/deref_separator.rs @@ -36,17 +36,18 @@ impl<'a, 'tcx> MutVisitor<'tcx> for DerefChecker<'a, 'tcx> { for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() { if !p_ref.projection.is_empty() && p_elem == ProjectionElem::Deref { let ty = p_ref.ty(self.local_decls, self.tcx).ty; - let temp = self.patcher.new_local_with_info( - ty, - self.local_decls[p_ref.local].source_info.span, - LocalInfo::DerefTemp, - ); // We are adding current p_ref's projections to our // temp value, excluding projections we already covered. let deref_place = Place::from(place_local) .project_deeper(&p_ref.projection[last_len..], self.tcx); + let temp = self.patcher.new_local_with_info( + ty, + self.local_decls[p_ref.local].source_info.span, + LocalInfo::DerefTemp { alias_for: deref_place }, + ); + self.patcher.add_assign( loc, Place::from(temp), diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index c667848d7eadb..1635ebb62713f 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1451,11 +1451,27 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } - if let Some(local) = dest.as_local() - && self.body.local_decls[local].is_deref_temp() - && !matches!(rvalue, Rvalue::CopyForDeref(_)) - { - self.fail(location, "assignment to a `DerefTemp` must use `CopyForDeref`") + if let Some(local) = dest.as_local() { + if let LocalInfo::DerefTemp { alias_for } = + self.body.local_decls[local].local_info() + { + if let Rvalue::CopyForDeref(place) = rvalue { + if place != alias_for { + self.fail( + location, + format!( + "Assigning `{place:?}` to `DerefTemp` that \ + should be alias for `{alias_for:?}`" + ), + ) + } + } else { + self.fail( + location, + "assignment to a `DerefTemp` must use `CopyForDeref`", + ) + } + } } } StatementKind::AscribeUserType(..) => { @@ -1629,17 +1645,30 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) { - if local_decl.is_deref_temp() { + if let LocalInfo::DerefTemp { alias_for } = local_decl.local_info() { if self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial) { self.fail( START_BLOCK.start_location(), "`DerefTemp` should have been removed in runtime MIR", ); - } else if local_decl.ty.builtin_deref(true).is_none() { - self.fail( - START_BLOCK.start_location(), - "`DerefTemp` should only be used for dereferenceable types", - ) + } else { + if local_decl.ty.builtin_deref(true).is_none() { + self.fail( + START_BLOCK.start_location(), + "`DerefTemp` should only be used for dereferenceable types", + ) + } + + let alias_for_ty = alias_for.ty(self.body, self.tcx).ty; + if local_decl.ty != alias_for_ty { + self.fail( + START_BLOCK.start_location(), + format!( + "type of `DerefTemp` ({:?}) doesn't match place it aliases ({:?})", + local_decl.ty, alias_for_ty + ), + ) + } } }