Refactor call terminator to always hold a destination place
This commit is contained in:
@@ -105,7 +105,7 @@ pub struct Frame<'mir, 'tcx, Tag: Provenance = AllocId, Extra = ()> {
|
||||
|
||||
/// The location where the result of the current stack frame should be written to,
|
||||
/// and its layout in the caller.
|
||||
pub return_place: Option<PlaceTy<'tcx, Tag>>,
|
||||
pub return_place: PlaceTy<'tcx, Tag>,
|
||||
|
||||
/// The list of locals for this stack frame, stored in order as
|
||||
/// `[return_ptr, arguments..., variables..., temporaries...]`.
|
||||
@@ -676,7 +676,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
&mut self,
|
||||
instance: ty::Instance<'tcx>,
|
||||
body: &'mir mir::Body<'tcx>,
|
||||
return_place: Option<&PlaceTy<'tcx, M::PointerTag>>,
|
||||
return_place: &PlaceTy<'tcx, M::PointerTag>,
|
||||
return_to_block: StackPopCleanup,
|
||||
) -> InterpResult<'tcx> {
|
||||
trace!("body: {:#?}", body);
|
||||
@@ -685,7 +685,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
body,
|
||||
loc: Err(body.span), // Span used for errors caused during preamble.
|
||||
return_to_block,
|
||||
return_place: return_place.copied(),
|
||||
return_place: *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(),
|
||||
@@ -807,14 +807,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
self.stack_mut().pop().expect("tried to pop a stack frame, but there were none");
|
||||
|
||||
if !unwinding {
|
||||
// Copy the return value to the caller's stack frame.
|
||||
if let Some(ref return_place) = frame.return_place {
|
||||
let op = self.access_local(&frame, mir::RETURN_PLACE, None)?;
|
||||
self.copy_op_transmute(&op, return_place)?;
|
||||
trace!("{:?}", self.dump_place(**return_place));
|
||||
} else {
|
||||
throw_ub!(Unreachable);
|
||||
}
|
||||
let op = self.access_local(&frame, mir::RETURN_PLACE, None)?;
|
||||
self.copy_op_transmute(&op, &frame.return_place)?;
|
||||
trace!("{:?}", self.dump_place(*frame.return_place));
|
||||
}
|
||||
|
||||
let return_to_block = frame.return_to_block;
|
||||
@@ -1055,7 +1050,7 @@ where
|
||||
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);
|
||||
return_place.hash_stable(hcx, hasher);
|
||||
locals.hash_stable(hcx, hasher);
|
||||
loc.hash_stable(hcx, hasher);
|
||||
extra.hash_stable(hcx, hasher);
|
||||
|
||||
@@ -115,13 +115,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
&mut self,
|
||||
instance: ty::Instance<'tcx>,
|
||||
args: &[OpTy<'tcx, M::PointerTag>],
|
||||
ret: Option<(&PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>,
|
||||
dest: &PlaceTy<'tcx, M::PointerTag>,
|
||||
ret: Option<mir::BasicBlock>,
|
||||
) -> InterpResult<'tcx, bool> {
|
||||
let substs = instance.substs;
|
||||
let intrinsic_name = self.tcx.item_name(instance.def_id());
|
||||
|
||||
// First handle intrinsics without return place.
|
||||
let (dest, ret) = match ret {
|
||||
let ret = match ret {
|
||||
None => match intrinsic_name {
|
||||
sym::transmute => throw_ub_format!("transmuting to uninhabited type"),
|
||||
sym::abort => M::abort(self, "the program aborted execution".to_owned())?,
|
||||
|
||||
@@ -169,7 +169,8 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
||||
instance: ty::Instance<'tcx>,
|
||||
abi: Abi,
|
||||
args: &[OpTy<'tcx, Self::PointerTag>],
|
||||
ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
|
||||
destination: &PlaceTy<'tcx, Self::PointerTag>,
|
||||
target: Option<mir::BasicBlock>,
|
||||
unwind: StackPopUnwind,
|
||||
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>>;
|
||||
|
||||
@@ -180,7 +181,8 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
||||
fn_val: Self::ExtraFnVal,
|
||||
abi: Abi,
|
||||
args: &[OpTy<'tcx, Self::PointerTag>],
|
||||
ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
|
||||
destination: &PlaceTy<'tcx, Self::PointerTag>,
|
||||
target: Option<mir::BasicBlock>,
|
||||
unwind: StackPopUnwind,
|
||||
) -> InterpResult<'tcx>;
|
||||
|
||||
@@ -190,7 +192,8 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
||||
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||
instance: ty::Instance<'tcx>,
|
||||
args: &[OpTy<'tcx, Self::PointerTag>],
|
||||
ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
|
||||
destination: &PlaceTy<'tcx, Self::PointerTag>,
|
||||
target: Option<mir::BasicBlock>,
|
||||
unwind: StackPopUnwind,
|
||||
) -> InterpResult<'tcx>;
|
||||
|
||||
@@ -470,7 +473,8 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
|
||||
fn_val: !,
|
||||
_abi: Abi,
|
||||
_args: &[OpTy<$tcx>],
|
||||
_ret: Option<(&PlaceTy<$tcx>, mir::BasicBlock)>,
|
||||
_destination: &PlaceTy<$tcx, Self::PointerTag>,
|
||||
_target: Option<mir::BasicBlock>,
|
||||
_unwind: StackPopUnwind,
|
||||
) -> InterpResult<$tcx> {
|
||||
match fn_val {}
|
||||
|
||||
@@ -57,7 +57,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
self.go_to_block(target_block);
|
||||
}
|
||||
|
||||
Call { ref func, ref args, destination, ref cleanup, from_hir_call: _, fn_span: _ } => {
|
||||
Call {
|
||||
ref func,
|
||||
ref args,
|
||||
destination,
|
||||
target,
|
||||
ref cleanup,
|
||||
from_hir_call: _,
|
||||
fn_span: _,
|
||||
} => {
|
||||
let old_stack = self.frame_idx();
|
||||
let old_loc = self.frame().loc;
|
||||
let func = self.eval_operand(func, None)?;
|
||||
@@ -91,20 +99,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
),
|
||||
};
|
||||
|
||||
let dest_place;
|
||||
let ret = match destination {
|
||||
Some((dest, ret)) => {
|
||||
dest_place = self.eval_place(dest)?;
|
||||
Some((&dest_place, ret))
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
let destination = self.eval_place(destination)?;
|
||||
self.eval_fn_call(
|
||||
fn_val,
|
||||
(fn_sig.abi, fn_abi),
|
||||
&args,
|
||||
with_caller_location,
|
||||
ret,
|
||||
&destination,
|
||||
target,
|
||||
match (cleanup, fn_abi.can_unwind) {
|
||||
(Some(cleanup), true) => StackPopUnwind::Cleanup(*cleanup),
|
||||
(None, true) => StackPopUnwind::Skip,
|
||||
@@ -299,7 +301,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
(caller_abi, caller_fn_abi): (Abi, &FnAbi<'tcx, Ty<'tcx>>),
|
||||
args: &[OpTy<'tcx, M::PointerTag>],
|
||||
with_caller_location: bool,
|
||||
ret: Option<(&PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>,
|
||||
destination: &PlaceTy<'tcx, M::PointerTag>,
|
||||
target: Option<mir::BasicBlock>,
|
||||
mut unwind: StackPopUnwind,
|
||||
) -> InterpResult<'tcx> {
|
||||
trace!("eval_fn_call: {:#?}", fn_val);
|
||||
@@ -307,7 +310,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
let instance = match fn_val {
|
||||
FnVal::Instance(instance) => instance,
|
||||
FnVal::Other(extra) => {
|
||||
return M::call_extra_fn(self, extra, caller_abi, args, ret, unwind);
|
||||
return M::call_extra_fn(
|
||||
self,
|
||||
extra,
|
||||
caller_abi,
|
||||
args,
|
||||
destination,
|
||||
target,
|
||||
unwind,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -315,7 +326,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
ty::InstanceDef::Intrinsic(def_id) => {
|
||||
assert!(self.tcx.is_intrinsic(def_id));
|
||||
// caller_fn_abi is not relevant here, we interpret the arguments directly for each intrinsic.
|
||||
M::call_intrinsic(self, instance, args, ret, unwind)
|
||||
M::call_intrinsic(self, instance, args, destination, target, unwind)
|
||||
}
|
||||
ty::InstanceDef::VtableShim(..)
|
||||
| ty::InstanceDef::ReifyShim(..)
|
||||
@@ -326,7 +337,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
| ty::InstanceDef::Item(_) => {
|
||||
// We need MIR for this fn
|
||||
let Some((body, instance)) =
|
||||
M::find_mir_or_eval_fn(self, instance, caller_abi, args, ret, unwind)? else {
|
||||
M::find_mir_or_eval_fn(self, instance, caller_abi, args, destination, target, unwind)? else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
@@ -362,8 +373,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
self.push_stack_frame(
|
||||
instance,
|
||||
body,
|
||||
ret.map(|p| p.0),
|
||||
StackPopCleanup::Goto { ret: ret.map(|p| p.1), unwind },
|
||||
destination,
|
||||
StackPopCleanup::Goto { ret: target, unwind },
|
||||
)?;
|
||||
|
||||
// If an error is raised here, pop the frame again to get an accurate backtrace.
|
||||
@@ -540,7 +551,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
(caller_abi, caller_fn_abi),
|
||||
&args,
|
||||
with_caller_location,
|
||||
ret,
|
||||
destination,
|
||||
target,
|
||||
unwind,
|
||||
)
|
||||
}
|
||||
@@ -582,7 +594,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
(Abi::Rust, fn_abi),
|
||||
&[arg.into()],
|
||||
false,
|
||||
Some((&dest.into(), target)),
|
||||
&dest.into(),
|
||||
Some(target),
|
||||
match unwind {
|
||||
Some(cleanup) => StackPopUnwind::Cleanup(cleanup),
|
||||
None => StackPopUnwind::Skip,
|
||||
|
||||
Reference in New Issue
Block a user