when terminating during unwinding, show the reason why
This commit is contained in:
parent
0b31792ef1
commit
4c53783f3c
88 changed files with 380 additions and 278 deletions
|
@ -756,6 +756,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
///
|
||||
/// If `target` is `UnwindAction::Unreachable`, that indicates the function does not allow
|
||||
/// unwinding, and doing so is UB.
|
||||
#[cold] // usually we have normal returns, not unwinding
|
||||
pub fn unwind_to_block(&mut self, target: mir::UnwindAction) -> InterpResult<'tcx> {
|
||||
self.frame_mut().loc = match target {
|
||||
mir::UnwindAction::Cleanup(block) => Left(mir::Location { block, statement_index: 0 }),
|
||||
|
@ -763,9 +764,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
mir::UnwindAction::Unreachable => {
|
||||
throw_ub_custom!(fluent::const_eval_unreachable_unwind);
|
||||
}
|
||||
mir::UnwindAction::Terminate => {
|
||||
mir::UnwindAction::Terminate(reason) => {
|
||||
self.frame_mut().loc = Right(self.frame_mut().body.span);
|
||||
M::unwind_terminate(self)?;
|
||||
M::unwind_terminate(self, reason)?;
|
||||
// This might have pushed a new stack frame, or it terminated execution.
|
||||
// Either way, `loc` will not be updated.
|
||||
return Ok(());
|
||||
|
|
|
@ -222,7 +222,10 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
|
|||
fn panic_nounwind(_ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: &str) -> InterpResult<'tcx>;
|
||||
|
||||
/// Called when unwinding reached a state where execution should be terminated.
|
||||
fn unwind_terminate(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx>;
|
||||
fn unwind_terminate(
|
||||
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||
reason: mir::UnwindTerminateReason,
|
||||
) -> InterpResult<'tcx>;
|
||||
|
||||
/// Called for all binary operations where the LHS has pointer type.
|
||||
///
|
||||
|
@ -462,6 +465,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
|
|||
|
||||
/// Called immediately after a stack frame got popped, but before jumping back to the caller.
|
||||
/// The `locals` have already been destroyed!
|
||||
#[inline(always)]
|
||||
fn after_stack_pop(
|
||||
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||
_frame: Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
|
||||
|
@ -501,7 +505,10 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn unwind_terminate(_ecx: &mut InterpCx<$mir, $tcx, Self>) -> InterpResult<$tcx> {
|
||||
fn unwind_terminate(
|
||||
_ecx: &mut InterpCx<$mir, $tcx, Self>,
|
||||
_reason: mir::UnwindTerminateReason,
|
||||
) -> InterpResult<$tcx> {
|
||||
unreachable!("unwinding cannot happen during compile-time evaluation")
|
||||
}
|
||||
|
||||
|
|
|
@ -196,8 +196,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
}
|
||||
|
||||
UnwindTerminate => {
|
||||
M::unwind_terminate(self)?;
|
||||
UnwindTerminate(reason) => {
|
||||
M::unwind_terminate(self, reason)?;
|
||||
}
|
||||
|
||||
// When we encounter Resume, we've finished unwinding
|
||||
|
|
|
@ -1037,7 +1037,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
self.check_op(ops::Generator(hir::GeneratorKind::Gen))
|
||||
}
|
||||
|
||||
TerminatorKind::UnwindTerminate => {
|
||||
TerminatorKind::UnwindTerminate(_) => {
|
||||
// Cleanup blocks are skipped for const checking (see `visit_basic_block_data`).
|
||||
span_bug!(self.span, "`Terminate` terminator outside of cleanup block")
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
mir::TerminatorKind::UnwindTerminate
|
||||
mir::TerminatorKind::UnwindTerminate(_)
|
||||
| mir::TerminatorKind::Call { .. }
|
||||
| mir::TerminatorKind::Assert { .. }
|
||||
| mir::TerminatorKind::FalseEdge { .. }
|
||||
|
|
|
@ -10,8 +10,8 @@ use rustc_middle::mir::{
|
|||
traversal, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping, Local, Location,
|
||||
MirPass, MirPhase, NonDivergingIntrinsic, NullOp, Operand, Place, PlaceElem, PlaceRef,
|
||||
ProjectionElem, RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind,
|
||||
Terminator, TerminatorKind, UnOp, UnwindAction, VarDebugInfo, VarDebugInfoContents,
|
||||
START_BLOCK,
|
||||
Terminator, TerminatorKind, UnOp, UnwindAction, UnwindTerminateReason, VarDebugInfo,
|
||||
VarDebugInfoContents, START_BLOCK,
|
||||
};
|
||||
use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_mir_dataflow::impls::MaybeStorageLive;
|
||||
|
@ -274,7 +274,16 @@ impl<'a, 'tcx> CfgChecker<'a, 'tcx> {
|
|||
self.fail(location, "`UnwindAction::Continue` in no-unwind function");
|
||||
}
|
||||
}
|
||||
UnwindAction::Unreachable | UnwindAction::Terminate => (),
|
||||
UnwindAction::Terminate(UnwindTerminateReason::InCleanup) => {
|
||||
if !is_cleanup {
|
||||
self.fail(
|
||||
location,
|
||||
"`UnwindAction::Terminate(InCleanup)` in a non-cleanup block",
|
||||
);
|
||||
}
|
||||
}
|
||||
// These are allowed everywhere.
|
||||
UnwindAction::Unreachable | UnwindAction::Terminate(UnwindTerminateReason::Abi) => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -501,7 +510,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
|
|||
self.fail(location, "Cannot `UnwindResume` in a function that cannot unwind")
|
||||
}
|
||||
}
|
||||
TerminatorKind::UnwindTerminate => {
|
||||
TerminatorKind::UnwindTerminate(_) => {
|
||||
let bb = location.block;
|
||||
if !self.body.basic_blocks[bb].is_cleanup {
|
||||
self.fail(location, "Cannot `UnwindTerminate` from non-cleanup basic block")
|
||||
|
@ -1233,7 +1242,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
| TerminatorKind::InlineAsm { .. }
|
||||
| TerminatorKind::GeneratorDrop
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable => {}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue