2016-11-03 10:38:08 +01:00
|
|
|
use rustc::mir;
|
2017-06-01 17:24:21 -07:00
|
|
|
use rustc::ty::{self, TypeVariants, Ty};
|
2017-03-22 13:13:52 +01:00
|
|
|
use rustc::ty::layout::Layout;
|
2017-02-10 03:21:33 -08:00
|
|
|
use syntax::codemap::Span;
|
2017-03-02 13:11:33 +01:00
|
|
|
use syntax::abi::Abi;
|
2016-06-23 01:03:58 -06:00
|
|
|
|
2017-08-10 08:48:38 -07:00
|
|
|
use super::{EvalError, EvalResult, EvalErrorKind, EvalContext, eval_context, TyAndPacked,
|
|
|
|
PtrAndAlign, Lvalue, MemoryPointer, PrimVal, Value, Machine, HasMemory};
|
2017-07-21 13:39:06 +02:00
|
|
|
use super::eval_context::IntegerExt;
|
|
|
|
|
2017-03-23 13:36:13 +01:00
|
|
|
use rustc_data_structures::indexed_vec::Idx;
|
2016-06-23 01:03:58 -06:00
|
|
|
|
2017-03-22 18:31:41 +01:00
|
|
|
mod drop;
|
2016-09-20 16:05:30 +02:00
|
|
|
|
2017-07-21 17:25:30 +02:00
|
|
|
impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|
|
|
pub fn goto_block(&mut self, target: mir::BasicBlock) {
|
2016-07-06 17:55:05 +02:00
|
|
|
self.frame_mut().block = target;
|
|
|
|
self.frame_mut().stmt = 0;
|
|
|
|
}
|
|
|
|
|
2016-06-23 01:03:58 -06:00
|
|
|
pub(super) fn eval_terminator(
|
|
|
|
&mut self,
|
|
|
|
terminator: &mir::Terminator<'tcx>,
|
2017-02-04 13:09:10 -08:00
|
|
|
) -> EvalResult<'tcx> {
|
2016-11-03 10:38:08 +01:00
|
|
|
use rustc::mir::TerminatorKind::*;
|
2016-06-23 01:03:58 -06:00
|
|
|
match terminator.kind {
|
2016-11-26 19:13:22 -08:00
|
|
|
Return => {
|
2017-06-19 13:29:04 +02:00
|
|
|
self.dump_local(self.frame().return_lvalue);
|
2016-11-26 19:13:22 -08:00
|
|
|
self.pop_stack_frame()?
|
|
|
|
}
|
2016-06-23 01:03:58 -06:00
|
|
|
|
2016-07-06 17:55:05 +02:00
|
|
|
Goto { target } => self.goto_block(target),
|
2016-06-23 01:03:58 -06:00
|
|
|
|
2017-08-10 08:48:38 -07:00
|
|
|
SwitchInt {
|
|
|
|
ref discr,
|
|
|
|
ref values,
|
|
|
|
ref targets,
|
|
|
|
..
|
|
|
|
} => {
|
2017-07-25 11:32:48 +02:00
|
|
|
// FIXME(CTFE): forbid branching
|
2017-02-24 10:39:55 +01:00
|
|
|
let discr_val = self.eval_operand(discr)?;
|
|
|
|
let discr_ty = self.operand_ty(discr);
|
2016-09-27 11:10:25 +02:00
|
|
|
let discr_prim = self.value_to_primval(discr_val, discr_ty)?;
|
2016-06-23 01:03:58 -06:00
|
|
|
|
|
|
|
// Branch to the `otherwise` case by default, if no match is found.
|
|
|
|
let mut target_block = targets[targets.len() - 1];
|
|
|
|
|
2017-02-24 10:39:55 +01:00
|
|
|
for (index, const_int) in values.iter().enumerate() {
|
|
|
|
let prim = PrimVal::Bytes(const_int.to_u128_unchecked());
|
2016-12-17 03:09:57 -08:00
|
|
|
if discr_prim.to_bytes()? == prim.to_bytes()? {
|
2016-06-23 01:03:58 -06:00
|
|
|
target_block = targets[index];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-06 17:55:05 +02:00
|
|
|
self.goto_block(target_block);
|
2016-06-23 01:03:58 -06:00
|
|
|
}
|
|
|
|
|
2017-08-10 08:48:38 -07:00
|
|
|
Call {
|
|
|
|
ref func,
|
|
|
|
ref args,
|
|
|
|
ref destination,
|
|
|
|
..
|
|
|
|
} => {
|
2016-07-06 17:55:05 +02:00
|
|
|
let destination = match *destination {
|
2016-10-14 03:31:45 -06:00
|
|
|
Some((ref lv, target)) => Some((self.eval_lvalue(lv)?, target)),
|
2016-07-06 17:55:05 +02:00
|
|
|
None => None,
|
|
|
|
};
|
2016-06-23 01:03:58 -06:00
|
|
|
|
|
|
|
let func_ty = self.operand_ty(func);
|
2017-03-22 14:19:29 +01:00
|
|
|
let (fn_def, sig) = match func_ty.sty {
|
2017-03-22 13:13:52 +01:00
|
|
|
ty::TyFnPtr(sig) => {
|
2016-12-16 22:01:01 -08:00
|
|
|
let fn_ptr = self.eval_operand_to_primval(func)?.to_ptr()?;
|
2017-06-21 21:45:51 -07:00
|
|
|
let instance = self.memory.get_fn(fn_ptr)?;
|
2017-03-23 17:57:40 +01:00
|
|
|
let instance_ty = instance.def.def_ty(self.tcx);
|
|
|
|
let instance_ty = self.monomorphize(instance_ty, instance.substs);
|
|
|
|
match instance_ty.sty {
|
2017-06-28 21:24:17 -04:00
|
|
|
ty::TyFnDef(..) => {
|
|
|
|
let real_sig = instance_ty.fn_sig(self.tcx);
|
2017-03-23 15:17:02 +01:00
|
|
|
let sig = self.erase_lifetimes(&sig);
|
|
|
|
let real_sig = self.erase_lifetimes(&real_sig);
|
2017-06-29 07:58:22 -04:00
|
|
|
let real_sig = self.tcx.normalize_associated_type(&real_sig);
|
2017-05-26 20:02:51 -07:00
|
|
|
if !self.check_sig_compat(sig, real_sig)? {
|
2017-08-02 16:59:01 +02:00
|
|
|
return err!(FunctionPointerTyMismatch(real_sig, sig));
|
2017-03-23 15:17:02 +01:00
|
|
|
}
|
2017-08-10 08:48:38 -07:00
|
|
|
}
|
2017-03-23 15:17:02 +01:00
|
|
|
ref other => bug!("instance def ty: {:?}", other),
|
|
|
|
}
|
|
|
|
(instance, sig)
|
2017-08-10 08:48:38 -07:00
|
|
|
}
|
|
|
|
ty::TyFnDef(def_id, substs) => (
|
|
|
|
eval_context::resolve(self.tcx, def_id, substs),
|
|
|
|
func_ty.fn_sig(self.tcx),
|
|
|
|
),
|
2016-11-26 22:58:01 -08:00
|
|
|
_ => {
|
|
|
|
let msg = format!("can't handle callee of type {:?}", func_ty);
|
2017-08-02 16:59:01 +02:00
|
|
|
return err!(Unimplemented(msg));
|
2016-11-26 22:58:01 -08:00
|
|
|
}
|
2017-02-28 12:35:00 +01:00
|
|
|
};
|
2017-03-22 14:19:29 +01:00
|
|
|
let sig = self.erase_lifetimes(&sig);
|
2017-08-10 08:48:38 -07:00
|
|
|
self.eval_fn_call(
|
|
|
|
fn_def,
|
|
|
|
destination,
|
|
|
|
args,
|
|
|
|
terminator.source_info.span,
|
|
|
|
sig,
|
|
|
|
)?;
|
2016-06-23 01:03:58 -06:00
|
|
|
}
|
|
|
|
|
2017-08-10 08:48:38 -07:00
|
|
|
Drop {
|
|
|
|
ref location,
|
|
|
|
target,
|
|
|
|
..
|
|
|
|
} => {
|
2017-03-22 17:32:20 +01:00
|
|
|
trace!("TerminatorKind::drop: {:?}, {:?}", location, self.substs());
|
2017-07-25 11:32:48 +02:00
|
|
|
// FIXME(CTFE): forbid drop in const eval
|
2017-03-22 13:13:52 +01:00
|
|
|
let lval = self.eval_lvalue(location)?;
|
|
|
|
let ty = self.lvalue_ty(location);
|
2017-03-22 17:32:20 +01:00
|
|
|
self.goto_block(target);
|
2017-07-20 16:40:57 +02:00
|
|
|
let ty = eval_context::apply_param_substs(self.tcx, self.substs(), &ty);
|
2017-03-22 13:13:52 +01:00
|
|
|
|
2017-07-20 16:40:57 +02:00
|
|
|
let instance = eval_context::resolve_drop_in_place(self.tcx, ty);
|
2017-08-10 08:48:38 -07:00
|
|
|
self.drop_lvalue(
|
|
|
|
lval,
|
|
|
|
instance,
|
|
|
|
ty,
|
|
|
|
terminator.source_info.span,
|
|
|
|
)?;
|
2017-03-22 13:13:52 +01:00
|
|
|
}
|
2016-06-23 01:03:58 -06:00
|
|
|
|
2017-08-10 08:48:38 -07:00
|
|
|
Assert {
|
|
|
|
ref cond,
|
|
|
|
expected,
|
|
|
|
ref msg,
|
|
|
|
target,
|
|
|
|
..
|
|
|
|
} => {
|
2016-12-16 22:01:01 -08:00
|
|
|
let cond_val = self.eval_operand_to_primval(cond)?.to_bool()?;
|
2016-09-19 02:19:31 -06:00
|
|
|
if expected == cond_val {
|
2016-07-06 17:55:05 +02:00
|
|
|
self.goto_block(target);
|
2016-06-23 01:03:58 -06:00
|
|
|
} else {
|
|
|
|
return match *msg {
|
|
|
|
mir::AssertMessage::BoundsCheck { ref len, ref index } => {
|
2016-09-19 19:01:28 -06:00
|
|
|
let span = terminator.source_info.span;
|
2016-11-26 22:58:01 -08:00
|
|
|
let len = self.eval_operand_to_primval(len)
|
|
|
|
.expect("can't eval len")
|
2016-12-16 22:01:01 -08:00
|
|
|
.to_u64()?;
|
2016-09-19 19:01:28 -06:00
|
|
|
let index = self.eval_operand_to_primval(index)
|
|
|
|
.expect("can't eval index")
|
2016-12-16 22:01:01 -08:00
|
|
|
.to_u64()?;
|
2017-08-02 16:59:01 +02:00
|
|
|
err!(ArrayIndexOutOfBounds(span, len, index))
|
2017-08-10 08:48:38 -07:00
|
|
|
}
|
|
|
|
mir::AssertMessage::Math(ref err) => {
|
|
|
|
err!(Math(terminator.source_info.span, err.clone()))
|
|
|
|
}
|
|
|
|
};
|
2016-06-23 01:03:58 -06:00
|
|
|
}
|
2017-08-10 08:48:38 -07:00
|
|
|
}
|
2016-06-23 01:03:58 -06:00
|
|
|
|
|
|
|
DropAndReplace { .. } => unimplemented!(),
|
|
|
|
Resume => unimplemented!(),
|
2017-08-02 16:59:01 +02:00
|
|
|
Unreachable => return err!(Unreachable),
|
2016-06-23 01:03:58 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2017-05-30 10:24:37 -07:00
|
|
|
/// Decides whether it is okay to call the method with signature `real_sig` using signature `sig`.
|
|
|
|
/// FIXME: This should take into account the platform-dependent ABI description.
|
2017-05-26 20:02:51 -07:00
|
|
|
fn check_sig_compat(
|
|
|
|
&mut self,
|
|
|
|
sig: ty::FnSig<'tcx>,
|
|
|
|
real_sig: ty::FnSig<'tcx>,
|
|
|
|
) -> EvalResult<'tcx, bool> {
|
2017-08-10 08:48:38 -07:00
|
|
|
fn check_ty_compat<'tcx>(ty: ty::Ty<'tcx>, real_ty: ty::Ty<'tcx>) -> bool {
|
|
|
|
if ty == real_ty {
|
|
|
|
return true;
|
|
|
|
} // This is actually a fast pointer comparison
|
2017-05-26 20:02:51 -07:00
|
|
|
return match (&ty.sty, &real_ty.sty) {
|
|
|
|
// Permit changing the pointer type of raw pointers and references as well as
|
|
|
|
// mutability of raw pointers.
|
|
|
|
// TODO: Should not be allowed when fat pointers are involved.
|
|
|
|
(&TypeVariants::TyRawPtr(_), &TypeVariants::TyRawPtr(_)) => true,
|
2017-08-10 08:48:38 -07:00
|
|
|
(&TypeVariants::TyRef(_, _), &TypeVariants::TyRef(_, _)) => {
|
|
|
|
ty.is_mutable_pointer() == real_ty.is_mutable_pointer()
|
|
|
|
}
|
2017-05-26 20:02:51 -07:00
|
|
|
// rule out everything else
|
2017-08-10 08:48:38 -07:00
|
|
|
_ => false,
|
|
|
|
};
|
2017-05-26 20:02:51 -07:00
|
|
|
}
|
|
|
|
|
2017-08-10 08:48:38 -07:00
|
|
|
if sig.abi == real_sig.abi && sig.variadic == real_sig.variadic &&
|
2017-05-26 20:02:51 -07:00
|
|
|
sig.inputs_and_output.len() == real_sig.inputs_and_output.len() &&
|
2017-08-10 08:48:38 -07:00
|
|
|
sig.inputs_and_output
|
|
|
|
.iter()
|
|
|
|
.zip(real_sig.inputs_and_output)
|
|
|
|
.all(|(ty, real_ty)| check_ty_compat(ty, real_ty))
|
|
|
|
{
|
2017-05-26 20:02:51 -07:00
|
|
|
// Definitely good.
|
|
|
|
return Ok(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
if sig.variadic || real_sig.variadic {
|
|
|
|
// We're not touching this
|
|
|
|
return Ok(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
// We need to allow what comes up when a non-capturing closure is cast to a fn().
|
|
|
|
match (sig.abi, real_sig.abi) {
|
|
|
|
(Abi::Rust, Abi::RustCall) // check the ABIs. This makes the test here non-symmetric.
|
|
|
|
if check_ty_compat(sig.output(), real_sig.output()) && real_sig.inputs_and_output.len() == 3 => {
|
|
|
|
// First argument of real_sig must be a ZST
|
|
|
|
let fst_ty = real_sig.inputs_and_output[0];
|
|
|
|
let layout = self.type_layout(fst_ty)?;
|
|
|
|
let size = layout.size(&self.tcx.data_layout).bytes();
|
|
|
|
if size == 0 {
|
|
|
|
// Second argument must be a tuple matching the argument list of sig
|
|
|
|
let snd_ty = real_sig.inputs_and_output[1];
|
|
|
|
match snd_ty.sty {
|
|
|
|
TypeVariants::TyTuple(tys, _) if sig.inputs().len() == tys.len() =>
|
|
|
|
if sig.inputs().iter().zip(tys).all(|(ty, real_ty)| check_ty_compat(ty, real_ty)) {
|
|
|
|
return Ok(true)
|
|
|
|
},
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Nope, this doesn't work.
|
|
|
|
return Ok(false);
|
|
|
|
}
|
|
|
|
|
2016-06-23 01:03:58 -06:00
|
|
|
fn eval_fn_call(
|
|
|
|
&mut self,
|
2017-03-21 13:53:55 +01:00
|
|
|
instance: ty::Instance<'tcx>,
|
2017-08-08 14:22:11 +02:00
|
|
|
destination: Option<(Lvalue, mir::BasicBlock)>,
|
2016-09-19 19:40:56 -06:00
|
|
|
arg_operands: &[mir::Operand<'tcx>],
|
2016-06-23 01:03:58 -06:00
|
|
|
span: Span,
|
2017-03-22 14:19:29 +01:00
|
|
|
sig: ty::FnSig<'tcx>,
|
2017-02-04 13:09:10 -08:00
|
|
|
) -> EvalResult<'tcx> {
|
2017-03-22 13:13:52 +01:00
|
|
|
trace!("eval_fn_call: {:#?}", instance);
|
|
|
|
match instance.def {
|
|
|
|
ty::InstanceDef::Intrinsic(..) => {
|
2017-01-12 09:59:00 +01:00
|
|
|
let (ret, target) = match destination {
|
2017-03-22 14:19:29 +01:00
|
|
|
Some(dest) => dest,
|
2017-08-02 16:59:01 +02:00
|
|
|
_ => return err!(Unreachable),
|
2017-01-12 09:59:00 +01:00
|
|
|
};
|
2017-03-22 14:19:29 +01:00
|
|
|
let ty = sig.output();
|
2017-07-21 13:39:06 +02:00
|
|
|
if !eval_context::is_inhabited(self.tcx, ty) {
|
2017-08-02 16:59:01 +02:00
|
|
|
return err!(Unreachable);
|
2017-03-22 14:19:29 +01:00
|
|
|
}
|
|
|
|
let layout = self.type_layout(ty)?;
|
2017-07-28 13:08:27 +02:00
|
|
|
M::call_intrinsic(self, instance, arg_operands, ret, ty, layout, target)?;
|
2017-02-07 01:03:40 -08:00
|
|
|
self.dump_local(ret);
|
2017-03-22 14:19:29 +01:00
|
|
|
Ok(())
|
2017-08-10 08:48:38 -07:00
|
|
|
}
|
|
|
|
ty::InstanceDef::ClosureOnceShim { .. } => {
|
2016-09-19 19:40:56 -06:00
|
|
|
let mut args = Vec::new();
|
|
|
|
for arg in arg_operands {
|
|
|
|
let arg_val = self.eval_operand(arg)?;
|
|
|
|
let arg_ty = self.operand_ty(arg);
|
|
|
|
args.push((arg_val, arg_ty));
|
2016-06-23 01:03:58 -06:00
|
|
|
}
|
2017-08-10 08:48:38 -07:00
|
|
|
if M::eval_fn_call(self, instance, destination, arg_operands, span, sig)? {
|
2017-03-23 17:36:10 +01:00
|
|
|
return Ok(());
|
|
|
|
}
|
2017-03-23 13:36:13 +01:00
|
|
|
let mut arg_locals = self.frame().mir.args_iter();
|
|
|
|
match sig.abi {
|
|
|
|
// closure as closure once
|
|
|
|
Abi::RustCall => {
|
|
|
|
for (arg_local, (arg_val, arg_ty)) in arg_locals.zip(args) {
|
|
|
|
let dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?;
|
|
|
|
self.write_value(arg_val, dest, arg_ty)?;
|
|
|
|
}
|
2017-08-10 08:48:38 -07:00
|
|
|
}
|
2017-03-23 13:36:13 +01:00
|
|
|
// non capture closure as fn ptr
|
|
|
|
// need to inject zst ptr for closure object (aka do nothing)
|
|
|
|
// and need to pack arguments
|
|
|
|
Abi::Rust => {
|
2017-08-10 08:48:38 -07:00
|
|
|
trace!(
|
|
|
|
"arg_locals: {:?}",
|
|
|
|
self.frame().mir.args_iter().collect::<Vec<_>>()
|
|
|
|
);
|
2017-03-23 13:36:13 +01:00
|
|
|
trace!("arg_operands: {:?}", arg_operands);
|
|
|
|
let local = arg_locals.nth(1).unwrap();
|
|
|
|
for (i, (arg_val, arg_ty)) in args.into_iter().enumerate() {
|
2017-08-10 08:48:38 -07:00
|
|
|
let dest = self.eval_lvalue(&mir::Lvalue::Local(local).field(
|
|
|
|
mir::Field::new(i),
|
|
|
|
arg_ty,
|
|
|
|
))?;
|
2017-03-23 13:36:13 +01:00
|
|
|
self.write_value(arg_val, dest, arg_ty)?;
|
|
|
|
}
|
2017-08-10 08:48:38 -07:00
|
|
|
}
|
2017-03-23 13:36:13 +01:00
|
|
|
_ => bug!("bad ABI for ClosureOnceShim: {:?}", sig.abi),
|
|
|
|
}
|
|
|
|
Ok(())
|
2017-03-22 13:13:52 +01:00
|
|
|
}
|
|
|
|
ty::InstanceDef::Item(_) => {
|
2017-03-23 13:36:13 +01:00
|
|
|
let mut args = Vec::new();
|
|
|
|
for arg in arg_operands {
|
|
|
|
let arg_val = self.eval_operand(arg)?;
|
|
|
|
let arg_ty = self.operand_ty(arg);
|
|
|
|
args.push((arg_val, arg_ty));
|
|
|
|
}
|
|
|
|
|
2017-05-25 22:38:07 -07:00
|
|
|
// Push the stack frame, and potentially be entirely done if the call got hooked
|
2017-08-10 08:48:38 -07:00
|
|
|
if M::eval_fn_call(self, instance, destination, arg_operands, span, sig)? {
|
2017-03-23 17:36:10 +01:00
|
|
|
return Ok(());
|
|
|
|
}
|
2017-03-23 13:36:13 +01:00
|
|
|
|
2017-05-25 22:38:07 -07:00
|
|
|
// Pass the arguments
|
2017-03-23 13:36:13 +01:00
|
|
|
let mut arg_locals = self.frame().mir.args_iter();
|
2017-03-23 16:09:36 +01:00
|
|
|
trace!("ABI: {:?}", sig.abi);
|
2017-08-10 08:48:38 -07:00
|
|
|
trace!(
|
|
|
|
"arg_locals: {:?}",
|
|
|
|
self.frame().mir.args_iter().collect::<Vec<_>>()
|
|
|
|
);
|
2017-03-23 16:09:36 +01:00
|
|
|
trace!("arg_operands: {:?}", arg_operands);
|
2017-03-23 13:36:13 +01:00
|
|
|
match sig.abi {
|
|
|
|
Abi::RustCall => {
|
|
|
|
assert_eq!(args.len(), 2);
|
|
|
|
|
2017-08-10 08:48:38 -07:00
|
|
|
{
|
|
|
|
// write first argument
|
2017-03-23 13:36:13 +01:00
|
|
|
let first_local = arg_locals.next().unwrap();
|
|
|
|
let dest = self.eval_lvalue(&mir::Lvalue::Local(first_local))?;
|
|
|
|
let (arg_val, arg_ty) = args.remove(0);
|
|
|
|
self.write_value(arg_val, dest, arg_ty)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
// unpack and write all other args
|
|
|
|
let (arg_val, arg_ty) = args.remove(0);
|
|
|
|
let layout = self.type_layout(arg_ty)?;
|
2017-08-10 08:48:38 -07:00
|
|
|
if let (&ty::TyTuple(fields, _),
|
|
|
|
&Layout::Univariant { ref variant, .. }) = (&arg_ty.sty, layout)
|
|
|
|
{
|
2017-03-23 16:09:36 +01:00
|
|
|
trace!("fields: {:?}", fields);
|
2017-03-23 15:07:33 +01:00
|
|
|
if self.frame().mir.args_iter().count() == fields.len() + 1 {
|
|
|
|
let offsets = variant.offsets.iter().map(|s| s.bytes());
|
2017-03-23 16:09:36 +01:00
|
|
|
match arg_val {
|
2017-08-08 15:53:07 +02:00
|
|
|
Value::ByRef(PtrAndAlign { ptr, aligned }) => {
|
2017-08-10 08:48:38 -07:00
|
|
|
assert!(
|
|
|
|
aligned,
|
|
|
|
"Unaligned ByRef-values cannot occur as function arguments"
|
|
|
|
);
|
|
|
|
for ((offset, ty), arg_local) in
|
|
|
|
offsets.zip(fields).zip(arg_locals)
|
|
|
|
{
|
2017-08-08 15:53:07 +02:00
|
|
|
let arg = Value::by_ref(ptr.offset(offset, &self)?);
|
2017-08-10 08:48:38 -07:00
|
|
|
let dest =
|
|
|
|
self.eval_lvalue(&mir::Lvalue::Local(arg_local))?;
|
|
|
|
trace!(
|
|
|
|
"writing arg {:?} to {:?} (type: {})",
|
|
|
|
arg,
|
|
|
|
dest,
|
|
|
|
ty
|
|
|
|
);
|
2017-03-23 16:09:36 +01:00
|
|
|
self.write_value(arg, dest, ty)?;
|
|
|
|
}
|
2017-08-10 08:48:38 -07:00
|
|
|
}
|
|
|
|
Value::ByVal(PrimVal::Undef) => {}
|
2017-03-23 16:09:36 +01:00
|
|
|
other => {
|
|
|
|
assert_eq!(fields.len(), 1);
|
2017-08-10 08:48:38 -07:00
|
|
|
let dest = self.eval_lvalue(&mir::Lvalue::Local(
|
|
|
|
arg_locals.next().unwrap(),
|
|
|
|
))?;
|
2017-03-23 16:09:36 +01:00
|
|
|
self.write_value(other, dest, fields[0])?;
|
2017-03-23 15:07:33 +01:00
|
|
|
}
|
2017-03-23 13:36:13 +01:00
|
|
|
}
|
2017-03-23 15:07:33 +01:00
|
|
|
} else {
|
2017-03-23 16:09:36 +01:00
|
|
|
trace!("manual impl of rust-call ABI");
|
2017-03-23 15:07:33 +01:00
|
|
|
// called a manual impl of a rust-call function
|
2017-08-10 08:48:38 -07:00
|
|
|
let dest = self.eval_lvalue(
|
|
|
|
&mir::Lvalue::Local(arg_locals.next().unwrap()),
|
|
|
|
)?;
|
2017-03-23 15:07:33 +01:00
|
|
|
self.write_value(arg_val, dest, arg_ty)?;
|
2017-03-23 13:36:13 +01:00
|
|
|
}
|
|
|
|
} else {
|
2017-08-10 08:48:38 -07:00
|
|
|
bug!(
|
|
|
|
"rust-call ABI tuple argument was {:?}, {:?}",
|
|
|
|
arg_ty,
|
|
|
|
layout
|
|
|
|
);
|
2017-03-23 13:36:13 +01:00
|
|
|
}
|
2017-08-10 08:48:38 -07:00
|
|
|
}
|
2017-05-30 10:24:37 -07:00
|
|
|
_ => {
|
|
|
|
for (arg_local, (arg_val, arg_ty)) in arg_locals.zip(args) {
|
|
|
|
let dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?;
|
|
|
|
self.write_value(arg_val, dest, arg_ty)?;
|
|
|
|
}
|
2017-03-23 13:36:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
2017-08-10 08:48:38 -07:00
|
|
|
}
|
2017-03-22 18:31:41 +01:00
|
|
|
ty::InstanceDef::DropGlue(..) => {
|
|
|
|
assert_eq!(arg_operands.len(), 1);
|
|
|
|
assert_eq!(sig.abi, Abi::Rust);
|
|
|
|
let val = self.eval_operand(&arg_operands[0])?;
|
|
|
|
let ty = self.operand_ty(&arg_operands[0]);
|
|
|
|
let (_, target) = destination.expect("diverging drop glue");
|
|
|
|
self.goto_block(target);
|
|
|
|
// FIXME: deduplicate these matches
|
|
|
|
let pointee_type = match ty.sty {
|
|
|
|
ty::TyRawPtr(ref tam) |
|
|
|
|
ty::TyRef(_, ref tam) => tam.ty,
|
2017-04-26 12:15:42 +02:00
|
|
|
ty::TyAdt(def, _) if def.is_box() => ty.boxed_ty(),
|
2017-03-22 18:31:41 +01:00
|
|
|
_ => bug!("can only deref pointer types"),
|
|
|
|
};
|
|
|
|
self.drop(val, instance, pointee_type, span)
|
2017-08-10 08:48:38 -07:00
|
|
|
}
|
2017-03-23 10:04:08 +01:00
|
|
|
ty::InstanceDef::FnPtrShim(..) => {
|
2017-03-23 13:36:13 +01:00
|
|
|
trace!("ABI: {}", sig.abi);
|
2017-03-23 10:04:08 +01:00
|
|
|
let mut args = Vec::new();
|
|
|
|
for arg in arg_operands {
|
|
|
|
let arg_val = self.eval_operand(arg)?;
|
|
|
|
let arg_ty = self.operand_ty(arg);
|
|
|
|
args.push((arg_val, arg_ty));
|
|
|
|
}
|
2017-08-10 08:48:38 -07:00
|
|
|
if M::eval_fn_call(self, instance, destination, arg_operands, span, sig)? {
|
2017-03-23 17:36:10 +01:00
|
|
|
return Ok(());
|
|
|
|
}
|
2017-03-23 13:36:13 +01:00
|
|
|
let arg_locals = self.frame().mir.args_iter();
|
2017-03-23 10:04:08 +01:00
|
|
|
match sig.abi {
|
|
|
|
Abi::Rust => {
|
|
|
|
args.remove(0);
|
2017-08-10 08:48:38 -07:00
|
|
|
}
|
|
|
|
Abi::RustCall => {}
|
2017-03-23 10:04:08 +01:00
|
|
|
_ => unimplemented!(),
|
2017-03-23 13:36:13 +01:00
|
|
|
};
|
|
|
|
for (arg_local, (arg_val, arg_ty)) in arg_locals.zip(args) {
|
|
|
|
let dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?;
|
|
|
|
self.write_value(arg_val, dest, arg_ty)?;
|
2017-03-23 10:04:08 +01:00
|
|
|
}
|
2017-03-23 13:36:13 +01:00
|
|
|
Ok(())
|
2017-08-10 08:48:38 -07:00
|
|
|
}
|
2017-03-23 14:24:02 +01:00
|
|
|
ty::InstanceDef::Virtual(_, idx) => {
|
|
|
|
let ptr_size = self.memory.pointer_size();
|
2017-08-10 08:48:38 -07:00
|
|
|
let (_, vtable) = self.eval_operand(&arg_operands[0])?.into_ptr_vtable_pair(
|
|
|
|
&self.memory,
|
|
|
|
)?;
|
|
|
|
let fn_ptr = self.memory.read_ptr(
|
|
|
|
vtable.offset(ptr_size * (idx as u64 + 3), &self)?,
|
|
|
|
)?;
|
2017-06-21 21:45:51 -07:00
|
|
|
let instance = self.memory.get_fn(fn_ptr.to_ptr()?)?;
|
2017-03-23 18:32:57 +01:00
|
|
|
let mut arg_operands = arg_operands.to_vec();
|
|
|
|
let ty = self.operand_ty(&arg_operands[0]);
|
2017-07-28 19:43:05 -07:00
|
|
|
let ty = self.get_field_ty(ty, 0)?.ty; // TODO: packed flag is ignored
|
2017-03-23 18:32:57 +01:00
|
|
|
match arg_operands[0] {
|
2017-08-10 08:48:38 -07:00
|
|
|
mir::Operand::Consume(ref mut lval) => {
|
|
|
|
*lval = lval.clone().field(mir::Field::new(0), ty)
|
|
|
|
}
|
2017-03-23 18:32:57 +01:00
|
|
|
_ => bug!("virtual call first arg cannot be a constant"),
|
|
|
|
}
|
2017-03-23 14:57:11 +01:00
|
|
|
// recurse with concrete function
|
2017-08-10 08:48:38 -07:00
|
|
|
self.eval_fn_call(instance, destination, &arg_operands, span, sig)
|
|
|
|
}
|
2017-02-28 12:35:00 +01:00
|
|
|
}
|
|
|
|
}
|
2016-06-23 01:03:58 -06:00
|
|
|
|
2017-08-10 08:48:38 -07:00
|
|
|
pub fn read_discriminant_value(
|
|
|
|
&self,
|
|
|
|
adt_ptr: MemoryPointer,
|
|
|
|
adt_ty: Ty<'tcx>,
|
|
|
|
) -> EvalResult<'tcx, u128> {
|
2016-06-23 01:03:58 -06:00
|
|
|
use rustc::ty::layout::Layout::*;
|
2016-11-17 17:23:40 +01:00
|
|
|
let adt_layout = self.type_layout(adt_ty)?;
|
2017-07-13 23:42:18 -07:00
|
|
|
//trace!("read_discriminant_value {:#?}", adt_layout);
|
2016-06-23 01:03:58 -06:00
|
|
|
|
|
|
|
let discr_val = match *adt_layout {
|
2017-08-10 08:48:38 -07:00
|
|
|
General { discr, .. } |
|
|
|
|
CEnum {
|
|
|
|
discr,
|
|
|
|
signed: false,
|
|
|
|
..
|
|
|
|
} => {
|
2016-06-23 01:03:58 -06:00
|
|
|
let discr_size = discr.size().bytes();
|
2016-11-18 12:55:14 +01:00
|
|
|
self.memory.read_uint(adt_ptr, discr_size)?
|
2016-06-23 01:03:58 -06:00
|
|
|
}
|
|
|
|
|
2017-08-10 08:48:38 -07:00
|
|
|
CEnum {
|
|
|
|
discr,
|
|
|
|
signed: true,
|
|
|
|
..
|
|
|
|
} => {
|
2016-11-05 02:53:02 +00:00
|
|
|
let discr_size = discr.size().bytes();
|
2017-01-12 08:28:42 +01:00
|
|
|
self.memory.read_int(adt_ptr, discr_size)? as u128
|
2016-11-05 02:53:02 +00:00
|
|
|
}
|
|
|
|
|
2016-11-11 13:10:47 +01:00
|
|
|
RawNullablePointer { nndiscr, value } => {
|
2016-11-18 12:55:14 +01:00
|
|
|
let discr_size = value.size(&self.tcx.data_layout).bytes();
|
2016-11-17 14:48:34 +01:00
|
|
|
trace!("rawnullablepointer with size {}", discr_size);
|
2017-08-10 08:48:38 -07:00
|
|
|
self.read_nonnull_discriminant_value(
|
|
|
|
adt_ptr,
|
|
|
|
nndiscr as u128,
|
|
|
|
discr_size,
|
|
|
|
)?
|
2016-06-23 01:03:58 -06:00
|
|
|
}
|
|
|
|
|
2017-08-10 08:48:38 -07:00
|
|
|
StructWrappedNullablePointer {
|
|
|
|
nndiscr,
|
|
|
|
ref discrfield_source,
|
|
|
|
..
|
|
|
|
} => {
|
|
|
|
let (offset, TyAndPacked { ty, packed }) = self.nonnull_offset_and_ty(
|
|
|
|
adt_ty,
|
|
|
|
nndiscr,
|
|
|
|
discrfield_source,
|
|
|
|
)?;
|
2017-07-26 23:43:13 -07:00
|
|
|
let nonnull = adt_ptr.offset(offset.bytes(), &*self)?;
|
2016-11-17 14:48:34 +01:00
|
|
|
trace!("struct wrapped nullable pointer type: {}", ty);
|
2016-11-11 13:10:47 +01:00
|
|
|
// only the pointer part of a fat pointer is used for this space optimization
|
2017-08-10 08:48:38 -07:00
|
|
|
let discr_size = self.type_size(ty)?.expect(
|
|
|
|
"bad StructWrappedNullablePointer discrfield",
|
|
|
|
);
|
|
|
|
self.read_maybe_aligned(!packed, |ectx| {
|
|
|
|
ectx.read_nonnull_discriminant_value(nonnull, nndiscr as u128, discr_size)
|
|
|
|
})?
|
2016-06-23 01:03:58 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// The discriminant_value intrinsic returns 0 for non-sum types.
|
2017-08-10 08:48:38 -07:00
|
|
|
Array { .. } |
|
|
|
|
FatPointer { .. } |
|
|
|
|
Scalar { .. } |
|
|
|
|
Univariant { .. } |
|
|
|
|
Vector { .. } |
|
|
|
|
UntaggedUnion { .. } => 0,
|
2016-06-23 01:03:58 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
Ok(discr_val)
|
|
|
|
}
|
|
|
|
|
2017-08-10 08:48:38 -07:00
|
|
|
fn read_nonnull_discriminant_value(
|
|
|
|
&self,
|
|
|
|
ptr: MemoryPointer,
|
|
|
|
nndiscr: u128,
|
|
|
|
discr_size: u64,
|
|
|
|
) -> EvalResult<'tcx, u128> {
|
|
|
|
trace!(
|
|
|
|
"read_nonnull_discriminant_value: {:?}, {}, {}",
|
|
|
|
ptr,
|
|
|
|
nndiscr,
|
|
|
|
discr_size
|
|
|
|
);
|
2016-11-11 13:10:47 +01:00
|
|
|
let not_null = match self.memory.read_uint(ptr, discr_size) {
|
2016-06-23 01:03:58 -06:00
|
|
|
Ok(0) => false,
|
2017-08-10 08:48:38 -07:00
|
|
|
Ok(_) |
|
|
|
|
Err(EvalError { kind: EvalErrorKind::ReadPointerAsBytes, .. }) => true,
|
2016-06-23 01:03:58 -06:00
|
|
|
Err(e) => return Err(e),
|
|
|
|
};
|
|
|
|
assert!(nndiscr == 0 || nndiscr == 1);
|
|
|
|
Ok(if not_null { nndiscr } else { 1 - nndiscr })
|
|
|
|
}
|
2016-09-20 12:52:01 +02:00
|
|
|
}
|