diff --git a/.gitmodules b/.gitmodules index d5ae2564654..2802c8d6391 100644 --- a/.gitmodules +++ b/.gitmodules @@ -39,3 +39,6 @@ [submodule "src/tools/rustfmt"] path = src/tools/rustfmt url = https://github.com/rust-lang-nursery/rustfmt.git +[submodule "src/tools/miri"] + path = src/tools/miri + url = https://github.com/solson/miri.git diff --git a/config.toml.example b/config.toml.example index 266f4250132..a3790c8d202 100644 --- a/config.toml.example +++ b/config.toml.example @@ -291,6 +291,10 @@ # When creating source tarballs whether or not to create a source tarball. #dist-src = false +# Whether to also run the Miri tests suite when running tests. +# As a side-effect also generates MIR for all libraries. +#test-miri = false + # ============================================================================= # Options for specific targets # diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 0baca9e58f4..fc27c5d3866 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -246,6 +246,12 @@ fn main() { } } + // When running miri tests, we need to generate MIR for all libraries + if env::var("TEST_MIRI").ok().map_or(false, |val| val == "true") && stage != "0" { + cmd.arg("-Zalways-encode-mir"); + cmd.arg("-Zmir-emit-validate=1"); + } + // Force all crates compiled by this compiler to (a) be unstable and (b) // allow the `rustc_private` feature to link to other unstable crates // also in the sysroot. diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 7ff0154bf8b..9df7d6c6bef 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -249,11 +249,11 @@ macro_rules! describe { tool::UnstableBookGen, tool::Tidy, tool::Linkchecker, tool::CargoTest, tool::Compiletest, tool::RemoteTestServer, tool::RemoteTestClient, tool::RustInstaller, tool::Cargo, tool::Rls, tool::Rustdoc, tool::Clippy, - native::Llvm, tool::Rustfmt), + native::Llvm, tool::Rustfmt, tool::Miri), Kind::Test => describe!(check::Tidy, check::Bootstrap, check::DefaultCompiletest, check::HostCompiletest, check::Crate, check::CrateLibrustc, check::Rustdoc, check::Linkcheck, check::Cargotest, check::Cargo, check::Rls, check::Docs, - check::ErrorIndex, check::Distcheck, check::Rustfmt), + check::ErrorIndex, check::Distcheck, check::Rustfmt, check::Miri), Kind::Bench => describe!(check::Crate, check::CrateLibrustc), Kind::Doc => describe!(doc::UnstableBook, doc::UnstableBookGen, doc::TheBook, doc::Standalone, doc::Std, doc::Test, doc::Rustc, doc::ErrorIndex, doc::Nomicon, @@ -475,6 +475,7 @@ pub fn cargo(&self, } else { PathBuf::from("/path/to/nowhere/rustdoc/not/required") }) + .env("TEST_MIRI", self.config.test_miri.to_string()) .env("RUSTC_FLAGS", self.rustc_flags(target).join(" ")); if mode != Mode::Tool { diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 94bb89145fb..d2e0a8e9368 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -293,6 +293,50 @@ fn run(self, builder: &Builder) { try_run(build, &mut cargo); } } +pub struct Miri { + host: Interned, +} + +impl Step for Miri { + type Output = (); + const ONLY_HOSTS: bool = true; + const DEFAULT: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + let test_miri = run.builder.build.config.test_miri; + run.path("src/tools/miri").default_condition(test_miri) + } + + fn make_run(run: RunConfig) { + run.builder.ensure(Miri { + host: run.target, + }); + } + + /// Runs `cargo test` for miri. + fn run(self, builder: &Builder) { + let build = builder.build; + let host = self.host; + let compiler = builder.compiler(1, host); + + let miri = builder.ensure(tool::Miri { compiler, target: self.host }); + let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test"); + cargo.arg("--manifest-path").arg(build.src.join("src/tools/miri/Cargo.toml")); + + // Don't build tests dynamically, just a pain to work with + cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); + // miri tests need to know about the stage sysroot + cargo.env("MIRI_SYSROOT", builder.sysroot(compiler)); + cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler)); + cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler)); + cargo.env("MIRI_PATH", miri); + + builder.add_rustc_lib_path(compiler, &mut cargo); + + try_run(build, &mut cargo); + } +} + fn path_for_cargo(builder: &Builder, compiler: Compiler) -> OsString { // Configure PATH to find the right rustc. NB. we have to use PATH diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 372e0906cc6..349482eab5f 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -111,6 +111,7 @@ pub struct Config { pub low_priority: bool, pub channel: String, pub quiet_tests: bool, + pub test_miri: bool, // Fallback musl-root for all targets pub musl_root: Option, pub prefix: Option, @@ -269,6 +270,7 @@ struct Rust { debug: Option, dist_src: Option, quiet_tests: Option, + test_miri: Option, } /// TOML representation of how each build target is configured. @@ -304,6 +306,7 @@ pub fn parse(args: &[String]) -> Config { config.codegen_tests = true; config.ignore_git = false; config.rust_dist_src = true; + config.test_miri = false; config.on_fail = flags.on_fail; config.stage = flags.stage; @@ -444,6 +447,7 @@ pub fn parse(args: &[String]) -> Config { set(&mut config.channel, rust.channel.clone()); set(&mut config.rust_dist_src, rust.dist_src); set(&mut config.quiet_tests, rust.quiet_tests); + set(&mut config.test_miri, rust.test_miri); config.rustc_default_linker = rust.default_linker.clone(); config.rustc_default_ar = rust.default_ar.clone(); config.musl_root = rust.musl_root.clone().map(PathBuf::from); diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index fa8b7613360..2438be89776 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -38,6 +38,7 @@ o("debug", "rust.debug", "debug mode; disables optimization unless `--enable-opt o("docs", "build.docs", "build standard library documentation") o("compiler-docs", "build.compiler-docs", "build compiler documentation") o("optimize-tests", "rust.optimize-tests", "build tests with optimizations") +o("test-miri", "rust.test-miri", "run miri's test suite") o("debuginfo-tests", "rust.debuginfo-tests", "build tests with debugger metadata") o("quiet-tests", "rust.quiet-tests", "enable quieter output when running tests") o("ccache", "llvm.ccache", "invoke gcc/clang via ccache to reuse object files between builds") diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 72be9c12e84..004f0c31024 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -56,6 +56,7 @@ check-aux: src/tools/cargo \ src/tools/rls \ src/tools/rustfmt \ + src/tools/miri \ src/test/pretty \ src/test/run-pass/pretty \ src/test/run-fail/pretty \ diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index d082012acc1..54124780485 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -479,6 +479,41 @@ fn run(self, builder: &Builder) -> PathBuf { } } + +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct Miri { + pub compiler: Compiler, + pub target: Interned, +} + +impl Step for Miri { + type Output = PathBuf; + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + let builder = run.builder; + run.path("src/tools/miri").default_condition(builder.build.config.test_miri) + } + + fn make_run(run: RunConfig) { + run.builder.ensure(Miri { + compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build), + target: run.target, + }); + } + + fn run(self, builder: &Builder) -> PathBuf { + builder.ensure(ToolBuild { + compiler: self.compiler, + target: self.target, + tool: "miri", + mode: Mode::Librustc, + path: "src/tools/miri", + }) + } +} + impl<'a> Builder<'a> { /// Get a `Command` which is ready to run `tool` in `stage` built for /// `host`. diff --git a/src/ci/docker/x86_64-gnu-aux/Dockerfile b/src/ci/docker/x86_64-gnu-aux/Dockerfile index 35a387221c6..a453c62cc9e 100644 --- a/src/ci/docker/x86_64-gnu-aux/Dockerfile +++ b/src/ci/docker/x86_64-gnu-aux/Dockerfile @@ -17,5 +17,5 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu +ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --enable-test-miri ENV RUST_CHECK_TARGET check-aux diff --git a/src/tools/miri b/src/tools/miri new file mode 160000 index 00000000000..ce3576f7d81 --- /dev/null +++ b/src/tools/miri @@ -0,0 +1 @@ +Subproject commit ce3576f7d81931f77264f85a3c68077605310019 diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 56c0b21cd53..90bf7a5e0a6 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -65,6 +65,7 @@ fn filter_dirs(path: &Path) -> bool { "src/tools/clippy", "src/tools/rust-installer", "src/tools/rustfmt", + "src/tools/miri", ]; skip.iter().any(|p| path.ends_with(p)) }