提交 63c48435 编写于 作者: O Oliver Schneider 提交者: GitHub

Merge pull request #299 from RalfJung/rustfmt

rustfmt
......@@ -7,9 +7,7 @@
#[bench]
fn fib(bencher: &mut Bencher) {
bencher.iter(|| {
fibonacci_helper::main();
})
bencher.iter(|| { fibonacci_helper::main(); })
}
#[bench]
......@@ -19,9 +17,7 @@ fn fib_miri(bencher: &mut Bencher) {
#[bench]
fn fib_iter(bencher: &mut Bencher) {
bencher.iter(|| {
fibonacci_helper_iterative::main();
})
bencher.iter(|| { fibonacci_helper_iterative::main(); })
}
#[bench]
......
......@@ -4,9 +4,5 @@ pub fn main() {
}
fn fib(n: usize) -> usize {
if n <= 2 {
1
} else {
fib(n - 1) + fib(n - 2)
}
if n <= 2 { 1 } else { fib(n - 1) + fib(n - 2) }
}
......@@ -19,9 +19,13 @@ fn find_sysroot() -> String {
let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
match (home, toolchain) {
(Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
_ => option_env!("RUST_SYSROOT")
.expect("need to specify RUST_SYSROOT env var or use rustup or multirust")
.to_owned(),
_ => {
option_env!("RUST_SYSROOT")
.expect(
"need to specify RUST_SYSROOT env var or use rustup or multirust",
)
.to_owned()
}
}
}
......@@ -30,7 +34,7 @@ pub fn run(filename: &str, bencher: &mut Bencher) {
"miri".to_string(),
format!("benches/helpers/{}.rs", filename),
"--sysroot".to_string(),
find_sysroot()
find_sysroot(),
];
let compiler_calls = &mut MiriCompilerCalls(Rc::new(RefCell::new(bencher)));
rustc_driver::run_compiler(args, compiler_calls, None, None);
......@@ -40,7 +44,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls<'a> {
fn build_controller(
&mut self,
_: &Session,
_: &getopts::Matches
_: &getopts::Matches,
) -> driver::CompileController<'a> {
let mut control: driver::CompileController<'a> = driver::CompileController::basic();
......@@ -51,14 +55,17 @@ fn build_controller(
state.session.abort_if_errors();
let tcx = state.tcx.unwrap();
let (entry_node_id, _) = state.session.entry_fn.borrow()
.expect("no main or start function found");
let (entry_node_id, _) = state.session.entry_fn.borrow().expect(
"no main or start function found",
);
let entry_def_id = tcx.map.local_def_id(entry_node_id);
let memory_size = 100*1024*1024; // 100MB
let memory_size = 100 * 1024 * 1024; // 100MB
let step_limit = 1000_000;
let stack_limit = 100;
bencher.borrow_mut().iter(|| { eval_main(tcx, entry_def_id, memory_size, step_limit, stack_limit); });
bencher.borrow_mut().iter(|| {
eval_main(tcx, entry_def_id, memory_size, step_limit, stack_limit);
});
state.session.abort_if_errors();
});
......
#[inline(never)]
pub fn main() {
}
pub fn main() {}
......@@ -7,9 +7,7 @@
#[bench]
fn noop(bencher: &mut Bencher) {
bencher.iter(|| {
smoke_helper::main();
})
bencher.iter(|| { smoke_helper::main(); })
}
/*
......
......@@ -50,29 +50,42 @@ fn main() {
let test = std::env::args().nth(2).map_or(false, |text| text == "test");
let skip = if test { 3 } else { 2 };
let manifest_path_arg = std::env::args().skip(skip).find(|val| val.starts_with("--manifest-path="));
let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) {
let manifest_path_arg = std::env::args().skip(skip).find(|val| {
val.starts_with("--manifest-path=")
});
let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(
manifest_path_arg.as_ref().map(AsRef::as_ref),
)
{
metadata
} else {
let _ = std::io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata."));
let _ = std::io::stderr().write_fmt(format_args!(
"error: Could not obtain cargo metadata."
));
std::process::exit(101);
};
let manifest_path = manifest_path_arg.map(|arg| PathBuf::from(Path::new(&arg["--manifest-path=".len()..])));
let manifest_path = manifest_path_arg.map(|arg| {
PathBuf::from(Path::new(&arg["--manifest-path=".len()..]))
});
let current_dir = std::env::current_dir();
let package_index = metadata.packages
let package_index = metadata
.packages
.iter()
.position(|package| {
let package_manifest_path = Path::new(&package.manifest_path);
if let Some(ref manifest_path) = manifest_path {
package_manifest_path == manifest_path
} else {
let current_dir = current_dir.as_ref().expect("could not read current directory");
let package_manifest_directory = package_manifest_path.parent()
.expect("could not find parent directory of package manifest");
let current_dir = current_dir.as_ref().expect(
"could not read current directory",
);
let package_manifest_directory = package_manifest_path.parent().expect(
"could not find parent directory of package manifest",
);
package_manifest_directory == current_dir
}
})
......@@ -80,13 +93,25 @@ fn main() {
let package = metadata.packages.remove(package_index);
for target in package.targets {
let args = std::env::args().skip(skip);
let kind = target.kind.get(0).expect("badly formatted cargo metadata: target::kind is an empty array");
let kind = target.kind.get(0).expect(
"badly formatted cargo metadata: target::kind is an empty array",
);
if test && kind == "test" {
if let Err(code) = process(vec!["--test".to_string(), target.name].into_iter().chain(args)) {
if let Err(code) = process(
vec!["--test".to_string(), target.name].into_iter().chain(
args,
),
)
{
std::process::exit(code);
}
} else if !test && kind == "bin" {
if let Err(code) = process(vec!["--bin".to_string(), target.name].into_iter().chain(args)) {
if let Err(code) = process(
vec!["--bin".to_string(), target.name].into_iter().chain(
args,
),
)
{
std::process::exit(code);
}
}
......@@ -118,7 +143,11 @@ fn main() {
let mut args: Vec<String> = if std::env::args().any(|s| s == "--sysroot") {
std::env::args().skip(1).collect()
} else {
std::env::args().skip(1).chain(Some("--sysroot".to_owned())).chain(Some(sys_root)).collect()
std::env::args()
.skip(1)
.chain(Some("--sysroot".to_owned()))
.chain(Some(sys_root))
.collect()
};
// this check ensures that dependencies are built but not interpreted and the final crate is
......@@ -137,9 +166,11 @@ fn main() {
args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-miri""#.to_owned()]);
match command.args(&args).status() {
Ok(exit) => if !exit.success() {
std::process::exit(exit.code().unwrap_or(42));
},
Ok(exit) => {
if !exit.success() {
std::process::exit(exit.code().unwrap_or(42));
}
}
Err(ref e) if miri_enabled => panic!("error during miri run: {:?}", e),
Err(ref e) => panic!("error during rustc call: {:?}", e),
}
......@@ -147,7 +178,8 @@ fn main() {
}
fn process<I>(old_args: I) -> Result<(), i32>
where I: Iterator<Item = String>
where
I: Iterator<Item = String>,
{
let mut args = vec!["rustc".to_owned()];
......
......@@ -16,7 +16,7 @@
use rustc::session::config::{self, Input, ErrorOutputType};
use rustc::hir::{self, itemlikevisit};
use rustc::ty::TyCtxt;
use syntax::ast::{MetaItemKind, NestedMetaItemKind, self};
use syntax::ast::{self, MetaItemKind, NestedMetaItemKind};
use std::path::PathBuf;
struct MiriCompilerCalls(RustcDefaultCalls);
......@@ -28,9 +28,15 @@ fn early_callback(
sopts: &config::Options,
cfg: &ast::CrateConfig,
descriptions: &rustc_errors::registry::Registry,
output: ErrorOutputType
output: ErrorOutputType,
) -> Compilation {
self.0.early_callback(matches, sopts, cfg, descriptions, output)
self.0.early_callback(
matches,
sopts,
cfg,
descriptions,
output,
)
}
fn no_input(
&mut self,
......@@ -39,9 +45,16 @@ fn no_input(
cfg: &ast::CrateConfig,
odir: &Option<PathBuf>,
ofile: &Option<PathBuf>,
descriptions: &rustc_errors::registry::Registry
descriptions: &rustc_errors::registry::Registry,
) -> Option<(Input, Option<PathBuf>)> {
self.0.no_input(matches, sopts, cfg, odir, ofile, descriptions)
self.0.no_input(
matches,
sopts,
cfg,
odir,
ofile,
descriptions,
)
}
fn late_callback(
&mut self,
......@@ -49,11 +62,15 @@ fn late_callback(
sess: &Session,
input: &Input,
odir: &Option<PathBuf>,
ofile: &Option<PathBuf>
ofile: &Option<PathBuf>,
) -> Compilation {
self.0.late_callback(matches, sess, input, odir, ofile)
}
fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> CompileController<'a> {
fn build_controller(
&mut self,
sess: &Session,
matches: &getopts::Matches,
) -> CompileController<'a> {
let mut control = self.0.build_controller(sess, matches);
control.after_hir_lowering.callback = Box::new(after_hir_lowering);
control.after_analysis.callback = Box::new(after_analysis);
......@@ -66,7 +83,10 @@ fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> Co
}
fn after_hir_lowering(state: &mut CompileState) {
let attr = (String::from("miri"), syntax::feature_gate::AttributeType::Whitelisted);
let attr = (
String::from("miri"),
syntax::feature_gate::AttributeType::Whitelisted,
);
state.session.plugin_attributes.borrow_mut().push(attr);
}
......@@ -77,13 +97,23 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) {
let limits = resource_limits_from_attributes(state);
if std::env::args().any(|arg| arg == "--test") {
struct Visitor<'a, 'tcx: 'a>(miri::ResourceLimits, TyCtxt<'a, 'tcx, 'tcx>, &'a CompileState<'a, 'tcx>);
struct Visitor<'a, 'tcx: 'a>(
miri::ResourceLimits,
TyCtxt<'a, 'tcx, 'tcx>,
&'a CompileState<'a, 'tcx>
);
impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> {
fn visit_item(&mut self, i: &'hir hir::Item) {
if let hir::Item_::ItemFn(_, _, _, _, _, body_id) = i.node {
if i.attrs.iter().any(|attr| attr.name().map_or(false, |n| n == "test")) {
if i.attrs.iter().any(|attr| {
attr.name().map_or(false, |n| n == "test")
})
{
let did = self.1.hir.body_owner_def_id(body_id);
println!("running test: {}", self.1.hir.def_path(did).to_string(self.1));
println!(
"running test: {}",
self.1.hir.def_path(did).to_string(self.1)
);
miri::eval_main(self.1, did, None, self.0);
self.2.session.abort_if_errors();
}
......@@ -92,11 +122,18 @@ fn visit_item(&mut self, i: &'hir hir::Item) {
fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {}
fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {}
}
state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(limits, tcx, state));
state.hir_crate.unwrap().visit_all_item_likes(
&mut Visitor(limits, tcx, state),
);
} else if let Some((entry_node_id, _)) = *state.session.entry_fn.borrow() {
let entry_def_id = tcx.hir.local_def_id(entry_node_id);
let start_wrapper = tcx.lang_items.start_fn().and_then(|start_fn|
if tcx.is_mir_available(start_fn) { Some(start_fn) } else { None });
let start_wrapper = tcx.lang_items.start_fn().and_then(|start_fn| {
if tcx.is_mir_available(start_fn) {
Some(start_fn)
} else {
None
}
});
miri::eval_main(tcx, entry_def_id, start_wrapper, limits);
state.session.abort_if_errors();
......@@ -112,11 +149,19 @@ fn resource_limits_from_attributes(state: &CompileState) -> miri::ResourceLimits
let extract_int = |lit: &syntax::ast::Lit| -> u128 {
match lit.node {
syntax::ast::LitKind::Int(i, _) => i,
_ => state.session.span_fatal(lit.span, "expected an integer literal"),
_ => {
state.session.span_fatal(
lit.span,
"expected an integer literal",
)
}
}
};
for attr in krate.attrs.iter().filter(|a| a.name().map_or(false, |n| n == "miri")) {
for attr in krate.attrs.iter().filter(|a| {
a.name().map_or(false, |n| n == "miri")
})
{
if let Some(items) = attr.meta_item_list() {
for item in items {
if let NestedMetaItemKind::MetaItem(ref inner) = item.node {
......@@ -165,7 +210,10 @@ fn init_logger() {
};
let mut builder = env_logger::LogBuilder::new();
builder.format(format).filter(None, log::LogLevelFilter::Info);
builder.format(format).filter(
None,
log::LogLevelFilter::Info,
);
if std::env::var("MIRI_LOG").is_ok() {
builder.parse(&std::env::var("MIRI_LOG").unwrap());
......@@ -184,9 +232,13 @@ fn find_sysroot() -> String {
let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
match (home, toolchain) {
(Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
_ => option_env!("RUST_SYSROOT")
.expect("need to specify RUST_SYSROOT env var or use rustup or multirust")
.to_owned(),
_ => {
option_env!("RUST_SYSROOT")
.expect(
"need to specify RUST_SYSROOT env var or use rustup or multirust",
)
.to_owned()
}
}
}
......
......@@ -9,10 +9,7 @@
use rustc_miri::interpret::*;
use super::{
TlsKey,
EvalContext,
};
use super::{TlsKey, EvalContext};
use tls::MemoryExt;
......@@ -62,13 +59,19 @@ fn eval_fn_call(
let mir = match self.load_mir(instance.def) {
Ok(mir) => mir,
Err(EvalError{ kind: EvalErrorKind::NoMirFor(path), ..} ) => {
self.call_missing_fn(instance, destination, arg_operands, sig, path)?;
Err(EvalError { kind: EvalErrorKind::NoMirFor(path), .. }) => {
self.call_missing_fn(
instance,
destination,
arg_operands,
sig,
path,
)?;
return Ok(true);
},
}
Err(other) => return Err(other),
};
let (return_lvalue, return_to_block) = match destination {
Some((lvalue, block)) => (lvalue, StackPopCleanup::Goto(block)),
None => (Lvalue::undef(), StackPopCleanup::None),
......@@ -99,7 +102,8 @@ fn call_c_abi(
.unwrap_or(name)
.as_str();
let args_res: EvalResult<Vec<Value>> = arg_operands.iter()
let args_res: EvalResult<Vec<Value>> = arg_operands
.iter()
.map(|arg| self.eval_operand(arg))
.collect();
let args = args_res?;
......@@ -121,7 +125,11 @@ fn call_c_abi(
"free" => {
let ptr = args[0].into_ptr(&mut self.memory)?;
if !ptr.is_null()? {
self.memory.deallocate(ptr.to_ptr()?, None, MemoryKind::C.into())?;
self.memory.deallocate(
ptr.to_ptr()?,
None,
MemoryKind::C.into(),
)?;
}
}
......@@ -132,9 +140,16 @@ fn call_c_abi(
// libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)
// is called if a `HashMap` is created the regular way.
match self.value_to_primval(args[0], usize)?.to_u64()? {
318 |
511 => return err!(Unimplemented("miri does not support random number generators".to_owned())),
id => return err!(Unimplemented(format!("miri does not support syscall id {}", id))),
318 | 511 => {
return err!(Unimplemented(
"miri does not support random number generators".to_owned(),
))
}
id => {
return err!(Unimplemented(
format!("miri does not support syscall id {}", id),
))
}
}
}
......@@ -144,7 +159,10 @@ fn call_c_abi(
let symbol_name = self.memory.read_c_str(symbol)?;
let err = format!("bad c unicode symbol: {:?}", symbol_name);
let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err);
return err!(Unimplemented(format!("miri does not support dynamically loading libraries (requested symbol: {})", symbol_name)));
return err!(Unimplemented(format!(
"miri does not support dynamically loading libraries (requested symbol: {})",
symbol_name
)));
}
"__rust_maybe_catch_panic" => {
......@@ -167,7 +185,12 @@ fn call_c_abi(
StackPopCleanup::Goto(dest_block),
)?;
let arg_local = self.frame().mir.args_iter().next().ok_or(EvalErrorKind::AbiViolation("Argument to __rust_maybe_catch_panic does not take enough arguments.".to_owned()))?;
let arg_local = self.frame().mir.args_iter().next().ok_or(
EvalErrorKind::AbiViolation(
"Argument to __rust_maybe_catch_panic does not take enough arguments."
.to_owned(),
),
)?;
let arg_dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?;
self.write_ptr(arg_dest, data, u8_ptr_ty)?;
......@@ -199,14 +222,21 @@ fn call_c_abi(
}
};
self.write_primval(dest, PrimVal::Bytes(result as u128), dest_ty)?;
self.write_primval(
dest,
PrimVal::Bytes(result as u128),
dest_ty,
)?;
}
"memrchr" => {
let ptr = args[0].into_ptr(&mut 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().rev().position(|&c| c == val) {
if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().rev().position(
|&c| c == val,
)
{
let new_ptr = ptr.offset(num - idx as u64 - 1, &self)?;
self.write_ptr(dest, new_ptr, dest_ty)?;
} else {
......@@ -218,7 +248,10 @@ fn call_c_abi(
let ptr = args[0].into_ptr(&mut 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) {
if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().position(
|&c| c == val,
)
{
let new_ptr = ptr.offset(idx as u64, &self)?;
self.write_ptr(dest, new_ptr, dest_ty)?;
} else {
......@@ -274,11 +307,19 @@ fn call_c_abi(
}
if let Some((name, value)) = new {
// +1 for the null terminator
let value_copy = self.memory.allocate((value.len() + 1) as u64, 1, MemoryKind::Env.into())?;
let value_copy = self.memory.allocate(
(value.len() + 1) as u64,
1,
MemoryKind::Env.into(),
)?;
self.memory.write_bytes(value_copy.into(), &value)?;
let trailing_zero_ptr = value_copy.offset(value.len() as u64, &self)?.into();
self.memory.write_bytes(trailing_zero_ptr, &[0])?;
if let Some(var) = self.machine_data.env_vars.insert(name.to_owned(), value_copy) {
if let Some(var) = self.machine_data.env_vars.insert(
name.to_owned(),
value_copy,
)
{
self.memory.deallocate(var, None, MemoryKind::Env.into())?;
}
self.write_null(dest, dest_ty)?;
......@@ -292,17 +333,29 @@ fn call_c_abi(
let buf = args[1].into_ptr(&mut self.memory)?;
let n = self.value_to_primval(args[2], usize)?.to_u64()?;
trace!("Called write({:?}, {:?}, {:?})", fd, buf, n);
let result = if fd == 1 || fd == 2 { // stdout/stderr
let result = if fd == 1 || fd == 2 {
// stdout/stderr
use std::io::{self, Write};
let buf_cont = self.memory.read_bytes(buf, n)?;
let res = if fd == 1 { io::stdout().write(buf_cont) } else { io::stderr().write(buf_cont) };
match res { Ok(n) => n as isize, Err(_) => -1 }
let res = if fd == 1 {
io::stdout().write(buf_cont)
} else {
io::stderr().write(buf_cont)
};
match res {
Ok(n) => n as isize,
Err(_) => -1,
}
} else {
info!("Ignored output to FD {}", fd);
n as isize // pretend it all went well
}; // now result is the value we return back to the program
self.write_primval(dest, PrimVal::Bytes(result as u128), dest_ty)?;
self.write_primval(
dest,
PrimVal::Bytes(result as u128),
dest_ty,
)?;
}
"strlen" => {
......@@ -328,7 +381,10 @@ fn call_c_abi(
let mut result = None;
for &(path, path_value) in paths {
if let Ok(instance) = self.resolve_path(path) {
let cid = GlobalId { instance, promoted: None };
let cid = GlobalId {
instance,
promoted: None,
};
// compute global if not cached
let val = match self.globals.get(&cid).cloned() {
Some(ptr) => self.value_to_primval(Value::ByRef(ptr), c_int)?.to_u64()?,
......@@ -343,7 +399,9 @@ fn call_c_abi(
if let Some(result) = result {
self.write_primval(dest, result, dest_ty)?;
} else {
return err!(Unimplemented(format!("Unimplemented sysconf name: {}", name)));
return err!(Unimplemented(
format!("Unimplemented sysconf name: {}", name),
));
}
}
......@@ -373,7 +431,11 @@ fn call_c_abi(
return err!(OutOfTls);
}
// TODO: Does this need checking for alignment?
self.memory.write_uint(key_ptr.to_ptr()?, key, key_size.bytes())?;
self.memory.write_uint(
key_ptr.to_ptr()?,
key,
key_size.bytes(),
)?;
// Return success (0)
self.write_null(dest, dest_ty)?;
......@@ -396,7 +458,7 @@ fn call_c_abi(
let key = self.value_to_primval(args[0], usize)?.to_u64()? as TlsKey;
let new_ptr = args[1].into_ptr(&mut self.memory)?;
self.memory.store_tls(key, new_ptr)?;
// Return success (0)
self.write_null(dest, dest_ty)?;
}
......@@ -405,10 +467,12 @@ fn call_c_abi(
link_name if link_name.starts_with("pthread_") => {
warn!("ignoring C ABI call: {}", link_name);
self.write_null(dest, dest_ty)?;
},
}
_ => {
return err!(Unimplemented(format!("can't call C ABI function: {}", link_name)));
return err!(Unimplemented(
format!("can't call C ABI function: {}", link_name),
));
}
}
......@@ -425,7 +489,8 @@ fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>> {
let cstore = &self.tcx.sess.cstore;
let crates = cstore.crates();
crates.iter()
crates
.iter()
.find(|&&krate| cstore.crate_name(krate) == path[0])
.and_then(|krate| {
let krate = DefId {
......@@ -450,9 +515,7 @@ fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>> {
None
})
.ok_or_else(|| {
let path = path.iter()
.map(|&s| s.to_owned())
.collect();
let path = path.iter().map(|&s| s.to_owned()).collect();
EvalErrorKind::PathNotFound(path).into()
})
}
......@@ -469,27 +532,36 @@ fn call_missing_fn(
match &path[..] {
"std::panicking::rust_panic_with_hook" |
"std::rt::begin_panic_fmt" => return err!(Panic),
_ => {},
_ => {}
}
let dest_ty = sig.output();
let (dest, dest_block) = destination.ok_or_else(|| EvalErrorKind::NoMirFor(path.clone()))?;
let (dest, dest_block) = destination.ok_or_else(
|| EvalErrorKind::NoMirFor(path.clone()),
)?;
if sig.abi == Abi::C {
// An external C function
// TODO: That functions actually has a similar preamble to what follows here. May make sense to
// unify these two mechanisms for "hooking into missing functions".
self.call_c_abi(instance.def_id(), arg_operands, dest, dest_ty, dest_block)?;
self.call_c_abi(
instance.def_id(),
arg_operands,
dest,
dest_ty,
dest_block,
)?;
return Ok(());
}
let args_res: EvalResult<Vec<Value>> = arg_operands.iter()
let args_res: EvalResult<Vec<Value>> = arg_operands
.iter()
.map(|arg| self.eval_operand(arg))
.collect();
let args = args_res?;
let usize = self.tcx.types.usize;
match &path[..] {
// Allocators are magic. They have no MIR, even when the rest of libstd does.
"alloc::heap::::__rust_alloc" => {
......@@ -527,7 +599,11 @@ fn call_missing_fn(
if !align.is_power_of_two() {
return err!(HeapAllocNonPowerOfTwoAlignment(align));
}
self.memory.deallocate(ptr, Some((old_size, align)), MemoryKind::Rust.into())?;
self.memory.deallocate(
ptr,
Some((old_size, align)),
MemoryKind::Rust.into(),
)?;
}
"alloc::heap::::__rust_realloc" => {
let ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?;
......@@ -544,17 +620,32 @@ fn call_missing_fn(
if !new_align.is_power_of_two() {
return err!(HeapAllocNonPowerOfTwoAlignment(new_align));
}
let new_ptr = self.memory.reallocate(ptr, old_size, old_align, new_size, new_align, MemoryKind::Rust.into())?;
let new_ptr = self.memory.reallocate(
ptr,
old_size,
old_align,
new_size,
new_align,
MemoryKind::Rust.into(),
)?;
self.write_primval(dest, PrimVal::Ptr(new_ptr), dest_ty)?;
}
// 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.
"std::io::_print" => {
trace!("Ignoring output. To run programs that print, make sure you have a libstd with full MIR.");
trace!(
"Ignoring output. To run programs that print, make sure you have a libstd with full MIR."
);
}
"std::thread::Builder::new" => {
return err!(Unimplemented("miri does not support threading".to_owned()))
}
"std::env::args" => {
return err!(Unimplemented(
"miri does not support program arguments".to_owned(),
))
}
"std::thread::Builder::new" => return err!(Unimplemented("miri does not support threading".to_owned())),
"std::env::args" => return err!(Unimplemented("miri does not support program arguments".to_owned())),
"std::panicking::panicking" |
"std::rt::panicking" => {
// we abort on panic -> `std::rt::panicking` always returns false
......
use rustc_miri::interpret::{
Pointer,
EvalResult,
PrimVal,
EvalContext,
};
use rustc_miri::interpret::{Pointer, EvalResult, PrimVal, EvalContext};
use rustc::ty::Ty;
......@@ -31,7 +26,9 @@ fn wrapping_pointer_offset(
offset: i64,
) -> EvalResult<'tcx, Pointer> {
// FIXME: assuming here that type size is < i64::max_value()
let pointee_size = self.type_size(pointee_ty)?.expect("cannot offset a pointer to an unsized type") as i64;
let pointee_size = self.type_size(pointee_ty)?.expect(
"cannot offset a pointer to an unsized type",
) as i64;
let offset = offset.overflowing_mul(pointee_size).0;
ptr.wrapping_signed_offset(offset, self)
}
......@@ -47,11 +44,18 @@ fn pointer_offset(
// We also consider the NULL pointer its own separate allocation, and all the remaining integers pointers their own
// allocation.
if ptr.is_null()? { // NULL pointers must only be offset by 0
return if offset == 0 { Ok(ptr) } else { err!(InvalidNullPointerUsage) };
if ptr.is_null()? {
// NULL pointers must only be offset by 0
return if offset == 0 {
Ok(ptr)
} else {
err!(InvalidNullPointerUsage)
};
}
// FIXME: assuming here that type size is < i64::max_value()
let pointee_size = self.type_size(pointee_ty)?.expect("cannot offset a pointer to an unsized type") as i64;
let pointee_size = self.type_size(pointee_ty)?.expect(
"cannot offset a pointer to an unsized type",
) as i64;
return if let Some(offset) = offset.checked_mul(pointee_size) {
let ptr = ptr.signed_offset(offset, self)?;
// Do not do bounds-checking for integers; they can never alias a normal pointer anyway.
......@@ -64,6 +68,6 @@ fn pointer_offset(
Ok(ptr)
} else {
err!(OverflowingMath)
}
};
}
}
此差异已折叠。
......@@ -20,10 +20,7 @@
use syntax::codemap::Span;
use std::collections::{
HashMap,
BTreeMap,
};
use std::collections::{HashMap, BTreeMap};
#[macro_use]
extern crate rustc_miri;
......@@ -57,7 +54,10 @@ fn run_main<'a, 'tcx: 'a>(
let mut cleanup_ptr = None; // Pointer to be deallocated when we are done
if !main_mir.return_ty.is_nil() || main_mir.arg_count != 0 {
return err!(Unimplemented("miri does not support main functions without `fn()` type signatures".to_owned()));
return err!(Unimplemented(
"miri does not support main functions without `fn()` type signatures"
.to_owned(),
));
}
if let Some(start_id) = start_wrapper {
......@@ -65,7 +65,10 @@ fn run_main<'a, 'tcx: 'a>(
let start_mir = ecx.load_mir(start_instance.def)?;
if start_mir.arg_count != 3 {
return err!(AbiViolation(format!("'start' lang item should have three arguments, but has {}", start_mir.arg_count)));
return err!(AbiViolation(format!(
"'start' lang item should have three arguments, but has {}",
start_mir.arg_count
)));
}
// Return value
......@@ -90,7 +93,11 @@ fn run_main<'a, 'tcx: 'a>(
let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?;
let main_ty = main_instance.def.def_ty(ecx.tcx);
let main_ptr_ty = ecx.tcx.mk_fn_ptr(main_ty.fn_sig(ecx.tcx));
ecx.write_value(Value::ByVal(PrimVal::Ptr(main_ptr)), dest, main_ptr_ty)?;
ecx.write_value(
Value::ByVal(PrimVal::Ptr(main_ptr)),
dest,
main_ptr_ty,
)?;
// Second argument (argc): 0
let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?;
......@@ -114,7 +121,11 @@ fn run_main<'a, 'tcx: 'a>(
while ecx.step()? {}
ecx.run_tls_dtors()?;
if let Some(cleanup_ptr) = cleanup_ptr {
ecx.memory_mut().deallocate(cleanup_ptr, None, MemoryKind::Stack)?;
ecx.memory_mut().deallocate(
cleanup_ptr,
None,
MemoryKind::Stack,
)?;
}
Ok(())
}
......
......@@ -37,20 +37,28 @@ fn ptr_op(
use rustc::mir::BinOp::*;
let usize = PrimValKind::from_uint_size(self.memory.pointer_size());
let isize = PrimValKind::from_int_size(self.memory.pointer_size());
let left_kind = self.ty_to_primval_kind(left_ty)?;
let left_kind = self.ty_to_primval_kind(left_ty)?;
let right_kind = self.ty_to_primval_kind(right_ty)?;
match bin_op {
Offset if left_kind == Ptr && right_kind == usize => {
let pointee_ty = left_ty.builtin_deref(true, ty::LvaluePreference::NoPreference).expect("Offset called on non-ptr type").ty;
let ptr = self.pointer_offset(left.into(), pointee_ty, right.to_bytes()? as i64)?;
let pointee_ty = left_ty
.builtin_deref(true, ty::LvaluePreference::NoPreference)
.expect("Offset called on non-ptr type")
.ty;
let ptr = self.pointer_offset(
left.into(),
pointee_ty,
right.to_bytes()? as i64,
)?;
Ok(Some((ptr.into_inner_primval(), false)))
},
}
// These work on anything
Eq if left_kind == right_kind => {
let result = match (left, right) {
(PrimVal::Bytes(left), PrimVal::Bytes(right)) => left == right,
(PrimVal::Ptr(left), PrimVal::Ptr(right)) => left == right,
(PrimVal::Undef, _) | (_, PrimVal::Undef) => return err!(ReadUndefBytes),
(PrimVal::Undef, _) |
(_, PrimVal::Undef) => return err!(ReadUndefBytes),
_ => false,
};
Ok(Some((PrimVal::from_bool(result), false)))
......@@ -59,16 +67,17 @@ fn ptr_op(
let result = match (left, right) {
(PrimVal::Bytes(left), PrimVal::Bytes(right)) => left != right,
(PrimVal::Ptr(left), PrimVal::Ptr(right)) => left != right,
(PrimVal::Undef, _) | (_, PrimVal::Undef) => return err!(ReadUndefBytes),
(PrimVal::Undef, _) |
(_, PrimVal::Undef) => return err!(ReadUndefBytes),
_ => true,
};
Ok(Some((PrimVal::from_bool(result), false)))
}
// These need both pointers to be in the same allocation
Lt | Le | Gt | Ge | Sub
if left_kind == right_kind
&& (left_kind == Ptr || left_kind == usize || left_kind == isize)
&& left.is_ptr() && right.is_ptr() => {
if left_kind == right_kind &&
(left_kind == Ptr || left_kind == usize || left_kind == isize) &&
left.is_ptr() && right.is_ptr() => {
let left = left.to_ptr()?;
let right = right.to_ptr()?;
if left.alloc_id == right.alloc_id {
......@@ -77,13 +86,15 @@ fn ptr_op(
Le => left.offset <= right.offset,
Gt => left.offset > right.offset,
Ge => left.offset >= right.offset,
Sub => return self.binary_op(
Sub,
PrimVal::Bytes(left.offset as u128),
self.tcx.types.usize,
PrimVal::Bytes(right.offset as u128),
self.tcx.types.usize,
).map(Some),
Sub => {
return self.binary_op(
Sub,
PrimVal::Bytes(left.offset as u128),
self.tcx.types.usize,
PrimVal::Bytes(right.offset as u128),
self.tcx.types.usize,
).map(Some)
}
_ => bug!("We already established it has to be one of these operators."),
};
Ok(Some((PrimVal::from_bool(res), false)))
......@@ -94,18 +105,28 @@ fn ptr_op(
}
// These work if one operand is a pointer, the other an integer
Add | BitAnd | Sub
if left_kind == right_kind && (left_kind == usize || left_kind == isize)
&& left.is_ptr() && right.is_bytes() => {
if left_kind == right_kind && (left_kind == usize || left_kind == isize) &&
left.is_ptr() && right.is_bytes() => {
// Cast to i128 is fine as we checked the kind to be ptr-sized
self.ptr_int_arithmetic(bin_op, left.to_ptr()?, right.to_bytes()? as i128, left_kind == isize).map(Some)
self.ptr_int_arithmetic(
bin_op,
left.to_ptr()?,
right.to_bytes()? as i128,
left_kind == isize,
).map(Some)
}
Add | BitAnd
if left_kind == right_kind && (left_kind == usize || left_kind == isize)
&& left.is_bytes() && right.is_ptr() => {
if left_kind == right_kind && (left_kind == usize || left_kind == isize) &&
left.is_bytes() && right.is_ptr() => {
// This is a commutative operation, just swap the operands
self.ptr_int_arithmetic(bin_op, right.to_ptr()?, left.to_bytes()? as i128, left_kind == isize).map(Some)
self.ptr_int_arithmetic(
bin_op,
right.to_ptr()?,
left.to_bytes()? as i128,
left_kind == isize,
).map(Some)
}
_ => Ok(None)
_ => Ok(None),
}
}
......@@ -118,7 +139,7 @@ fn ptr_int_arithmetic(
) -> EvalResult<'tcx, (PrimVal, bool)> {
use rustc::mir::BinOp::*;
fn map_to_primval((res, over) : (MemoryPointer, bool)) -> (PrimVal, bool) {
fn map_to_primval((res, over): (MemoryPointer, bool)) -> (PrimVal, bool) {
(PrimVal::Ptr(res), over)
}
......
use rustc::{ty, mir};
use super::{
TlsKey, TlsEntry,
EvalResult, EvalErrorKind,
Pointer,
Memory,
Evaluator,
Lvalue,
StackPopCleanup, EvalContext,
};
use super::{TlsKey, TlsEntry, EvalResult, EvalErrorKind, Pointer, Memory, Evaluator, Lvalue,
StackPopCleanup, EvalContext};
pub trait MemoryExt<'tcx> {
fn create_tls_key(&mut self, dtor: Option<ty::Instance<'tcx>>) -> TlsKey;
fn delete_tls_key(&mut self, key: TlsKey) -> EvalResult<'tcx>;
fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Pointer>;
fn store_tls(&mut self, key: TlsKey, new_data: Pointer) -> EvalResult<'tcx>;
fn fetch_tls_dtor(&mut self, key: Option<TlsKey>) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Pointer, TlsKey)>>;
fn fetch_tls_dtor(
&mut self,
key: Option<TlsKey>,
) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Pointer, TlsKey)>>;
}
pub trait EvalContextExt<'tcx> {
......@@ -26,7 +22,13 @@ impl<'a, 'tcx: 'a> MemoryExt<'tcx> for Memory<'a, 'tcx, Evaluator> {
fn create_tls_key(&mut self, dtor: Option<ty::Instance<'tcx>>) -> TlsKey {
let new_key = self.data.next_thread_local;
self.data.next_thread_local += 1;
self.data.thread_local.insert(new_key, TlsEntry { data: Pointer::null(), dtor });
self.data.thread_local.insert(
new_key,
TlsEntry {
data: Pointer::null(),
dtor,
},
);
trace!("New TLS key allocated: {} with dtor {:?}", new_key, dtor);
return new_key;
}
......@@ -36,9 +38,9 @@ fn delete_tls_key(&mut self, key: TlsKey) -> EvalResult<'tcx> {
Some(_) => {
trace!("TLS key {} removed", key);
Ok(())
},
None => err!(TlsOutOfBounds)
}
}
None => err!(TlsOutOfBounds),
};
}
fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Pointer> {
......@@ -46,9 +48,9 @@ fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Pointer> {
Some(&TlsEntry { data, .. }) => {
trace!("TLS key {} loaded: {:?}", key, data);
Ok(data)
},
None => err!(TlsOutOfBounds)
}
}
None => err!(TlsOutOfBounds),
};
}
fn store_tls(&mut self, key: TlsKey, new_data: Pointer) -> EvalResult<'tcx> {
......@@ -57,11 +59,11 @@ fn store_tls(&mut self, key: TlsKey, new_data: Pointer) -> EvalResult<'tcx> {
trace!("TLS key {} stored: {:?}", key, new_data);
*data = new_data;
Ok(())
},
None => err!(TlsOutOfBounds)
}
}
None => err!(TlsOutOfBounds),
};
}
/// Returns a dtor, its argument and its index, if one is supposed to run
///
/// An optional destructor function may be associated with each key value.
......@@ -80,13 +82,18 @@ fn store_tls(&mut self, key: TlsKey, new_data: Pointer) -> EvalResult<'tcx> {
/// with associated destructors, implementations may stop calling destructors,
/// or they may continue calling destructors until no non-NULL values with
/// associated destructors exist, even though this might result in an infinite loop.
fn fetch_tls_dtor(&mut self, key: Option<TlsKey>) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Pointer, TlsKey)>> {
fn fetch_tls_dtor(
&mut self,
key: Option<TlsKey>,
) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Pointer, TlsKey)>> {
use std::collections::Bound::*;
let start = match key {
Some(key) => Excluded(key),
None => Unbounded,
};
for (&key, &mut TlsEntry { ref mut data, dtor }) in self.data.thread_local.range_mut((start, Unbounded)) {
for (&key, &mut TlsEntry { ref mut data, dtor }) in
self.data.thread_local.range_mut((start, Unbounded))
{
if !data.is_null()? {
if let Some(dtor) = dtor {
let ret = Some((dtor, *data, key));
......@@ -115,7 +122,9 @@ fn run_tls_dtors(&mut self) -> EvalResult<'tcx> {
Lvalue::undef(),
StackPopCleanup::None,
)?;
let arg_local = self.frame().mir.args_iter().next().ok_or(EvalErrorKind::AbiViolation("TLS dtor does not take enough arguments.".to_owned()))?;
let arg_local = self.frame().mir.args_iter().next().ok_or(
EvalErrorKind::AbiViolation("TLS dtor does not take enough arguments.".to_owned()),
)?;
let dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?;
let ty = self.tcx.mk_mut_ptr(self.tcx.types.u8);
self.write_ptr(dest, ptr, ty)?;
......
use rustc::ty::{self, Ty};
use syntax::ast::{FloatTy, IntTy, UintTy};
use super::{
PrimVal,
EvalContext,
EvalResult,
MemoryPointer, PointerArithmetic,
Machine,
};
use super::{PrimVal, EvalContext, EvalResult, MemoryPointer, PointerArithmetic, Machine};
impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
pub(super) fn cast_primval(
&self,
val: PrimVal,
src_ty: Ty<'tcx>,
dest_ty: Ty<'tcx>
dest_ty: Ty<'tcx>,
) -> EvalResult<'tcx, PrimVal> {
let src_kind = self.ty_to_primval_kind(src_ty)?;
......@@ -29,11 +23,11 @@ pub(super) fn cast_primval(
I8 | I16 | I32 | I64 | I128 => {
self.cast_from_signed_int(val.to_i128()?, dest_ty)
},
}
Bool | Char | U8 | U16 | U32 | U64 | U128 | FnPtr | Ptr => {
self.cast_from_int(val.to_u128()?, dest_ty, false)
},
}
}
}
}
......@@ -43,18 +37,22 @@ fn cast_from_signed_int(&self, val: i128, ty: ty::Ty<'tcx>) -> EvalResult<'tcx,
self.cast_from_int(val as u128, ty, val < 0)
}
fn cast_from_int(&self, v: u128, ty: ty::Ty<'tcx>, negative: bool) -> EvalResult<'tcx, PrimVal> {
fn cast_from_int(
&self,
v: u128,
ty: ty::Ty<'tcx>,
negative: bool,
) -> EvalResult<'tcx, PrimVal> {
use rustc::ty::TypeVariants::*;
match ty.sty {
// Casts to bool are not permitted by rustc, no need to handle them here.
TyInt(IntTy::I8) => Ok(PrimVal::Bytes(v as i128 as i8 as u128)),
TyInt(IntTy::I8) => Ok(PrimVal::Bytes(v as i128 as i8 as u128)),
TyInt(IntTy::I16) => Ok(PrimVal::Bytes(v as i128 as i16 as u128)),
TyInt(IntTy::I32) => Ok(PrimVal::Bytes(v as i128 as i32 as u128)),
TyInt(IntTy::I64) => Ok(PrimVal::Bytes(v as i128 as i64 as u128)),
TyInt(IntTy::I128) => Ok(PrimVal::Bytes(v as u128)),
TyUint(UintTy::U8) => Ok(PrimVal::Bytes(v as u8 as u128)),
TyUint(UintTy::U8) => Ok(PrimVal::Bytes(v as u8 as u128)),
TyUint(UintTy::U16) => Ok(PrimVal::Bytes(v as u16 as u128)),
TyUint(UintTy::U32) => Ok(PrimVal::Bytes(v as u32 as u128)),
TyUint(UintTy::U64) => Ok(PrimVal::Bytes(v as u64 as u128)),
......@@ -73,9 +71,9 @@ fn cast_from_int(&self, v: u128, ty: ty::Ty<'tcx>, negative: bool) -> EvalResult
}
TyFloat(FloatTy::F64) if negative => Ok(PrimVal::from_f64(v as i128 as f64)),
TyFloat(FloatTy::F64) => Ok(PrimVal::from_f64(v as f64)),
TyFloat(FloatTy::F64) => Ok(PrimVal::from_f64(v as f64)),
TyFloat(FloatTy::F32) if negative => Ok(PrimVal::from_f32(v as i128 as f32)),
TyFloat(FloatTy::F32) => Ok(PrimVal::from_f32(v as f32)),
TyFloat(FloatTy::F32) => Ok(PrimVal::from_f32(v as f32)),
TyChar if v as u8 as u128 == v => Ok(PrimVal::Bytes(v)),
TyChar => err!(InvalidChar(v)),
......@@ -92,7 +90,7 @@ fn cast_from_float(&self, val: f64, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
match ty.sty {
// Casting negative floats to unsigned integers yields zero.
TyUint(_) if val < 0.0 => self.cast_from_int(0, ty, false),
TyInt(_) if val < 0.0 => self.cast_from_int(val as i128 as u128, ty, true),
TyInt(_) if val < 0.0 => self.cast_from_int(val as i128 as u128, ty, true),
TyInt(_) | ty::TyUint(_) => self.cast_from_int(val as u128, ty, false),
......@@ -106,8 +104,9 @@ fn cast_from_ptr(&self, ptr: MemoryPointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Pr
use rustc::ty::TypeVariants::*;
match ty.sty {
// Casting to a reference or fn pointer is not permitted by rustc, no need to support it here.
TyRawPtr(_) | TyInt(IntTy::Is) | TyUint(UintTy::Us) =>
Ok(PrimVal::Ptr(ptr)),
TyRawPtr(_) |
TyInt(IntTy::Is) |
TyUint(UintTy::Us) => Ok(PrimVal::Ptr(ptr)),
TyInt(_) | TyUint(_) => err!(ReadPointerAsBytes),
_ => err!(Unimplemented(format!("ptr to {:?} cast", ty))),
}
......
......@@ -5,13 +5,8 @@
use syntax::ast::Mutability;
use syntax::codemap::Span;
use super::{
EvalResult, EvalError, EvalErrorKind,
GlobalId, Lvalue, Value,
PrimVal,
EvalContext, StackPopCleanup, PtrAndAlign,
MemoryKind,
};
use super::{EvalResult, EvalError, EvalErrorKind, GlobalId, Lvalue, Value, PrimVal, EvalContext,
StackPopCleanup, PtrAndAlign, MemoryKind};
use rustc_const_math::ConstInt;
......@@ -24,22 +19,37 @@ pub fn eval_body_as_primval<'a, 'tcx>(
) -> EvalResult<'tcx, (PrimVal, Ty<'tcx>)> {
let limits = super::ResourceLimits::default();
let mut ecx = EvalContext::<CompileTimeFunctionEvaluator>::new(tcx, limits, (), ());
let cid = GlobalId { instance, promoted: None };
let cid = GlobalId {
instance,
promoted: None,
};
if ecx.tcx.has_attr(instance.def_id(), "linkage") {
return Err(ConstEvalError::NotConst("extern global".to_string()).into());
}
let mir = ecx.load_mir(instance.def)?;
if !ecx.globals.contains_key(&cid) {
let size = ecx.type_size_with_substs(mir.return_ty, instance.substs)?.expect("unsized global");
let size = ecx.type_size_with_substs(mir.return_ty, instance.substs)?
.expect("unsized global");
let align = ecx.type_align_with_substs(mir.return_ty, instance.substs)?;
let ptr = ecx.memory.allocate(size, align, MemoryKind::UninitializedStatic)?;
let ptr = ecx.memory.allocate(
size,
align,
MemoryKind::UninitializedStatic,
)?;
let aligned = !ecx.is_packed(mir.return_ty)?;
ecx.globals.insert(cid, PtrAndAlign { ptr: ptr.into(), aligned });
ecx.globals.insert(
cid,
PtrAndAlign {
ptr: ptr.into(),
aligned,
},
);
let mutable = !mir.return_ty.is_freeze(
ecx.tcx,
ty::ParamEnv::empty(Reveal::All),
mir.span);
ecx.tcx,
ty::ParamEnv::empty(Reveal::All),
mir.span,
);
let mutability = if mutable {
Mutability::Mutable
} else {
......@@ -77,14 +87,26 @@ pub fn eval_body_as_integer<'a, 'tcx>(
TyInt(IntTy::I32) => ConstInt::I32(prim as i128 as i32),
TyInt(IntTy::I64) => ConstInt::I64(prim as i128 as i64),
TyInt(IntTy::I128) => ConstInt::I128(prim as i128),
TyInt(IntTy::Is) => ConstInt::Isize(ConstIsize::new(prim as i128 as i64, tcx.sess.target.int_type).expect("miri should already have errored")),
TyInt(IntTy::Is) => ConstInt::Isize(
ConstIsize::new(prim as i128 as i64, tcx.sess.target.int_type)
.expect("miri should already have errored"),
),
TyUint(UintTy::U8) => ConstInt::U8(prim as u8),
TyUint(UintTy::U16) => ConstInt::U16(prim as u16),
TyUint(UintTy::U32) => ConstInt::U32(prim as u32),
TyUint(UintTy::U64) => ConstInt::U64(prim as u64),
TyUint(UintTy::U128) => ConstInt::U128(prim),
TyUint(UintTy::Us) => ConstInt::Usize(ConstUsize::new(prim as u64, tcx.sess.target.uint_type).expect("miri should already have errored")),
_ => return Err(ConstEvalError::NeedsRfc("evaluating anything other than isize/usize during typeck".to_string()).into()),
TyUint(UintTy::Us) => ConstInt::Usize(
ConstUsize::new(prim as u64, tcx.sess.target.uint_type)
.expect("miri should already have errored"),
),
_ => {
return Err(
ConstEvalError::NeedsRfc(
"evaluating anything other than isize/usize during typeck".to_string(),
).into(),
)
}
})
}
......@@ -106,10 +128,14 @@ impl fmt::Display for ConstEvalError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::ConstEvalError::*;
match *self {
NeedsRfc(ref msg) =>
write!(f, "\"{}\" needs an rfc before being allowed inside constants", msg),
NotConst(ref msg) =>
write!(f, "Cannot evaluate within constants: \"{}\"", msg),
NeedsRfc(ref msg) => {
write!(
f,
"\"{}\" needs an rfc before being allowed inside constants",
msg
)
}
NotConst(ref msg) => write!(f, "Cannot evaluate within constants: \"{}\"", msg),
}
}
}
......@@ -118,10 +144,8 @@ impl Error for ConstEvalError {
fn description(&self) -> &str {
use self::ConstEvalError::*;
match *self {
NeedsRfc(_) =>
"this feature needs an rfc before being allowed inside constants",
NotConst(_) =>
"this feature is not compatible with constant evaluation",
NeedsRfc(_) => "this feature needs an rfc before being allowed inside constants",
NotConst(_) => "this feature is not compatible with constant evaluation",
}
}
......@@ -143,14 +167,19 @@ fn eval_fn_call<'a>(
_sig: ty::FnSig<'tcx>,
) -> EvalResult<'tcx, bool> {
if !ecx.tcx.is_const_fn(instance.def_id()) {
return Err(ConstEvalError::NotConst(format!("calling non-const fn `{}`", instance)).into());
return Err(
ConstEvalError::NotConst(format!("calling non-const fn `{}`", instance)).into(),
);
}
let mir = match ecx.load_mir(instance.def) {
Ok(mir) => mir,
Err(EvalError{ kind: EvalErrorKind::NoMirFor(path), ..} ) => {
Err(EvalError { kind: EvalErrorKind::NoMirFor(path), .. }) => {
// some simple things like `malloc` might get accepted in the future
return Err(ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path)).into());
},
return Err(
ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path))
.into(),
);
}
Err(other) => return Err(other),
};
let (return_lvalue, return_to_block) = match destination {
......@@ -178,7 +207,9 @@ fn call_intrinsic<'a>(
_dest_layout: &'tcx layout::Layout,
_target: mir::BasicBlock,
) -> EvalResult<'tcx> {
Err(ConstEvalError::NeedsRfc("calling intrinsics".to_string()).into())
Err(
ConstEvalError::NeedsRfc("calling intrinsics".to_string()).into(),
)
}
fn try_ptr_op<'a>(
......@@ -192,7 +223,9 @@ fn try_ptr_op<'a>(
if left.is_bytes() && right.is_bytes() {
Ok(None)
} else {
Err(ConstEvalError::NeedsRfc("Pointer arithmetic or comparison".to_string()).into())
Err(
ConstEvalError::NeedsRfc("Pointer arithmetic or comparison".to_string()).into(),
)
}
}
......@@ -204,6 +237,8 @@ fn box_alloc<'a>(
_ecx: &mut EvalContext<'a, 'tcx, Self>,
_ty: ty::Ty<'tcx>,
) -> EvalResult<'tcx, PrimVal> {
Err(ConstEvalError::NeedsRfc("Heap allocations via `box` keyword".to_string()).into())
Err(
ConstEvalError::NeedsRfc("Heap allocations via `box` keyword".to_string()).into(),
)
}
}
......@@ -3,14 +3,7 @@
use rustc::ty::{self, Ty};
use rustc_data_structures::indexed_vec::Idx;
use super::{
EvalResult,
EvalContext,
MemoryPointer,
PrimVal, Value, Pointer,
Machine,
PtrAndAlign,
};
use super::{EvalResult, EvalContext, MemoryPointer, PrimVal, Value, Pointer, Machine, PtrAndAlign};
#[derive(Copy, Clone, Debug)]
pub enum Lvalue {
......@@ -25,10 +18,7 @@ pub enum Lvalue {
/// An lvalue referring to a value on the stack. Represented by a stack frame index paired with
/// a Mir local index.
Local {
frame: usize,
local: mir::Local,
},
Local { frame: usize, local: mir::Local },
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
......@@ -57,7 +47,10 @@ pub fn undef() -> Self {
}
pub fn from_primval_ptr(ptr: Pointer) -> Self {
Lvalue::Ptr { ptr: PtrAndAlign { ptr, aligned: true }, extra: LvalueExtra::None }
Lvalue::Ptr {
ptr: PtrAndAlign { ptr, aligned: true },
extra: LvalueExtra::None,
}
}
pub fn from_ptr(ptr: MemoryPointer) -> Self {
......@@ -87,7 +80,12 @@ pub(super) fn elem_ty_and_len(self, ty: Ty<'tcx>) -> (Ty<'tcx>, u64) {
ty::TySlice(elem) => {
match self {
Lvalue::Ptr { extra: LvalueExtra::Length(len), .. } => (elem, len),
_ => bug!("elem_ty_and_len of a TySlice given non-slice lvalue: {:?}", self),
_ => {
bug!(
"elem_ty_and_len of a TySlice given non-slice lvalue: {:?}",
self
)
}
}
}
......@@ -99,7 +97,10 @@ pub(super) fn elem_ty_and_len(self, ty: Ty<'tcx>) -> (Ty<'tcx>, u64) {
impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
/// Reads a value from the lvalue without going through the intermediate step of obtaining
/// a `miri::Lvalue`
pub fn try_read_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>) -> EvalResult<'tcx, Option<Value>> {
pub fn try_read_lvalue(
&mut self,
lvalue: &mir::Lvalue<'tcx>,
) -> EvalResult<'tcx, Option<Value>> {
use rustc::mir::Lvalue::*;
match *lvalue {
// Might allow this in the future, right now there's no way to do this from Rust code anyway
......@@ -109,14 +110,22 @@ pub fn try_read_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>) -> EvalResult<'tcx
// Directly reading a static will always succeed
Static(ref static_) => {
let instance = ty::Instance::mono(self.tcx, static_.def_id);
let cid = GlobalId { instance, promoted: None };
Ok(Some(Value::ByRef(*self.globals.get(&cid).expect("global not cached"))))
},
let cid = GlobalId {
instance,
promoted: None,
};
Ok(Some(Value::ByRef(
*self.globals.get(&cid).expect("global not cached"),
)))
}
Projection(ref proj) => self.try_read_lvalue_projection(proj),
}
}
fn try_read_lvalue_projection(&mut self, proj: &mir::LvalueProjection<'tcx>) -> EvalResult<'tcx, Option<Value>> {
fn try_read_lvalue_projection(
&mut self,
proj: &mir::LvalueProjection<'tcx>,
) -> EvalResult<'tcx, Option<Value>> {
use rustc::mir::ProjectionElem::*;
let base = match self.try_read_lvalue(&proj.base)? {
Some(base) => base,
......@@ -147,7 +156,10 @@ fn try_read_lvalue_projection(&mut self, proj: &mir::LvalueProjection<'tcx>) ->
}
/// Returns a value and (in case of a ByRef) if we are supposed to use aligned accesses.
pub(super) fn eval_and_read_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>) -> EvalResult<'tcx, Value> {
pub(super) fn eval_and_read_lvalue(
&mut self,
lvalue: &mir::Lvalue<'tcx>,
) -> EvalResult<'tcx, Value> {
// Shortcut for things like accessing a fat pointer's field,
// which would otherwise (in the `eval_lvalue` path) require moving a `ByValPair` to memory
// and returning an `Lvalue::Ptr` to it
......@@ -164,9 +176,7 @@ pub fn read_lvalue(&self, lvalue: Lvalue) -> EvalResult<'tcx, Value> {
assert_eq!(extra, LvalueExtra::None);
Ok(Value::ByRef(ptr))
}
Lvalue::Local { frame, local } => {
self.stack[frame].get_local(local)
}
Lvalue::Local { frame, local } => self.stack[frame].get_local(local),
}
}
......@@ -174,11 +184,17 @@ pub fn eval_lvalue(&mut self, mir_lvalue: &mir::Lvalue<'tcx>) -> EvalResult<'tcx
use rustc::mir::Lvalue::*;
let lvalue = match *mir_lvalue {
Local(mir::RETURN_POINTER) => self.frame().return_lvalue,
Local(local) => Lvalue::Local { frame: self.cur_frame(), local },
Local(local) => Lvalue::Local {
frame: self.cur_frame(),
local,
},
Static(ref static_) => {
let instance = ty::Instance::mono(self.tcx, static_.def_id);
let gid = GlobalId { instance, promoted: None };
let gid = GlobalId {
instance,
promoted: None,
};
Lvalue::Ptr {
ptr: *self.globals.get(&gid).expect("uncached global"),
extra: LvalueExtra::None,
......@@ -209,9 +225,7 @@ pub fn lvalue_field(
let base_layout = self.type_layout(base_ty)?;
use rustc::ty::layout::Layout::*;
let (offset, packed) = match *base_layout {
Univariant { ref variant, .. } => {
(variant.offsets[field_index], variant.packed)
},
Univariant { ref variant, .. } => (variant.offsets[field_index], variant.packed),
General { ref variants, .. } => {
let (_, base_extra) = base.to_ptr_extra_aligned();
......@@ -249,8 +263,13 @@ pub fn lvalue_field(
ty::TyArray(elem_ty, n) => {
assert!(field < n as u64);
self.type_size(elem_ty)?.expect("array elements are sized") as u64
},
_ => bug!("lvalue_field: got Array layout but non-array type {:?}", base_ty),
}
_ => {
bug!(
"lvalue_field: got Array layout but non-array type {:?}",
base_ty
)
}
};
(Size::from_bytes(field * elem_size), false)
}
......@@ -267,22 +286,36 @@ pub fn lvalue_field(
// Do not allocate in trivial cases
let (base_ptr, base_extra) = match base {
Lvalue::Ptr { ptr, extra } => (ptr, extra),
Lvalue::Local { frame, local } => match self.stack[frame].get_local(local)? {
// in case the type has a single field, just return the value
Value::ByVal(_) if self.get_field_count(base_ty).map(|c| c == 1).unwrap_or(false) => {
assert_eq!(offset.bytes(), 0, "ByVal can only have 1 non zst field with offset 0");
return Ok(base);
},
Value::ByRef{..} |
Value::ByValPair(..) |
Value::ByVal(_) => self.force_allocation(base)?.to_ptr_extra_aligned(),
},
Lvalue::Local { frame, local } => {
match self.stack[frame].get_local(local)? {
// in case the type has a single field, just return the value
Value::ByVal(_)
if self.get_field_count(base_ty).map(|c| c == 1).unwrap_or(
false,
) => {
assert_eq!(
offset.bytes(),
0,
"ByVal can only have 1 non zst field with offset 0"
);
return Ok(base);
}
Value::ByRef { .. } |
Value::ByValPair(..) |
Value::ByVal(_) => self.force_allocation(base)?.to_ptr_extra_aligned(),
}
}
};
let offset = match base_extra {
LvalueExtra::Vtable(tab) => {
let (_, align) = self.size_and_align_of_dst(base_ty, base_ptr.ptr.to_value_with_vtable(tab))?;
offset.abi_align(Align::from_bytes(align, align).unwrap()).bytes()
let (_, align) = self.size_and_align_of_dst(
base_ty,
base_ptr.ptr.to_value_with_vtable(tab),
)?;
offset
.abi_align(Align::from_bytes(align, align).unwrap())
.bytes()
}
_ => offset.bytes(),
};
......@@ -299,41 +332,63 @@ pub fn lvalue_field(
} else {
match base_extra {
LvalueExtra::None => bug!("expected fat pointer"),
LvalueExtra::DowncastVariant(..) =>
bug!("Rust doesn't support unsized fields in enum variants"),
LvalueExtra::DowncastVariant(..) => {
bug!("Rust doesn't support unsized fields in enum variants")
}
LvalueExtra::Vtable(_) |
LvalueExtra::Length(_) => {},
LvalueExtra::Length(_) => {}
}
base_extra
};
Ok(Lvalue::Ptr { ptr, extra } )
Ok(Lvalue::Ptr { ptr, extra })
}
pub(super) fn val_to_lvalue(&self, val: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, Lvalue> {
Ok(match self.tcx.struct_tail(ty).sty {
ty::TyDynamic(..) => {
let (ptr, vtable) = val.into_ptr_vtable_pair(&self.memory)?;
Lvalue::Ptr { ptr: PtrAndAlign { ptr, aligned: true }, extra: LvalueExtra::Vtable(vtable) }
},
Lvalue::Ptr {
ptr: PtrAndAlign { ptr, aligned: true },
extra: LvalueExtra::Vtable(vtable),
}
}
ty::TyStr | ty::TySlice(_) => {
let (ptr, len) = val.into_slice(&self.memory)?;
Lvalue::Ptr { ptr: PtrAndAlign { ptr, aligned: true }, extra: LvalueExtra::Length(len) }
},
Lvalue::Ptr {
ptr: PtrAndAlign { ptr, aligned: true },
extra: LvalueExtra::Length(len),
}
}
_ => Lvalue::from_primval_ptr(val.into_ptr(&self.memory)?),
})
}
pub(super) fn lvalue_index(&mut self, base: Lvalue, outer_ty: Ty<'tcx>, n: u64) -> EvalResult<'tcx, Lvalue> {
pub(super) fn lvalue_index(
&mut self,
base: Lvalue,
outer_ty: Ty<'tcx>,
n: u64,
) -> EvalResult<'tcx, Lvalue> {
// Taking the outer type here may seem odd; it's needed because for array types, the outer type gives away the length.
let base = self.force_allocation(base)?;
let (base_ptr, _) = base.to_ptr_extra_aligned();
let (elem_ty, len) = base.elem_ty_and_len(outer_ty);
let elem_size = self.type_size(elem_ty)?.expect("slice element must be sized");
assert!(n < len, "Tried to access element {} of array/slice with length {}", n, len);
let elem_size = self.type_size(elem_ty)?.expect(
"slice element must be sized",
);
assert!(
n < len,
"Tried to access element {} of array/slice with length {}",
n,
len
);
let ptr = base_ptr.offset(n * elem_size, self.memory.layout)?;
Ok(Lvalue::Ptr { ptr, extra: LvalueExtra::None })
Ok(Lvalue::Ptr {
ptr,
extra: LvalueExtra::None,
})
}
pub(super) fn eval_lvalue_projection(
......@@ -357,7 +412,8 @@ pub(super) fn eval_lvalue_projection(
use rustc::ty::layout::Layout::*;
let extra = match *base_layout {
General { .. } => LvalueExtra::DowncastVariant(variant),
RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => base_extra,
RawNullablePointer { .. } |
StructWrappedNullablePointer { .. } => base_extra,
_ => bug!("variant downcast on non-aggregate: {:?}", base_layout),
};
(base_ptr, extra)
......@@ -386,13 +442,19 @@ pub(super) fn eval_lvalue_projection(
return self.lvalue_index(base, base_ty, n);
}
ConstantIndex { offset, min_length, from_end } => {
ConstantIndex {
offset,
min_length,
from_end,
} => {
// FIXME(solson)
let base = self.force_allocation(base)?;
let (base_ptr, _) = base.to_ptr_extra_aligned();
let (elem_ty, n) = base.elem_ty_and_len(base_ty);
let elem_size = self.type_size(elem_ty)?.expect("sequence element must be sized");
let elem_size = self.type_size(elem_ty)?.expect(
"sequence element must be sized",
);
assert!(n >= min_length as u64);
let index = if from_end {
......@@ -411,7 +473,9 @@ pub(super) fn eval_lvalue_projection(
let (base_ptr, _) = base.to_ptr_extra_aligned();
let (elem_ty, n) = base.elem_ty_and_len(base_ty);
let elem_size = self.type_size(elem_ty)?.expect("slice element must be sized");
let elem_size = self.type_size(elem_ty)?.expect(
"slice element must be sized",
);
assert!(u64::from(from) <= n - u64::from(to));
let ptr = base_ptr.offset(u64::from(from) * elem_size, &self)?;
let extra = LvalueExtra::Length(n - u64::from(to) - u64::from(from));
......@@ -423,6 +487,9 @@ pub(super) fn eval_lvalue_projection(
}
pub(super) fn lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> {
self.monomorphize(lvalue.ty(self.mir(), self.tcx).to_ty(self.tcx), self.substs())
self.monomorphize(
lvalue.ty(self.mir(), self.tcx).to_ty(self.tcx),
self.substs(),
)
}
}
......@@ -2,12 +2,7 @@
//! This separation exists to ensure that no fancy miri features like
//! interpreting common C functions leak into CTFE.
use super::{
EvalResult,
EvalContext,
Lvalue,
PrimVal
};
use super::{EvalResult, EvalContext, Lvalue, PrimVal};
use rustc::{mir, ty};
use syntax::codemap::Span;
......@@ -76,4 +71,3 @@ fn box_alloc<'a>(
ty: ty::Ty<'tcx>,
) -> EvalResult<'tcx, PrimVal>;
}
......@@ -20,62 +20,23 @@
mod traits;
mod value;
pub use self::error::{
EvalError,
EvalResult,
EvalErrorKind,
};
pub use self::error::{EvalError, EvalResult, EvalErrorKind};
pub use self::eval_context::{
EvalContext,
Frame,
ResourceLimits,
StackPopCleanup,
DynamicLifetime,
TyAndPacked,
PtrAndAlign,
};
pub use self::eval_context::{EvalContext, Frame, ResourceLimits, StackPopCleanup, DynamicLifetime,
TyAndPacked, PtrAndAlign};
pub use self::lvalue::{
Lvalue,
LvalueExtra,
GlobalId,
};
pub use self::lvalue::{Lvalue, LvalueExtra, GlobalId};
pub use self::memory::{
AllocId,
Memory,
MemoryPointer,
MemoryKind,
HasMemory,
};
pub use self::memory::{AllocId, Memory, MemoryPointer, MemoryKind, HasMemory};
use self::memory::{
PointerArithmetic,
Lock,
AccessKind,
};
use self::memory::{PointerArithmetic, Lock, AccessKind};
use self::range_map::{
RangeMap
};
use self::range_map::RangeMap;
pub use self::value::{
PrimVal,
PrimValKind,
Value,
Pointer,
};
pub use self::value::{PrimVal, PrimValKind, Value, Pointer};
pub use self::const_eval::{
eval_body_as_integer,
eval_body_as_primval,
};
pub use self::const_eval::{eval_body_as_integer, eval_body_as_primval};
pub use self::machine::{
Machine,
};
pub use self::machine::Machine;
pub use self::validation::{
ValidationQuery,
};
pub use self::validation::ValidationQuery;
此差异已折叠。
......@@ -2,29 +2,45 @@
use rustc::ty::{self, Ty};
use syntax::codemap::Span;
use interpret::{
EvalResult,
EvalContext, StackPopCleanup,
Lvalue, LvalueExtra,
PrimVal, Value,
Machine,
};
use interpret::{EvalResult, EvalContext, StackPopCleanup, Lvalue, LvalueExtra, PrimVal, Value,
Machine};
impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
pub(crate) fn drop_lvalue(&mut self, lval: Lvalue, instance: ty::Instance<'tcx>, ty: Ty<'tcx>, span: Span) -> EvalResult<'tcx> {
pub(crate) fn drop_lvalue(
&mut self,
lval: Lvalue,
instance: ty::Instance<'tcx>,
ty: Ty<'tcx>,
span: Span,
) -> EvalResult<'tcx> {
trace!("drop_lvalue: {:#?}", lval);
// We take the address of the object. This may well be unaligned, which is fine for us here.
// However, unaligned accesses will probably make the actual drop implementation fail -- a problem shared
// by rustc.
let val = match self.force_allocation(lval)? {
Lvalue::Ptr { ptr, extra: LvalueExtra::Vtable(vtable) } => ptr.ptr.to_value_with_vtable(vtable),
Lvalue::Ptr { ptr, extra: LvalueExtra::Length(len) } => ptr.ptr.to_value_with_len(len),
Lvalue::Ptr { ptr, extra: LvalueExtra::None } => ptr.ptr.to_value(),
Lvalue::Ptr {
ptr,
extra: LvalueExtra::Vtable(vtable),
} => ptr.ptr.to_value_with_vtable(vtable),
Lvalue::Ptr {
ptr,
extra: LvalueExtra::Length(len),
} => ptr.ptr.to_value_with_len(len),
Lvalue::Ptr {
ptr,
extra: LvalueExtra::None,
} => ptr.ptr.to_value(),
_ => bug!("force_allocation broken"),
};
self.drop(val, instance, ty, span)
}
pub(crate) fn drop(&mut self, arg: Value, mut instance: ty::Instance<'tcx>, ty: Ty<'tcx>, span: Span) -> EvalResult<'tcx> {
pub(crate) fn drop(
&mut self,
arg: Value,
mut instance: ty::Instance<'tcx>,
ty: Ty<'tcx>,
span: Span,
) -> EvalResult<'tcx> {
trace!("drop: {:#?}, {:?}, {:?}", arg, ty.sty, instance.def);
if let ty::InstanceDef::DropGlue(_, None) = instance.def {
......@@ -42,11 +58,11 @@ pub(crate) fn drop(&mut self, arg: Value, mut instance: ty::Instance<'tcx>, ty:
Some(func) => {
instance = func;
self.load_mir(func.def)?
},
}
// no drop fn -> bail out
None => return Ok(()),
}
},
}
_ => self.load_mir(instance.def)?,
};
......
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册