Merge pull request from oli-obk/rustc_run_pass

various things that allow miri to crash less and execute more code
This commit is contained in:
Scott Olson 2016-09-16 02:36:09 -06:00 committed by GitHub
commit 8a2e2dd665
4 changed files with 99 additions and 41 deletions

@ -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);
}