Skip to content

Commit 38472e0

Browse files
author
hyd-dev
committed
Move the check to unwind_to_block
1 parent 116172d commit 38472e0

File tree

1 file changed

+34
-30
lines changed

1 file changed

+34
-30
lines changed

compiler/rustc_mir/src/interpret/eval_context.rs

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -757,13 +757,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
757757
/// *Unwind* to the given `target` basic block.
758758
/// Do *not* use for returning! Use `return_to_block` instead.
759759
///
760-
/// If `target` is `None`, that indicates the function does not need cleanup during
761-
/// unwinding, and we will just keep propagating that upwards.
762-
pub fn unwind_to_block(&mut self, target: Option<mir::BasicBlock>) {
760+
/// If `target` is `StackPopUnwind::Skip`, that indicates the function does not need cleanup
761+
/// during unwinding, and we will just keep propagating that upwards.
762+
///
763+
/// If `target` is `StackPopUnwind::NotAllowed`, that indicates the function does not allow
764+
/// unwinding, and doing so is UB.
765+
pub fn unwind_to_block(&mut self, target: StackPopUnwind) -> InterpResult<'tcx> {
763766
self.frame_mut().loc = match target {
764-
Some(block) => Ok(mir::Location { block, statement_index: 0 }),
765-
None => Err(self.frame_mut().body.span),
767+
StackPopUnwind::Cleanup(block) => Ok(mir::Location { block, statement_index: 0 }),
768+
StackPopUnwind::Skip => Err(self.frame_mut().body.span),
769+
StackPopUnwind::NotAllowed => {
770+
throw_ub_format!("unwinding past a frame that does not allow unwinding")
771+
}
766772
};
773+
Ok(())
767774
}
768775

769776
/// Pops the current frame from the stack, deallocating the
@@ -798,27 +805,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
798805
throw_ub_format!("unwinding past the topmost frame of the stack");
799806
}
800807

801-
// Where do we jump next?
802-
803-
// Usually we want to clean up (deallocate locals), but in a few rare cases we don't.
804-
// In that case, we return early. We also avoid validation in that case,
805-
// because this is CTFE and the final value will be thoroughly validated anyway.
806-
let (cleanup, next_block) = match (self.frame().return_to_block, unwinding) {
807-
(StackPopCleanup::Goto { ret, .. }, false) => (true, Some(ret)),
808-
(StackPopCleanup::Goto { unwind, .. }, true) => (
809-
true,
810-
Some(match unwind {
811-
StackPopUnwind::Cleanup(unwind) => Some(unwind),
812-
StackPopUnwind::Skip => None,
813-
StackPopUnwind::NotAllowed => {
814-
throw_ub_format!("unwinding past a frame that does not allow unwinding")
815-
}
816-
}),
817-
),
818-
(StackPopCleanup::None { cleanup, .. }, _) => (cleanup, None),
819-
};
820-
821-
let frame = self.stack_mut().pop().unwrap();
808+
let frame =
809+
self.stack_mut().pop().expect("tried to pop a stack frame, but there were none");
822810

823811
if !unwinding {
824812
// Copy the return value to the caller's stack frame.
@@ -831,9 +819,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
831819
}
832820
}
833821

822+
let return_to_block = frame.return_to_block;
823+
824+
// Now where do we jump next?
825+
826+
// Usually we want to clean up (deallocate locals), but in a few rare cases we don't.
827+
// In that case, we return early. We also avoid validation in that case,
828+
// because this is CTFE and the final value will be thoroughly validated anyway.
829+
let cleanup = match return_to_block {
830+
StackPopCleanup::Goto { .. } => true,
831+
StackPopCleanup::None { cleanup, .. } => cleanup,
832+
};
833+
834834
if !cleanup {
835835
assert!(self.stack().is_empty(), "only the topmost frame should ever be leaked");
836-
assert!(next_block.is_none(), "tried to skip cleanup when we have a next block!");
837836
assert!(!unwinding, "tried to skip cleanup during unwinding");
838837
// Leak the locals, skip validation, skip machine hook.
839838
return Ok(());
@@ -852,11 +851,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
852851
// Normal return, figure out where to jump.
853852
if unwinding {
854853
// Follow the unwind edge.
855-
let unwind = next_block.expect("Encountered StackPopCleanup::None when unwinding!");
856-
self.unwind_to_block(unwind);
854+
let unwind = match return_to_block {
855+
StackPopCleanup::Goto { unwind, .. } => unwind,
856+
StackPopCleanup::None { .. } => {
857+
panic!("Encountered StackPopCleanup::None when unwinding!")
858+
}
859+
};
860+
self.unwind_to_block(unwind)?;
857861
} else {
858862
// Follow the normal return edge.
859-
if let Some(ret) = next_block {
863+
if let StackPopCleanup::Goto { ret, .. } = return_to_block {
860864
self.return_to_block(ret)?;
861865
}
862866
}

0 commit comments

Comments
 (0)