Refactor call terminator to always hold a destination place
This commit is contained in:
parent
222c5724ec
commit
09b0936db2
67 changed files with 422 additions and 412 deletions
|
@ -60,7 +60,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
|
|||
ecx.push_stack_frame(
|
||||
cid.instance,
|
||||
body,
|
||||
Some(&ret.into()),
|
||||
&ret.into(),
|
||||
StackPopCleanup::Root { cleanup: false },
|
||||
)?;
|
||||
|
||||
|
|
|
@ -265,7 +265,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
|||
instance: ty::Instance<'tcx>,
|
||||
_abi: Abi,
|
||||
args: &[OpTy<'tcx>],
|
||||
_ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>,
|
||||
_dest: &PlaceTy<'tcx>,
|
||||
_ret: Option<mir::BasicBlock>,
|
||||
_unwind: StackPopUnwind, // unwinding is not supported in consts
|
||||
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
|
||||
debug!("find_mir_or_eval_fn: {:?}", instance);
|
||||
|
@ -293,6 +294,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
|||
new_instance,
|
||||
_abi,
|
||||
args,
|
||||
_dest,
|
||||
_ret,
|
||||
_unwind,
|
||||
)?
|
||||
|
@ -307,17 +309,18 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
|||
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||
instance: ty::Instance<'tcx>,
|
||||
args: &[OpTy<'tcx>],
|
||||
ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>,
|
||||
dest: &PlaceTy<'tcx, Self::PointerTag>,
|
||||
target: Option<mir::BasicBlock>,
|
||||
_unwind: StackPopUnwind,
|
||||
) -> InterpResult<'tcx> {
|
||||
// Shared intrinsics.
|
||||
if ecx.emulate_intrinsic(instance, args, ret)? {
|
||||
if ecx.emulate_intrinsic(instance, args, dest, target)? {
|
||||
return Ok(());
|
||||
}
|
||||
let intrinsic_name = ecx.tcx.item_name(instance.def_id());
|
||||
|
||||
// CTFE-specific intrinsics.
|
||||
let Some((dest, ret)) = ret else {
|
||||
let Some(ret) = target else {
|
||||
return Err(ConstEvalErrKind::NeedsRfc(format!(
|
||||
"calling intrinsic `{}`",
|
||||
intrinsic_name
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -788,7 +788,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
} else {
|
||||
let terminator = self.source[loc.block].terminator_mut();
|
||||
let target = match terminator.kind {
|
||||
TerminatorKind::Call { destination: Some((_, target)), .. } => target,
|
||||
TerminatorKind::Call { target: Some(target), .. } => target,
|
||||
ref kind => {
|
||||
span_bug!(terminator.source_info.span, "{:?} not promotable", kind);
|
||||
}
|
||||
|
@ -814,7 +814,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
func,
|
||||
args,
|
||||
cleanup: None,
|
||||
destination: Some((Place::from(new_temp), new_target)),
|
||||
destination: Place::from(new_temp),
|
||||
target: Some(new_target),
|
||||
from_hir_call,
|
||||
fn_span,
|
||||
},
|
||||
|
@ -1054,11 +1055,9 @@ pub fn is_const_fn_in_array_repeat_expression<'tcx>(
|
|||
{
|
||||
if let Operand::Constant(box Constant { literal, .. }) = func {
|
||||
if let ty::FnDef(def_id, _) = *literal.ty().kind() {
|
||||
if let Some((destination_place, _)) = destination {
|
||||
if destination_place == place {
|
||||
if ccx.tcx.is_const_fn(def_id) {
|
||||
return true;
|
||||
}
|
||||
if destination == place {
|
||||
if ccx.tcx.is_const_fn(def_id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -673,7 +673,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
self.check_edge(location, *unwind, EdgeKind::Unwind);
|
||||
}
|
||||
}
|
||||
TerminatorKind::Call { func, args, destination, cleanup, .. } => {
|
||||
TerminatorKind::Call { func, args, destination, target, cleanup, .. } => {
|
||||
let func_ty = func.ty(&self.body.local_decls, self.tcx);
|
||||
match func_ty.kind() {
|
||||
ty::FnPtr(..) | ty::FnDef(..) => {}
|
||||
|
@ -682,7 +682,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
format!("encountered non-callable type {} in `Call` terminator", func_ty),
|
||||
),
|
||||
}
|
||||
if let Some((_, target)) = destination {
|
||||
if let Some(target) = target {
|
||||
self.check_edge(location, *target, EdgeKind::Normal);
|
||||
}
|
||||
if let Some(cleanup) = cleanup {
|
||||
|
@ -693,9 +693,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
// passed by a reference to the callee. Consequently they must be non-overlapping.
|
||||
// Currently this simply checks for duplicate places.
|
||||
self.place_cache.clear();
|
||||
if let Some((destination, _)) = destination {
|
||||
self.place_cache.push(destination.as_ref());
|
||||
}
|
||||
self.place_cache.push(destination.as_ref());
|
||||
for arg in args {
|
||||
if let Operand::Move(place) = arg {
|
||||
self.place_cache.push(place.as_ref());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue