-
Notifications
You must be signed in to change notification settings - Fork 385
rustup to rustc 1.15.0-dev (ace092f56 2016-12-13) #93
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
69fa3eb
8b8c743
9ec97ba
2420360
fd0c21e
0a79304
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -90,7 +90,16 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { | |
ty::TyFnPtr(bare_fn_ty) => { | ||
let fn_ptr = self.eval_operand_to_primval(func)?.to_ptr(); | ||
let (def_id, substs, abi, sig) = self.memory.get_fn(fn_ptr.alloc_id)?; | ||
if abi != bare_fn_ty.abi || sig != bare_fn_ty.sig.skip_binder() { | ||
let bare_sig = self.tcx.erase_late_bound_regions_and_normalize(&bare_fn_ty.sig); | ||
let bare_sig = self.tcx.erase_regions(&bare_sig); | ||
// transmuting function pointers in miri is fine as long as the number of | ||
// arguments and the abi don't change. | ||
// FIXME: also check the size of the arguments' type and the return type | ||
// Didn't get it to work, since that triggers an assertion in rustc which | ||
// checks whether the type has escaping regions | ||
if abi != bare_fn_ty.abi || | ||
sig.variadic != bare_sig.variadic || | ||
sig.inputs().len() != bare_sig.inputs().len() { | ||
return Err(EvalError::FunctionPointerTyMismatch(abi, sig, bare_fn_ty)); | ||
} | ||
self.eval_fn_call(def_id, substs, bare_fn_ty, destination, args, | ||
|
@@ -189,15 +198,15 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { | |
use syntax::abi::Abi; | ||
match fn_ty.abi { | ||
Abi::RustIntrinsic => { | ||
let ty = fn_ty.sig.0.output; | ||
let ty = fn_ty.sig.0.output(); | ||
let layout = self.type_layout(ty)?; | ||
let (ret, target) = destination.unwrap(); | ||
self.call_intrinsic(def_id, substs, arg_operands, ret, ty, layout, target)?; | ||
Ok(()) | ||
} | ||
|
||
Abi::C => { | ||
let ty = fn_ty.sig.0.output; | ||
let ty = fn_ty.sig.0.output(); | ||
let (ret, target) = destination.unwrap(); | ||
self.call_c_abi(def_id, arg_operands, ret, ty)?; | ||
self.goto_block(target); | ||
|
@@ -320,11 +329,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { | |
.collect(); | ||
let args = args_res?; | ||
|
||
if link_name.starts_with("pthread_") { | ||
warn!("ignoring C ABI call: {}", link_name); | ||
return Ok(()); | ||
} | ||
|
||
let usize = self.tcx.types.usize; | ||
|
||
match &link_name[..] { | ||
|
@@ -371,6 +375,37 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { | |
self.write_primval(dest, PrimVal::new(result as u64), dest_ty)?; | ||
} | ||
|
||
"memchr" => { | ||
let ptr = args[0].read_ptr(&self.memory)?; | ||
let val = self.value_to_primval(args[1], usize)?.to_u64() as u8; | ||
let num = self.value_to_primval(args[2], usize)?.to_u64(); | ||
if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().position(|&c| c == val) { | ||
let new_ptr = ptr.offset(idx as u64); | ||
self.write_value(Value::ByVal(PrimVal::from_ptr(new_ptr)), dest, dest_ty)?; | ||
} else { | ||
self.write_value(Value::ByVal(PrimVal::new(0)), dest, dest_ty)?; | ||
} | ||
} | ||
|
||
"getenv" => { | ||
{ | ||
let name = args[0].read_ptr(&self.memory)?; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
let name = self.memory.read_c_str(name)?; | ||
info!("ignored env var request for `{:?}`", ::std::str::from_utf8(name)); | ||
} | ||
self.write_value(Value::ByVal(PrimVal::new(0)), dest, dest_ty)?; | ||
} | ||
|
||
// unix panic code inside libstd will read the return value of this function | ||
"pthread_rwlock_rdlock" => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is fine for our current experimentation, but I guess we'll need a plan for stuff like this eventually. For the real CTFE that gets put into rustc, it would probably make more sense to have @eddyb Have you thought about this? Panicking, printing when panicking, and even There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. real ctfe can only evaluate Also we can't do any There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We want to make panic allowed in real CTFE in some form, though, don't we? Otherwise we can't call anything that has any code path leading to panic. It doesn't need to be literally There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Allowing panicking in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In fact, hooking libc calls is effectively just one version of "tell CTFE to do something differently", but we could perhaps do it in a more first-class, maintainable way if it was explicit in the code implementing panic. But I'm still pretty unsure. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The easiest thing would be to create an unstable attribute that libstd can use to annotate functions that CTFE should not go into this function, but instead do some magic. |
||
self.write_primval(dest, PrimVal::new(0), dest_ty)?; | ||
} | ||
|
||
link_name if link_name.starts_with("pthread_") => { | ||
warn!("ignoring C ABI call: {}", link_name); | ||
return Ok(()); | ||
}, | ||
|
||
_ => { | ||
return Err(EvalError::Unimplemented(format!("can't call C ABI function: {}", link_name))); | ||
} | ||
|
@@ -520,7 +555,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { | |
let offset = idx * self.memory.pointer_size(); | ||
let fn_ptr = self.memory.read_ptr(vtable.offset(offset))?; | ||
let (def_id, substs, _abi, sig) = self.memory.get_fn(fn_ptr.alloc_id)?; | ||
*first_ty = sig.inputs[0]; | ||
*first_ty = sig.inputs()[0]; | ||
Ok((def_id, substs, Vec::new())) | ||
} else { | ||
Err(EvalError::VtableForArgumentlessMethod) | ||
|
@@ -664,7 +699,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { | |
// some values don't need to call a drop impl, so the value is null | ||
if drop_fn != Pointer::from_int(0) { | ||
let (def_id, substs, _abi, sig) = self.memory.get_fn(drop_fn.alloc_id)?; | ||
let real_ty = sig.inputs[0]; | ||
let real_ty = sig.inputs()[0]; | ||
self.drop(Lvalue::from_ptr(ptr), real_ty, drop)?; | ||
drop.push((def_id, Value::ByVal(PrimVal::from_ptr(ptr)), substs)); | ||
} else { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,15 @@ fn run_pass() { | |
compiletest::run_tests(&config); | ||
} | ||
|
||
fn miri_pass(path: &str, target: &str) { | ||
let mut config = compiletest::default_config(); | ||
config.mode = "mir-opt".parse().expect("Invalid mode"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. mir-opt is not ideal
The clean solution would be to add a "compile-pass" test to compiletest But it saves us this giant mess below, which would just get bigger if we started to play with auxiliary builds. |
||
config.src_base = PathBuf::from(path); | ||
config.target = target.to_owned(); | ||
config.rustc_path = PathBuf::from("target/debug/miri"); | ||
compiletest::run_tests(&config); | ||
} | ||
|
||
fn for_all_targets<F: FnMut(String)>(sysroot: &str, mut f: F) { | ||
for target in std::fs::read_dir(format!("{}/lib/rustlib/", sysroot)).unwrap() { | ||
let target = target.unwrap(); | ||
|
@@ -57,65 +66,10 @@ fn compile_test() { | |
}; | ||
run_pass(); | ||
for_all_targets(&sysroot, |target| { | ||
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(); | ||
|
||
if !file.metadata().unwrap().is_file() || !path.to_str().unwrap().ends_with(".rs") { | ||
continue; | ||
} | ||
|
||
let stderr = std::io::stderr(); | ||
write!(stderr.lock(), "test [miri-pass] {} ... ", path.display()).unwrap(); | ||
let mut cmd = std::process::Command::new("target/debug/miri"); | ||
cmd.arg(path); | ||
cmd.arg(format!("--target={}", target)); | ||
let libs = Path::new(&sysroot).join("lib"); | ||
let sysroot = libs.join("rustlib").join(&target).join("lib"); | ||
let paths = std::env::join_paths(&[libs, sysroot]).unwrap(); | ||
cmd.env(compiletest::procsrv::dylib_env_var(), paths); | ||
|
||
match cmd.output() { | ||
Ok(ref output) if output.status.success() => { | ||
success += 1; | ||
writeln!(stderr.lock(), "ok").unwrap() | ||
}, | ||
Ok(output) => { | ||
let output_err = std::str::from_utf8(&output.stderr).unwrap(); | ||
if let Some(text) = output_err.splitn(2, "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!("failed to execute miri"); | ||
}, | ||
} | ||
miri_pass("tests/run-pass", &target); | ||
if let Ok(path) = std::env::var("MIRI_RUSTC_TEST") { | ||
miri_pass(&path, &target); | ||
} | ||
let stderr = std::io::stderr(); | ||
writeln!(stderr.lock(), "{} success, {} mir not found, {} crate not found, {} failed", success, mir_not_found, crate_not_found, failed).unwrap(); | ||
assert_eq!(failed, 0, "some tests failed"); | ||
}); | ||
compile_fail(&sysroot); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
// aux-build:dep.rs | ||
|
||
extern crate dep; | ||
|
||
fn main() { | ||
dep::foo(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pub fn foo() {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this and the
check_defined
need to usesize + 1
to ensure the found null byte also is defined and not part of a relocation.