Merge remote-tracking branch 'origin/master' into oflo
This commit is contained in:
55
README.md
55
README.md
@@ -1,52 +1,58 @@
|
||||
# Miri
|
||||
# Miri [[slides](https://solson.me/miri-slides.pdf)] [[report](https://solson.me/miri-report.pdf)] [](https://travis-ci.org/solson/miri)
|
||||
|
||||
[[slides](https://solson.me/miri-slides.pdf)]
|
||||
[[report](https://solson.me/miri-report.pdf)]
|
||||
|
||||
An experimental interpreter for [Rust][rust]'s [mid-level intermediate
|
||||
representation][mir] (MIR). This project began as part of my work for the
|
||||
undergraduate research course at the [University of Saskatchewan][usask].
|
||||
|
||||
[](https://travis-ci.org/solson/miri)
|
||||
## Installing Rust
|
||||
|
||||
## Download Rust nightly
|
||||
|
||||
I currently recommend that you install [multirust][multirust] and then use it to
|
||||
install the current rustc nightly version:
|
||||
I recommend that you install [rustup][rustup] and then use it to install the
|
||||
current Rust nightly version:
|
||||
|
||||
```sh
|
||||
multirust update nightly
|
||||
rustup update nightly
|
||||
```
|
||||
|
||||
## Build
|
||||
You should also make `nightly` the default version for your Miri directory by
|
||||
running the following command while you're in it. If you don't do this, you can
|
||||
run the later `cargo` commands by prefixing them with `rustup run nightly`.
|
||||
|
||||
```sh
|
||||
multirust run nightly cargo build
|
||||
rustup override add nightly
|
||||
```
|
||||
|
||||
## Building Miri
|
||||
|
||||
```sh
|
||||
cargo build
|
||||
```
|
||||
|
||||
If Miri fails to build, it's likely because a change in the latest nightly
|
||||
compiler broke it. You could try an older nightly with `multirust update
|
||||
compiler broke it. You could try an older nightly with `rustup update
|
||||
nightly-<date>` where `<date>` is a few days or weeks ago, e.g. `2016-05-20` for
|
||||
May 20th. Otherwise, you could notify me in an issue or on IRC. Or, if you know
|
||||
how to fix it, you could send a PR. :smile:
|
||||
|
||||
## Run a test
|
||||
## Running tests
|
||||
|
||||
```sh
|
||||
multirust run nightly cargo run -- \
|
||||
--sysroot $HOME/.multirust/toolchains/nightly \
|
||||
test/filename.rs
|
||||
cargo run tests/run-pass/vecs.rs # Or whatever test you like.
|
||||
```
|
||||
|
||||
If you are using [rustup][rustup] (the name of the multirust rewrite in Rust),
|
||||
the `sysroot` path will also include your build target (e.g.
|
||||
`$HOME/.multirust/toolchains/nightly-x86_64-apple-darwin`). You can see the
|
||||
current toolchain's directory by running `rustup which cargo` (ignoring the
|
||||
trailing `/bin/cargo`).
|
||||
## Debugging
|
||||
|
||||
If you installed without using multirust or rustup, you'll need to adjust the
|
||||
command to run your cargo and set the `sysroot` to the directory where your
|
||||
Rust compiler is installed (`$sysroot/bin/rustc` should be a valid path).
|
||||
You can get detailed, statement-by-statement traces by setting the `MIRI_RUN`
|
||||
environment variable to `trace`. These traces are indented based on call stack
|
||||
depth. You can get a much less verbose set of information with other logging
|
||||
levels such as `warn`.
|
||||
|
||||
## Contributing and getting help
|
||||
|
||||
Check out the issues on this GitHub repository for some ideas. There's lots that
|
||||
needs to be done that I haven't documented in the issues yet, however. For more
|
||||
ideas or help with running or hacking on Miri, you can contact me (`scott`) on
|
||||
Mozilla IRC in any of the Rust IRC channels (`#rust`, `#rust-offtopic`, etc).
|
||||
|
||||
## License
|
||||
|
||||
@@ -65,5 +71,4 @@ additional terms or conditions.
|
||||
[rust]: https://www.rust-lang.org/
|
||||
[mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md
|
||||
[usask]: https://www.usask.ca/
|
||||
[multirust]: https://github.com/brson/multirust
|
||||
[rustup]: https://www.rustup.rs
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
#![feature(custom_attribute, test)]
|
||||
#![feature(rustc_private)]
|
||||
#![allow(unused_attributes)]
|
||||
#![feature(test, rustc_private)]
|
||||
|
||||
extern crate test;
|
||||
use test::Bencher;
|
||||
|
||||
mod fibonacci_helper;
|
||||
mod helpers;
|
||||
use helpers::*;
|
||||
|
||||
#[bench]
|
||||
fn fib(bencher: &mut Bencher) {
|
||||
@@ -14,15 +12,11 @@ fn fib(bencher: &mut Bencher) {
|
||||
})
|
||||
}
|
||||
|
||||
mod miri_helper;
|
||||
|
||||
#[bench]
|
||||
fn fib_miri(bencher: &mut Bencher) {
|
||||
miri_helper::run("fibonacci_helper", bencher);
|
||||
}
|
||||
|
||||
mod fibonacci_helper_iterative;
|
||||
|
||||
#[bench]
|
||||
fn fib_iter(bencher: &mut Bencher) {
|
||||
bencher.iter(|| {
|
||||
|
||||
65
benches/helpers/miri_helper.rs
Normal file
65
benches/helpers/miri_helper.rs
Normal file
@@ -0,0 +1,65 @@
|
||||
extern crate getopts;
|
||||
extern crate miri;
|
||||
extern crate rustc;
|
||||
extern crate rustc_driver;
|
||||
extern crate test;
|
||||
|
||||
use self::miri::eval_main;
|
||||
use self::rustc::session::Session;
|
||||
use self::rustc_driver::{driver, CompilerCalls, Compilation};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use test::Bencher;
|
||||
|
||||
pub struct MiriCompilerCalls<'a>(Rc<RefCell<&'a mut Bencher>>);
|
||||
|
||||
fn find_sysroot() -> String {
|
||||
// Taken from https://github.com/Manishearth/rust-clippy/pull/911.
|
||||
let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
|
||||
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(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(filename: &str, bencher: &mut Bencher) {
|
||||
let args = &[
|
||||
"miri".to_string(),
|
||||
format!("benches/helpers/{}.rs", filename),
|
||||
"--sysroot".to_string(),
|
||||
find_sysroot()
|
||||
];
|
||||
let compiler_calls = &mut MiriCompilerCalls(Rc::new(RefCell::new(bencher)));
|
||||
rustc_driver::run_compiler(args, compiler_calls);
|
||||
}
|
||||
|
||||
impl<'a> CompilerCalls<'a> for MiriCompilerCalls<'a> {
|
||||
fn build_controller(
|
||||
&mut self,
|
||||
_: &Session,
|
||||
_: &getopts::Matches
|
||||
) -> driver::CompileController<'a> {
|
||||
let mut control: driver::CompileController<'a> = driver::CompileController::basic();
|
||||
|
||||
let bencher = self.0.clone();
|
||||
|
||||
control.after_analysis.stop = Compilation::Stop;
|
||||
control.after_analysis.callback = Box::new(move |state| {
|
||||
state.session.abort_if_errors();
|
||||
|
||||
let tcx = state.tcx.unwrap();
|
||||
let mir_map = state.mir_map.unwrap();
|
||||
let (node_id, _) = state.session.entry_fn.borrow()
|
||||
.expect("no main or start function found");
|
||||
|
||||
bencher.borrow_mut().iter(|| { eval_main(tcx, mir_map, node_id); });
|
||||
|
||||
state.session.abort_if_errors();
|
||||
});
|
||||
|
||||
control
|
||||
}
|
||||
}
|
||||
7
benches/helpers/mod.rs
Normal file
7
benches/helpers/mod.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
// This module gets included in multiple crates, and they each only use part of it.
|
||||
#![allow(dead_code)]
|
||||
|
||||
pub mod fibonacci_helper;
|
||||
pub mod fibonacci_helper_iterative;
|
||||
pub mod miri_helper;
|
||||
pub mod smoke_helper;
|
||||
@@ -1,48 +0,0 @@
|
||||
#![feature(custom_attribute, test)]
|
||||
#![feature(rustc_private)]
|
||||
#![allow(unused_attributes)]
|
||||
|
||||
extern crate getopts;
|
||||
extern crate miri;
|
||||
extern crate rustc;
|
||||
extern crate rustc_driver;
|
||||
extern crate test;
|
||||
|
||||
use self::miri::interpreter;
|
||||
use self::rustc::session::Session;
|
||||
use self::rustc_driver::{driver, CompilerCalls, Compilation};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use std::env::var;
|
||||
use test::Bencher;
|
||||
|
||||
pub struct MiriCompilerCalls<'a>(Rc<RefCell<&'a mut Bencher>>);
|
||||
|
||||
pub fn run(filename: &str, bencher: &mut Bencher) {
|
||||
let path = var("RUST_SYSROOT").expect("env variable `RUST_SYSROOT` not set");
|
||||
rustc_driver::run_compiler(&[
|
||||
"miri".to_string(), format!("benches/{}.rs", filename), "--sysroot".to_string(), path.to_string(),
|
||||
], &mut MiriCompilerCalls(Rc::new(RefCell::new(bencher))));
|
||||
}
|
||||
|
||||
impl<'a> CompilerCalls<'a> for MiriCompilerCalls<'a> {
|
||||
fn build_controller(
|
||||
&mut self,
|
||||
_: &Session,
|
||||
_: &getopts::Matches
|
||||
) -> driver::CompileController<'a> {
|
||||
let mut control: driver::CompileController<'a> = driver::CompileController::basic();
|
||||
|
||||
let bencher = self.0.clone();
|
||||
|
||||
control.after_analysis.stop = Compilation::Stop;
|
||||
control.after_analysis.callback = Box::new(move |state| {
|
||||
state.session.abort_if_errors();
|
||||
bencher.borrow_mut().iter(|| {
|
||||
interpreter::interpret_start_points(state.tcx.unwrap(), state.mir_map.unwrap());
|
||||
})
|
||||
});
|
||||
|
||||
control
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,9 @@
|
||||
#![feature(custom_attribute, test)]
|
||||
#![feature(rustc_private)]
|
||||
#![allow(unused_attributes)]
|
||||
#![feature(test, rustc_private)]
|
||||
|
||||
extern crate test;
|
||||
use test::Bencher;
|
||||
|
||||
mod smoke_helper;
|
||||
mod helpers;
|
||||
use helpers::*;
|
||||
|
||||
#[bench]
|
||||
fn noop(bencher: &mut Bencher) {
|
||||
@@ -33,8 +31,6 @@ fn noop_miri_full(bencher: &mut Bencher) {
|
||||
}
|
||||
*/
|
||||
|
||||
mod miri_helper;
|
||||
|
||||
#[bench]
|
||||
fn noop_miri_interpreter(bencher: &mut Bencher) {
|
||||
miri_helper::run("smoke_helper", bencher);
|
||||
|
||||
@@ -9,17 +9,9 @@ extern crate log_settings;
|
||||
extern crate syntax;
|
||||
#[macro_use] extern crate log;
|
||||
|
||||
use miri::{
|
||||
EvalContext,
|
||||
CachedMir,
|
||||
step,
|
||||
EvalError,
|
||||
Frame,
|
||||
};
|
||||
use miri::eval_main;
|
||||
use rustc::session::Session;
|
||||
use rustc_driver::{driver, CompilerCalls, Compilation};
|
||||
use rustc::ty::{TyCtxt, subst};
|
||||
use rustc::hir::def_id::DefId;
|
||||
|
||||
struct MiriCompilerCalls;
|
||||
|
||||
@@ -37,40 +29,10 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
|
||||
|
||||
let tcx = state.tcx.unwrap();
|
||||
let mir_map = state.mir_map.unwrap();
|
||||
let (node_id, _) = state.session.entry_fn.borrow()
|
||||
.expect("no main or start function found");
|
||||
eval_main(tcx, mir_map, node_id);
|
||||
|
||||
let (node_id, span) = state.session.entry_fn.borrow().expect("no main or start function found");
|
||||
debug!("found `main` function at: {:?}", span);
|
||||
|
||||
let mir = mir_map.map.get(&node_id).expect("no mir for main function");
|
||||
let def_id = tcx.map.local_def_id(node_id);
|
||||
let mut ecx = EvalContext::new(tcx, mir_map);
|
||||
let substs = tcx.mk_substs(subst::Substs::empty());
|
||||
let return_ptr = ecx.alloc_ret_ptr(mir.return_ty, substs).expect("main function should not be diverging");
|
||||
|
||||
ecx.push_stack_frame(def_id, mir.span, CachedMir::Ref(mir), substs, Some(return_ptr));
|
||||
|
||||
if mir.arg_decls.len() == 2 {
|
||||
// start function
|
||||
let ptr_size = ecx.memory().pointer_size;
|
||||
let nargs = ecx.memory_mut().allocate(ptr_size);
|
||||
ecx.memory_mut().write_usize(nargs, 0).unwrap();
|
||||
let args = ecx.memory_mut().allocate(ptr_size);
|
||||
ecx.memory_mut().write_usize(args, 0).unwrap();
|
||||
ecx.frame_mut().locals[0] = nargs;
|
||||
ecx.frame_mut().locals[1] = args;
|
||||
}
|
||||
|
||||
loop {
|
||||
match step(&mut ecx) {
|
||||
Ok(true) => {}
|
||||
Ok(false) => break,
|
||||
// FIXME: diverging functions can end up here in some future miri
|
||||
Err(e) => {
|
||||
report(tcx, &ecx, e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
state.session.abort_if_errors();
|
||||
});
|
||||
|
||||
@@ -78,43 +40,26 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
|
||||
}
|
||||
}
|
||||
|
||||
fn report(tcx: TyCtxt, ecx: &EvalContext, e: EvalError) {
|
||||
let frame = ecx.stack().last().expect("stackframe was empty");
|
||||
let block = &frame.mir.basic_blocks()[frame.block];
|
||||
let span = if frame.stmt < block.statements.len() {
|
||||
block.statements[frame.stmt].source_info.span
|
||||
} else {
|
||||
block.terminator().source_info.span
|
||||
};
|
||||
let mut err = tcx.sess.struct_span_err(span, &e.to_string());
|
||||
for &Frame { def_id, substs, span, .. } in ecx.stack().iter().rev() {
|
||||
// FIXME(solson): Find a way to do this without this Display impl hack.
|
||||
use rustc::util::ppaux;
|
||||
use std::fmt;
|
||||
struct Instance<'tcx>(DefId, &'tcx subst::Substs<'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, &[],
|
||||
|tcx| Some(tcx.lookup_item_type(self.0).generics))
|
||||
}
|
||||
}
|
||||
err.span_note(span, &format!("inside call to {}", Instance(def_id, substs)));
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
|
||||
fn init_logger() {
|
||||
const NSPACES: usize = 40;
|
||||
const MAX_INDENT: usize = 40;
|
||||
|
||||
let format = |record: &log::LogRecord| {
|
||||
// prepend spaces to indent the final string
|
||||
let indentation = log_settings::settings().indentation;
|
||||
format!("{lvl}:{module}{depth:2}{indent:<indentation$} {text}",
|
||||
lvl = record.level(),
|
||||
module = record.location().module_path(),
|
||||
depth = indentation / NSPACES,
|
||||
indentation = indentation % NSPACES,
|
||||
indent = "",
|
||||
text = record.args())
|
||||
if record.level() == log::LogLevel::Trace {
|
||||
// prepend spaces to indent the final string
|
||||
let indentation = log_settings::settings().indentation;
|
||||
format!("{lvl}:{module}{depth:2}{indent:<indentation$} {text}",
|
||||
lvl = record.level(),
|
||||
module = record.location().module_path(),
|
||||
depth = indentation / MAX_INDENT,
|
||||
indentation = indentation % MAX_INDENT,
|
||||
indent = "",
|
||||
text = record.args())
|
||||
} else {
|
||||
format!("{lvl}:{module}: {text}",
|
||||
lvl = record.level(),
|
||||
module = record.location().module_path(),
|
||||
text = record.args())
|
||||
}
|
||||
};
|
||||
|
||||
let mut builder = env_logger::LogBuilder::new();
|
||||
|
||||
@@ -1546,3 +1546,65 @@ impl StructExt for layout::Struct {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eval_main<'a, 'tcx: 'a>(
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
mir_map: &'a MirMap<'tcx>,
|
||||
node_id: ast::NodeId,
|
||||
) {
|
||||
let mir = mir_map.map.get(&node_id).expect("no mir for main function");
|
||||
let def_id = tcx.map.local_def_id(node_id);
|
||||
let mut ecx = EvalContext::new(tcx, mir_map);
|
||||
let substs = tcx.mk_substs(subst::Substs::empty());
|
||||
let return_ptr = ecx.alloc_ret_ptr(mir.return_ty, substs).expect("main function should not be diverging");
|
||||
|
||||
ecx.push_stack_frame(def_id, mir.span, CachedMir::Ref(mir), substs, Some(return_ptr));
|
||||
|
||||
if mir.arg_decls.len() == 2 {
|
||||
// start function
|
||||
let ptr_size = ecx.memory().pointer_size;
|
||||
let nargs = ecx.memory_mut().allocate(ptr_size);
|
||||
ecx.memory_mut().write_usize(nargs, 0).unwrap();
|
||||
let args = ecx.memory_mut().allocate(ptr_size);
|
||||
ecx.memory_mut().write_usize(args, 0).unwrap();
|
||||
ecx.frame_mut().locals[0] = nargs;
|
||||
ecx.frame_mut().locals[1] = args;
|
||||
}
|
||||
|
||||
loop {
|
||||
match step(&mut ecx) {
|
||||
Ok(true) => {}
|
||||
Ok(false) => break,
|
||||
// FIXME: diverging functions can end up here in some future miri
|
||||
Err(e) => {
|
||||
report(tcx, &ecx, e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn report(tcx: TyCtxt, ecx: &EvalContext, e: EvalError) {
|
||||
let frame = ecx.stack().last().expect("stackframe was empty");
|
||||
let block = &frame.mir.basic_blocks()[frame.block];
|
||||
let span = if frame.stmt < block.statements.len() {
|
||||
block.statements[frame.stmt].source_info.span
|
||||
} else {
|
||||
block.terminator().source_info.span
|
||||
};
|
||||
let mut err = tcx.sess.struct_span_err(span, &e.to_string());
|
||||
for &Frame { def_id, substs, span, .. } in ecx.stack().iter().rev() {
|
||||
// FIXME(solson): Find a way to do this without this Display impl hack.
|
||||
use rustc::util::ppaux;
|
||||
use std::fmt;
|
||||
struct Instance<'tcx>(DefId, &'tcx subst::Substs<'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, &[],
|
||||
|tcx| Some(tcx.lookup_item_type(self.0).generics))
|
||||
}
|
||||
}
|
||||
err.span_note(span, &format!("inside call to {}", Instance(def_id, substs)));
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
|
||||
@@ -32,10 +32,11 @@ pub use error::{
|
||||
};
|
||||
|
||||
pub use interpreter::{
|
||||
EvalContext,
|
||||
step,
|
||||
Frame,
|
||||
CachedMir,
|
||||
EvalContext,
|
||||
Frame,
|
||||
eval_main,
|
||||
step,
|
||||
};
|
||||
|
||||
pub use memory::Memory;
|
||||
|
||||
@@ -57,20 +57,23 @@ fn compile_test() {
|
||||
for_all_targets(&sysroot, |target| {
|
||||
for file in std::fs::read_dir("tests/run-pass").unwrap() {
|
||||
let file = file.unwrap();
|
||||
if !file.metadata().unwrap().is_file() {
|
||||
let path = file.path();
|
||||
|
||||
if !file.metadata().unwrap().is_file() || !path.to_str().unwrap().ends_with(".rs") {
|
||||
continue;
|
||||
}
|
||||
let file = file.path();
|
||||
|
||||
let stderr = std::io::stderr();
|
||||
write!(stderr.lock(), "test [miri-pass] {} ", file.to_str().unwrap()).unwrap();
|
||||
write!(stderr.lock(), "test [miri-pass] {} ... ", path.display()).unwrap();
|
||||
let mut cmd = std::process::Command::new("target/debug/miri");
|
||||
cmd.arg(file);
|
||||
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");
|
||||
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() => writeln!(stderr.lock(), "ok").unwrap(),
|
||||
Ok(output) => {
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
#![feature(custom_attribute)]
|
||||
#![allow(dead_code, unused_attributes)]
|
||||
|
||||
#[miri_run]
|
||||
fn simple() -> i32 {
|
||||
let y = 10;
|
||||
let f = |x| x + y;
|
||||
f(2)
|
||||
}
|
||||
|
||||
#[miri_run]
|
||||
fn crazy_closure() -> (i32, i32, i32) {
|
||||
fn inner<T: Copy>(t: T) -> (i32, T, T) {
|
||||
struct NonCopy;
|
||||
@@ -26,7 +21,7 @@ fn crazy_closure() -> (i32, i32, i32) {
|
||||
inner(10)
|
||||
}
|
||||
|
||||
// #[miri_run]
|
||||
// TODO(solson): Implement closure argument adjustment and uncomment this test.
|
||||
// fn closure_arg_adjustment_problem() -> i64 {
|
||||
// fn once<F: FnOnce(i64)>(f: F) { f(2); }
|
||||
// let mut y = 1;
|
||||
@@ -37,7 +32,7 @@ fn crazy_closure() -> (i32, i32, i32) {
|
||||
// y
|
||||
// }
|
||||
|
||||
#[miri_run]
|
||||
fn main() {
|
||||
assert_eq!(simple(), 12);
|
||||
assert_eq!(crazy_closure(), (84, 10, 10));
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
#![feature(custom_attribute)]
|
||||
#![allow(dead_code, unused_attributes)]
|
||||
|
||||
const A: usize = *&5;
|
||||
|
||||
#[miri_run]
|
||||
fn foo() -> usize {
|
||||
A
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
fn main() {
|
||||
assert_eq!(foo(), A);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
#![feature(custom_attribute)]
|
||||
#![allow(dead_code, unused_attributes)]
|
||||
|
||||
// This tests that the size of Option<Box<i32>> is the same as *const i32.
|
||||
|
||||
#[miri_run]
|
||||
fn option_box_deref() -> i32 {
|
||||
let val = Some(Box::new(42));
|
||||
unsafe {
|
||||
@@ -12,4 +7,6 @@ fn option_box_deref() -> i32 {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
fn main() {
|
||||
assert_eq!(option_box_deref(), 42);
|
||||
}
|
||||
|
||||
@@ -1,17 +1,11 @@
|
||||
#![feature(custom_attribute)]
|
||||
#![allow(dead_code, unused_attributes)]
|
||||
|
||||
#[miri_run]
|
||||
fn tuple() -> (i16,) {
|
||||
(1,)
|
||||
}
|
||||
|
||||
#[miri_run]
|
||||
fn tuple_2() -> (i16, i16) {
|
||||
(1, 2)
|
||||
}
|
||||
|
||||
#[miri_run]
|
||||
fn tuple_5() -> (i16, i16, i16, i16, i16) {
|
||||
(1, 2, 3, 4, 5)
|
||||
}
|
||||
@@ -19,19 +13,16 @@ fn tuple_5() -> (i16, i16, i16, i16, i16) {
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct Pair { x: i8, y: i8 }
|
||||
|
||||
#[miri_run]
|
||||
fn pair() -> Pair {
|
||||
Pair { x: 10, y: 20 }
|
||||
}
|
||||
|
||||
#[miri_run]
|
||||
fn field_access() -> (i8, i8) {
|
||||
let mut p = Pair { x: 10, y: 20 };
|
||||
p.x += 5;
|
||||
(p.x, p.y)
|
||||
}
|
||||
|
||||
#[miri_run]
|
||||
fn main() {
|
||||
assert_eq!(tuple(), (1,));
|
||||
assert_eq!(tuple_2(), (1, 2));
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
#![feature(custom_attribute, specialization)]
|
||||
#![allow(dead_code, unused_attributes)]
|
||||
|
||||
trait IsUnit {
|
||||
fn is_unit() -> bool;
|
||||
}
|
||||
@@ -13,12 +10,10 @@ impl IsUnit for () {
|
||||
fn is_unit() -> bool { true }
|
||||
}
|
||||
|
||||
#[miri_run]
|
||||
fn specialization() -> (bool, bool) {
|
||||
(i32::is_unit(), <()>::is_unit())
|
||||
}
|
||||
|
||||
#[miri_run]
|
||||
fn main() {
|
||||
assert_eq!(specialization(), (false, true));
|
||||
}
|
||||
|
||||
@@ -1,29 +1,27 @@
|
||||
#![feature(custom_attribute)]
|
||||
#![allow(dead_code, unused_attributes)]
|
||||
|
||||
#[miri_run]
|
||||
fn empty() -> &'static str {
|
||||
""
|
||||
}
|
||||
|
||||
#[miri_run]
|
||||
fn hello() -> &'static str {
|
||||
"Hello, world!"
|
||||
}
|
||||
|
||||
#[miri_run]
|
||||
fn hello_bytes() -> &'static [u8; 13] {
|
||||
b"Hello, world!"
|
||||
}
|
||||
|
||||
#[miri_run]
|
||||
fn hello_bytes_fat() -> &'static [u8] {
|
||||
b"Hello, world!"
|
||||
}
|
||||
|
||||
#[miri_run]
|
||||
fn fat_pointer_on_32_bit() {
|
||||
Some(5).expect("foo");
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
fn main() {
|
||||
assert_eq!(empty(), "");
|
||||
assert_eq!(hello(), "Hello, world!");
|
||||
assert_eq!(hello_bytes(), b"Hello, world!");
|
||||
assert_eq!(hello_bytes_fat(), b"Hello, world!");
|
||||
fat_pointer_on_32_bit(); // Should run without crashing.
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#![feature(custom_attribute)]
|
||||
#![allow(dead_code, unused_attributes)]
|
||||
// FIXME(solson): 32-bit mode doesn't test anything currently.
|
||||
#![cfg_attr(target_pointer_width = "32", allow(dead_code))]
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum Unit { Unit(()) } // Force non-C-enum representation.
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
#![feature(custom_attribute)]
|
||||
#![allow(dead_code, unused_attributes)]
|
||||
|
||||
#[miri_run]
|
||||
fn empty() {}
|
||||
|
||||
#[miri_run]
|
||||
fn unit_var() {
|
||||
let x = ();
|
||||
x
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
fn main() {
|
||||
empty();
|
||||
unit_var();
|
||||
}
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
#![feature(custom_attribute)]
|
||||
#![allow(dead_code, unused_attributes)]
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
struct A;
|
||||
|
||||
#[miri_run]
|
||||
fn zst_ret() -> A {
|
||||
A
|
||||
}
|
||||
|
||||
#[miri_run]
|
||||
fn use_zst() -> A {
|
||||
let a = A;
|
||||
a
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
fn main() {
|
||||
assert_eq!(zst_ret(), A);
|
||||
assert_eq!(use_zst(), A);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user