From 8de72e4e8bc3ca13213e2b0d4d54823e0b09d51f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Mar 2024 18:55:28 +0100 Subject: [PATCH] interpret: avoid a long-lived PlaceTy in stack frames --- compiler/rustc_const_eval/src/interpret/eval_context.rs | 7 ++++--- compiler/rustc_const_eval/src/interpret/place.rs | 6 ++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index cb308ab53ecfb..a99620937ef98 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -108,7 +108,7 @@ pub struct Frame<'mir, 'tcx, Prov: Provenance = CtfeProvenance, Extra = ()> { /// The location where the result of the current stack frame should be written to, /// and its layout in the caller. - pub return_place: PlaceTy<'tcx, Prov>, + pub return_place: MPlaceTy<'tcx, Prov>, /// The list of locals for this stack frame, stored in order as /// `[return_ptr, arguments..., variables..., temporaries...]`. @@ -777,12 +777,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { trace!("body: {:#?}", body); let dead_local = LocalState { value: LocalValue::Dead, layout: Cell::new(None) }; let locals = IndexVec::from_elem(dead_local, &body.local_decls); + let return_place = self.force_allocation(return_place)?; // avoid a long-lived `PlaceTy` // First push a stack frame so we have access to the local args let pre_frame = Frame { body, loc: Right(body.span), // Span used for errors caused during preamble. return_to_block, - return_place: return_place.clone(), + return_place, locals, instance, tracing_span: SpanGuard::new(), @@ -912,7 +913,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } else { self.copy_op_allow_transmute(&op, &dest) }; - trace!("return value: {:?}", self.dump_place(&dest)); + trace!("return value: {:?}", self.dump_place(&dest.into())); // We delay actually short-circuiting on this error until *after* the stack frame is // popped, since we want this error to be attributed to the caller, whose type defines // this transmute. diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 6e987784ff9ee..330e9b28bb79b 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -194,6 +194,12 @@ pub(super) enum Place { Local { frame: usize, local: mir::Local, offset: Option }, } +/// An evaluated place, together with its type. +/// +/// This may reference a stack frame by its index, so `PlaceTy` should generally not be kept around +/// for longer than a single operation. Popping and then pushing a stack frame can make `PlaceTy` +/// point to the wrong destination. If the interpreter has multiple stacks, stack switching will +/// also invalidate a `PlaceTy`. #[derive(Clone)] pub struct PlaceTy<'tcx, Prov: Provenance = CtfeProvenance> { place: Place, // Keep this private; it helps enforce invariants.