Merge pull request #56 from oli-obk/rustc_run_pass
various things that allow miri to crash less and execute more code
This commit is contained in:
commit
8a2e2dd665
@ -1093,12 +1093,20 @@ fn report(tcx: TyCtxt, ecx: &EvalContext, e: EvalError) {
|
||||
use rustc::util::ppaux;
|
||||
use std::fmt;
|
||||
struct Instance<'tcx>(DefId, &'tcx subst::Substs<'tcx>);
|
||||
impl<'tcx> ::std::panic::UnwindSafe for Instance<'tcx> {}
|
||||
impl<'tcx> ::std::panic::RefUnwindSafe for Instance<'tcx> {}
|
||||
impl<'tcx> fmt::Display for Instance<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
ppaux::parameterized(f, self.1, self.0, ppaux::Ns::Value, &[])
|
||||
}
|
||||
}
|
||||
err.span_note(span, &format!("inside call to {}", Instance(def_id, substs)));
|
||||
let inst = Instance(def_id, substs);
|
||||
match ::std::panic::catch_unwind(|| {
|
||||
format!("inside call to {}", inst)
|
||||
}) {
|
||||
Ok(msg) => err.span_note(span, &msg),
|
||||
Err(_) => err.span_note(span, &format!("ppaux::parameterized failed: {:?}, {:?}", def_id, substs)),
|
||||
};
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
|
@ -182,29 +182,27 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
// Only trait methods can have a Self parameter.
|
||||
let (resolved_def_id, resolved_substs) =
|
||||
if let Some(trait_id) = self.tcx.trait_of_item(def_id) {
|
||||
self.trait_method(trait_id, def_id, substs, arg_srcs.get_mut(0))?
|
||||
self.trait_method(trait_id, def_id, substs, &mut arg_srcs)?
|
||||
} else {
|
||||
(def_id, substs)
|
||||
};
|
||||
|
||||
if fn_ty.abi == Abi::RustCall && !args.is_empty() {
|
||||
arg_srcs.pop();
|
||||
let last_arg = args.last().unwrap();
|
||||
let last = self.eval_operand(last_arg)?;
|
||||
let last_ty = self.operand_ty(last_arg);
|
||||
let last_layout = self.type_layout(last_ty);
|
||||
match (&last_ty.sty, last_layout) {
|
||||
(&ty::TyTuple(fields),
|
||||
&Layout::Univariant { ref variant, .. }) => {
|
||||
let offsets = iter::once(0)
|
||||
.chain(variant.offset_after_field.iter()
|
||||
.map(|s| s.bytes()));
|
||||
for (offset, ty) in offsets.zip(fields) {
|
||||
let src = last.offset(offset as isize);
|
||||
arg_srcs.push((src, ty));
|
||||
if fn_ty.abi == Abi::RustCall {
|
||||
if let Some((last, last_ty)) = arg_srcs.pop() {
|
||||
let last_layout = self.type_layout(last_ty);
|
||||
match (&last_ty.sty, last_layout) {
|
||||
(&ty::TyTuple(fields),
|
||||
&Layout::Univariant { ref variant, .. }) => {
|
||||
let offsets = iter::once(0)
|
||||
.chain(variant.offset_after_field.iter()
|
||||
.map(|s| s.bytes()));
|
||||
for (offset, ty) in offsets.zip(fields) {
|
||||
let src = last.offset(offset as isize);
|
||||
arg_srcs.push((src, ty));
|
||||
}
|
||||
}
|
||||
ty => bug!("expected tuple as last argument in function with 'rust-call' ABI, got {:?}", ty),
|
||||
}
|
||||
ty => bug!("expected tuple as last argument in function with 'rust-call' ABI, got {:?}", ty),
|
||||
}
|
||||
}
|
||||
|
||||
@ -300,6 +298,20 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
self.memory.copy(src, dest, count as usize * elem_size, elem_align)?;
|
||||
}
|
||||
|
||||
"ctpop" => {
|
||||
let elem_ty = substs.type_at(0);
|
||||
let elem_size = self.type_size(elem_ty);
|
||||
let num = self.memory.read_uint(args_ptrs[0], elem_size)?.count_ones();
|
||||
self.memory.write_uint(dest, num.into(), elem_size)?;
|
||||
}
|
||||
|
||||
"ctlz" => {
|
||||
let elem_ty = substs.type_at(0);
|
||||
let elem_size = self.type_size(elem_ty);
|
||||
let num = self.memory.read_uint(args_ptrs[0], elem_size)?.leading_zeros();
|
||||
self.memory.write_uint(dest, num.into(), elem_size)?;
|
||||
}
|
||||
|
||||
"discriminant_value" => {
|
||||
let ty = substs.type_at(0);
|
||||
let adt_ptr = self.memory.read_ptr(args_ptrs[0])?;
|
||||
@ -495,7 +507,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
trait_id: DefId,
|
||||
def_id: DefId,
|
||||
substs: &'tcx Substs<'tcx>,
|
||||
first_arg: Option<&mut (Pointer, Ty<'tcx>)>,
|
||||
args: &mut Vec<(Pointer, Ty<'tcx>)>,
|
||||
) -> EvalResult<'tcx, (DefId, &'tcx Substs<'tcx>)> {
|
||||
let trait_ref = ty::TraitRef::from_method(self.tcx, trait_id, substs);
|
||||
let trait_ref = self.tcx.normalize_associated_type(&ty::Binder(trait_ref));
|
||||
@ -514,23 +526,18 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
traits::VtableClosure(vtable_closure) =>
|
||||
Ok((vtable_closure.closure_def_id, vtable_closure.substs.func_substs)),
|
||||
|
||||
traits::VtableFnPointer(_fn_ty) => {
|
||||
let _trait_closure_kind = self.tcx.lang_items.fn_trait_kind(trait_id).unwrap();
|
||||
unimplemented!()
|
||||
// let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, fn_ty);
|
||||
|
||||
// let method_ty = def_ty(tcx, def_id, substs);
|
||||
// let fn_ptr_ty = match method_ty.sty {
|
||||
// ty::TyFnDef(_, _, fty) => tcx.mk_ty(ty::TyFnPtr(fty)),
|
||||
// _ => unreachable!("expected fn item type, found {}",
|
||||
// method_ty)
|
||||
// };
|
||||
// Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty))
|
||||
traits::VtableFnPointer(vtable_fn_ptr) => {
|
||||
if let ty::TyFnDef(did, ref substs, _) = vtable_fn_ptr.fn_ty.sty {
|
||||
args.remove(0);
|
||||
Ok((did, substs))
|
||||
} else {
|
||||
bug!("VtableFnPointer did not contain a concrete function: {:?}", vtable_fn_ptr)
|
||||
}
|
||||
}
|
||||
|
||||
traits::VtableObject(ref data) => {
|
||||
let idx = self.tcx.get_vtable_index_of_object_method(data, def_id);
|
||||
if let Some(&mut(first_arg, ref mut first_ty)) = first_arg {
|
||||
if let Some(&mut(first_arg, ref mut first_ty)) = args.get_mut(0) {
|
||||
let (_, vtable) = self.get_fat_ptr(first_arg);
|
||||
let vtable = self.memory.read_ptr(vtable)?;
|
||||
let idx = idx + 3;
|
||||
|
@ -22,6 +22,8 @@ fn run_pass() {
|
||||
let mut config = compiletest::default_config();
|
||||
config.mode = "run-pass".parse().expect("Invalid mode");
|
||||
config.src_base = PathBuf::from("tests/run-pass".to_string());
|
||||
config.target_rustcflags = Some("-Dwarnings".to_string());
|
||||
config.host_rustcflags = Some("-Dwarnings".to_string());
|
||||
compiletest::run_tests(&config);
|
||||
}
|
||||
|
||||
@ -55,7 +57,17 @@ fn compile_test() {
|
||||
compile_fail(&sysroot);
|
||||
run_pass();
|
||||
for_all_targets(&sysroot, |target| {
|
||||
for file in std::fs::read_dir("tests/run-pass").unwrap() {
|
||||
let files = std::fs::read_dir("tests/run-pass").unwrap();
|
||||
let files: Box<Iterator<Item=_>> = if let Ok(path) = std::env::var("MIRI_RUSTC_TEST") {
|
||||
Box::new(files.chain(std::fs::read_dir(path).unwrap()))
|
||||
} else {
|
||||
Box::new(files)
|
||||
};
|
||||
let mut mir_not_found = 0;
|
||||
let mut crate_not_found = 0;
|
||||
let mut success = 0;
|
||||
let mut failed = 0;
|
||||
for file in files {
|
||||
let file = file.unwrap();
|
||||
let path = file.path();
|
||||
|
||||
@ -67,7 +79,6 @@ fn compile_test() {
|
||||
write!(stderr.lock(), "test [miri-pass] {} ... ", path.display()).unwrap();
|
||||
let mut cmd = std::process::Command::new("target/debug/miri");
|
||||
cmd.arg(path);
|
||||
cmd.arg("-Dwarnings");
|
||||
cmd.arg(format!("--target={}", target));
|
||||
let libs = Path::new(&sysroot).join("lib");
|
||||
let sysroot = libs.join("rustlib").join(&target).join("lib");
|
||||
@ -75,20 +86,34 @@ fn compile_test() {
|
||||
cmd.env(compiletest::procsrv::dylib_env_var(), paths);
|
||||
|
||||
match cmd.output() {
|
||||
Ok(ref output) if output.status.success() => writeln!(stderr.lock(), "ok").unwrap(),
|
||||
Ok(ref output) if output.status.success() => {
|
||||
success += 1;
|
||||
writeln!(stderr.lock(), "ok").unwrap()
|
||||
},
|
||||
Ok(output) => {
|
||||
writeln!(stderr.lock(), "FAILED with exit code {:?}", output.status.code()).unwrap();
|
||||
writeln!(stderr.lock(), "stdout: \n {}", std::str::from_utf8(&output.stdout).unwrap()).unwrap();
|
||||
writeln!(stderr.lock(), "stderr: \n {}", std::str::from_utf8(&output.stderr).unwrap()).unwrap();
|
||||
panic!("some tests failed");
|
||||
let output_err = std::str::from_utf8(&output.stderr).unwrap();
|
||||
if let Some(text) = output_err.splitn(2, "thread 'main' panicked at 'no mir for `").nth(1) {
|
||||
mir_not_found += 1;
|
||||
let end = text.find('`').unwrap();
|
||||
writeln!(stderr.lock(), "NO MIR FOR `{}`", &text[..end]).unwrap();
|
||||
} else if let Some(text) = output_err.splitn(2, "can't find crate for `").nth(1) {
|
||||
crate_not_found += 1;
|
||||
let end = text.find('`').unwrap();
|
||||
writeln!(stderr.lock(), "CAN'T FIND CRATE FOR `{}`", &text[..end]).unwrap();
|
||||
} else {
|
||||
failed += 1;
|
||||
writeln!(stderr.lock(), "FAILED with exit code {:?}", output.status.code()).unwrap();
|
||||
writeln!(stderr.lock(), "stdout: \n {}", std::str::from_utf8(&output.stdout).unwrap()).unwrap();
|
||||
writeln!(stderr.lock(), "stderr: \n {}", output_err).unwrap();
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
writeln!(stderr.lock(), "FAILED: {}", e).unwrap();
|
||||
panic!("some tests failed");
|
||||
panic!("failed to execute miri");
|
||||
},
|
||||
}
|
||||
}
|
||||
let stderr = std::io::stderr();
|
||||
writeln!(stderr.lock(), "").unwrap();
|
||||
writeln!(stderr.lock(), "{} success, {} mir not found, {} crate not found, {} failed", success, mir_not_found, crate_not_found, failed).unwrap();
|
||||
});
|
||||
}
|
||||
|
@ -2,6 +2,10 @@ fn f() -> i32 {
|
||||
42
|
||||
}
|
||||
|
||||
fn g(i: i32) -> i32 {
|
||||
i*42
|
||||
}
|
||||
|
||||
fn return_fn_ptr() -> fn() -> i32 {
|
||||
f
|
||||
}
|
||||
@ -10,8 +14,22 @@ fn call_fn_ptr() -> i32 {
|
||||
return_fn_ptr()()
|
||||
}
|
||||
|
||||
fn indirect<F: Fn() -> i32>(f: F) -> i32 { f() }
|
||||
fn indirect_mut<F: FnMut() -> i32>(mut f: F) -> i32 { f() }
|
||||
fn indirect_once<F: FnOnce() -> i32>(f: F) -> i32 { f() }
|
||||
|
||||
fn indirect2<F: Fn(i32) -> i32>(f: F) -> i32 { f(10) }
|
||||
fn indirect_mut2<F: FnMut(i32) -> i32>(mut f: F) -> i32 { f(10) }
|
||||
fn indirect_once2<F: FnOnce(i32) -> i32>(f: F) -> i32 { f(10) }
|
||||
|
||||
fn main() {
|
||||
assert_eq!(call_fn_ptr(), 42);
|
||||
assert_eq!(indirect(f), 42);
|
||||
assert_eq!(indirect_mut(f), 42);
|
||||
assert_eq!(indirect_once(f), 42);
|
||||
assert_eq!(indirect2(g), 420);
|
||||
assert_eq!(indirect_mut2(g), 420);
|
||||
assert_eq!(indirect_once2(g), 420);
|
||||
assert!(return_fn_ptr() == f);
|
||||
assert!(return_fn_ptr() as unsafe fn() -> i32 == f as fn() -> i32 as unsafe fn() -> i32);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user