diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index fb3f4f21a9734..fa7b537b4df8d 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -593,17 +593,28 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { _ => {} } + // Now where do we jump next? + + // Determine if we leave this function normally or via unwinding. + let cur_unwinding = match stack_pop_info { + StackPopInfo::StartUnwinding => true, + StackPopInfo::StopUnwinding => false, + _ => unwinding + }; + // Usually we want to clean up (deallocate locals), but in a few rare cases we don't. // In that case, we return early. We also avoid validation in that case, // because this is CTFE and the final value will be thoroughly validated anyway. - let cleanup = unwinding || match frame.return_to_block { - StackPopCleanup::Goto{ .. } => true, - StackPopCleanup::None { cleanup, .. } => { - cleanup - } + let (cleanup, next_block) = match frame.return_to_block { + StackPopCleanup::Goto { ret, unwind } => { + (true, Some(if cur_unwinding { unwind } else { ret })) + }, + StackPopCleanup::None { cleanup, .. } => (cleanup, None) }; + if !cleanup { assert!(self.stack.is_empty(), "only the topmost frame should ever be leaked"); + assert!(next_block.is_none(), "tried to skip cleanup when we have a next block!"); // Leak the locals, skip validation. return Ok(()); } @@ -613,29 +624,16 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.deallocate_local(local.value)?; } - // Now where do we jump next? - - // Determine if we leave this function normally or via unwinding. - let cur_unwinding = match stack_pop_info { - StackPopInfo::StartUnwinding => true, - StackPopInfo::StopUnwinding => false, - _ => unwinding - }; trace!("StackPopCleanup: {:?} StackPopInfo: {:?} cur_unwinding = {:?}", frame.return_to_block, stack_pop_info, cur_unwinding); if cur_unwinding { // Follow the unwind edge. - match frame.return_to_block { - StackPopCleanup::Goto { unwind, .. } => { - let next_frame = self.frame_mut(); - // If `unwind` is `None`, we'll leave that function immediately again. - next_frame.block = unwind; - next_frame.stmt = 0; - }, - StackPopCleanup::None { .. } => - bug!("Encountered StackPopCleanup::None while unwinding"), - } + let unwind = next_block.expect("Encounted StackPopCleanup::None when unwinding!"); + let next_frame = self.frame_mut(); + // If `unwind` is `None`, we'll leave that function immediately again. + next_frame.block = unwind; + next_frame.stmt = 0; } else { // Follow the normal return edge. // Validate the return value. Do this after deallocating so that we catch dangling @@ -661,11 +659,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } // Jump to new block -- *after* validation so that the spans make more sense. - match frame.return_to_block { - StackPopCleanup::Goto { ret, .. } => { - self.goto_block(ret)?; - } - StackPopCleanup::None { .. } => {} + if let Some(ret) = next_block { + self.goto_block(ret)?; } }