diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index ae4ad49fe667f..02fce7dfb43c2 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -81,14 +81,9 @@ pub struct Frame<'mir, 'tcx, Tag = (), Extra = ()> { //////////////////////////////////////////////////////////////////////////////// // Current position within the function //////////////////////////////////////////////////////////////////////////////// - /// The block that is currently executed (or will be executed after the above call stacks - /// return). /// If this is `None`, we are unwinding and this function doesn't need any clean-up. /// Just continue the same as with `Resume`. - pub block: Option, - - /// The index of the currently evaluated statement. - pub stmt: usize, + pub loc: Option, } #[derive(Clone, Eq, PartialEq, Debug, HashStable)] // Miri debug-prints these @@ -168,8 +163,7 @@ impl<'mir, 'tcx, Tag> Frame<'mir, 'tcx, Tag> { return_to_block: self.return_to_block, return_place: self.return_place, locals: self.locals, - block: self.block, - stmt: self.stmt, + loc: self.loc, extra, } } @@ -178,10 +172,10 @@ impl<'mir, 'tcx, Tag> Frame<'mir, 'tcx, Tag> { impl<'mir, 'tcx, Tag, Extra> Frame<'mir, 'tcx, Tag, Extra> { /// Return the `SourceInfo` of the current instruction. pub fn current_source_info(&self) -> Option { - self.block.map(|block| { - let block = &self.body.basic_blocks()[block]; - if self.stmt < block.statements.len() { - block.statements[self.stmt].source_info + self.loc.map(|loc| { + let block = &self.body.basic_blocks()[loc.block]; + if loc.statement_index < block.statements.len() { + block.statements[loc.statement_index].source_info } else { block.terminator().source_info } @@ -615,14 +609,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // first push a stack frame so we have access to the local substs let pre_frame = Frame { body, - block: Some(mir::START_BLOCK), + loc: Some(mir::Location::START), return_to_block, return_place, // empty local array, we fill it in below, after we are inside the stack frame and // all methods actually know about the frame locals: IndexVec::new(), instance, - stmt: 0, extra: (), }; let frame = M::init_frame_extra(self, pre_frame)?; @@ -671,9 +664,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Jump to the given block. #[inline] pub fn go_to_block(&mut self, target: mir::BasicBlock) { - let frame = self.frame_mut(); - frame.block = Some(target); - frame.stmt = 0; + self.frame_mut().loc = Some(mir::Location { block: target, statement_index: 0 }); } /// *Return* to the given `target` basic block. @@ -695,9 +686,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// If `target` is `None`, that indicates the function does not need cleanup during /// unwinding, and we will just keep propagating that upwards. pub fn unwind_to_block(&mut self, target: Option) { - let frame = self.frame_mut(); - frame.block = target; - frame.stmt = 0; + self.frame_mut().loc = target.map(|block| mir::Location { block, statement_index: 0 }); } /// Pops the current frame from the stack, deallocating the @@ -724,9 +713,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Sanity check `unwinding`. assert_eq!( unwinding, - match self.frame().block { + match self.frame().loc { None => true, - Some(block) => self.body().basic_blocks()[block].is_cleanup, + Some(loc) => self.body().basic_blocks()[loc.block].is_cleanup, } ); @@ -987,13 +976,14 @@ where Tag: HashStable>, { fn hash_stable(&self, hcx: &mut StableHashingContext<'ctx>, hasher: &mut StableHasher) { - self.body.hash_stable(hcx, hasher); - self.instance.hash_stable(hcx, hasher); - self.return_to_block.hash_stable(hcx, hasher); - self.return_place.as_ref().map(|r| &**r).hash_stable(hcx, hasher); - self.locals.hash_stable(hcx, hasher); - self.block.hash_stable(hcx, hasher); - self.stmt.hash_stable(hcx, hasher); - self.extra.hash_stable(hcx, hasher); + // Exhaustive match on fields to make sure we forget no field. + let Frame { body, instance, return_to_block, return_place, locals, loc, extra } = self; + body.hash_stable(hcx, hasher); + instance.hash_stable(hcx, hasher); + return_to_block.hash_stable(hcx, hasher); + return_place.as_ref().map(|r| &**r).hash_stable(hcx, hasher); + locals.hash_stable(hcx, hasher); + loc.hash_stable(hcx, hasher); + extra.hash_stable(hcx, hasher); } } diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index aae708827b953..bb4c0156c88cf 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -46,8 +46,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { return Ok(false); } - let block = match self.frame().block { - Some(block) => block, + let loc = match self.frame().loc { + Some(loc) => loc, None => { // We are unwinding and this fn has no cleanup code. // Just go on unwinding. @@ -56,13 +56,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { return Ok(true); } }; - let stmt_id = self.frame().stmt; - let body = self.body(); - let basic_block = &body.basic_blocks()[block]; + let basic_block = &self.body().basic_blocks()[loc.block]; let old_frames = self.frame_idx(); - if let Some(stmt) = basic_block.statements.get(stmt_id) { + if let Some(stmt) = basic_block.statements.get(loc.statement_index) { assert_eq!(old_frames, self.frame_idx()); self.statement(stmt)?; return Ok(true); @@ -126,7 +124,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { LlvmInlineAsm { .. } => throw_unsup_format!("inline assembly is not supported"), } - self.stack_mut()[frame_idx].stmt += 1; + self.stack_mut()[frame_idx].loc.as_mut().unwrap().statement_index += 1; Ok(()) } @@ -279,8 +277,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.eval_terminator(terminator)?; if !self.stack().is_empty() { - if let Some(block) = self.frame().block { - info!("// executing {:?}", block); + if let Some(loc) = self.frame().loc { + info!("// executing {:?}", loc.block); } } Ok(()) diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index 7157225e5c9bb..6ead962dcd869 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -53,7 +53,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Call { ref func, ref args, destination, ref cleanup, .. } => { let old_stack = self.frame_idx(); - let old_bb = self.frame().block; + let old_loc = self.frame().loc; let func = self.eval_operand(func, None)?; let (fn_val, abi) = match func.layout.ty.kind { ty::FnPtr(sig) => { @@ -80,7 +80,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.eval_fn_call(fn_val, abi, &args[..], ret, *cleanup)?; // Sanity-check that `eval_fn_call` either pushed a new frame or // did a jump to another block. - if self.frame_idx() == old_stack && self.frame().block == old_bb { + if self.frame_idx() == old_stack && self.frame().loc == old_loc { span_bug!(terminator.source_info.span, "evaluating this call made no progress"); } }