diff --git a/.github/scripts/run_own_tests.sh b/.github/scripts/run_own_tests.sh deleted file mode 100755 index 378322f..0000000 --- a/.github/scripts/run_own_tests.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env bash -# Execute our own set of tests using a local `compiletest` tool based on `ui_test`. -# This will run cargo under the repository path and, by default, will run the toolchain -# specified in the `rust-toolchain.toml` file. -set -e -set -u - -# Where we will store the SMIR tools (Optional). -TOOLS_BIN="${TOOLS_BIN:-"/tmp/smir/bin"}" -# Assume we are inside SMIR repository -SMIR_PATH=$(git rev-parse --show-toplevel) -REPO_TOOLCHAIN=$(rustup show active-toolchain | (read toolchain _; echo $toolchain)) -TOOLCHAIN="${TOOLCHAIN:-${REPO_TOOLCHAIN}}" -export RUST_BACKTRACE=1 - -# Build stable_mir tools -function build_smir_tools() { - echo "#### Build tools. Toolchain: ${TOOLCHAIN}" - cargo +${TOOLCHAIN} build -Z unstable-options --out-dir "${TOOLS_BIN}" - export PATH="${TOOLS_BIN}":"${PATH}" -} - -# Run tests -function run_tests() { - SUITES=( - "sanity-checks pass" - "fixme fix-me" - ) - for suite_cfg in "${SUITES[@]}"; do - # Hack to work on older bash like the ones on MacOS. - suite_pair=($suite_cfg) - suite=${suite_pair[0]} - mode=${suite_pair[1]} - echo "#### Running suite: ${suite} mode: ${mode}" - compiletest \ - --driver-path="${TOOLS_BIN}/test-drive" \ - --mode=${mode} \ - --src-base="tests/${suite}" \ - --output-dir="target/tests/" \ - --no-capture - done -} - -pushd "${SMIR_PATH}" > /dev/null -build_smir_tools -run_tests diff --git a/.github/scripts/run_rustc_tests.sh b/.github/scripts/run_rustc_tests.sh deleted file mode 100755 index a967dac..0000000 --- a/.github/scripts/run_rustc_tests.sh +++ /dev/null @@ -1,116 +0,0 @@ -#!/usr/bin/env bash - -# Run rustc test suites using our test driver using nightly. -# This script leverages the rustc's repo compiletest crate. -# -# The suites configuration should match: -# https://github.com/rust-lang/rust/blob/master/src/bootstrap/test.rs - -set -e -set -u -export RUST_BACKTRACE=1 - -# Location of a rust repository. Clone one if path doesn't exist. -RUST_REPO="${RUST_REPO:-"/tmp/rustc"}" - -# Where we will store the SMIR tools (Optional). -TOOLS_BIN="${TOOLS_BIN:-"/tmp/smir/bin"}" - -# Assume we are inside SMIR repository -SMIR_PATH=$(git rev-parse --show-toplevel) - -# Set the toolchain to be used in this script -REPO_TOOLCHAIN=$(rustup show active-toolchain | (read toolchain _; echo $toolchain)) -TOOLCHAIN="${TOOLCHAIN:-${REPO_TOOLCHAIN}}" - -# Build stable_mir tools -function build_smir_tools() { - pushd "${SMIR_PATH}" - cargo +${TOOLCHAIN} build -Z unstable-options --out-dir "${TOOLS_BIN}" - export PATH="${TOOLS_BIN}":"${PATH}" -} - -# Set up rustc repository -function setup_rustc_repo() { - if [[ ! -e "${RUST_REPO}" ]]; then - mkdir -p "$(dirname ${RUST_REPO})" - git clone -b master https://github.com/rust-lang/rust.git "${RUST_REPO}" - pushd "${RUST_REPO}" - commit="$(rustc +${TOOLCHAIN} -vV | awk '/^commit-hash/ { print $2 }')" - if [[ "${commit}" != "unknown" ]]; then - # For custom toolchain, this may return "unknown". Skip this step if that's the case. - # In that case, we will use the HEAD of the main branch. - git checkout "${commit}" - fi - git submodule init -- "library/stdarch" - git submodule update - else - pushd "${RUST_REPO}" - fi -} - -function run_tests() { - # Run the following suite configuration for now (test suite + mode) - SUITES=( - "codegen codegen" - "codegen-units codegen-units" - # -- The suites below are failing because of fully qualified paths for standard library - # E.g.: - # - _10 = _eprint(move _11) -> [return: bb6, unwind unreachable]; - # + _10 = std::io::_eprint(move _11) -> [return: bb6, unwind unreachable]; - # - #"ui ui" - #"mir-opt mir-opt" - #"pretty pretty" -- 2 failing tests - ) - - SYSROOT=$(rustc +${TOOLCHAIN} --print sysroot) - PY_PATH=$(type -P python3) - HOST=$(rustc +${TOOLCHAIN} -vV | awk '/^host/ { print $2 }') - FILE_CHECK="$(which FileCheck-12 || which FileCheck-13 || which FileCheck-14)" - - echo "#---------- Variables -------------" - echo "RUST_REPO: ${RUST_REPO}" - echo "TOOLS_BIN: ${TOOLS_BIN}" - echo "TOOLCHAIN: ${TOOLCHAIN}" - echo "SYSROOT: ${SYSROOT}" - echo "FILE_CHECK: ${FILE_CHECK}" - echo "-----------------------------------" - - for suite_cfg in "${SUITES[@]}"; do - # Hack to work on older bash like the ones on MacOS. - suite_pair=($suite_cfg) - suite=${suite_pair[0]} - mode=${suite_pair[1]} - - echo "#### Running suite: ${suite} mode: ${mode}" - cargo +${TOOLCHAIN} run -p compiletest -- \ - --compile-lib-path="${SYSROOT}/lib" \ - --run-lib-path="${SYSROOT}/lib"\ - --python="${PY_PATH}" \ - --rustc-path="${TOOLS_BIN}/test-drive" \ - --mode=${mode} \ - --suite="${suite}" \ - --src-base="tests/${suite}" \ - --build-base="$(pwd)/build/${HOST}/stage1/tests/${suite}" \ - --sysroot-base="$SYSROOT" \ - --stage-id=stage1-${HOST} \ - --cc= \ - --cxx= \ - --cflags= \ - --cxxflags= \ - --llvm-components= \ - --android-cross-path= \ - --target=${HOST} \ - --llvm-filecheck="${FILE_CHECK}" \ - --channel=nightly \ - --git-repository="rust-lang/project-stable-mir" \ - --nightly-branch="main" \ - --target-rustcflags="--smir-check" \ - --host-rustcflags="--smir-check" - done -} - -build_smir_tools -setup_rustc_repo -run_tests diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index aa42e1c..46cc11f 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -11,7 +11,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 + + - name: Rust Toolchain + uses: dtolnay/rust-toolchain@nightly - name: Run Rust Format - run: cargo fmt --check + run: ./x fmt --check diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 8f7bf0a..625ba8b 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -6,28 +6,29 @@ on: workflow_dispatch: # Allow manual dispatching pull_request: +defaults: + run: + shell: bash + jobs: - compile-test: - name: Rust Compiler Tests + msrv: + name: MSRV Nightly Tests runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Install latest nightly - uses: actions-rs/toolchain@v1 + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master with: - toolchain: nightly - - - name: Test local suites - run: ./.github/scripts/run_own_tests.sh - env: - TOOLS_BIN: "/tmp/smir/bin" + # Note that the downloaded version is dated 2025-08-09. + toolchain: nightly-2025-08-10 + components: rust-src + - run: ./x test - - name: Test rustc suites - run: ./.github/scripts/run_rustc_tests.sh - env: - RUST_REPO: "/tmp/rustc" - TOOLS_BIN: "/tmp/smir/bin" - # Don't fail CI for now. See: https://github.com/rust-lang/project-stable-mir/issues/39 - continue-on-error: true + latest: + name: Latest Nightly Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@nightly + with: + components: rust-src + - run: ./x test diff --git a/.gitignore b/.gitignore index b68cfbd..5b84052 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,13 @@ /book/build **/target +# direnv +.envrc +/.direnv + .idea *.swp *.swo .vscode + +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml index 8f02265..85b1d6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,13 @@ -# Cargo workspace for utility tools used to check stable-mir in CI [workspace] resolver = "2" members = [ - "tools/compiletest", - "tools/test-drive", + "devtool", + "rustc_public", + "test-drive", ] exclude = [ "build", - "target", "demo", + "target", ] diff --git a/devtool/Cargo.toml b/devtool/Cargo.toml new file mode 100644 index 0000000..4ad3ea5 --- /dev/null +++ b/devtool/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "devtool" +version = "0.0.0" +authors = ["rustc_public team"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang/project-stable-mir" +edition = "2021" + +[dependencies] +anyhow = "1.0.99" +clap = { version = "4.1.3", features = ["derive"] } +xshell = "0.2.6" diff --git a/devtool/src/main.rs b/devtool/src/main.rs new file mode 100644 index 0000000..2037987 --- /dev/null +++ b/devtool/src/main.rs @@ -0,0 +1,240 @@ +mod utils; + +use std::env; +use std::path::PathBuf; + +use anyhow::Result; +use clap::{Parser, Subcommand}; +use xshell::{Cmd, Shell, cmd}; + +use crate::utils::active_toolchain; + +#[derive(Debug, Subcommand)] +pub enum Command { + /// Build rustc_public itself. + Build { + /// Flags that are passed through to `cargo build`. + #[arg(trailing_var_arg = true, allow_hyphen_values = true)] + flags: Vec, + }, + /// Run rustc_public test suites. + Test { + /// Overwrite *.stderr/stdout files. + #[arg(long)] + bless: bool, + /// Run test-drive on verbose mode to print test outputs. + #[arg(long)] + verbose: bool, + /// Flags that are passed through to the test harness. + #[arg(trailing_var_arg = true, allow_hyphen_values = true)] + flags: Vec, + }, + /// Clean out build directories. + Clean { + /// Flags that are passed through to `cargo clean`. + #[arg(trailing_var_arg = true, allow_hyphen_values = true)] + flags: Vec, + }, + /// Run rustfmt. + Fmt { + /// Run rustfmt check. + #[arg(long)] + check: bool, + /// Flags that are passed through to `rustfmt`. + #[arg(trailing_var_arg = true, allow_hyphen_values = true)] + flags: Vec, + }, + /// Bump the Minimum Supported Rust Version. + MSRV { + /// The nightly version you want to bump to. Note that it should be a date. + #[arg(long)] + date: String, + }, + /// Install the git hook to perform format check just before pushing. + Githook { + #[command(subcommand)] + command: GithookCommand, + }, +} + +#[derive(Debug, Subcommand)] +pub enum GithookCommand { + /// Install our `pre-push.sh` to `.git/hooks/pre-push`. + Install, + /// Uninstall our `pre-push.sh` from `.git/hooks/pre-push`. + Uninstall, +} + +#[derive(Parser)] +#[command(name = "devtool")] +pub struct Cli { + #[command(subcommand)] + pub command: Command, +} + +pub struct DevCx { + /// The root path of the rustc_public checkout. + root_dir: PathBuf, + /// The toolchain that we use to compile our crates. + toolchain: String, + /// We use this shell to execute commands. + sh: Shell, + /// The cargo we use. + cargo_bin: String, +} + +impl DevCx { + pub fn new() -> Result { + let root_dir = utils::rustc_public_dir(); + let toolchain = active_toolchain()?; + let sh: Shell = Shell::new()?; + let cargo_bin = env::var("CARGO").unwrap_or_else(|_| "cargo".to_string()); + Ok(Self { root_dir, toolchain, sh, cargo_bin }) + } + + pub fn cargo(&self, cmd: &str, crate_dir: &str) -> Cmd<'_> { + let Self { root_dir, toolchain, sh, cargo_bin } = self; + let mainfest: PathBuf = + [root_dir.to_str().unwrap(), crate_dir, "Cargo.toml"].iter().collect(); + cmd!(sh, "{cargo_bin} +{toolchain} {cmd} --manifest-path {mainfest}") + } + + pub fn git(&self, cmd: &str) -> Cmd<'_> { + cmd!(self.sh, "git {cmd}") + } + + pub fn build(&self, crate_dir: &str, flags: &Vec) -> Result<()> { + let cmd = self.cargo("build", crate_dir).args(&["--all-targets"]).args(flags); + cmd.run()?; + Ok(()) + } + + pub fn test(&self, bless: bool, verbose: bool, flags: &Vec) -> Result<()> { + let test_drive_path = + utils::rustc_public_dir().join("target").join("debug").join("test-drive"); + // compiletest needs this var to run test suites + self.sh.set_var("RP_TEST_DRIVER_PATH", test_drive_path); + if verbose { + self.sh.set_var("RP_TEST_DRIVER_VERBOSE", "Ciallo"); + } + if bless { + self.sh.set_var("RP_TEST_DRIVER_BLESS", "Ciallo"); + } + let cmd = self.cargo("test", "rustc_public").args(flags); + cmd.run()?; + Ok(()) + } + + pub fn clean(&self, flags: &Vec) -> Result<()> { + let cmd = self.cargo("clean", ".").args(flags); + cmd.run()?; + Ok(()) + } + + pub fn fmt(&self, check: bool, crate_dir: &str, flags: &Vec) -> Result<()> { + let mut cmd = self.cargo("fmt", crate_dir).args(flags); + if check { + cmd = cmd.args(&["--check"]); + } + cmd.run()?; + Ok(()) + } + + pub fn bump_msrv(&self, date: String) -> Result<()> { + let _ = date; + todo!() + } + + pub fn install_git_book(&self) -> Result<()> { + let cmd = self.git("rev-parse").arg("--git-common-dir"); + let git_dir = cmd.read()?; + let git_dir = PathBuf::from(git_dir.trim()); + let hooks_dir = git_dir.join("hooks"); + let dst = hooks_dir.join("pre-push"); + if dst.exists() { + // The git hook has already been set up. + println!("`.git/hooks/pre-push` has already been installed."); + return Ok(()); + } + if !hooks_dir.exists() { + let _ = std::fs::create_dir(hooks_dir); + } + let pre_push = self.root_dir.join("scripts").join("pre-push.sh"); + match std::fs::hard_link(pre_push, &dst) { + Err(e) => { + eprintln!( + "ERROR: could not create hook {}: do you already have the git hook installed?\n{}", + dst.display(), + e + ); + return Err(e.into()); + } + Ok(_) => println!("Linked `scripts/pre-push.sh` to `.git/hooks/pre-push`"), + }; + Ok(()) + } + + pub fn uninstall_git_book(&self) -> Result<()> { + let cmd = self.git("rev-parse").arg("--git-common-dir"); + let git_dir = cmd.read()?; + let git_dir = PathBuf::from(git_dir.trim()); + let hooks_dir = git_dir.join("hooks"); + let dst = hooks_dir.join("pre-push"); + if !dst.exists() { + // The git hook has not been set up yet. + println!("`.git/hooks/pre-push` has not been set up yet."); + return Ok(()); + } + match std::fs::remove_file(&dst) { + Ok(_) => println!("`.git/hooks/pre-push` is removed"), + Err(e) => { + eprintln!("ERROR: could not remove hook {}\n{}", dst.display(), e); + return Err(e.into()); + } + } + Ok(()) + } +} + +fn main() -> Result<()> { + let cli = Cli::parse(); + match cli.command { + Command::Build { flags } => { + let cx = DevCx::new()?; + cx.build("rustc_public", &flags)?; + Ok(()) + } + Command::Test { bless, verbose, flags } => { + let cx = DevCx::new()?; + cx.build("rustc_public", &flags)?; + cx.build("test-drive", &flags)?; + cx.test(bless, verbose, &flags)?; + Ok(()) + } + Command::Clean { flags } => { + let cx = DevCx::new()?; + cx.clean(&flags)?; + Ok(()) + } + Command::MSRV { date } => { + let cx = DevCx::new()?; + cx.bump_msrv(date)?; + Ok(()) + } + Command::Fmt { check, flags } => { + let cx = DevCx::new()?; + cx.fmt(check, "rustc_public", &flags)?; + cx.fmt(check, "devtool", &flags)?; + cx.fmt(check, "test-drive", &flags)?; + Ok(()) + } + Command::Githook { command } => { + let cx = DevCx::new()?; + match command { + GithookCommand::Install => cx.install_git_book()?, + GithookCommand::Uninstall => cx.uninstall_git_book()?, + } + Ok(()) + } + } +} diff --git a/devtool/src/utils.rs b/devtool/src/utils.rs new file mode 100644 index 0000000..24700d6 --- /dev/null +++ b/devtool/src/utils.rs @@ -0,0 +1,16 @@ +use std::path::PathBuf; + +use anyhow::{Context, Result}; +use xshell::{Shell, cmd}; + +pub fn rustc_public_dir() -> PathBuf { + let dev_tool_dir: PathBuf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + dev_tool_dir.parent().unwrap().to_path_buf() +} + +pub fn active_toolchain() -> Result { + let sh = Shell::new()?; + sh.change_dir(rustc_public_dir()); + let stdout = cmd!(sh, "rustup show active-toolchain").read()?; + Ok(stdout.split_whitespace().next().context("Could not obtain active Rust toolchain")?.into()) +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml index ee9dc17..27f28bd 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,2 @@ [toolchain] -channel = "nightly" components = ["llvm-tools-preview", "rustc-dev", "rust-src", "rustfmt"] diff --git a/rustc_public/Cargo.toml b/rustc_public/Cargo.toml index 70af30c..22da2c0 100644 --- a/rustc_public/Cargo.toml +++ b/rustc_public/Cargo.toml @@ -1,26 +1,38 @@ [package] name = "rustc_public" version = "0.1.0-preview" +authors = ["rustc_public team"] +description = "Define compiler intermediate representation usable by external tools" +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang/project-stable-mir" edition = "2024" +[lib] +path = "src/lib.rs" + [dependencies] -# tidy-alphabetical-start -rustc_abi = { path = "../rustc_abi" } -rustc_hir = { path = "../rustc_hir" } -rustc_middle = { path = "../rustc_middle" } -rustc_public_bridge = { path = "../rustc_public_bridge" } -rustc_session = { path = "../rustc_session" } -rustc_span = { path = "../rustc_span" } -rustc_target = { path = "../rustc_target" } scoped-tls = "1.0" serde = { version = "1.0.125", features = [ "derive" ] } tracing = "0.1" -# tidy-alphabetical-end + +[build-dependencies] +rustversion = "1" + +[dev-dependencies] +regex = "1.5.5" +ui_test = "0.30.2" + +[[test]] +name = "compiletest" +harness = false [features] -# tidy-alphabetical-start # Provides access to APIs that expose internals of the rust compiler. # APIs enabled by this feature are unstable. They can be removed or modified # at any point and they are not included in the crate's semantic versioning. rustc_internal = [] -# tidy-alphabetical-end + +[package.metadata.rust-analyzer] +# This crate uses #[feature(rustc_private)]. +# See https://github.com/rust-analyzer/rust-analyzer/pull/7891 +rustc_private = true diff --git a/rustc_public/build.rs b/rustc_public/build.rs new file mode 100644 index 0000000..9d68c24 --- /dev/null +++ b/rustc_public/build.rs @@ -0,0 +1,30 @@ +use std::process::{self, Command}; +use std::{env, str}; + +use rustversion; + +const MSRV: &str = "2025-08-09"; +const SUPPORTED: bool = rustversion::cfg!(since(2025-08-09)); + +fn main() { + if !SUPPORTED { + let current = rustc_version().unwrap_or(String::from("unknown")); + eprintln!( + "\nERROR: rustc_public requires rustc nightly-{MSRV} or newer\n\ + current: {current}\n\ + help: run `rustup update nightly`.\n" + ); + process::exit(1); + } + println!("cargo:rerun-if-changed=build.rs"); +} + +fn rustc_version() -> Option { + let rustc = env::var_os("RUSTC").unwrap_or_else(|| { + eprintln!("RUSTC is not set during build script execution.\n"); + process::exit(1); + }); + let output = Command::new(rustc).arg("--version").output().ok()?; + let version = str::from_utf8(&output.stdout).ok()?; + version.parse().ok() +} diff --git a/rustc_public/src/lib.rs b/rustc_public/src/lib.rs index 958b3b2..1a91515 100644 --- a/rustc_public/src/lib.rs +++ b/rustc_public/src/lib.rs @@ -6,6 +6,7 @@ //! //! This API is still completely unstable and subject to change. +#![feature(rustc_private)] #![allow(rustc::usage_of_ty_tykind)] #![doc( html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", @@ -19,6 +20,15 @@ //! The goal is to eventually be published on //! [crates.io](https://crates.io). +extern crate rustc_abi; +extern crate rustc_driver; +extern crate rustc_hir; +extern crate rustc_middle; +extern crate rustc_public_bridge; +extern crate rustc_session; +extern crate rustc_span; +extern crate rustc_target; + use std::fmt::Debug; use std::{fmt, io}; diff --git a/rustc_public/tests/compiletest.rs b/rustc_public/tests/compiletest.rs new file mode 100644 index 0000000..d131ddf --- /dev/null +++ b/rustc_public/tests/compiletest.rs @@ -0,0 +1,212 @@ +use std::env; +use std::ffi::OsString; +use std::path::PathBuf; +use std::sync::OnceLock; + +use regex::bytes::Regex; +use ui_test::color_eyre::eyre::Result; +use ui_test::spanned::Spanned; +use ui_test::status_emitter::StatusEmitter; +use ui_test::{ + Args, CommandBuilder, Config, Match, bless_output_files, error_on_output_conflict, + run_tests_generic, +}; + +#[derive(Copy, Clone, Debug)] +/// Decides what is expected of each test's exit status. +enum Mode { + /// The test passes a full execution of the rustc driver. + Pass, + /// The rustc driver should emit an error. + Fail, + /// The test is currently failing but is expected to succeed. + /// This is used to add test cases that reproduce an existing bug. This help us identify issues + /// that may be "accidentally" fixed. + FixMe, + /// The test passes a full execution of `cargo build` + CargoPass, +} + +#[derive(Debug)] +struct TestCx { + /// Path for the rustc_public driver. + driver_path: PathBuf, + /// Arguments from the `cargo test` command. + args: Args, +} + +impl TestCx { + fn new() -> Result { + let driver_path: PathBuf = PathBuf::from( + env::var("RP_TEST_DRIVER_PATH") + .expect("RP_TEST_DRIVER_PATH must be set to run rustc_public test suites"), + ); + let args = Args::test()?; + Ok(Self { driver_path, args }) + } + + fn run_test(&mut self, mode: Mode, test_dir: &str) -> Result<()> { + let config = config(mode, test_dir, self); + eprintln!("Compiler: {}", config.program.display()); + run_tests_generic( + vec![config], + ui_test::default_file_filter, + ui_test::default_per_file_config, + Box::::from(self.args.format), + )?; + + Ok(()) + } +} + +fn config(mode: Mode, test_dir: &str, cx: &mut TestCx) -> Config { + let config = if matches!(mode, Mode::CargoPass) { + cargo_config(mode, test_dir, cx) + } else { + driver_config(mode, test_dir, cx) + }; + cx.args.bless |= env::var("RP_TEST_DRIVER_BLESS").is_ok_and(|v| v != "0"); + + common_settings(config, mode, cx.args.bless) +} + +/// Configure cargo tests that will run the test-driver instead of rustc. +fn cargo_config(mode: Mode, test_dir: &str, cx: &TestCx) -> Config { + let mut config = Config::cargo(test_dir); + config + .program + .envs + .push(("RUST".into(), Some(cx.driver_path.clone().into_os_string()))); + config.program.envs.push(( + "CARGO_ENCODED_RUSTFLAGS".into(), + Some(rustc_flags(mode).join(&OsString::from("\x1f")).into()), + )); + config +} + +/// Configure tests that will invoke the test-driver directly as rustc. +fn driver_config(mode: Mode, test_dir: &str, cx: &TestCx) -> Config { + let mut config = Config::rustc(test_dir); + config.program = CommandBuilder::rustc(); + config.program.program = cx.driver_path.clone(); + config.program.args = rustc_flags(mode); + config +} + +fn common_settings(mut config: Config, mode: Mode, bless: bool) -> Config { + // Recommend that users should use this command to bless failing tests. + config.bless_command = Some("./x test --bless".into()); + config.output_conflict_handling = if bless { + bless_output_files + } else { + error_on_output_conflict + }; + config.comment_defaults.base().exit_status = match mode { + Mode::Pass | Mode::CargoPass => Some(0), + Mode::Fail | Mode::FixMe => Some(1), + } + .map(Spanned::dummy) + .into(); + config.comment_defaults.base().require_annotations = + Spanned::dummy(matches!(mode, Mode::Fail)).into(); + config.comment_defaults.base().normalize_stderr = stderr_filters() + .iter() + .map(|(m, p)| (m.clone(), p.to_vec())) + .collect(); + config.comment_defaults.base().normalize_stdout = stdout_filters() + .iter() + .map(|(m, p)| (m.clone(), p.to_vec())) + .collect(); + config.out_dir = PathBuf::from(env!("CARGO_TARGET_TMPDIR")).join("rp_tests"); + config +} + +fn rustc_flags(mode: Mode) -> Vec { + let mut flags = vec!["--smir-check".into()]; + let verbose = env::var("RP_TEST_DRIVER_VERBOSE").is_ok_and(|v| v != "0"); + if verbose { + flags.push("--smir-verbose".into()); + } + if matches!(mode, Mode::FixMe) { + // Enable checks that should pass but may trigger an existing issue. + flags.push("--smir-fixme".into()); + } + flags +} + +fn run_all(mut cx: TestCx) -> Result<()> { + cx.run_test(Mode::Pass, "tests/sanity-checks")?; + cx.run_test(Mode::Pass, "tests/print")?; + cx.run_test(Mode::FixMe, "tests/fixme")?; + cx.run_test(Mode::Fail, "tests/fail")?; + Ok(()) +} + +fn main() -> Result<()> { + let cx = TestCx::new()?; + run_all(cx)?; + Ok(()) +} + +macro_rules! regexes { + ($name:ident: $($regex:expr => $replacement:expr,)*) => { + fn $name() -> &'static [(Match, &'static [u8])] { + static S: OnceLock> = OnceLock::new(); + S.get_or_init(|| vec![ + $((Regex::new($regex).unwrap().into(), $replacement.as_bytes()),)* + ]) + } + }; +} + +regexes! { + stdout_filters: + // Windows file paths + r"\\" => "/", + // erase borrow tags + "<[0-9]+>" => "", + "<[0-9]+=" => " "$$DIR", +} + +regexes! { + stderr_filters: + // erase line and column info + r"\.rs:[0-9]+:[0-9]+(: [0-9]+:[0-9]+)?" => ".rs:LL:CC", + // erase alloc ids + "alloc[0-9]+" => "ALLOC", + // erase thread ids + r"unnamed-[0-9]+" => "unnamed-ID", + r"thread '(?P.*?)' \(\d+\) panicked" => "thread '$name' ($$TID) panicked", + // erase borrow tags + "<[0-9]+>" => "", + "<[0-9]+=" => " "$1", + // erase whitespace that differs between platforms + r" +at (.*\.rs)" => " at $1", + // erase generics in backtraces + "([0-9]+: .*)::<.*>" => "$1", + // erase long hexadecimals + r"0x[0-9a-fA-F]+[0-9a-fA-F]{2,2}" => "$$HEX", + // erase specific alignments + "alignment [0-9]+" => "alignment ALIGN", + "[0-9]+ byte alignment but found [0-9]+" => "ALIGN byte alignment but found ALIGN", + // erase thread caller ids + r"call [0-9]+" => "call ID", + // erase platform module paths + r"\bsys::([a-z_]+)::[a-z]+::" => "sys::$1::PLATFORM::", + // Windows file paths + r"\\" => "/", + // test-drive tags + r"\[T-DRIVE\].*\n" => "", + // erase Rust stdlib path + "[^ \n`]*/(rust[^/]*|checkout)/library/" => "RUSTLIB/", + // erase rustc path + "[^ \n`]*/(rust[^/]*|checkout)/compiler/" => "RUSTC/", + // erase platform file paths + r"\bsys/([a-z_]+)/[a-z]+\b" => "sys/$1/PLATFORM", + // erase paths into the crate registry + r"[^ ]*/\.?cargo/registry/.*/(.*\.rs)" => "CARGO_REGISTRY/.../$1", +} diff --git a/rustc_public/tests/fixme/ice_too_generic.rs b/rustc_public/tests/fixme/ice_too_generic.rs new file mode 100644 index 0000000..234b49d --- /dev/null +++ b/rustc_public/tests/fixme/ice_too_generic.rs @@ -0,0 +1,14 @@ +//@compile-flags: -Copt-level=1 + +#![allow(dead_code, unused_variables)] +use std::fmt::Debug; + +pub trait Meow { + fn foo(&self, a: Option<&A>) -> A; + + fn fzz(&self) -> A { + self.foo(None) + } +} + +fn main() {} \ No newline at end of file diff --git a/rustc_public/tests/fixme/ice_too_generic.stderr b/rustc_public/tests/fixme/ice_too_generic.stderr new file mode 100644 index 0000000..dd03ec8 --- /dev/null +++ b/rustc_public/tests/fixme/ice_too_generic.stderr @@ -0,0 +1,6 @@ + +thread 'rustc' ($TID) panicked at rustc_public/src/alloc.rs:LL:CC: +Failed to convert: Scalar($HEX) to std::option::Option<&'{erased} A/#1> +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +Test sanity_checks::test_all_fns: Failed: + - Panic! diff --git a/rustc_public/tests/print/async-closure.rs b/rustc_public/tests/print/async-closure.rs new file mode 100644 index 0000000..4cbc2b5 --- /dev/null +++ b/rustc_public/tests/print/async-closure.rs @@ -0,0 +1,12 @@ +//@ compile-flags: -Z unpretty=stable-mir --crate-type lib -C panic=abort -Zmir-opt-level=0 -Ztrim-diagnostic-paths=true +//@check-pass +//@ edition: 2024 + +#![allow(dead_code, unused_variables)] + +pub fn foo() { + let y = 0; + let x = async || { + let y = y; + }; +} diff --git a/rustc_public/tests/print/async-closure.stdout b/rustc_public/tests/print/async-closure.stdout new file mode 100644 index 0000000..3230755 --- /dev/null +++ b/rustc_public/tests/print/async-closure.stdout @@ -0,0 +1,113 @@ +// WARNING: This is highly experimental output it's intended for rustc_public developers only. +// If you find a bug or want to improve the output open a issue at https://github.com/rust-lang/project-stable-mir. +fn foo() -> () { + let mut _0: (); + let _1: i32; + let _2: {async closure@$DIR/async-closure.rs:9:13: 9:21}; + let mut _3: &i32; + debug y => _1; + debug x => _2; + bb0: { + StorageLive(_1); + _1 = 0_i32; + StorageLive(_2); + StorageLive(_3); + _3 = &_1; + _2 = {coroutine-closure@$DIR/async-closure.rs:9:13: 9:21}(move _3); + StorageDead(_3); + _0 = (); + StorageDead(_2); + StorageDead(_1); + return; + } +} +fn foo::{closure#0}(_1: &{async closure@$DIR/async-closure.rs:9:13: 9:21}) -> {async closure body@$DIR/async-closure.rs:9:22: 11:6} { + let mut _0: {async closure body@$DIR/async-closure.rs:9:22: 11:6}; + let mut _2: &i32; + let mut _3: &i32; + debug y => (*((*_1).0: &i32)); + bb0: { + StorageLive(_2); + _3 = CopyForDeref(((*_1).0: &i32)); + _2 = &(*_3); + _0 = {coroutine@$DIR/async-closure.rs:9:22: 11:6}(move _2); + StorageDead(_2); + return; + } +} +fn foo::{closure#0}::{closure#0}(_1: std::pin::Pin<&mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}>, _2: &mut std::task::Context<'_>) -> std::task::Poll<()> { + let mut _0: std::task::Poll<()>; + let _3: i32; + let mut _4: &i32; + let mut _5: (); + let mut _6: &mut std::task::Context<'_>; + let mut _7: u32; + let mut _8: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}; + let mut _9: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}; + let mut _10: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}; + debug _task_context => _6; + debug y => (*((*(_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})).0: &i32)); + debug y => _3; + bb0: { + _8 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); + _7 = discriminant((*_8)); + switchInt(move _7) -> [0: bb1, 1: bb2, otherwise: bb3]; + } + bb1: { + _6 = move _2; + StorageLive(_3); + _9 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); + _4 = CopyForDeref(((*_9).0: &i32)); + _3 = (*_4); + _5 = (); + StorageDead(_3); + _0 = std::task::Poll::Ready(move _5); + _10 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); + discriminant((*_10)) = 1; + return; + } + bb2: { + assert(false, `async fn` resumed after completion) -> [success: bb2, unwind unreachable]; + } + bb3: { + unreachable; + } +} +fn foo::{closure#0}::{synthetic#0}(_1: std::pin::Pin<&mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}>, _2: &mut std::task::Context<'_>) -> std::task::Poll<()> { + let mut _0: std::task::Poll<()>; + let _3: i32; + let mut _4: &i32; + let mut _5: (); + let mut _6: &mut std::task::Context<'_>; + let mut _7: u32; + let mut _8: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}; + let mut _9: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}; + let mut _10: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}; + debug _task_context => _6; + debug y => (*((*(_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})).0: &i32)); + debug y => _3; + bb0: { + _8 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); + _7 = discriminant((*_8)); + switchInt(move _7) -> [0: bb1, 1: bb2, otherwise: bb3]; + } + bb1: { + _6 = move _2; + StorageLive(_3); + _9 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); + _4 = CopyForDeref(((*_9).0: &i32)); + _3 = (*_4); + _5 = (); + StorageDead(_3); + _0 = std::task::Poll::Ready(move _5); + _10 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); + discriminant((*_10)) = 1; + return; + } + bb2: { + assert(false, `async fn` resumed after completion) -> [success: bb2, unwind unreachable]; + } + bb3: { + unreachable; + } +} diff --git a/rustc_public/tests/print/basic_function.rs b/rustc_public/tests/print/basic_function.rs new file mode 100644 index 0000000..d43d812 --- /dev/null +++ b/rustc_public/tests/print/basic_function.rs @@ -0,0 +1,25 @@ +//@ compile-flags: -Z unpretty=stable-mir -Zmir-opt-level=0 -Ztrim-diagnostic-paths=true +//@check-pass + +#![allow(dead_code, unused_variables)] + +fn foo(i: i32) -> i32 { + i + 1 +} + +fn bar(vec: &mut Vec) -> Vec { + let mut new_vec = vec.clone(); + new_vec.push(1); + new_vec +} + +pub fn demux(input: u8) -> u8 { + match input { + 0 => 10, + 1 => 6, + 2 => 8, + _ => 0, + } +} + +fn main() {} diff --git a/rustc_public/tests/print/basic_function.stdout b/rustc_public/tests/print/basic_function.stdout new file mode 100644 index 0000000..701b4fe --- /dev/null +++ b/rustc_public/tests/print/basic_function.stdout @@ -0,0 +1,87 @@ +// WARNING: This is highly experimental output it's intended for rustc_public developers only. +// If you find a bug or want to improve the output open a issue at https://github.com/rust-lang/project-stable-mir. +fn foo(_1: i32) -> i32 { + let mut _0: i32; + let mut _2: i32; + let mut _3: (i32, bool); + debug i => _1; + bb0: { + StorageLive(_2); + _2 = _1; + _3 = CheckedAdd(_2, 1_i32); + assert(!move (_3.1: bool), "attempt to compute `{} + {}`, which would overflow", move _2, 1_i32) -> [success: bb1, unwind continue]; + } + bb1: { + _0 = move (_3.0: i32); + StorageDead(_2); + return; + } +} +fn bar(_1: &mut std::vec::Vec) -> std::vec::Vec { + let mut _0: std::vec::Vec; + let mut _2: std::vec::Vec; + let mut _3: &std::vec::Vec; + let _4: (); + let mut _5: &mut std::vec::Vec; + debug vec => _1; + debug new_vec => _2; + bb0: { + StorageLive(_2); + StorageLive(_3); + _3 = &(*_1); + _2 = as std::clone::Clone>::clone(move _3) -> [return: bb1, unwind continue]; + } + bb1: { + StorageDead(_3); + StorageLive(_4); + StorageLive(_5); + _5 = &mut _2; + _4 = std::vec::Vec::::push(move _5, 1_i32) -> [return: bb2, unwind: bb3]; + } + bb2: { + StorageDead(_5); + StorageDead(_4); + _0 = move _2; + StorageDead(_2); + return; + } + bb3: { + drop(_2) -> [return: bb4, unwind terminate]; + } + bb4: { + resume; + } +} +fn demux(_1: u8) -> u8 { + let mut _0: u8; + debug input => _1; + bb0: { + switchInt(_1) -> [0: bb4, 1: bb3, 2: bb2, otherwise: bb1]; + } + bb1: { + _0 = 0_u8; + goto -> bb5; + } + bb2: { + _0 = 8_u8; + goto -> bb5; + } + bb3: { + _0 = 6_u8; + goto -> bb5; + } + bb4: { + _0 = 10_u8; + goto -> bb5; + } + bb5: { + return; + } +} +fn main() -> () { + let mut _0: (); + bb0: { + _0 = (); + return; + } +} diff --git a/rustc_public/tests/print/operands.rs b/rustc_public/tests/print/operands.rs new file mode 100644 index 0000000..5687738 --- /dev/null +++ b/rustc_public/tests/print/operands.rs @@ -0,0 +1,48 @@ +//@ compile-flags: -Z unpretty=stable-mir --crate-type lib -C panic=abort -Zmir-opt-level=0 +//@ check-pass +//@ only-host: x86_64 +//! Check how stable mir pretty printer prints different operands and abort strategy. +#![allow(dead_code, unused_variables)] + +pub fn operands(val: u8) { + let array = [val; 10]; + let first = array[0]; + let last = array[10 - 1]; + assert_eq!(first, last); + + let reference = &first; + let dereferenced = *reference; + assert_eq!(dereferenced, first); + + let tuple = (first, last); + let (first_again, _) = tuple; + let first_again_again = tuple.0; + assert_eq!(first_again, first_again_again); + + let length = array.len(); + let size_of = std::mem::size_of_val(&length); + assert_eq!(length, size_of); +} + +pub struct Dummy { + c: char, + i: i32, +} + +pub enum Ctors { + Unit, + StructLike { d: Dummy }, + TupLike(bool), +} + +pub fn more_operands() -> [Ctors; 3] { + let dummy = Dummy { c: 'a', i: i32::MIN }; + let unit = Ctors::Unit; + let struct_like = Ctors::StructLike { d: dummy }; + let tup_like = Ctors::TupLike(false); + [unit, struct_like, tup_like] +} + +pub fn closures(x: bool, z: bool) -> impl FnOnce(bool) -> bool { + move |y: bool| (x ^ y) || z +} diff --git a/rustc_public/tests/print/operands.stdout b/rustc_public/tests/print/operands.stdout new file mode 100644 index 0000000..5bd1ae8 --- /dev/null +++ b/rustc_public/tests/print/operands.stdout @@ -0,0 +1,506 @@ +// WARNING: This is highly experimental output it's intended for rustc_public developers only. +// If you find a bug or want to improve the output open a issue at https://github.com/rust-lang/project-stable-mir. +fn operands(_1: u8) -> () { + let mut _0: (); + let _2: [u8; 10]; + let mut _3: u8; + let _4: u8; + let _5: usize; + let mut _6: bool; + let _7: u8; + let _8: usize; + let mut _9: (usize, bool); + let mut _10: bool; + let _11: (); + let mut _12: (&u8, &u8); + let mut _13: &u8; + let mut _14: &u8; + let _15: &u8; + let _16: &u8; + let mut _17: bool; + let mut _18: u8; + let mut _19: u8; + let mut _20: !; + let _21: core::panicking::AssertKind; + let _22: !; + let mut _23: core::panicking::AssertKind; + let mut _24: &u8; + let _25: &u8; + let mut _26: &u8; + let _27: &u8; + let mut _28: std::option::Option>; + let _29: &u8; + let _30: u8; + let _31: (); + let mut _32: (&u8, &u8); + let mut _33: &u8; + let mut _34: &u8; + let _35: &u8; + let _36: &u8; + let mut _37: bool; + let mut _38: u8; + let mut _39: u8; + let mut _40: !; + let _41: core::panicking::AssertKind; + let _42: !; + let mut _43: core::panicking::AssertKind; + let mut _44: &u8; + let _45: &u8; + let mut _46: &u8; + let _47: &u8; + let mut _48: std::option::Option>; + let _49: (u8, u8); + let mut _50: u8; + let mut _51: u8; + let _52: u8; + let _53: u8; + let _54: (); + let mut _55: (&u8, &u8); + let mut _56: &u8; + let mut _57: &u8; + let _58: &u8; + let _59: &u8; + let mut _60: bool; + let mut _61: u8; + let mut _62: u8; + let mut _63: !; + let _64: core::panicking::AssertKind; + let _65: !; + let mut _66: core::panicking::AssertKind; + let mut _67: &u8; + let _68: &u8; + let mut _69: &u8; + let _70: &u8; + let mut _71: std::option::Option>; + let _72: usize; + let mut _73: &[u8]; + let mut _74: &[u8; 10]; + let _75: usize; + let mut _76: &usize; + let _77: &usize; + let _78: (); + let mut _79: (&usize, &usize); + let mut _80: &usize; + let mut _81: &usize; + let _82: &usize; + let _83: &usize; + let mut _84: bool; + let mut _85: usize; + let mut _86: usize; + let mut _87: !; + let _88: core::panicking::AssertKind; + let _89: !; + let mut _90: core::panicking::AssertKind; + let mut _91: &usize; + let _92: &usize; + let mut _93: &usize; + let _94: &usize; + let mut _95: std::option::Option>; + debug val => _1; + debug array => _2; + debug first => _4; + debug last => _7; + debug left_val => _15; + debug right_val => _16; + debug kind => _21; + debug reference => _29; + debug dereferenced => _30; + debug left_val => _35; + debug right_val => _36; + debug kind => _41; + debug tuple => _49; + debug first_again => _52; + debug first_again_again => _53; + debug left_val => _58; + debug right_val => _59; + debug kind => _64; + debug length => _72; + debug size_of => _75; + debug left_val => _82; + debug right_val => _83; + debug kind => _88; + bb0: { + StorageLive(_2); + StorageLive(_3); + _3 = _1; + _2 = [move _3; 10]; + StorageDead(_3); + StorageLive(_4); + StorageLive(_5); + _5 = 0_usize; + _6 = Lt(_5, 10_usize); + assert(move _6, "index out of bounds: the length is {} but the index is {}", 10_usize, _5) -> [success: bb1, unwind unreachable]; + } + bb1: { + _4 = _2[_5]; + StorageDead(_5); + StorageLive(_7); + StorageLive(_8); + _9 = CheckedSub(10_usize, 1_usize); + assert(!move (_9.1: bool), "attempt to compute `{} - {}`, which would overflow", 10_usize, 1_usize) -> [success: bb2, unwind unreachable]; + } + bb2: { + _8 = move (_9.0: usize); + _10 = Lt(_8, 10_usize); + assert(move _10, "index out of bounds: the length is {} but the index is {}", 10_usize, _8) -> [success: bb3, unwind unreachable]; + } + bb3: { + _7 = _2[_8]; + StorageDead(_8); + StorageLive(_11); + StorageLive(_12); + StorageLive(_13); + _13 = &_4; + StorageLive(_14); + _14 = &_7; + _12 = (move _13, move _14); + StorageDead(_14); + StorageDead(_13); + StorageLive(_15); + _15 = (_12.0: &u8); + StorageLive(_16); + _16 = (_12.1: &u8); + StorageLive(_17); + StorageLive(_18); + _18 = (*_15); + StorageLive(_19); + _19 = (*_16); + _17 = Eq(move _18, move _19); + switchInt(move _17) -> [0: bb5, otherwise: bb4]; + } + bb4: { + StorageDead(_19); + StorageDead(_18); + _11 = (); + StorageDead(_17); + StorageDead(_16); + StorageDead(_15); + StorageDead(_12); + StorageDead(_11); + StorageLive(_29); + _29 = &_4; + StorageLive(_30); + _30 = (*_29); + StorageLive(_31); + StorageLive(_32); + StorageLive(_33); + _33 = &_30; + StorageLive(_34); + _34 = &_4; + _32 = (move _33, move _34); + StorageDead(_34); + StorageDead(_33); + StorageLive(_35); + _35 = (_32.0: &u8); + StorageLive(_36); + _36 = (_32.1: &u8); + StorageLive(_37); + StorageLive(_38); + _38 = (*_35); + StorageLive(_39); + _39 = (*_36); + _37 = Eq(move _38, move _39); + switchInt(move _37) -> [0: bb7, otherwise: bb6]; + } + bb5: { + StorageDead(_19); + StorageDead(_18); + StorageLive(_21); + _21 = core::panicking::AssertKind::Eq; + StorageLive(_22); + StorageLive(_23); + _23 = move _21; + StorageLive(_24); + StorageLive(_25); + _25 = &(*_15); + _24 = &(*_25); + StorageLive(_26); + StorageLive(_27); + _27 = &(*_16); + _26 = &(*_27); + StorageLive(_28); + _28 = std::option::Option::None; + _22 = core::panicking::assert_failed::(move _23, move _24, move _26, move _28) -> unwind unreachable; + } + bb6: { + StorageDead(_39); + StorageDead(_38); + _31 = (); + StorageDead(_37); + StorageDead(_36); + StorageDead(_35); + StorageDead(_32); + StorageDead(_31); + StorageLive(_49); + StorageLive(_50); + _50 = _4; + StorageLive(_51); + _51 = _7; + _49 = (move _50, move _51); + StorageDead(_51); + StorageDead(_50); + StorageLive(_52); + _52 = (_49.0: u8); + StorageLive(_53); + _53 = (_49.0: u8); + StorageLive(_54); + StorageLive(_55); + StorageLive(_56); + _56 = &_52; + StorageLive(_57); + _57 = &_53; + _55 = (move _56, move _57); + StorageDead(_57); + StorageDead(_56); + StorageLive(_58); + _58 = (_55.0: &u8); + StorageLive(_59); + _59 = (_55.1: &u8); + StorageLive(_60); + StorageLive(_61); + _61 = (*_58); + StorageLive(_62); + _62 = (*_59); + _60 = Eq(move _61, move _62); + switchInt(move _60) -> [0: bb9, otherwise: bb8]; + } + bb7: { + StorageDead(_39); + StorageDead(_38); + StorageLive(_41); + _41 = core::panicking::AssertKind::Eq; + StorageLive(_42); + StorageLive(_43); + _43 = move _41; + StorageLive(_44); + StorageLive(_45); + _45 = &(*_35); + _44 = &(*_45); + StorageLive(_46); + StorageLive(_47); + _47 = &(*_36); + _46 = &(*_47); + StorageLive(_48); + _48 = std::option::Option::None; + _42 = core::panicking::assert_failed::(move _43, move _44, move _46, move _48) -> unwind unreachable; + } + bb8: { + StorageDead(_62); + StorageDead(_61); + _54 = (); + StorageDead(_60); + StorageDead(_59); + StorageDead(_58); + StorageDead(_55); + StorageDead(_54); + StorageLive(_72); + StorageLive(_73); + StorageLive(_74); + _74 = &_2; + _73 = move _74 as &[u8]; + StorageDead(_74); + _72 = core::slice::::len(move _73) -> [return: bb10, unwind unreachable]; + } + bb9: { + StorageDead(_62); + StorageDead(_61); + StorageLive(_64); + _64 = core::panicking::AssertKind::Eq; + StorageLive(_65); + StorageLive(_66); + _66 = move _64; + StorageLive(_67); + StorageLive(_68); + _68 = &(*_58); + _67 = &(*_68); + StorageLive(_69); + StorageLive(_70); + _70 = &(*_59); + _69 = &(*_70); + StorageLive(_71); + _71 = std::option::Option::None; + _65 = core::panicking::assert_failed::(move _66, move _67, move _69, move _71) -> unwind unreachable; + } + bb10: { + StorageDead(_73); + StorageLive(_75); + StorageLive(_76); + StorageLive(_77); + _77 = &_72; + _76 = &(*_77); + _75 = std::mem::size_of_val::(move _76) -> [return: bb11, unwind unreachable]; + } + bb11: { + StorageDead(_76); + StorageDead(_77); + StorageLive(_78); + StorageLive(_79); + StorageLive(_80); + _80 = &_72; + StorageLive(_81); + _81 = &_75; + _79 = (move _80, move _81); + StorageDead(_81); + StorageDead(_80); + StorageLive(_82); + _82 = (_79.0: &usize); + StorageLive(_83); + _83 = (_79.1: &usize); + StorageLive(_84); + StorageLive(_85); + _85 = (*_82); + StorageLive(_86); + _86 = (*_83); + _84 = Eq(move _85, move _86); + switchInt(move _84) -> [0: bb13, otherwise: bb12]; + } + bb12: { + StorageDead(_86); + StorageDead(_85); + _78 = (); + StorageDead(_84); + StorageDead(_83); + StorageDead(_82); + StorageDead(_79); + StorageDead(_78); + _0 = (); + StorageDead(_75); + StorageDead(_72); + StorageDead(_53); + StorageDead(_52); + StorageDead(_49); + StorageDead(_30); + StorageDead(_29); + StorageDead(_7); + StorageDead(_4); + StorageDead(_2); + return; + } + bb13: { + StorageDead(_86); + StorageDead(_85); + StorageLive(_88); + _88 = core::panicking::AssertKind::Eq; + StorageLive(_89); + StorageLive(_90); + _90 = move _88; + StorageLive(_91); + StorageLive(_92); + _92 = &(*_82); + _91 = &(*_92); + StorageLive(_93); + StorageLive(_94); + _94 = &(*_83); + _93 = &(*_94); + StorageLive(_95); + _95 = std::option::Option::None; + _89 = core::panicking::assert_failed::(move _90, move _91, move _93, move _95) -> unwind unreachable; + } +} +fn operands::{constant#0}() -> usize { + let mut _0: usize; + bb0: { + _0 = 10_usize; + return; + } +} +fn more_operands() -> [Ctors; 3] { + let mut _0: [Ctors; 3]; + let _1: Dummy; + let _2: Ctors; + let _3: Ctors; + let mut _4: Dummy; + let _5: Ctors; + let mut _6: Ctors; + let mut _7: Ctors; + let mut _8: Ctors; + debug dummy => _1; + debug unit => _2; + debug struct_like => _3; + debug tup_like => _5; + bb0: { + StorageLive(_1); + _1 = Dummy('a', core::num::::MIN); + StorageLive(_2); + _2 = Ctors::Unit; + StorageLive(_3); + StorageLive(_4); + _4 = move _1; + _3 = Ctors::StructLike(move _4); + StorageDead(_4); + StorageLive(_5); + _5 = Ctors::TupLike(false); + StorageLive(_6); + _6 = move _2; + StorageLive(_7); + _7 = move _3; + StorageLive(_8); + _8 = move _5; + _0 = [move _6, move _7, move _8]; + StorageDead(_8); + StorageDead(_7); + StorageDead(_6); + StorageDead(_5); + StorageDead(_3); + StorageDead(_2); + StorageDead(_1); + return; + } +} +fn more_operands::{constant#0}() -> usize { + let mut _0: usize; + bb0: { + _0 = 3_usize; + return; + } +} +fn closures(_1: bool, _2: bool) -> {closure@$DIR/operands.rs:47:5: 47:19} { + let mut _0: {closure@$DIR/operands.rs:47:5: 47:19}; + debug x => _1; + debug z => _2; + bb0: { + _0 = {closure@$DIR/operands.rs:47:5: 47:19}(_1, _2); + return; + } +} +fn closures::{closure#0}(_1: {closure@$DIR/operands.rs:47:5: 47:19}, _2: bool) -> bool { + let mut _0: bool; + let mut _3: bool; + let mut _4: bool; + let mut _5: bool; + debug y => _2; + debug x => (_1.0: bool); + debug z => (_1.1: bool); + bb0: { + StorageLive(_3); + StorageLive(_4); + _4 = (_1.0: bool); + StorageLive(_5); + _5 = _2; + _3 = BitXor(move _4, move _5); + switchInt(move _3) -> [0: bb2, otherwise: bb1]; + } + bb1: { + StorageDead(_5); + StorageDead(_4); + _0 = true; + goto -> bb3; + } + bb2: { + StorageDead(_5); + StorageDead(_4); + _0 = (_1.1: bool); + goto -> bb3; + } + bb3: { + StorageDead(_3); + return; + } +} +fn Ctors::TupLike(_1: bool) -> Ctors { + let mut _0: Ctors; + bb0: { + _0 = Ctors::TupLike(move _1); + return; + } +} diff --git a/tests/sanity-checks/associated-items/methods.rs b/rustc_public/tests/sanity-checks/associated-items/methods.rs similarity index 99% rename from tests/sanity-checks/associated-items/methods.rs rename to rustc_public/tests/sanity-checks/associated-items/methods.rs index 4d1ac0d..62a3cb0 100644 --- a/tests/sanity-checks/associated-items/methods.rs +++ b/rustc_public/tests/sanity-checks/associated-items/methods.rs @@ -1,3 +1,5 @@ +//@check-pass + //! Example derived from #![feature(box_into_inner)] diff --git a/tests/sanity-checks/simple/simple_lib.rs b/rustc_public/tests/sanity-checks/simple/simple_lib.rs similarity index 97% rename from tests/sanity-checks/simple/simple_lib.rs rename to rustc_public/tests/sanity-checks/simple/simple_lib.rs index b86f9fe..c259492 100644 --- a/tests/sanity-checks/simple/simple_lib.rs +++ b/rustc_public/tests/sanity-checks/simple/simple_lib.rs @@ -1,3 +1,5 @@ +//@check-pass + //! Just a simple library pub struct Point { diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..7556efe --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,21 @@ +# Run rustfmt with this config (it should be picked up automatically). +# We are supposed to follow the style used by rustc. +style_edition = "2024" +use_small_heuristics = "Max" +merge_derives = false +group_imports = "StdExternalCrate" +imports_granularity = "Module" +use_field_init_shorthand = true + +# Files to ignore. +ignore = [ + "/build/", + "/*-build/", + "/build-*/", + + # Do not format tests. + "rustc_public/tests", + + # Ignore build.rs. + "rustc_public/build.rs", +] diff --git a/scripts/pre-push.sh b/scripts/pre-push.sh new file mode 100755 index 0000000..767bc1f --- /dev/null +++ b/scripts/pre-push.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# +# Call `./x fmt --check` before git push +# Copy this script to .git/hooks to activate, +# and remove it from .git/hooks to deactivate. +# + +set -Euo pipefail + +# Check if the push is doing anything other than deleting remote branches +SKIP=true +while read LOCAL_REF LOCAL_SHA REMOTE_REF REMOTE_SHA; do + if [[ "$LOCAL_REF" != "(delete)" || \ + "$LOCAL_SHA" != "0000000000000000000000000000000000000000" ]]; then + SKIP=false + fi +done + +if $SKIP; then + echo "Skipping fmt check for branch deletion" + exit 0 +fi + +ROOT_DIR="$(git rev-parse --show-toplevel)" + +echo "Running pre-push script $ROOT_DIR/x fmt --check" + +cd "$ROOT_DIR" +./x fmt --check +if [ $? -ne 0 ]; then + echo "You may use \`git push --no-verify\` to skip this check." + exit 1 +fi diff --git a/tools/test-drive/Cargo.toml b/test-drive/Cargo.toml similarity index 57% rename from tools/test-drive/Cargo.toml rename to test-drive/Cargo.toml index 8fc1468..d2fcd4b 100644 --- a/tools/test-drive/Cargo.toml +++ b/test-drive/Cargo.toml @@ -1,9 +1,12 @@ [package] name = "test-drive" -description = "A rustc wrapper that can be used to test stable-mir on a crate" +description = "A rustc wrapper that can be used to test rustc_public on a crate" version = "0.0.0" edition = "2021" +[dependencies] +rustc_public = { path = "../rustc_public", features = ["rustc_internal"] } + [package.metadata.rust-analyzer] # This crate uses #[feature(rustc_private)]. # See https://github.com/rust-analyzer/rust-analyzer/pull/7891 diff --git a/tools/test-drive/build.rs b/test-drive/build.rs similarity index 67% rename from tools/test-drive/build.rs rename to test-drive/build.rs index 44c9940..f0c35e2 100644 --- a/tools/test-drive/build.rs +++ b/test-drive/build.rs @@ -5,11 +5,6 @@ pub fn main() { // Add rustup to the rpath in order to properly link with the correct rustc version. let rustup_home = env::var("RUSTUP_HOME").unwrap(); let toolchain = env::var("RUSTUP_TOOLCHAIN").unwrap(); - let rustc_lib: PathBuf = [&rustup_home, "toolchains", &toolchain, "lib"] - .iter() - .collect(); - println!( - "cargo:rustc-link-arg-bin=test-drive=-Wl,-rpath,{}", - rustc_lib.display() - ); + let rustc_lib: PathBuf = [&rustup_home, "toolchains", &toolchain, "lib"].iter().collect(); + println!("cargo:rustc-link-arg-bin=test-drive=-Wl,-rpath,{}", rustc_lib.display()); } diff --git a/tools/test-drive/src/main.rs b/test-drive/src/main.rs similarity index 81% rename from tools/test-drive/src/main.rs rename to test-drive/src/main.rs index cacae85..a5abf06 100644 --- a/tools/test-drive/src/main.rs +++ b/test-drive/src/main.rs @@ -7,17 +7,15 @@ mod sanity_checks; extern crate rustc_driver; extern crate rustc_interface; -#[macro_use] -extern crate rustc_smir; -extern crate stable_mir; +extern crate rustc_middle; -use rustc_smir::{run, rustc_internal}; -use stable_mir::CompilerError; use std::ops::ControlFlow; -use std::panic::{catch_unwind, AssertUnwindSafe}; +use std::panic::{AssertUnwindSafe, catch_unwind}; use std::process::ExitCode; use std::sync::atomic::{AtomicBool, Ordering}; +use rustc_public::{CompilerError, run}; + // ---- Arguments that should be parsed by the test-driver (w/ "smir" prefix) const CHECK_ARG: &str = "--smir-check"; /// Enable verbose mode. @@ -40,17 +38,11 @@ fn main() -> ExitCode { let args = std::env::args(); let (smir_args, rustc_args): (Vec, _) = args.partition(|arg| arg.starts_with("--smir")); let result = if smir_args.contains(&CHECK_ARG.to_string()) { - VERBOSE.store( - smir_args.contains(&VERBOSE_ARG.to_string()), - Ordering::Relaxed, - ); - FIXME_CHECKS.store( - smir_args.contains(&FIXME_ARG.to_string()), - Ordering::Relaxed, - ); - run!(rustc_args, test_stable_mir) + VERBOSE.store(smir_args.contains(&VERBOSE_ARG.to_string()), Ordering::Relaxed); + FIXME_CHECKS.store(smir_args.contains(&FIXME_ARG.to_string()), Ordering::Relaxed); + run!(&rustc_args, test_stable_mir) } else { - run!(rustc_args, || ControlFlow::<()>::Continue(())) + run!(&rustc_args, || ControlFlow::<()>::Continue(())) }; if result.is_ok() || matches!(result, Err(CompilerError::Skipped)) { ExitCode::SUCCESS @@ -93,11 +85,7 @@ fn test_stable_mir() -> ControlFlow<()> { success.len(), failure.len() )); - if failure.is_empty() { - ControlFlow::<()>::Continue(()) - } else { - ControlFlow::<()>::Break(()) - } + if failure.is_empty() { ControlFlow::<()>::Continue(()) } else { ControlFlow::<()>::Break(()) } } fn run_test TestResult>(name: &str, f: F) -> TestResult { diff --git a/tools/test-drive/src/sanity_checks.rs b/test-drive/src/sanity_checks.rs similarity index 74% rename from tools/test-drive/src/sanity_checks.rs rename to test-drive/src/sanity_checks.rs index aae7fc9..0ac52f7 100644 --- a/tools/test-drive/src/sanity_checks.rs +++ b/test-drive/src/sanity_checks.rs @@ -3,71 +3,57 @@ //! //! These checks should only depend on StableMIR APIs. See other modules for tests that compare //! the result between StableMIR and internal APIs. -use crate::TestResult; -use stable_mir::ty::{ImplDef, TraitDef}; -use stable_mir::{self, mir, mir::MirVisitor, ty, CrateDef}; use std::collections::HashSet; use std::fmt::Debug; use std::iter::zip; +use rustc_public::mir::MirVisitor; +use rustc_public::ty::{ImplDef, TraitDef}; +use rustc_public::{self, CrateDef, mir, ty}; + +use crate::TestResult; + fn check_equal(val: T, expected: T, msg: &str) -> TestResult where T: Debug + PartialEq, { if val != expected { - Err(format!( - "{}: \n Expected: `{:?}`\n Found: `{:?}`", - msg, expected, val - )) + Err(format!("{}: \n Expected: `{:?}`\n Found: `{:?}`", msg, expected, val)) } else { Ok(()) } } pub fn check(val: bool, msg: String) -> TestResult { - if !val { - Err(msg) - } else { - Ok(()) - } + if !val { Err(msg) } else { Ok(()) } } // Test that if there is an entry point, the function is part of `all_local_items`. pub fn test_entry_fn() -> TestResult { - let entry_fn = stable_mir::entry_fn(); + let entry_fn = rustc_public::entry_fn(); entry_fn.map_or(Ok(()), |entry_fn| { - check_body(&entry_fn.name(), &entry_fn.body())?; - let all_items = stable_mir::all_local_items(); - check( - all_items.contains(&entry_fn), - format!("Failed to find entry_fn: `{:?}`", entry_fn), - )?; - check_equal( - entry_fn.kind(), - stable_mir::ItemKind::Fn, - "Entry must be a function", - ) + check_body(&entry_fn.name(), &entry_fn.body().unwrap())?; + let all_items = rustc_public::all_local_items(); + check(all_items.contains(&entry_fn), format!("Failed to find entry_fn: `{:?}`", entry_fn))?; + check_equal(entry_fn.kind(), rustc_public::ItemKind::Fn, "Entry must be a function") }) } /// Iterate over local function bodies. pub fn test_all_fns() -> TestResult { - let all_items = stable_mir::all_local_items(); + let all_items = rustc_public::all_local_items(); for item in all_items { // Get body and iterate over items let body = item.body(); - check_body(&item.name(), &body)?; + check_body(&item.name(), &body.unwrap())?; } Ok(()) } /// Test that we can retrieve information about the trait declaration for every trait implementation. pub fn test_traits() -> TestResult { - let all_traits = HashSet::::from_iter(stable_mir::all_trait_decls().into_iter()); - for trait_impl in stable_mir::all_trait_impls() - .iter() - .map(ImplDef::trait_impl) - { + let all_traits = HashSet::::from_iter(rustc_public::all_trait_decls().into_iter()); + for trait_impl in rustc_public::all_trait_impls().iter().map(ImplDef::trait_impl) { check( all_traits.contains(&trait_impl.value.def_id), format!("Failed to find trait definition: `{trait_impl:?}`"), @@ -77,26 +63,26 @@ pub fn test_traits() -> TestResult { } pub fn test_crates() -> TestResult { - for krate in stable_mir::external_crates() { + for krate in rustc_public::external_crates() { check( - stable_mir::find_crates(&krate.name.as_str()).contains(&krate), + rustc_public::find_crates(&krate.name.as_str()).contains(&krate), format!("Cannot find `{krate:?}`"), )?; } - let local = stable_mir::local_crate(); + let local = rustc_public::local_crate(); check( - stable_mir::find_crates(&local.name.as_str()).contains(&local), + rustc_public::find_crates(&local.name.as_str()).contains(&local), format!("Cannot find local: `{local:?}`"), ) } pub fn test_instances() -> TestResult { - let all_items = stable_mir::all_local_items(); + let all_items = rustc_public::all_local_items(); let mut queue = all_items .iter() .filter_map(|item| { - (item.kind() == stable_mir::ItemKind::Fn) + (item.kind() == rustc_public::ItemKind::Fn) .then(|| mir::mono::Instance::try_from(*item).ok()) .flatten() }) @@ -114,8 +100,7 @@ pub fn test_instances() -> TestResult { // We currently don't support Copy / Move `ty()` due to missing Place::ty(). // https://github.com/rust-lang/project-stable-mir/issues/49 mir::TerminatorKind::Call { - func: mir::Operand::Constant(constant), - .. + func: mir::Operand::Constant(constant), .. } => { match constant.ty().kind().rigid() { Some(ty::RigidTy::FnDef(def, args)) => { @@ -150,11 +135,7 @@ fn check_body(name: &str, body: &mir::Body) -> Result { )?; for (idx, bb) in body.blocks.iter().enumerate() { for (stmt, visited_stmt) in zip(&bb.statements, &visitor.statements[idx]) { - check_equal( - stmt, - visited_stmt, - &format!("Function `{name}`: Visited statement"), - )?; + check_equal(stmt, visited_stmt, &format!("Function `{name}`: Visited statement"))?; } check_equal( &bb.terminator, @@ -167,10 +148,7 @@ fn check_body(name: &str, body: &mir::Body) -> Result { if !visitor.types.contains(&local.ty) { // Format fails due to unsupported CoroutineWitness. // See https://github.com/rust-lang/project-stable-mir/issues/50. - check( - false, - format!("Function `{name}`: Missing type `{:?}`", local.ty), - )?; + check(false, format!("Function `{name}`: Missing type `{:?}`", local.ty))?; }; } Ok(visitor) diff --git a/tools/compiletest/Cargo.toml b/tools/compiletest/Cargo.toml deleted file mode 100644 index dedf166..0000000 --- a/tools/compiletest/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "compiletest" -description = "Run tests using compiletest-rs" -version = "0.0.0" -edition = "2021" - -[dependencies] -ui_test = "0.20.0" -clap = { version = "4.1.3", features = ["derive"] } - -[package.metadata.rust-analyzer] -# This crate uses #[feature(rustc_private)]. -# See https://github.com/rust-analyzer/rust-analyzer/pull/7891 -rustc_private = true diff --git a/tools/compiletest/build.rs b/tools/compiletest/build.rs deleted file mode 100644 index 63fcfb5..0000000 --- a/tools/compiletest/build.rs +++ /dev/null @@ -1,16 +0,0 @@ -use std::env; -use std::path::PathBuf; - -pub fn main() { - // Add rustup to the rpath in order to properly link with the correct rustc version. - let rustup_home = env::var("RUSTUP_HOME").unwrap(); - let toolchain = env::var("RUSTUP_TOOLCHAIN").unwrap(); - let rustc_lib: PathBuf = [&rustup_home, "toolchains", &toolchain, "lib"] - .iter() - .collect(); - println!( - "cargo:rustc-link-arg-bin=compiletest=-Wl,-rpath,{}", - rustc_lib.display() - ); - println!("cargo:rustc-env=RUSTC_LIB_PATH={}", rustc_lib.display()); -} diff --git a/tools/compiletest/src/args.rs b/tools/compiletest/src/args.rs deleted file mode 100644 index acdd003..0000000 --- a/tools/compiletest/src/args.rs +++ /dev/null @@ -1,131 +0,0 @@ -use std::ffi::OsString; -/// Create our own parser and build the Config from it. -use std::fmt::Debug; -use std::path::PathBuf; -use ui_test::{CommandBuilder, Config, OutputConflictHandling, RustfixMode}; - -#[derive(Copy, Clone, Debug, clap::ValueEnum)] -/// Decides what is expected of each test's exit status. -pub enum Mode { - /// The test passes a full execution of the rustc driver. - Pass, - /// The test produces an executable binary that can get executed on the host. - Run, - /// The rustc driver should emit an error. - Fail, - /// The test is currently failing but is expected to succeed. - /// This is used to add test cases that reproduce an existing bug. This help us identify issues - /// that may be "accidentally" fixed. - FixMe, - /// Run the tests, but always pass them as long as all annotations are satisfied and stderr files match. - Yolo, - /// The test passes a full execution of `cargo build` - CargoPass, -} - -#[derive(Debug, clap::Parser)] -#[command(version, name = "compiletest")] -pub struct Args { - /// The path where all tests are - #[arg(long)] - src_base: PathBuf, - - /// The mode according to ui_test modes. - #[arg(long, default_value = "yolo")] - mode: Mode, - - /// Path for the stable-mir driver. - #[arg(long)] - driver_path: PathBuf, - - /// Path for where the output should be stored. - #[arg(long)] - output_dir: PathBuf, - - #[arg(long)] - pub verbose: bool, - - /// Run test-driver on verbose mode to print test outputs. - #[arg(long)] - pub no_capture: bool, - - /// Override the output files when there's a difference instead of failing the test. - #[arg(long)] - pub bless: bool, -} - -impl From for ui_test::Mode { - /// Use rustc configuration as default but override arguments to fit our use case. - fn from(mode: Mode) -> ui_test::Mode { - match mode { - Mode::Pass | Mode::CargoPass => ui_test::Mode::Pass, - Mode::Run => ui_test::Mode::Run { exit_code: 0 }, - Mode::FixMe | Mode::Fail => ui_test::Mode::Fail { - require_patterns: false, - rustfix: RustfixMode::Disabled, - }, - Mode::Yolo => ui_test::Mode::Yolo { - rustfix: RustfixMode::Disabled, - }, - } - } -} - -impl From for Config { - /// Use rustc configuration as default but override arguments to fit our use case. - fn from(args: Args) -> Config { - let mut config = if matches!(args.mode, Mode::CargoPass) { - cargo_config(&args) - } else { - driver_config(&args) - }; - config.filter(r"\[T-DRIVE\].*\n", ""); - // Remove stable mir details, since they can include internal variables which are fairly - // unstable. - config.filter(r"(?[^`]*)`[^`]+`(?[^`]*)", "$a``$b"); - config.mode = ui_test::Mode::from(args.mode); - config.output_conflict_handling = if args.bless { - OutputConflictHandling::Bless - } else { - OutputConflictHandling::Error("Should Fail".to_string()) - }; - config.out_dir = args.output_dir; - //config.run_lib_path = PathBuf::from(env!("RUSTC_LIB_PATH")); - config - } -} - -fn rustc_flags(args: &Args) -> Vec { - let mut flags = vec!["--smir-check".into()]; - if args.verbose || args.no_capture { - flags.push("--smir-verbose".into()); - } - if matches!(args.mode, Mode::FixMe) { - // Enable checks that should pass but may trigger an existing issue. - flags.push("--smir-fixme".into()); - } - flags -} - -/// Configure cargo tests that will run the test-driver instead of rustc. -fn cargo_config(args: &Args) -> Config { - let mut config = Config::cargo(args.src_base.clone()); - config.program.envs.push(( - "RUST".into(), - Some(args.driver_path.clone().into_os_string()), - )); - config.program.envs.push(( - "CARGO_ENCODED_RUSTFLAGS".into(), - Some(rustc_flags(args).join(&OsString::from("\x1f")).into()), - )); - config -} - -/// Configure tests that will invoke the test-driver directly as rustc. -fn driver_config(args: &Args) -> Config { - let mut config = Config::rustc(args.src_base.clone()); - config.program = CommandBuilder::rustc(); - config.program.program = args.driver_path.clone(); - config.program.args = rustc_flags(args); - config -} diff --git a/tools/compiletest/src/main.rs b/tools/compiletest/src/main.rs deleted file mode 100644 index 1e96c79..0000000 --- a/tools/compiletest/src/main.rs +++ /dev/null @@ -1,39 +0,0 @@ -//! Run compiletest on a given folder. - -mod args; - -use clap::Parser; -use std::process::ExitCode; -use ui_test::{status_emitter, Config}; - -fn main() -> ExitCode { - let args = args::Args::parse(); - let verbose = args.verbose; - if verbose { - println!("args: ${args:?}"); - } - let config = Config::from(args); - if verbose { - println!("Compiler: {}", config.program.display()); - } - - let name = config.root_dir.display().to_string(); - - let text = if verbose { - status_emitter::Text::verbose() - } else { - status_emitter::Text::quiet() - }; - - let result = ui_test::run_tests_generic( - vec![config], - ui_test::default_file_filter, - ui_test::default_per_file_config, - (text, status_emitter::Gha:: { name }), - ); - if result.is_ok() { - ExitCode::SUCCESS - } else { - ExitCode::FAILURE - } -} diff --git a/x b/x new file mode 100755 index 0000000..d9231b8 --- /dev/null +++ b/x @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -eu + +# Assume we are inside rustc_public repository +ROOT_DIR=$(git rev-parse --show-toplevel) +# Mix the outputs so that we can do `cargo clean` in one go. +TARGET_DIR="$ROOT_DIR"/target + +REPO_TOOLCHAIN=$(rustup show active-toolchain | (read toolchain _; echo $toolchain)) +TOOLCHAIN="${TOOLCHAIN:-${REPO_TOOLCHAIN}}" + +cargo +${TOOLCHAIN} build --manifest-path "${ROOT_DIR}"/devtool/Cargo.toml \ + --target-dir "${TARGET_DIR}" + +"${TARGET_DIR}"/debug/devtool "$@"