Add UnwindAction::Unreachable
This also makes eval machine's `StackPopUnwind` redundant so that is replaced.
This commit is contained in:
parent
daeb844e0c
commit
5e6ed132fa
23 changed files with 160 additions and 149 deletions
|
@ -23,7 +23,7 @@ use rustc_target::spec::abi::Abi as CallAbi;
|
|||
|
||||
use crate::interpret::{
|
||||
self, compile_time_machine, AllocId, ConstAllocation, FnVal, Frame, ImmTy, InterpCx,
|
||||
InterpResult, OpTy, PlaceTy, Pointer, Scalar, StackPopUnwind,
|
||||
InterpResult, OpTy, PlaceTy, Pointer, Scalar,
|
||||
};
|
||||
|
||||
use super::error::*;
|
||||
|
@ -271,7 +271,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
|
|||
/* with_caller_location = */ false,
|
||||
dest,
|
||||
ret,
|
||||
StackPopUnwind::NotAllowed,
|
||||
mir::UnwindAction::Unreachable,
|
||||
)?;
|
||||
Ok(ControlFlow::Break(()))
|
||||
} else {
|
||||
|
@ -401,7 +401,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
|||
args: &[OpTy<'tcx>],
|
||||
dest: &PlaceTy<'tcx>,
|
||||
ret: Option<mir::BasicBlock>,
|
||||
_unwind: StackPopUnwind, // unwinding is not supported in consts
|
||||
_unwind: mir::UnwindAction, // unwinding is not supported in consts
|
||||
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
|
||||
debug!("find_mir_or_eval_fn: {:?}", instance);
|
||||
|
||||
|
@ -450,7 +450,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
|||
args: &[OpTy<'tcx>],
|
||||
dest: &PlaceTy<'tcx, Self::Provenance>,
|
||||
target: Option<mir::BasicBlock>,
|
||||
_unwind: StackPopUnwind,
|
||||
_unwind: mir::UnwindAction,
|
||||
) -> InterpResult<'tcx> {
|
||||
// Shared intrinsics.
|
||||
if ecx.emulate_intrinsic(instance, args, dest, target)? {
|
||||
|
|
|
@ -139,17 +139,6 @@ pub struct FrameInfo<'tcx> {
|
|||
pub lint_root: Option<hir::HirId>,
|
||||
}
|
||||
|
||||
/// Unwind information.
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||
pub enum StackPopUnwind {
|
||||
/// The cleanup block.
|
||||
Cleanup(mir::BasicBlock),
|
||||
/// No cleanup needs to be done.
|
||||
Skip,
|
||||
/// Unwinding is not allowed (UB).
|
||||
NotAllowed,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)] // Miri debug-prints these
|
||||
pub enum StackPopCleanup {
|
||||
/// Jump to the next block in the caller, or cause UB if None (that's a function
|
||||
|
@ -157,7 +146,7 @@ pub enum StackPopCleanup {
|
|||
/// we can validate it at that layout.
|
||||
/// `ret` stores the block we jump to on a normal return, while `unwind`
|
||||
/// stores the block used for cleanup during unwinding.
|
||||
Goto { ret: Option<mir::BasicBlock>, unwind: StackPopUnwind },
|
||||
Goto { ret: Option<mir::BasicBlock>, unwind: mir::UnwindAction },
|
||||
/// The root frame of the stack: nowhere else to jump to.
|
||||
/// `cleanup` says whether locals are deallocated. Static computation
|
||||
/// wants them leaked to intern what they need (and just throw away
|
||||
|
@ -735,16 +724,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
/// *Unwind* to the given `target` basic block.
|
||||
/// Do *not* use for returning! Use `return_to_block` instead.
|
||||
///
|
||||
/// If `target` is `StackPopUnwind::Skip`, that indicates the function does not need cleanup
|
||||
/// If `target` is `UnwindAction::Continue`, that indicates the function does not need cleanup
|
||||
/// during unwinding, and we will just keep propagating that upwards.
|
||||
///
|
||||
/// If `target` is `StackPopUnwind::NotAllowed`, that indicates the function does not allow
|
||||
/// If `target` is `UnwindAction::Unreachable`, that indicates the function does not allow
|
||||
/// unwinding, and doing so is UB.
|
||||
pub fn unwind_to_block(&mut self, target: StackPopUnwind) -> InterpResult<'tcx> {
|
||||
pub fn unwind_to_block(&mut self, target: mir::UnwindAction) -> InterpResult<'tcx> {
|
||||
self.frame_mut().loc = match target {
|
||||
StackPopUnwind::Cleanup(block) => Left(mir::Location { block, statement_index: 0 }),
|
||||
StackPopUnwind::Skip => Right(self.frame_mut().body.span),
|
||||
StackPopUnwind::NotAllowed => {
|
||||
mir::UnwindAction::Cleanup(block) => Left(mir::Location { block, statement_index: 0 }),
|
||||
mir::UnwindAction::Continue => Right(self.frame_mut().body.span),
|
||||
mir::UnwindAction::Unreachable => {
|
||||
throw_ub_format!("unwinding past a stack frame that does not allow unwinding")
|
||||
}
|
||||
};
|
||||
|
|
|
@ -18,7 +18,7 @@ use crate::const_eval::CheckAlignment;
|
|||
|
||||
use super::{
|
||||
AllocBytes, AllocId, AllocRange, Allocation, ConstAllocation, Frame, ImmTy, InterpCx,
|
||||
InterpResult, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, StackPopUnwind,
|
||||
InterpResult, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar,
|
||||
};
|
||||
|
||||
/// Data returned by Machine::stack_pop,
|
||||
|
@ -185,7 +185,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
|||
args: &[OpTy<'tcx, Self::Provenance>],
|
||||
destination: &PlaceTy<'tcx, Self::Provenance>,
|
||||
target: Option<mir::BasicBlock>,
|
||||
unwind: StackPopUnwind,
|
||||
unwind: mir::UnwindAction,
|
||||
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>>;
|
||||
|
||||
/// Execute `fn_val`. It is the hook's responsibility to advance the instruction
|
||||
|
@ -197,7 +197,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
|||
args: &[OpTy<'tcx, Self::Provenance>],
|
||||
destination: &PlaceTy<'tcx, Self::Provenance>,
|
||||
target: Option<mir::BasicBlock>,
|
||||
unwind: StackPopUnwind,
|
||||
unwind: mir::UnwindAction,
|
||||
) -> InterpResult<'tcx>;
|
||||
|
||||
/// Directly process an intrinsic without pushing a stack frame. It is the hook's
|
||||
|
@ -208,7 +208,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
|||
args: &[OpTy<'tcx, Self::Provenance>],
|
||||
destination: &PlaceTy<'tcx, Self::Provenance>,
|
||||
target: Option<mir::BasicBlock>,
|
||||
unwind: StackPopUnwind,
|
||||
unwind: mir::UnwindAction,
|
||||
) -> InterpResult<'tcx>;
|
||||
|
||||
/// Called to evaluate `Assert` MIR terminators that trigger a panic.
|
||||
|
@ -487,7 +487,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
|
|||
_args: &[OpTy<$tcx>],
|
||||
_destination: &PlaceTy<$tcx, Self::Provenance>,
|
||||
_target: Option<mir::BasicBlock>,
|
||||
_unwind: StackPopUnwind,
|
||||
_unwind: mir::UnwindAction,
|
||||
) -> InterpResult<$tcx> {
|
||||
match fn_val {}
|
||||
}
|
||||
|
|
|
@ -20,9 +20,7 @@ mod visitor;
|
|||
|
||||
pub use rustc_middle::mir::interpret::*; // have all the `interpret` symbols in one place: here
|
||||
|
||||
pub use self::eval_context::{
|
||||
Frame, FrameInfo, InterpCx, LocalState, LocalValue, StackPopCleanup, StackPopUnwind,
|
||||
};
|
||||
pub use self::eval_context::{Frame, FrameInfo, InterpCx, LocalState, LocalValue, StackPopCleanup};
|
||||
pub use self::intern::{intern_const_alloc_recursive, InternKind};
|
||||
pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump};
|
||||
pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
|
||||
|
|
|
@ -13,7 +13,7 @@ use rustc_target::spec::abi::Abi;
|
|||
|
||||
use super::{
|
||||
FnVal, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemoryKind, OpTy, Operand,
|
||||
PlaceTy, Scalar, StackPopCleanup, StackPopUnwind,
|
||||
PlaceTy, Scalar, StackPopCleanup,
|
||||
};
|
||||
|
||||
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
|
@ -60,7 +60,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
ref args,
|
||||
destination,
|
||||
target,
|
||||
ref unwind,
|
||||
unwind,
|
||||
from_hir_call: _,
|
||||
fn_span: _,
|
||||
} => {
|
||||
|
@ -106,13 +106,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
with_caller_location,
|
||||
&destination,
|
||||
target,
|
||||
match (unwind, fn_abi.can_unwind) {
|
||||
(mir::UnwindAction::Cleanup(cleanup), true) => {
|
||||
StackPopUnwind::Cleanup(*cleanup)
|
||||
}
|
||||
(mir::UnwindAction::Continue, true) => StackPopUnwind::Skip,
|
||||
(_, false) => StackPopUnwind::NotAllowed,
|
||||
},
|
||||
if fn_abi.can_unwind { unwind } else { mir::UnwindAction::Unreachable },
|
||||
)?;
|
||||
// Sanity-check that `eval_fn_call` either pushed a new frame or
|
||||
// did a jump to another block.
|
||||
|
@ -353,7 +347,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
with_caller_location: bool,
|
||||
destination: &PlaceTy<'tcx, M::Provenance>,
|
||||
target: Option<mir::BasicBlock>,
|
||||
mut unwind: StackPopUnwind,
|
||||
mut unwind: mir::UnwindAction,
|
||||
) -> InterpResult<'tcx> {
|
||||
trace!("eval_fn_call: {:#?}", fn_val);
|
||||
|
||||
|
@ -412,9 +406,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
}
|
||||
|
||||
if !matches!(unwind, StackPopUnwind::NotAllowed) && !callee_fn_abi.can_unwind {
|
||||
// The callee cannot unwind.
|
||||
unwind = StackPopUnwind::NotAllowed;
|
||||
if !callee_fn_abi.can_unwind {
|
||||
// The callee cannot unwind, so force the `Unreachable` unwind handling.
|
||||
unwind = mir::UnwindAction::Unreachable;
|
||||
}
|
||||
|
||||
self.push_stack_frame(
|
||||
|
@ -719,10 +713,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
false,
|
||||
&ret.into(),
|
||||
Some(target),
|
||||
match unwind {
|
||||
mir::UnwindAction::Cleanup(cleanup) => StackPopUnwind::Cleanup(cleanup),
|
||||
mir::UnwindAction::Continue => StackPopUnwind::Skip,
|
||||
},
|
||||
unwind,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue