Merge pull request #566 from RalfJung/foreign-full-mir
Support building and running with full MIR on foreign architectures, drop support for missing MIR
This commit is contained in:
commit
4f61314fc5
90 changed files with 139 additions and 238 deletions
33
.travis.yml
33
.travis.yml
|
|
@ -9,47 +9,52 @@ cache:
|
|||
os:
|
||||
- linux
|
||||
- osx
|
||||
dist: xenial
|
||||
|
||||
before_script:
|
||||
# install extra stuff for cross-compilation
|
||||
- if [[ "$TRAVIS_OS_NAME" == linux ]]; then sudo apt update && sudo apt install gcc-multilib; fi
|
||||
# macOS weirdness (https://github.com/travis-ci/travis-ci/issues/6307, https://github.com/travis-ci/travis-ci/issues/10165)
|
||||
- if [[ "$TRAVIS_OS_NAME" == osx ]]; then rvm get stable; fi
|
||||
# Compute the rust version we use. We do not use "language: rust" to have more control here.
|
||||
- |
|
||||
if [ "$TRAVIS_EVENT_TYPE" = cron ]; then
|
||||
if [[ "$TRAVIS_EVENT_TYPE" == cron ]]; then
|
||||
RUST_TOOLCHAIN=nightly
|
||||
else
|
||||
RUST_TOOLCHAIN=$(cat rust-version)
|
||||
fi
|
||||
- |
|
||||
if [ "$TRAVIS_OS_NAME" == osx ]; then
|
||||
export MIRI_SYSROOT_BASE=~/Library/Caches/miri.miri.miri/
|
||||
else
|
||||
export MIRI_SYSROOT_BASE=~/.cache/miri/
|
||||
fi
|
||||
# install Rust
|
||||
- curl https://build.travis-ci.org/files/rustup-init.sh -sSf | sh -s -- -y --default-toolchain "$RUST_TOOLCHAIN"
|
||||
- export PATH=$HOME/.cargo/bin:$PATH
|
||||
- rustc --version
|
||||
# customize installation
|
||||
- rustup target add i686-unknown-linux-gnu
|
||||
- rustup target add i686-pc-windows-gnu
|
||||
- rustup target add i686-pc-windows-msvc
|
||||
|
||||
script:
|
||||
- set -e
|
||||
- |
|
||||
# Test and install plain miri
|
||||
# Build and install miri
|
||||
cargo build --release --all-features --all-targets &&
|
||||
cargo test --release --all-features &&
|
||||
cargo install --all-features --force --path .
|
||||
- |
|
||||
# Get ourselves a MIR-full libstd, and use it henceforth
|
||||
# Get ourselves a MIR-full libstd for the host and a foreign architecture
|
||||
cargo miri setup &&
|
||||
if [ "$TRAVIS_OS_NAME" == osx ]; then
|
||||
export MIRI_SYSROOT=~/Library/Caches/miri.miri.miri/HOST
|
||||
if [[ "$TRAVIS_OS_NAME" == osx ]]; then
|
||||
cargo miri setup --target i686-apple-darwin
|
||||
else
|
||||
export MIRI_SYSROOT=~/.cache/miri/HOST
|
||||
cargo miri setup --target i686-unknown-linux-gnu
|
||||
fi
|
||||
- |
|
||||
# Test miri with full MIR
|
||||
cargo test --release --all-features
|
||||
# Test miri with full MIR, on the host and other architectures
|
||||
MIRI_SYSROOT=$MIRI_SYSROOT_BASE/HOST cargo test --release --all-features &&
|
||||
MIRI_SYSROOT=$MIRI_SYSROOT_BASE cargo test --release --all-features
|
||||
- |
|
||||
# Test cargo integration
|
||||
(cd cargo-miri-test && ./run-test.py)
|
||||
(cd test-cargo-miri && MIRI_SYSROOT=$MIRI_SYSROOT_BASE/HOST ./run-test.py)
|
||||
|
||||
notifications:
|
||||
email:
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ required-features = ["rustc_tests"]
|
|||
byteorder = { version = "1.1", features = ["i128"]}
|
||||
cargo_metadata = { version = "0.6", optional = true }
|
||||
directories = { version = "1.0", optional = true }
|
||||
rustc_version = { version = "0.2.3", optional = true }
|
||||
env_logger = "0.5"
|
||||
log = "0.4"
|
||||
|
||||
|
|
@ -44,7 +45,7 @@ vergen = "3"
|
|||
|
||||
[features]
|
||||
default = ["cargo_miri"]
|
||||
cargo_miri = ["cargo_metadata", "directories"]
|
||||
cargo_miri = ["cargo_metadata", "directories", "rustc_version"]
|
||||
rustc_tests = []
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
|||
|
|
@ -133,9 +133,6 @@ cp config.toml.example config.toml
|
|||
rustup toolchain link custom build/x86_64-unknown-linux-gnu/stage2
|
||||
# Now cd to your Miri directory, then configure rustup
|
||||
rustup override set custom
|
||||
# We also need to tell Miri where to find its sysroot. Since we set
|
||||
# `test-miri` above, we can just use rustc' sysroot.
|
||||
export MIRI_SYSROOT=$(rustc --print sysroot)
|
||||
```
|
||||
|
||||
With this, you should now have a working development setup! See
|
||||
|
|
|
|||
|
|
@ -27,13 +27,12 @@ build: false
|
|||
test_script:
|
||||
- set RUSTFLAGS=-g
|
||||
- set RUST_BACKTRACE=1
|
||||
# Test plain miri
|
||||
# Build miri
|
||||
- cargo build --release --all-features --all-targets
|
||||
- cargo test --release --all-features
|
||||
# Get ourselves a MIR-full libstd, and use it henceforth
|
||||
- cargo run --release --all-features --bin cargo-miri -- miri setup
|
||||
- set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\miri\miri\cache\HOST
|
||||
# Test miri with full MIR
|
||||
# Test miri
|
||||
- cargo test --release --all-features
|
||||
|
||||
notifications:
|
||||
|
|
|
|||
|
|
@ -53,14 +53,34 @@ fn show_error(msg: String) -> ! {
|
|||
std::process::exit(1)
|
||||
}
|
||||
|
||||
fn list_targets(mut args: impl Iterator<Item=String>) -> impl Iterator<Item=cargo_metadata::Target> {
|
||||
fn get_arg_flag_value(name: &str) -> Option<String> {
|
||||
// stop searching at `--`
|
||||
let mut args = std::env::args().skip_while(|val| !(val.starts_with(name) || val == "--"));
|
||||
|
||||
match args.next() {
|
||||
Some(ref p) if p == "--" => None,
|
||||
Some(ref p) if p == name => args.next(),
|
||||
Some(p) => {
|
||||
// Make sure this really starts with `$name=`, we didn't test for the `=` yet.
|
||||
let v = &p[name.len()..]; // strip leading `$name`
|
||||
if v.starts_with('=') {
|
||||
Some(v[1..].to_owned()) // strip leading `=`
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn list_targets() -> impl Iterator<Item=cargo_metadata::Target> {
|
||||
// We need to get the manifest, and then the metadata, to enumerate targets.
|
||||
let manifest_path_arg = args.find(|val| {
|
||||
val.starts_with("--manifest-path=")
|
||||
});
|
||||
let manifest_path = get_arg_flag_value("--manifest-path").map(|m|
|
||||
Path::new(&m).canonicalize().unwrap()
|
||||
);
|
||||
|
||||
let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(
|
||||
manifest_path_arg.as_ref().map(AsRef::as_ref),
|
||||
manifest_path.as_ref().map(AsRef::as_ref),
|
||||
)
|
||||
{
|
||||
metadata
|
||||
|
|
@ -68,10 +88,6 @@ fn list_targets(mut args: impl Iterator<Item=String>) -> impl Iterator<Item=carg
|
|||
show_error(format!("error: Could not obtain cargo metadata."));
|
||||
};
|
||||
|
||||
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
|
||||
|
|
@ -176,17 +192,28 @@ path = "lib.rs"
|
|||
"#).unwrap();
|
||||
File::create(dir.join("lib.rs")).unwrap();
|
||||
// Run xargo
|
||||
if !Command::new("xargo").arg("build").arg("-q")
|
||||
let target = get_arg_flag_value("--target");
|
||||
let mut command = Command::new("xargo");
|
||||
command.arg("build").arg("-q")
|
||||
.current_dir(&dir)
|
||||
.env("RUSTFLAGS", miri::miri_default_args().join(" "))
|
||||
.env("XARGO_HOME", dir.to_str().unwrap())
|
||||
.status().unwrap().success()
|
||||
.env("XARGO_HOME", dir.to_str().unwrap());
|
||||
if let Some(ref target) = target {
|
||||
command.arg("--target").arg(&target);
|
||||
}
|
||||
if !command.status().unwrap().success()
|
||||
{
|
||||
show_error(format!("Failed to run xargo"));
|
||||
}
|
||||
|
||||
// That should be it!
|
||||
let sysroot = dir.join("HOST");
|
||||
// That should be it! But we need to figure out where xargo built stuff.
|
||||
// Unfortunately, it puts things into a different directory when the
|
||||
// architecture matches the host.
|
||||
let is_host = match target {
|
||||
None => true,
|
||||
Some(target) => target == rustc_version::version_meta().unwrap().host,
|
||||
};
|
||||
let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) };
|
||||
std::env::set_var("MIRI_SYSROOT", &sysroot);
|
||||
if !ask_user {
|
||||
println!("A libstd for miri is now available in `{}`", sysroot.display());
|
||||
|
|
@ -232,7 +259,7 @@ fn main() {
|
|||
}
|
||||
|
||||
// Now run the command.
|
||||
for target in list_targets(std::env::args().skip(skip)) {
|
||||
for target in list_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",
|
||||
|
|
@ -315,11 +342,11 @@ fn main() {
|
|||
.collect()
|
||||
};
|
||||
args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string));
|
||||
args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-miri""#.to_owned()]);
|
||||
|
||||
// this check ensures that dependencies are built but not interpreted and the final crate is
|
||||
// interpreted but not built
|
||||
let miri_enabled = std::env::args().any(|s| s == "--emit=dep-info,metadata");
|
||||
|
||||
let mut command = if miri_enabled {
|
||||
let mut path = std::env::current_exe().expect("current executable path invalid");
|
||||
path.set_file_name("miri");
|
||||
|
|
@ -327,10 +354,9 @@ fn main() {
|
|||
} else {
|
||||
Command::new("rustc")
|
||||
};
|
||||
command.args(&args);
|
||||
|
||||
args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-miri""#.to_owned()]);
|
||||
|
||||
match command.args(&args).status() {
|
||||
match command.status() {
|
||||
Ok(exit) => {
|
||||
if !exit.success() {
|
||||
std::process::exit(exit.code().unwrap_or(42));
|
||||
|
|
@ -361,7 +387,7 @@ where
|
|||
args.push(r#"feature="cargo-miri""#.to_owned());
|
||||
|
||||
let path = std::env::current_exe().expect("current executable path invalid");
|
||||
let exit_status = std::process::Command::new("cargo")
|
||||
let exit_status = Command::new("cargo")
|
||||
.args(&args)
|
||||
.env("RUSTC", path)
|
||||
.spawn()
|
||||
|
|
|
|||
|
|
@ -17,18 +17,6 @@ pub trait EvalContextExt<'tcx, 'mir> {
|
|||
ret: mir::BasicBlock,
|
||||
) -> EvalResult<'tcx>;
|
||||
|
||||
/// Emulate a function that should have MIR but does not.
|
||||
/// This is solely to support execution without full MIR.
|
||||
/// Fail if emulating this function is not supported.
|
||||
/// This function will handle `goto_block` if needed.
|
||||
fn emulate_missing_fn(
|
||||
&mut self,
|
||||
path: String,
|
||||
args: &[OpTy<'tcx, Borrow>],
|
||||
dest: Option<PlaceTy<'tcx, Borrow>>,
|
||||
ret: Option<mir::BasicBlock>,
|
||||
) -> EvalResult<'tcx>;
|
||||
|
||||
fn find_fn(
|
||||
&mut self,
|
||||
instance: ty::Instance<'tcx>,
|
||||
|
|
@ -81,24 +69,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo
|
|||
return Ok(None);
|
||||
}
|
||||
|
||||
// Otherwise we really want to see the MIR -- but if we do not have it, maybe we can
|
||||
// emulate something. This is a HACK to support running without a full-MIR libstd.
|
||||
let mir = match self.load_mir(instance.def) {
|
||||
Ok(mir) => mir,
|
||||
Err(EvalError { kind: EvalErrorKind::NoMirFor(path), .. }) => {
|
||||
self.emulate_missing_fn(
|
||||
path,
|
||||
args,
|
||||
dest,
|
||||
ret,
|
||||
)?;
|
||||
// `goto_block` already handled
|
||||
return Ok(None);
|
||||
}
|
||||
Err(other) => return Err(other),
|
||||
};
|
||||
|
||||
Ok(Some(mir))
|
||||
// Otherwise, load the MIR
|
||||
Ok(Some(self.load_mir(instance.def)?))
|
||||
}
|
||||
|
||||
fn emulate_foreign_item(
|
||||
|
|
@ -113,6 +85,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo
|
|||
Some(name) => name.as_str(),
|
||||
None => self.tcx.item_name(def_id).as_str(),
|
||||
};
|
||||
// Strip linker suffixes (seen on 32bit macOS)
|
||||
let link_name = link_name.trim_end_matches("$UNIX2003");
|
||||
|
||||
let tcx = &{self.tcx.tcx};
|
||||
|
||||
|
|
@ -655,58 +629,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn emulate_missing_fn(
|
||||
&mut self,
|
||||
path: String,
|
||||
_args: &[OpTy<'tcx, Borrow>],
|
||||
dest: Option<PlaceTy<'tcx, Borrow>>,
|
||||
ret: Option<mir::BasicBlock>,
|
||||
) -> EvalResult<'tcx> {
|
||||
// In some cases in non-MIR libstd-mode, not having a destination is legit. Handle these early.
|
||||
match &path[..] {
|
||||
"std::panicking::rust_panic_with_hook" |
|
||||
"core::panicking::panic_fmt::::panic_impl" |
|
||||
"std::rt::begin_panic_fmt" =>
|
||||
return err!(MachineError("the evaluated program panicked".to_string())),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let dest = dest.ok_or_else(
|
||||
// Must be some function we do not support
|
||||
|| EvalErrorKind::NoMirFor(path.clone()),
|
||||
)?;
|
||||
|
||||
match &path[..] {
|
||||
// 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" |
|
||||
"std::io::_eprint" => {
|
||||
warn!(
|
||||
"Ignoring output. To run programs that prints, 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::panicking::panicking" |
|
||||
"std::rt::panicking" => {
|
||||
// we abort on panic -> `std::rt::panicking` always returns false
|
||||
self.write_scalar(Scalar::from_bool(false), dest)?;
|
||||
}
|
||||
|
||||
_ => return err!(NoMirFor(path)),
|
||||
}
|
||||
|
||||
self.goto_block(ret)?;
|
||||
self.dump_place(*dest);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_null(&mut self, dest: PlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> {
|
||||
self.write_scalar(Scalar::from_int(0, dest.layout.size), dest)
|
||||
}
|
||||
|
|
|
|||
126
src/lib.rs
126
src/lib.rs
|
|
@ -80,82 +80,62 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>(
|
|||
));
|
||||
}
|
||||
|
||||
let libstd_has_mir = {
|
||||
let rustc_panic = ecx.resolve_path(&["std", "panicking", "rust_panic"])?;
|
||||
ecx.load_mir(rustc_panic.def).is_ok()
|
||||
};
|
||||
let start_id = tcx.lang_items().start_fn().unwrap();
|
||||
let main_ret_ty = tcx.fn_sig(main_id).output();
|
||||
let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
|
||||
let start_instance = ty::Instance::resolve(
|
||||
ecx.tcx.tcx,
|
||||
ty::ParamEnv::reveal_all(),
|
||||
start_id,
|
||||
ecx.tcx.mk_substs(
|
||||
::std::iter::once(ty::subst::Kind::from(main_ret_ty)))
|
||||
).unwrap();
|
||||
let start_mir = ecx.load_mir(start_instance.def)?;
|
||||
|
||||
if libstd_has_mir {
|
||||
let start_id = tcx.lang_items().start_fn().unwrap();
|
||||
let main_ret_ty = tcx.fn_sig(main_id).output();
|
||||
let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
|
||||
let start_instance = ty::Instance::resolve(
|
||||
ecx.tcx.tcx,
|
||||
ty::ParamEnv::reveal_all(),
|
||||
start_id,
|
||||
ecx.tcx.mk_substs(
|
||||
::std::iter::once(ty::subst::Kind::from(main_ret_ty)))
|
||||
).unwrap();
|
||||
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 value (in static memory so that it does not count as leak)
|
||||
let ret = ecx.layout_of(start_mir.return_ty())?;
|
||||
let ret_ptr = ecx.allocate(ret, MiriMemoryKind::MutStatic.into())?;
|
||||
|
||||
// Push our stack frame
|
||||
ecx.push_stack_frame(
|
||||
start_instance,
|
||||
DUMMY_SP, // there is no call site, we want no span
|
||||
start_mir,
|
||||
Some(ret_ptr.into()),
|
||||
StackPopCleanup::None { cleanup: true },
|
||||
)?;
|
||||
|
||||
let mut args = ecx.frame().mir.args_iter();
|
||||
|
||||
// First argument: pointer to main()
|
||||
let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance).with_default_tag();
|
||||
let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?;
|
||||
ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?;
|
||||
|
||||
// Second argument (argc): 1
|
||||
let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?;
|
||||
ecx.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
|
||||
|
||||
// FIXME: extract main source file path
|
||||
// Third argument (argv): &[b"foo"]
|
||||
let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?;
|
||||
let foo = ecx.memory_mut().allocate_static_bytes(b"foo\0").with_default_tag();
|
||||
let foo_ty = ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8);
|
||||
let foo_layout = ecx.layout_of(foo_ty)?;
|
||||
let foo_place = ecx.allocate(foo_layout, MiriMemoryKind::Env.into())?;
|
||||
ecx.write_scalar(Scalar::Ptr(foo), foo_place.into())?;
|
||||
ecx.memory_mut().mark_immutable(foo_place.to_ptr()?.alloc_id)?;
|
||||
ecx.write_scalar(foo_place.ptr, dest)?;
|
||||
|
||||
assert!(args.next().is_none(), "start lang item has more arguments than expected");
|
||||
} else {
|
||||
let ret_place = MPlaceTy::dangling(ecx.layout_of(tcx.mk_unit())?, &ecx).into();
|
||||
ecx.push_stack_frame(
|
||||
main_instance,
|
||||
DUMMY_SP, // there is no call site, we want no span
|
||||
main_mir,
|
||||
Some(ret_place),
|
||||
StackPopCleanup::None { cleanup: true },
|
||||
)?;
|
||||
|
||||
// No arguments
|
||||
let mut args = ecx.frame().mir.args_iter();
|
||||
assert!(args.next().is_none(), "main function must not have arguments");
|
||||
if start_mir.arg_count != 3 {
|
||||
return err!(AbiViolation(format!(
|
||||
"'start' lang item should have three arguments, but has {}",
|
||||
start_mir.arg_count
|
||||
)));
|
||||
}
|
||||
|
||||
// Return value (in static memory so that it does not count as leak)
|
||||
let ret = ecx.layout_of(start_mir.return_ty())?;
|
||||
let ret_ptr = ecx.allocate(ret, MiriMemoryKind::MutStatic.into())?;
|
||||
|
||||
// Push our stack frame
|
||||
ecx.push_stack_frame(
|
||||
start_instance,
|
||||
DUMMY_SP, // there is no call site, we want no span
|
||||
start_mir,
|
||||
Some(ret_ptr.into()),
|
||||
StackPopCleanup::None { cleanup: true },
|
||||
)?;
|
||||
|
||||
let mut args = ecx.frame().mir.args_iter();
|
||||
|
||||
// First argument: pointer to main()
|
||||
let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance).with_default_tag();
|
||||
let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?;
|
||||
ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?;
|
||||
|
||||
// Second argument (argc): 1
|
||||
let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?;
|
||||
ecx.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
|
||||
|
||||
// FIXME: extract main source file path
|
||||
// Third argument (argv): &[b"foo"]
|
||||
let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?;
|
||||
let foo = ecx.memory_mut().allocate_static_bytes(b"foo\0").with_default_tag();
|
||||
let foo_ty = ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8);
|
||||
let foo_layout = ecx.layout_of(foo_ty)?;
|
||||
let foo_place = ecx.allocate(foo_layout, MiriMemoryKind::Env.into())?;
|
||||
ecx.write_scalar(Scalar::Ptr(foo), foo_place.into())?;
|
||||
ecx.memory_mut().mark_immutable(foo_place.to_ptr()?.alloc_id)?;
|
||||
ecx.write_scalar(foo_place.ptr, dest)?;
|
||||
|
||||
assert!(args.next().is_none(), "start lang item has more arguments than expected");
|
||||
|
||||
Ok(ecx)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#![feature(slice_concat_ext, custom_test_frameworks)]
|
||||
// Custom test runner, to avoid libtest being wrapped around compiletest which wraps libtest.
|
||||
#![test_runner(test_runner)]
|
||||
|
||||
use std::slice::SliceConcatExt;
|
||||
|
|
@ -24,11 +25,6 @@ fn rustc_lib_path() -> PathBuf {
|
|||
option_env!("RUSTC_LIB_PATH").unwrap().into()
|
||||
}
|
||||
|
||||
fn have_fullmir() -> bool {
|
||||
// We assume we have full MIR when MIRI_SYSROOT is set or when we are in rustc
|
||||
std::env::var("MIRI_SYSROOT").is_ok() || rustc_test_suite().is_some()
|
||||
}
|
||||
|
||||
fn mk_config(mode: &str) -> compiletest::common::ConfigWithTemp {
|
||||
let mut config = compiletest::Config::default().tempdir();
|
||||
config.mode = mode.parse().expect("Invalid mode");
|
||||
|
|
@ -41,16 +37,7 @@ fn mk_config(mode: &str) -> compiletest::common::ConfigWithTemp {
|
|||
config
|
||||
}
|
||||
|
||||
fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: bool, opt: bool) {
|
||||
if need_fullmir && !have_fullmir() {
|
||||
eprintln!("{}\n", format!(
|
||||
"## Skipping compile-fail tests in {} against miri for target {} due to missing mir",
|
||||
path,
|
||||
target
|
||||
).yellow().bold());
|
||||
return;
|
||||
}
|
||||
|
||||
fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, opt: bool) {
|
||||
let opt_str = if opt { " with optimizations" } else { "" };
|
||||
eprintln!("{}", format!(
|
||||
"## Running compile-fail tests in {} against miri for target {}{}",
|
||||
|
|
@ -78,16 +65,7 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullm
|
|||
compiletest::run_tests(&config);
|
||||
}
|
||||
|
||||
fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: bool, opt: bool) {
|
||||
if need_fullmir && !have_fullmir() {
|
||||
eprintln!("{}\n", format!(
|
||||
"## Skipping run-pass tests in {} against miri for target {} due to missing mir",
|
||||
path,
|
||||
target
|
||||
).yellow().bold());
|
||||
return;
|
||||
}
|
||||
|
||||
fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, opt: bool) {
|
||||
let opt_str = if opt { " with optimizations" } else { "" };
|
||||
eprintln!("{}", format!(
|
||||
"## Running run-pass tests in {} against miri for target {}{}",
|
||||
|
|
@ -105,10 +83,6 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir:
|
|||
// whitelist.
|
||||
flags.push("-Zmir-opt-level=1".to_owned());
|
||||
}
|
||||
if !have_fullmir() {
|
||||
// FIXME: Validation relies on the EscapeToRaw statements being emitted
|
||||
flags.push("-Zmiri-disable-validation".to_owned());
|
||||
}
|
||||
|
||||
let mut config = mk_config("ui");
|
||||
config.src_base = PathBuf::from(path);
|
||||
|
|
@ -132,7 +106,7 @@ fn target_has_std<P: Into<PathBuf>>(path: P) -> bool {
|
|||
.map(|entry| entry.unwrap())
|
||||
.filter(|entry| entry.file_type().unwrap().is_file())
|
||||
.filter_map(|entry| entry.file_name().into_string().ok())
|
||||
.any(|file_name| file_name.starts_with("libstd") && file_name.ends_with(".rlib"))
|
||||
.any(|file_name| file_name == "libstd.rlib")
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -168,17 +142,15 @@ fn get_sysroot() -> PathBuf {
|
|||
|
||||
fn get_host() -> String {
|
||||
let rustc = rustc_test_suite().unwrap_or(PathBuf::from("rustc"));
|
||||
let host = std::process::Command::new(rustc)
|
||||
let rustc_version = std::process::Command::new(rustc)
|
||||
.arg("-vV")
|
||||
.output()
|
||||
.expect("rustc not found for -vV")
|
||||
.stdout;
|
||||
let host = std::str::from_utf8(&host).expect("sysroot is not utf8");
|
||||
let host = host.split("\nhost: ").nth(1).expect(
|
||||
"no host: part in rustc -vV",
|
||||
);
|
||||
let host = host.split('\n').next().expect("no \n after host");
|
||||
String::from(host)
|
||||
let rustc_version = std::str::from_utf8(&rustc_version).expect("rustc -vV is not utf8");
|
||||
let version_meta = rustc_version::version_meta_for(&rustc_version)
|
||||
.expect("failed to parse rustc version info");
|
||||
version_meta.host
|
||||
}
|
||||
|
||||
fn run_pass_miri(opt: bool) {
|
||||
|
|
@ -186,18 +158,17 @@ fn run_pass_miri(opt: bool) {
|
|||
let host = get_host();
|
||||
|
||||
for_all_targets(&sysroot, |target| {
|
||||
miri_pass(&sysroot, "tests/run-pass", &target, &host, false, opt);
|
||||
miri_pass(&sysroot, "tests/run-pass", &target, &host, opt);
|
||||
});
|
||||
miri_pass(&sysroot, "tests/run-pass-fullmir", &host, &host, true, opt);
|
||||
}
|
||||
|
||||
fn compile_fail_miri(opt: bool) {
|
||||
let sysroot = get_sysroot();
|
||||
let host = get_host();
|
||||
|
||||
// FIXME: run tests for other targets, too
|
||||
compile_fail(&sysroot, "tests/compile-fail", &host, &host, false, opt);
|
||||
compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true, opt);
|
||||
for_all_targets(&sysroot, |target| {
|
||||
compile_fail(&sysroot, "tests/compile-fail", &target, &host, opt);
|
||||
});
|
||||
}
|
||||
|
||||
fn test_runner(_tests: &[&()]) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue