unify the way we intercept missing MIR and C ABI calls; only intercept C ABI calls if MIR is missing

This commit is contained in:
Ralf Jung 2017-05-26 12:25:25 -07:00
parent 14b16dcf45
commit 55438fe5bf

View File

@ -172,7 +172,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
if self.eval_fn_call_inner(
instance,
destination,
arg_operands,
span,
sig,
)? {
return Ok(());
}
@ -202,18 +204,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Ok(())
}
ty::InstanceDef::Item(_) => {
match sig.abi {
Abi::C => {
let ty = sig.output();
let (ret, target) = destination.unwrap();
self.call_c_abi(instance.def_id(), arg_operands, ret, ty)?;
self.dump_local(ret);
self.goto_block(target);
return Ok(());
},
Abi::Rust | Abi::RustCall => {},
_ => unimplemented!(),
}
let mut args = Vec::new();
for arg in arg_operands {
let arg_val = self.eval_operand(arg)?;
@ -225,7 +215,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
if self.eval_fn_call_inner(
instance,
destination,
arg_operands,
span,
sig,
)? {
return Ok(());
}
@ -236,7 +228,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
trace!("arg_locals: {:?}", self.frame().mir.args_iter().collect::<Vec<_>>());
trace!("arg_operands: {:?}", arg_operands);
match sig.abi {
Abi::Rust => {
Abi::Rust | Abi::C => {
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)?;
@ -316,7 +308,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
if self.eval_fn_call_inner(
instance,
destination,
arg_operands,
span,
sig,
)? {
return Ok(());
}
@ -363,7 +357,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
&mut self,
instance: ty::Instance<'tcx>,
destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>,
arg_operands: &[mir::Operand<'tcx>],
span: Span,
sig: ty::FnSig<'tcx>,
) -> EvalResult<'tcx, bool> {
trace!("eval_fn_call_inner: {:#?}, {:#?}", instance, destination);
@ -372,28 +368,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let mir = match self.load_mir(instance.def) {
Ok(mir) => mir,
Err(EvalError::NoMirFor(path)) => {
return match &path[..] {
// Intercept some methods if we cannot find their MIR.
"std::io::_print" => {
trace!("Ignoring output.");
self.goto_block(destination.unwrap().1);
Ok(true)
},
"std::thread::Builder::new" => Err(EvalError::Unimplemented("miri does not support threading".to_owned())),
"std::env::args" => Err(EvalError::Unimplemented("miri does not support program arguments".to_owned())),
"std::panicking::rust_panic_with_hook" |
"std::rt::begin_panic_fmt" => Err(EvalError::Panic),
"std::panicking::panicking" |
"std::rt::panicking" => {
let (lval, block) = destination.expect("std::rt::panicking does not diverge");
// we abort on panic -> `std::rt::panicking` always returns false
let bool = self.tcx.types.bool;
self.write_primval(lval, PrimVal::from_bool(false), bool)?;
self.goto_block(block);
Ok(true)
}
_ => Err(EvalError::NoMirFor(path)),
};
self.call_missing_fn(instance, destination, arg_operands, sig, path)?;
return Ok(true);
},
Err(other) => return Err(other),
};
@ -466,6 +442,50 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
assert!(nndiscr == 0 || nndiscr == 1);
Ok(if not_null { nndiscr } else { 1 - nndiscr })
}
/// Returns Ok() when the function was handled, fail otherwise
fn call_missing_fn(
&mut self,
instance: ty::Instance<'tcx>,
destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>,
arg_operands: &[mir::Operand<'tcx>],
sig: ty::FnSig<'tcx>,
path: String,
) -> EvalResult<'tcx> {
if sig.abi == Abi::C {
// An external C function
let ty = sig.output();
let (ret, target) = destination.unwrap();
self.call_c_abi(instance.def_id(), arg_operands, ret, ty)?;
self.dump_local(ret);
self.goto_block(target);
return Ok(());
}
// A Rust function is missing, which means we are running with MIR missing for libstd (or other dependencies).
// Still, we can make many things mostly work by "emulating" or ignoring some functions.
match &path[..] {
"std::io::_print" => {
trace!("Ignoring output.");
self.goto_block(destination.unwrap().1);
Ok(())
},
"std::thread::Builder::new" => Err(EvalError::Unimplemented("miri does not support threading".to_owned())),
"std::env::args" => Err(EvalError::Unimplemented("miri does not support program arguments".to_owned())),
"std::panicking::rust_panic_with_hook" |
"std::rt::begin_panic_fmt" => Err(EvalError::Panic),
"std::panicking::panicking" |
"std::rt::panicking" => {
let (lval, block) = destination.expect("std::rt::panicking does not diverge");
// we abort on panic -> `std::rt::panicking` always returns false
let bool = self.tcx.types.bool;
self.write_primval(lval, PrimVal::from_bool(false), bool)?;
self.goto_block(block);
Ok(())
}
_ => Err(EvalError::NoMirFor(path)),
}
}
fn call_c_abi(
&mut self,