src/bootstrap/src/core/build_steps/test.rs RUST 4,285 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 4,285.
1//! Build-and-run steps for `./x.py test` test fixtures2//!3//! `./x.py test` (aka [`Kind::Test`]) is currently allowed to reach build steps in other modules.4//! However, this contains ~all test parts we expect people to be able to build and run locally.56// (This file should be split up, but having tidy block all changes is not helpful.)7// ignore-tidy-filelength89use std::collections::HashSet;10use std::env::split_paths;11use std::ffi::{OsStr, OsString};12use std::path::{Path, PathBuf};13use std::{env, fs, iter};1415use build_helper::exit;1617use crate::core::build_steps::compile::{ArtifactKeepMode, Std, run_cargo};18use crate::core::build_steps::doc::{DocumentationFormat, prepare_doc_compiler};19use crate::core::build_steps::gcc::{Gcc, GccTargetPair, add_cg_gcc_cargo_flags};20use crate::core::build_steps::llvm::get_llvm_version;21use crate::core::build_steps::run::{get_completion_paths, get_help_path};22use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget;23use crate::core::build_steps::test::compiletest::CompiletestMode;24use crate::core::build_steps::tool::{25    self, RustcPrivateCompilers, SourceType, TEST_FLOAT_PARSE_ALLOW_FEATURES, Tool,26    ToolTargetBuildMode, get_tool_target_compiler,27};28use crate::core::build_steps::toolstate::ToolState;29use crate::core::build_steps::{compile, dist, llvm};30use crate::core::builder::{31    self, Alias, Builder, Compiler, Kind, RunConfig, ShouldRun, Step, StepMetadata,32    crate_description,33};34use crate::core::config::TargetSelection;35use crate::core::config::flags::{Subcommand, get_completion, top_level_help};36use crate::core::{android, debuggers};37use crate::utils::build_stamp::{self, BuildStamp};38use crate::utils::exec::{BootstrapCommand, command};39use crate::utils::helpers::{40    self, LldThreads, TestFilterCategory, add_dylib_path, add_rustdoc_cargo_linker_args,41    dylib_path, dylib_path_var, linker_args, linker_flags, t, target_supports_cranelift_backend,42    up_to_date,43};44use crate::utils::render_tests::{add_flags_and_try_run_tests, try_run_tests};45use crate::{CLang, CodegenBackendKind, GitRepo, Mode, PathSet, TestTarget, envify};4647mod compiletest;4849/// Runs `cargo test` on various internal tools used by bootstrap.50#[derive(Debug, Clone, PartialEq, Eq, Hash)]51pub struct CrateBootstrap {52    path: PathBuf,53    host: TargetSelection,54}5556impl Step for CrateBootstrap {57    type Output = ();58    const IS_HOST: bool = true;5960    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {61        // This step is responsible for several different tool paths.62        //63        // By default, it will test all of them, but requesting specific tools on the command-line64        // (e.g. `./x test src/tools/coverage-dump`) will test only the specified tools.65        run.path("src/tools/jsondoclint")66            .path("src/tools/replace-version-placeholder")67            .path("src/tools/coverage-dump")68            // We want `./x test tidy` to _run_ the tidy tool, not its tests.69            // So we need a separate alias to test the tidy tool itself.70            .alias("tidyselftest")71    }7273    fn is_default_step(_builder: &Builder<'_>) -> bool {74        true75    }7677    fn make_run(run: RunConfig<'_>) {78        // Create and ensure a separate instance of this step for each path79        // that was selected on the command-line (or selected by default).80        for path in run.paths {81            let path = path.assert_single_path().path.clone();82            run.builder.ensure(CrateBootstrap { host: run.target, path });83        }84    }8586    fn run(self, builder: &Builder<'_>) {87        let bootstrap_host = builder.config.host_target;88        let compiler = builder.compiler(0, bootstrap_host);89        let mut path = self.path.to_str().unwrap();9091        // Map alias `tidyselftest` back to the actual crate path of tidy.92        if path == "tidyselftest" {93            path = "src/tools/tidy";94        }9596        let cargo = tool::prepare_tool_cargo(97            builder,98            compiler,99            Mode::ToolBootstrap,100            bootstrap_host,101            Kind::Test,102            path,103            SourceType::InTree,104            &[],105        );106107        let crate_name = path.rsplit_once('/').unwrap().1;108        run_cargo_test(cargo, &[], &[], crate_name, bootstrap_host, builder);109    }110111    fn metadata(&self) -> Option<StepMetadata> {112        Some(113            StepMetadata::test("crate-bootstrap", self.host)114                .with_metadata(self.path.as_path().to_string_lossy().to_string()),115        )116    }117}118119#[derive(Debug, Clone, PartialEq, Eq, Hash)]120pub struct Linkcheck {121    host: TargetSelection,122}123124impl Step for Linkcheck {125    type Output = ();126    const IS_HOST: bool = true;127128    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {129        run.path("src/tools/linkchecker")130    }131132    fn is_default_step(builder: &Builder<'_>) -> bool {133        builder.config.docs134    }135136    fn make_run(run: RunConfig<'_>) {137        run.builder.ensure(Linkcheck { host: run.target });138    }139140    /// Runs the `linkchecker` tool as compiled in `stage` by the `host` compiler.141    ///142    /// This tool in `src/tools` will verify the validity of all our links in the143    /// documentation to ensure we don't have a bunch of dead ones.144    fn run(self, builder: &Builder<'_>) {145        let host = self.host;146        let hosts = &builder.hosts;147        let targets = &builder.targets;148149        // if we have different hosts and targets, some things may be built for150        // the host (e.g. rustc) and others for the target (e.g. std). The151        // documentation built for each will contain broken links to152        // docs built for the other platform (e.g. rustc linking to cargo)153        if (hosts != targets) && !hosts.is_empty() && !targets.is_empty() {154            panic!(155                "Linkcheck currently does not support builds with different hosts and targets.156You can skip linkcheck with --skip src/tools/linkchecker"157            );158        }159160        builder.info(&format!("Linkcheck ({host})"));161162        // Test the linkchecker itself.163        let bootstrap_host = builder.config.host_target;164        let compiler = builder.compiler(0, bootstrap_host);165166        let cargo = tool::prepare_tool_cargo(167            builder,168            compiler,169            Mode::ToolBootstrap,170            bootstrap_host,171            Kind::Test,172            "src/tools/linkchecker",173            SourceType::InTree,174            &[],175        );176        run_cargo_test(cargo, &[], &[], "linkchecker self tests", bootstrap_host, builder);177178        if !builder.test_target.runs_doctests() {179            return;180        }181182        // Build all the default documentation.183        builder.run_default_doc_steps();184185        // Build the linkchecker before calling `msg`, since GHA doesn't support nested groups.186        let linkchecker = builder.tool_cmd(Tool::Linkchecker);187188        // Run the linkchecker.189        let _guard = builder.msg_test("Linkcheck", bootstrap_host, 1);190        let _time = helpers::timeit(builder);191        linkchecker.delay_failure().arg(builder.out.join(host).join("doc")).run(builder);192    }193194    fn metadata(&self) -> Option<StepMetadata> {195        Some(StepMetadata::test("link-check", self.host))196    }197}198199fn check_if_tidy_is_installed(builder: &Builder<'_>) -> bool {200    command("tidy")201        .allow_failure()202        .arg("--version")203        // Cache the output to avoid running this command more than once (per builder).204        .cached()205        .run_capture_stdout(builder)206        .is_success()207}208209#[derive(Debug, Clone, PartialEq, Eq, Hash)]210pub struct HtmlCheck {211    target: TargetSelection,212}213214impl Step for HtmlCheck {215    type Output = ();216    const IS_HOST: bool = true;217218    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {219        run.path("src/tools/html-checker")220    }221222    fn is_default_step(builder: &Builder<'_>) -> bool {223        check_if_tidy_is_installed(builder)224    }225226    fn make_run(run: RunConfig<'_>) {227        run.builder.ensure(HtmlCheck { target: run.target });228    }229230    fn run(self, builder: &Builder<'_>) {231        if !check_if_tidy_is_installed(builder) {232            eprintln!("not running HTML-check tool because `tidy` is missing");233            eprintln!(234                "You need the HTML tidy tool https://www.html-tidy.org/, this tool is *not* part of the rust project and needs to be installed separately, for example via your package manager."235            );236            panic!("Cannot run html-check tests");237        }238        // Ensure that a few different kinds of documentation are available.239        builder.run_default_doc_steps();240        builder.ensure(crate::core::build_steps::doc::Rustc::for_stage(241            builder,242            builder.top_stage,243            self.target,244        ));245246        builder247            .tool_cmd(Tool::HtmlChecker)248            .delay_failure()249            .arg(builder.doc_out(self.target))250            .run(builder);251    }252253    fn metadata(&self) -> Option<StepMetadata> {254        Some(StepMetadata::test("html-check", self.target))255    }256}257258/// Builds cargo and then runs the `src/tools/cargotest` tool, which checks out259/// some representative crate repositories and runs `cargo test` on them, in260/// order to test cargo.261#[derive(Debug, Clone, PartialEq, Eq, Hash)]262pub struct Cargotest {263    build_compiler: Compiler,264    host: TargetSelection,265}266267impl Step for Cargotest {268    type Output = ();269    const IS_HOST: bool = true;270271    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {272        run.path("src/tools/cargotest")273    }274275    fn make_run(run: RunConfig<'_>) {276        if run.builder.top_stage == 0 {277            eprintln!(278                "ERROR: running cargotest with stage 0 is currently unsupported. Use at least stage 1."279            );280            exit!(1);281        }282        // We want to build cargo stage N (where N == top_stage), and rustc stage N,283        // and test both of these together.284        // So we need to get a build compiler stage N-1 to build the stage N components.285        run.builder.ensure(Cargotest {286            build_compiler: run.builder.compiler(run.builder.top_stage - 1, run.target),287            host: run.target,288        });289    }290291    /// Runs the `cargotest` tool as compiled in `stage` by the `host` compiler.292    ///293    /// This tool in `src/tools` will check out a few Rust projects and run `cargo294    /// test` to ensure that we don't regress the test suites there.295    fn run(self, builder: &Builder<'_>) {296        // cargotest's staging has several pieces:297        // consider ./x test cargotest --stage=2.298        //299        // The test goal is to exercise a (stage 2 cargo, stage 2 rustc) pair through a stage 2300        // cargotest tool.301        // To produce the stage 2 cargo and cargotest, we need to do so with the stage 1 rustc and std.302        // Importantly, the stage 2 rustc being tested (`tested_compiler`) via stage 2 cargotest is303        // the rustc built by an earlier stage 1 rustc (the build_compiler). These are two different304        // compilers!305        let cargo =306            builder.ensure(tool::Cargo::from_build_compiler(self.build_compiler, self.host));307        let tested_compiler = builder.compiler(self.build_compiler.stage + 1, self.host);308        builder.std(tested_compiler, self.host);309310        // Note that this is a short, cryptic, and not scoped directory name. This311        // is currently to minimize the length of path on Windows where we otherwise312        // quickly run into path name limit constraints.313        let out_dir = builder.out.join("ct");314        t!(fs::create_dir_all(&out_dir));315316        let _time = helpers::timeit(builder);317        let mut cmd = builder.tool_cmd(Tool::CargoTest);318        cmd.arg(&cargo.tool_path)319            .arg(&out_dir)320            .args(builder.config.test_args())321            .env("RUSTC", builder.rustc(tested_compiler))322            .env("RUSTDOC", builder.rustdoc_for_compiler(tested_compiler));323        add_rustdoc_cargo_linker_args(&mut cmd, builder, tested_compiler.host, LldThreads::No);324        cmd.delay_failure().run(builder);325    }326327    fn metadata(&self) -> Option<StepMetadata> {328        Some(StepMetadata::test("cargotest", self.host).stage(self.build_compiler.stage + 1))329    }330}331332/// Runs `cargo test` for cargo itself.333/// We label these tests as "cargo self-tests".334#[derive(Debug, Clone, PartialEq, Eq, Hash)]335pub struct Cargo {336    build_compiler: Compiler,337    host: TargetSelection,338}339340impl Cargo {341    const CRATE_PATH: &str = "src/tools/cargo";342}343344impl Step for Cargo {345    type Output = ();346    const IS_HOST: bool = true;347348    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {349        run.path(Self::CRATE_PATH)350    }351352    fn make_run(run: RunConfig<'_>) {353        run.builder.ensure(Cargo {354            build_compiler: get_tool_target_compiler(355                run.builder,356                ToolTargetBuildMode::Build(run.target),357            ),358            host: run.target,359        });360    }361362    /// Runs `cargo test` for `cargo` packaged with Rust.363    fn run(self, builder: &Builder<'_>) {364        // When we do a "stage 1 cargo self-test", it means that we test the stage 1 rustc365        // using stage 1 cargo. So we actually build cargo using the stage 0 compiler, and then366        // run its tests against the stage 1 compiler (called `tested_compiler` below).367        builder.ensure(tool::Cargo::from_build_compiler(self.build_compiler, self.host));368369        let tested_compiler = builder.compiler(self.build_compiler.stage + 1, self.host);370        builder.std(tested_compiler, self.host);371        // We also need to build rustdoc for cargo tests372        // It will be located in the bindir of `tested_compiler`, so we don't need to explicitly373        // pass its path to Cargo.374        builder.rustdoc_for_compiler(tested_compiler);375376        let cargo = tool::prepare_tool_cargo(377            builder,378            self.build_compiler,379            Mode::ToolTarget,380            self.host,381            Kind::Test,382            Self::CRATE_PATH,383            SourceType::Submodule,384            &[],385        );386387        // NOTE: can't use `run_cargo_test` because we need to overwrite `PATH`388        let mut cargo = prepare_cargo_test(cargo, &[], &[], self.host, builder);389390        // Don't run cross-compile tests, we may not have cross-compiled libstd libs391        // available.392        cargo.env("CFG_DISABLE_CROSS_TESTS", "1");393        // Forcibly disable tests using nightly features since any changes to394        // those features won't be able to land.395        cargo.env("CARGO_TEST_DISABLE_NIGHTLY", "1");396397        // Configure PATH to find the right rustc. NB. we have to use PATH398        // and not RUSTC because the Cargo test suite has tests that will399        // fail if rustc is not spelled `rustc`.400        cargo.env("PATH", bin_path_for_cargo(builder, tested_compiler));401402        // The `cargo` command configured above has dylib dir path set to the `build_compiler`'s403        // libdir. That causes issues in cargo test, because the programs that cargo compiles are404        // incorrectly picking that libdir, even though they should be picking the405        // `tested_compiler`'s libdir. We thus have to override the precedence here.406        let mut existing_dylib_paths = cargo407            .get_envs()408            .find(|(k, _)| *k == OsStr::new(dylib_path_var()))409            .and_then(|(_, v)| v)410            .map(|value| split_paths(value).collect::<Vec<PathBuf>>())411            .unwrap_or_default();412        existing_dylib_paths.insert(0, builder.rustc_libdir(tested_compiler));413        add_dylib_path(existing_dylib_paths, &mut cargo);414415        // Cargo's test suite uses `CARGO_RUSTC_CURRENT_DIR` to determine the path that `file!` is416        // relative to. Cargo no longer sets this env var, so we have to do that. This has to be the417        // same value as `-Zroot-dir`.418        cargo.env("CARGO_RUSTC_CURRENT_DIR", builder.src.display().to_string());419420        #[cfg(feature = "build-metrics")]421        builder.metrics.begin_test_suite(422            build_helper::metrics::TestSuiteMetadata::CargoPackage {423                crates: vec!["cargo".into()],424                target: self.host.triple.to_string(),425                host: self.host.triple.to_string(),426                stage: self.build_compiler.stage + 1,427            },428            builder,429        );430431        let _time = helpers::timeit(builder);432        add_flags_and_try_run_tests(builder, &mut cargo);433    }434435    fn metadata(&self) -> Option<StepMetadata> {436        Some(StepMetadata::test("cargo", self.host).built_by(self.build_compiler))437    }438}439440#[derive(Debug, Clone, PartialEq, Eq, Hash)]441pub struct RustAnalyzer {442    compilers: RustcPrivateCompilers,443}444445impl Step for RustAnalyzer {446    type Output = ();447    const IS_HOST: bool = true;448449    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {450        run.path("src/tools/rust-analyzer")451    }452453    fn is_default_step(_builder: &Builder<'_>) -> bool {454        true455    }456457    fn make_run(run: RunConfig<'_>) {458        run.builder.ensure(Self {459            compilers: RustcPrivateCompilers::new(460                run.builder,461                run.builder.top_stage,462                run.builder.host_target,463            ),464        });465    }466467    /// Runs `cargo test` for rust-analyzer468    fn run(self, builder: &Builder<'_>) {469        let build_compiler = self.compilers.build_compiler();470        let target = self.compilers.target();471472        // NOTE: rust-analyzer repo currently (as of 2025-12-11) does not run tests against 32-bit473        // targets, so we also don't run them in rust-lang/rust CI (because that will just mean that474        // subtree syncs will keep getting 32-bit-specific failures that are not observed in475        // rust-analyzer repo CI).476        //477        // Some 32-bit specific failures include e.g. target pointer width specific hashes.478479        // FIXME: eventually, we should probably reduce the amount of target tuple substring480        // matching in bootstrap.481        if target.starts_with("i686") {482            return;483        }484485        let mut cargo = tool::prepare_tool_cargo(486            builder,487            build_compiler,488            Mode::ToolRustcPrivate,489            target,490            Kind::Test,491            "src/tools/rust-analyzer",492            SourceType::InTree,493            &["in-rust-tree".to_owned()],494        );495        cargo.allow_features(tool::RustAnalyzer::ALLOW_FEATURES);496497        // N.B. it turns out _setting_ `CARGO_WORKSPACE_DIR` actually somehow breaks `expect-test`,498        // even though previously we actually needed to set that hack to allow `expect-test` to499        // correctly discover the r-a workspace instead of the outer r-l/r workspace.500501        // FIXME: RA's test suite tries to write to the source directory, that can't work in Rust CI502        // without properly wiring up the writable test dir.503        cargo.env("SKIP_SLOW_TESTS", "1");504505        // NOTE: we need to skip `src/tools/rust-analyzer/xtask` as they seem to exercise rustup /506        // stable rustfmt.507        //508        // NOTE: you can only skip a specific workspace package via `--exclude=...` if you *also*509        // specify `--workspace`.510        cargo.arg("--workspace");511        cargo.arg("--exclude=xtask");512513        if build_compiler.stage == 0 {514            // This builds a proc macro against the bootstrap libproc_macro, which is not ABI515            // compatible with the ABI proc-macro-srv expects to load.516            cargo.arg("--exclude=proc-macro-srv");517            cargo.arg("--exclude=proc-macro-srv-cli");518        }519520        let mut skip_tests = vec![];521522        // NOTE: the following test skips is a bit cheeky in that it assumes there are no523        // identically named tests across different r-a packages, where we want to run the524        // identically named test in one package but not another. If we want to support that use525        // case, we'd have to run the r-a tests in two batches (with one excluding the package that526        // we *don't* want to run the test for, and the other batch including).527528        // Across all platforms.529        skip_tests.extend_from_slice(&[530            // FIXME: this test wants to find a `rustc`. We need to provide it with a path to staged531            // in-tree `rustc`, but setting `RUSTC` env var requires some reworking of bootstrap.532            "tests::smoke_test_real_sysroot_cargo",533            // NOTE: part of `smol-str` test suite; this tries to access a stable rustfmt from the534            // environment, which is not something we want to do.535            "check_code_formatting",536        ]);537538        let skip_tests = skip_tests.iter().map(|name| format!("--skip={name}")).collect::<Vec<_>>();539        let skip_tests = skip_tests.iter().map(|s| s.as_str()).collect::<Vec<_>>();540541        cargo.add_rustc_lib_path(builder);542        run_cargo_test(cargo, skip_tests.as_slice(), &[], "rust-analyzer", target, builder);543    }544545    fn metadata(&self) -> Option<StepMetadata> {546        Some(547            StepMetadata::test("rust-analyzer", self.compilers.target())548                .built_by(self.compilers.build_compiler()),549        )550    }551}552553/// Runs `cargo test` for rustfmt.554#[derive(Debug, Clone, PartialEq, Eq, Hash)]555pub struct Rustfmt {556    compilers: RustcPrivateCompilers,557}558559impl Step for Rustfmt {560    type Output = ();561    const IS_HOST: bool = true;562563    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {564        run.path("src/tools/rustfmt")565    }566567    fn make_run(run: RunConfig<'_>) {568        run.builder.ensure(Rustfmt {569            compilers: RustcPrivateCompilers::new(570                run.builder,571                run.builder.top_stage,572                run.builder.host_target,573            ),574        });575    }576577    /// Runs `cargo test` for rustfmt.578    fn run(self, builder: &Builder<'_>) {579        let build_compiler = self.compilers.build_compiler();580        let target = self.compilers.target();581582        let mut cargo = tool::prepare_tool_cargo(583            builder,584            build_compiler,585            Mode::ToolRustcPrivate,586            target,587            Kind::Test,588            "src/tools/rustfmt",589            SourceType::InTree,590            &[],591        );592593        let dir = testdir(builder, target);594        t!(fs::create_dir_all(&dir));595        cargo.env("RUSTFMT_TEST_DIR", dir);596597        cargo.add_rustc_lib_path(builder);598599        run_cargo_test(cargo, &[], &[], "rustfmt", target, builder);600    }601602    fn metadata(&self) -> Option<StepMetadata> {603        Some(604            StepMetadata::test("rustfmt", self.compilers.target())605                .built_by(self.compilers.build_compiler()),606        )607    }608}609610#[derive(Debug, Clone, PartialEq, Eq, Hash)]611pub struct Miri {612    target: TargetSelection,613}614615impl Miri {616    /// Run `cargo miri setup` for the given target, return where the Miri sysroot was put.617    pub fn build_miri_sysroot(618        builder: &Builder<'_>,619        compiler: Compiler,620        target: TargetSelection,621    ) -> PathBuf {622        let miri_sysroot = builder.out.join(compiler.host).join("miri-sysroot");623        let mut cargo = builder::Cargo::new(624            builder,625            compiler,626            Mode::Std,627            SourceType::Submodule,628            target,629            Kind::MiriSetup,630        );631632        // Tell `cargo miri setup` where to find the sources.633        cargo.env("MIRI_LIB_SRC", builder.src.join("library"));634        // Tell it where to put the sysroot.635        cargo.env("MIRI_SYSROOT", &miri_sysroot);636637        let mut cargo = BootstrapCommand::from(cargo);638        let _guard =639            builder.msg(Kind::Build, "miri sysroot", Mode::ToolRustcPrivate, compiler, target);640        cargo.run(builder);641642        // # Determine where Miri put its sysroot.643        // To this end, we run `cargo miri setup --print-sysroot` and capture the output.644        // (We do this separately from the above so that when the setup actually645        // happens we get some output.)646        // We re-use the `cargo` from above.647        cargo.arg("--print-sysroot");648649        builder.do_if_verbose(|| println!("running: {cargo:?}"));650        let stdout = cargo.run_capture_stdout(builder).stdout();651        // Output is "<sysroot>\n".652        let sysroot = stdout.trim_end();653        builder.do_if_verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}"));654        PathBuf::from(sysroot)655    }656}657658impl Step for Miri {659    type Output = ();660661    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {662        run.path("src/tools/miri")663    }664665    fn make_run(run: RunConfig<'_>) {666        run.builder.ensure(Miri { target: run.target });667    }668669    /// Runs `cargo test` for miri.670    fn run(self, builder: &Builder<'_>) {671        let host = builder.build.host_target;672        let target = self.target;673        let stage = builder.top_stage;674        if stage == 0 {675            eprintln!("miri cannot be tested at stage 0");676            std::process::exit(1);677        }678679        // This compiler runs on the host, we'll just use it for the target.680        let compilers = RustcPrivateCompilers::new(builder, stage, host);681682        // Build our tools.683        let miri = builder.ensure(tool::Miri::from_compilers(compilers));684        // the ui tests also assume cargo-miri has been built685        builder.ensure(tool::CargoMiri::from_compilers(compilers));686687        let target_compiler = compilers.target_compiler();688689        // We also need sysroots, for Miri and for the host (the latter for build scripts).690        // This is for the tests so everything is done with the target compiler.691        let miri_sysroot = Miri::build_miri_sysroot(builder, target_compiler, target);692        builder.std(target_compiler, host);693        let host_sysroot = builder.sysroot(target_compiler);694695        // Miri has its own "target dir" for ui test dependencies. Make sure it gets cleared when696        // the sysroot gets rebuilt, to avoid "found possibly newer version of crate `std`" errors.697        if !builder.config.dry_run() {698            // This has to match `CARGO_TARGET_TMPDIR` in Miri's `ui.rs`.699            // This means we need `host` here as that's the target `ui.rs` is built for.700            let ui_test_dep_dir = builder701                .stage_out(miri.build_compiler, Mode::ToolStd)702                .join(host)703                .join("tmp")704                .join("miri_ui");705            // The mtime of `miri_sysroot` changes when the sysroot gets rebuilt (also see706            // <https://github.com/RalfJung/rustc-build-sysroot/commit/10ebcf60b80fe2c3dc765af0ff19fdc0da4b7466>).707            // We can hence use that directly as a signal to clear the ui test dir.708            build_stamp::clear_if_dirty(builder, &ui_test_dep_dir, &miri_sysroot);709        }710711        // Run `cargo test`.712        // This is with the Miri crate, so it uses the host compiler.713        let mut cargo = tool::prepare_tool_cargo(714            builder,715            miri.build_compiler,716            Mode::ToolRustcPrivate,717            host,718            Kind::Test,719            "src/tools/miri",720            SourceType::InTree,721            &[],722        );723724        cargo.add_rustc_lib_path(builder);725726        // We can NOT use `run_cargo_test` since Miri's integration tests do not use the usual test727        // harness and therefore do not understand the flags added by `add_flags_and_try_run_test`.728        let mut cargo = prepare_cargo_test(cargo, &[], &[], host, builder);729730        // miri tests need to know about the stage sysroot731        cargo.env("MIRI_SYSROOT", &miri_sysroot);732        cargo.env("MIRI_HOST_SYSROOT", &host_sysroot);733734        // Set the target.735        cargo.env("MIRI_TEST_TARGET", target.rustc_target_arg());736737        {738            let _guard = builder.msg_test("miri", target, target_compiler.stage);739            let _time = helpers::timeit(builder);740            cargo.run(builder);741        }742743        // Run it again for mir-opt-level 4 to catch some miscompilations.744        if builder.config.test_args().is_empty() {745            cargo.env(746                "MIRIFLAGS",747                format!(748                    "{} -O -Zmir-opt-level=4 -Cdebug-assertions=yes",749                    env::var("MIRIFLAGS").unwrap_or_default()750                ),751            );752            // Optimizations can change backtraces753            cargo.env("MIRI_SKIP_UI_CHECKS", "1");754            // `MIRI_SKIP_UI_CHECKS` and `RUSTC_BLESS` are incompatible755            cargo.env_remove("RUSTC_BLESS");756            // Optimizations can change error locations and remove UB so don't run `fail` tests.757            cargo.args(["tests/pass", "tests/panic"]);758759            {760                let _guard =761                    builder.msg_test("miri (mir-opt-level 4)", target, target_compiler.stage);762                let _time = helpers::timeit(builder);763                cargo.run(builder);764            }765        }766    }767}768769/// Runs `cargo miri test` to demonstrate that `src/tools/miri/cargo-miri`770/// works and that libtest works under miri.771#[derive(Debug, Clone, PartialEq, Eq, Hash)]772pub struct CargoMiri {773    target: TargetSelection,774}775776impl Step for CargoMiri {777    type Output = ();778779    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {780        run.path("src/tools/miri/cargo-miri")781    }782783    fn make_run(run: RunConfig<'_>) {784        run.builder.ensure(CargoMiri { target: run.target });785    }786787    /// Tests `cargo miri test`.788    fn run(self, builder: &Builder<'_>) {789        let host = builder.build.host_target;790        let target = self.target;791        let stage = builder.top_stage;792        if stage == 0 {793            eprintln!("cargo-miri cannot be tested at stage 0");794            std::process::exit(1);795        }796797        // This compiler runs on the host, we'll just use it for the target.798        let build_compiler = builder.compiler(stage, host);799800        // Run `cargo miri test`.801        // This is just a smoke test (Miri's own CI invokes this in a bunch of different ways and ensures802        // that we get the desired output), but that is sufficient to make sure that the libtest harness803        // itself executes properly under Miri, and that all the logic in `cargo-miri` does not explode.804        let mut cargo = tool::prepare_tool_cargo(805            builder,806            build_compiler,807            Mode::ToolStd, // it's unclear what to use here, we're not building anything just doing a smoke test!808            target,809            Kind::MiriTest,810            "src/tools/miri/test-cargo-miri",811            SourceType::Submodule,812            &[],813        );814815        // If we are testing stage 2+ cargo miri, make sure that it works with the in-tree cargo.816        // We want to do this *somewhere* to ensure that Miri + nightly cargo actually works.817        if stage >= 2 {818            let built_cargo = builder819                .ensure(tool::Cargo::from_build_compiler(820                    // Build stage 1 cargo here, we don't need it to be built in any special way,821                    // just that it is built from in-tree sources.822                    builder.compiler(0, builder.host_target),823                    builder.host_target,824                ))825                .tool_path;826            cargo.env("CARGO", built_cargo);827        }828829        // We're not using `prepare_cargo_test` so we have to do this ourselves.830        // (We're not using that as the test-cargo-miri crate is not known to bootstrap.)831        match builder.test_target {832            TestTarget::AllTargets => {833                cargo.args(["--lib", "--bins", "--examples", "--tests", "--benches"])834            }835            TestTarget::Default => &mut cargo,836            TestTarget::DocOnly => cargo.arg("--doc"),837            TestTarget::Tests => cargo.arg("--tests"),838        };839        cargo.arg("--").args(builder.config.test_args());840841        // Finally, run everything.842        let mut cargo = BootstrapCommand::from(cargo);843        {844            let _guard = builder.msg_test("cargo-miri", target, stage);845            let _time = helpers::timeit(builder);846            cargo.run(builder);847        }848    }849}850851#[derive(Debug, Clone, PartialEq, Eq, Hash)]852pub struct CompiletestTest {853    host: TargetSelection,854}855856impl Step for CompiletestTest {857    type Output = ();858859    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {860        run.path("src/tools/compiletest")861    }862863    fn make_run(run: RunConfig<'_>) {864        run.builder.ensure(CompiletestTest { host: run.target });865    }866867    /// Runs `cargo test` for compiletest.868    fn run(self, builder: &Builder<'_>) {869        let host = self.host;870871        // Now that compiletest uses only stable Rust, building it always uses872        // the stage 0 compiler. However, some of its unit tests need to be able873        // to query information from an in-tree compiler, so we treat `--stage`874        // as selecting the stage of that secondary compiler.875876        if builder.top_stage == 0 && !builder.config.compiletest_allow_stage0 {877            eprintln!("\878ERROR: `--stage 0` causes compiletest to query information from the stage0 (precompiled) compiler, instead of the in-tree compiler, which can cause some tests to fail inappropriately879NOTE: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `--set build.compiletest-allow-stage0=true`."880            );881            crate::exit!(1);882        }883884        let bootstrap_compiler = builder.compiler(0, host);885        let staged_compiler = builder.compiler(builder.top_stage, host);886887        let mut cargo = tool::prepare_tool_cargo(888            builder,889            bootstrap_compiler,890            Mode::ToolBootstrap,891            host,892            Kind::Test,893            "src/tools/compiletest",894            SourceType::InTree,895            &[],896        );897898        // Used for `compiletest` self-tests to have the path to the *staged* compiler. Getting this899        // right is important, as `compiletest` is intended to only support one target spec JSON900        // format, namely that of the staged compiler.901        cargo.env("TEST_RUSTC", builder.rustc(staged_compiler));902903        run_cargo_test(cargo, &[], &[], "compiletest self test", host, builder);904    }905}906907#[derive(Debug, Clone, PartialEq, Eq, Hash)]908pub struct Clippy {909    compilers: RustcPrivateCompilers,910}911912impl Step for Clippy {913    type Output = ();914    const IS_HOST: bool = true;915916    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {917        run.suite_path("src/tools/clippy/tests").path("src/tools/clippy")918    }919920    fn is_default_step(_builder: &Builder<'_>) -> bool {921        false922    }923924    fn make_run(run: RunConfig<'_>) {925        run.builder.ensure(Clippy {926            compilers: RustcPrivateCompilers::new(927                run.builder,928                run.builder.top_stage,929                run.builder.host_target,930            ),931        });932    }933934    /// Runs `cargo test` for clippy.935    fn run(self, builder: &Builder<'_>) {936        let target = self.compilers.target();937938        // We need to carefully distinguish the compiler that builds clippy, and the compiler939        // that is linked into the clippy being tested. `target_compiler` is the latter,940        // and it must also be used by clippy's test runner to build tests and their dependencies.941        let target_compiler = self.compilers.target_compiler();942        let build_compiler = self.compilers.build_compiler();943944        let mut cargo = tool::prepare_tool_cargo(945            builder,946            build_compiler,947            Mode::ToolRustcPrivate,948            target,949            Kind::Test,950            "src/tools/clippy",951            SourceType::InTree,952            &[],953        );954955        cargo.env("RUSTC_TEST_SUITE", builder.rustc(build_compiler));956        cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(build_compiler));957        let host_libs = builder958            .stage_out(build_compiler, Mode::ToolRustcPrivate)959            .join(builder.cargo_dir(Mode::ToolRustcPrivate));960        cargo.env("HOST_LIBS", host_libs);961962        // Build the standard library that the tests can use.963        builder.std(target_compiler, target);964        cargo.env("TEST_SYSROOT", builder.sysroot(target_compiler));965        cargo.env("TEST_RUSTC", builder.rustc(target_compiler));966        cargo.env("TEST_RUSTC_LIB", builder.rustc_libdir(target_compiler));967968        // Collect paths of tests to run969        'partially_test: {970            let paths = &builder.config.paths[..];971            let mut test_names = Vec::new();972            for path in paths {973                match helpers::is_valid_test_suite_arg(path, "src/tools/clippy/tests", builder) {974                    TestFilterCategory::Arg(path) => {975                        test_names.push(path);976                    }977                    TestFilterCategory::Fullsuite => {978                        // When src/tools/clippy is called directly, all tests should be run.979                        break 'partially_test;980                    }981                    TestFilterCategory::Uninteresting => {}982                }983            }984            cargo.env("TESTNAME", test_names.join(","));985        }986987        cargo.add_rustc_lib_path(builder);988        let cargo = prepare_cargo_test(cargo, &[], &[], target, builder);989990        let _guard = builder.msg_test("clippy", target, target_compiler.stage);991992        // Clippy reports errors if it blessed the outputs993        if cargo.allow_failure().run(builder) {994            // The tests succeeded; nothing to do.995            return;996        }997998        if !builder.config.cmd.bless() {999            crate::exit!(1);1000        }1001    }10021003    fn metadata(&self) -> Option<StepMetadata> {1004        Some(1005            StepMetadata::test("clippy", self.compilers.target())1006                .built_by(self.compilers.build_compiler()),1007        )1008    }1009}10101011fn bin_path_for_cargo(builder: &Builder<'_>, compiler: Compiler) -> OsString {1012    let path = builder.sysroot(compiler).join("bin");1013    let old_path = env::var_os("PATH").unwrap_or_default();1014    env::join_paths(iter::once(path).chain(env::split_paths(&old_path))).expect("")1015}10161017/// Run the rustdoc-themes tool to test a given compiler.1018#[derive(Debug, Clone, Hash, PartialEq, Eq)]1019pub struct RustdocTheme {1020    /// The compiler (more accurately, its rustdoc) that we test.1021    test_compiler: Compiler,1022}10231024impl Step for RustdocTheme {1025    type Output = ();1026    const IS_HOST: bool = true;10271028    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1029        run.path("src/tools/rustdoc-themes")1030    }10311032    fn is_default_step(_builder: &Builder<'_>) -> bool {1033        true1034    }10351036    fn make_run(run: RunConfig<'_>) {1037        let test_compiler = run.builder.compiler(run.builder.top_stage, run.target);10381039        run.builder.ensure(RustdocTheme { test_compiler });1040    }10411042    fn run(self, builder: &Builder<'_>) {1043        let rustdoc = builder.bootstrap_out.join("rustdoc");1044        let mut cmd = builder.tool_cmd(Tool::RustdocTheme);1045        cmd.arg(rustdoc.to_str().unwrap())1046            .arg(builder.src.join("src/librustdoc/html/static/css/rustdoc.css").to_str().unwrap())1047            .env("RUSTC_STAGE", self.test_compiler.stage.to_string())1048            .env("RUSTC_SYSROOT", builder.sysroot(self.test_compiler))1049            .env(1050                "RUSTDOC_LIBDIR",1051                builder.sysroot_target_libdir(self.test_compiler, self.test_compiler.host),1052            )1053            .env("CFG_RELEASE_CHANNEL", &builder.config.channel)1054            .env("RUSTDOC_REAL", builder.rustdoc_for_compiler(self.test_compiler))1055            .env("RUSTC_BOOTSTRAP", "1");1056        cmd.args(linker_args(builder, self.test_compiler.host, LldThreads::No));10571058        cmd.delay_failure().run(builder);1059    }10601061    fn metadata(&self) -> Option<StepMetadata> {1062        Some(1063            StepMetadata::test("rustdoc-theme", self.test_compiler.host)1064                .stage(self.test_compiler.stage),1065        )1066    }1067}10681069/// Test rustdoc JS for the standard library.1070#[derive(Debug, Clone, Hash, PartialEq, Eq)]1071pub struct RustdocJSStd {1072    /// Compiler that will build the standary library.1073    build_compiler: Compiler,1074    target: TargetSelection,1075}10761077impl Step for RustdocJSStd {1078    type Output = ();1079    const IS_HOST: bool = true;10801081    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1082        run.suite_path("tests/rustdoc-js-std")1083    }10841085    fn is_default_step(builder: &Builder<'_>) -> bool {1086        builder.config.nodejs.is_some()1087    }10881089    fn make_run(run: RunConfig<'_>) {1090        run.builder.ensure(RustdocJSStd {1091            build_compiler: run.builder.compiler(run.builder.top_stage, run.builder.host_target),1092            target: run.target,1093        });1094    }10951096    fn run(self, builder: &Builder<'_>) {1097        let nodejs =1098            builder.config.nodejs.as_ref().expect("need nodejs to run rustdoc-js-std tests");1099        let mut command = command(nodejs);1100        command1101            .arg(builder.src.join("src/tools/rustdoc-js/tester.js"))1102            .arg("--crate-name")1103            .arg("std")1104            .arg("--resource-suffix")1105            .arg(&builder.version)1106            .arg("--doc-folder")1107            .arg(builder.doc_out(self.target))1108            .arg("--test-folder")1109            .arg(builder.src.join("tests/rustdoc-js-std"));11101111        let full_suite = builder.paths.iter().any(|path| {1112            matches!(1113                helpers::is_valid_test_suite_arg(path, "tests/rustdoc-js-std", builder),1114                TestFilterCategory::Fullsuite1115            )1116        });11171118        // If we have to also run the full suite, don't worry about the individual arguments.1119        // They will be covered by running the entire suite1120        if !full_suite {1121            for path in &builder.paths {1122                if let TestFilterCategory::Arg(p) =1123                    helpers::is_valid_test_suite_arg(path, "tests/rustdoc-js-std", builder)1124                {1125                    if !p.ends_with(".js") {1126                        eprintln!("A non-js file was given: `{}`", path.display());1127                        panic!("Cannot run rustdoc-js-std tests");1128                    }1129                    command.arg("--test-file").arg(path);1130                }1131            }1132        }11331134        builder.ensure(crate::core::build_steps::doc::Std::from_build_compiler(1135            self.build_compiler,1136            self.target,1137            DocumentationFormat::Html,1138        ));1139        let _guard = builder.msg_test("rustdoc-js-std", self.target, self.build_compiler.stage);1140        command.run(builder);1141    }11421143    fn metadata(&self) -> Option<StepMetadata> {1144        Some(StepMetadata::test("rustdoc-js-std", self.target).stage(self.build_compiler.stage))1145    }1146}11471148#[derive(Debug, Clone, Hash, PartialEq, Eq)]1149pub struct RustdocJSNotStd {1150    pub target: TargetSelection,1151    pub compiler: Compiler,1152}11531154impl Step for RustdocJSNotStd {1155    type Output = ();1156    const IS_HOST: bool = true;11571158    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1159        run.suite_path("tests/rustdoc-js")1160    }11611162    fn is_default_step(builder: &Builder<'_>) -> bool {1163        builder.config.nodejs.is_some()1164    }11651166    fn make_run(run: RunConfig<'_>) {1167        let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());1168        run.builder.ensure(RustdocJSNotStd { target: run.target, compiler });1169    }11701171    fn run(self, builder: &Builder<'_>) {1172        builder.ensure(Compiletest {1173            test_compiler: self.compiler,1174            target: self.target,1175            mode: CompiletestMode::RustdocJs,1176            suite: "rustdoc-js",1177            path: "tests/rustdoc-js",1178            compare_mode: None,1179        });1180    }1181}11821183fn get_browser_ui_test_version_inner(1184    builder: &Builder<'_>,1185    yarn: &Path,1186    global: bool,1187) -> Option<String> {1188    let mut command = command(yarn);1189    command1190        .arg("--cwd")1191        .arg(&builder.build.out)1192        .arg("list")1193        .arg("--parseable")1194        .arg("--long")1195        .arg("--depth=0");1196    if global {1197        command.arg("--global");1198    }1199    // Cache the command output so that `test::RustdocGUI` only performs these1200    // command-line probes once.1201    let lines = command.allow_failure().cached().run_capture(builder).stdout();1202    lines1203        .lines()1204        .find_map(|l| l.split(':').nth(1)?.strip_prefix("browser-ui-test@"))1205        .map(|v| v.to_owned())1206}12071208fn get_browser_ui_test_version(builder: &Builder<'_>) -> Option<String> {1209    let yarn = builder.config.yarn.as_deref()?;1210    get_browser_ui_test_version_inner(builder, yarn, false)1211        .or_else(|| get_browser_ui_test_version_inner(builder, yarn, true))1212}12131214/// Run GUI tests on a given rustdoc.1215#[derive(Debug, Clone, Hash, PartialEq, Eq)]1216pub struct RustdocGUI {1217    /// The compiler whose rustdoc we are testing.1218    test_compiler: Compiler,1219    target: TargetSelection,1220}12211222impl Step for RustdocGUI {1223    type Output = ();1224    const IS_HOST: bool = true;12251226    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1227        run.suite_path("tests/rustdoc-gui")1228    }12291230    fn is_default_step(builder: &Builder<'_>) -> bool {1231        builder.config.nodejs.is_some()1232            && builder.test_target != TestTarget::DocOnly1233            && get_browser_ui_test_version(builder).is_some()1234    }12351236    fn make_run(run: RunConfig<'_>) {1237        let test_compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());1238        run.builder.ensure(RustdocGUI { test_compiler, target: run.target });1239    }12401241    fn run(self, builder: &Builder<'_>) {1242        builder.std(self.test_compiler, self.target);12431244        let mut cmd = builder.tool_cmd(Tool::RustdocGUITest);12451246        let out_dir = builder.test_out(self.target).join("rustdoc-gui");1247        build_stamp::clear_if_dirty(1248            builder,1249            &out_dir,1250            &builder.rustdoc_for_compiler(self.test_compiler),1251        );12521253        if let Some(src) = builder.config.src.to_str() {1254            cmd.arg("--rust-src").arg(src);1255        }12561257        if let Some(out_dir) = out_dir.to_str() {1258            cmd.arg("--out-dir").arg(out_dir);1259        }12601261        if let Some(initial_cargo) = builder.config.initial_cargo.to_str() {1262            cmd.arg("--initial-cargo").arg(initial_cargo);1263        }12641265        cmd.arg("--jobs").arg(builder.jobs().to_string());12661267        cmd.env("RUSTDOC", builder.rustdoc_for_compiler(self.test_compiler))1268            .env("RUSTC", builder.rustc(self.test_compiler));12691270        add_rustdoc_cargo_linker_args(&mut cmd, builder, self.test_compiler.host, LldThreads::No);12711272        let full_suite = builder.paths.iter().any(|path| {1273            matches!(1274                helpers::is_valid_test_suite_arg(path, "tests/rustdoc-js-std", builder),1275                TestFilterCategory::Fullsuite1276            )1277        });12781279        // If we have to also run the full suite, don't worry about the individual arguments.1280        // They will be covered by running the entire suite1281        if !full_suite {1282            for path in &builder.paths {1283                if let TestFilterCategory::Arg(p) =1284                    helpers::is_valid_test_suite_arg(path, "tests/rustdoc-gui", builder)1285                {1286                    if !p.ends_with(".goml") {1287                        eprintln!("A non-goml file was given: `{}`", path.display());1288                        panic!("Cannot run rustdoc-gui tests");1289                    }1290                    if let Some(name) = path.file_name().and_then(|f| f.to_str()) {1291                        cmd.arg("--goml-file").arg(name);1292                    }1293                }1294            }1295        }12961297        for test_arg in builder.config.test_args() {1298            cmd.arg("--test-arg").arg(test_arg);1299        }13001301        if let Some(ref nodejs) = builder.config.nodejs {1302            cmd.arg("--nodejs").arg(nodejs);1303        }13041305        if let Some(ref yarn) = builder.config.yarn {1306            cmd.arg("--yarn").arg(yarn);1307        }13081309        let _time = helpers::timeit(builder);1310        let _guard = builder.msg_test("rustdoc-gui", self.target, self.test_compiler.stage);1311        try_run_tests(builder, &mut cmd, true);1312    }13131314    fn metadata(&self) -> Option<StepMetadata> {1315        Some(StepMetadata::test("rustdoc-gui", self.target).stage(self.test_compiler.stage))1316    }1317}13181319/// Runs `src/tools/tidy` and `cargo fmt --check` to detect various style1320/// problems in the repository.1321///1322/// (To run the tidy tool's internal tests, use the alias "tidyselftest" instead.)1323#[derive(Debug, Clone, PartialEq, Eq, Hash)]1324pub struct Tidy;13251326impl Step for Tidy {1327    type Output = ();1328    const IS_HOST: bool = true;13291330    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1331        run.path("src/tools/tidy")1332    }13331334    fn is_default_step(builder: &Builder<'_>) -> bool {1335        builder.test_target != TestTarget::DocOnly1336    }13371338    fn make_run(run: RunConfig<'_>) {1339        run.builder.ensure(Tidy);1340    }13411342    /// Runs the `tidy` tool.1343    ///1344    /// This tool in `src/tools` checks up on various bits and pieces of style and1345    /// otherwise just implements a few lint-like checks that are specific to the1346    /// compiler itself.1347    ///1348    /// Once tidy passes, this step also runs `fmt --check` if tests are being run1349    /// for the `dev` or `nightly` channels.1350    fn run(self, builder: &Builder<'_>) {1351        let mut cmd = builder.tool_cmd(Tool::Tidy);1352        cmd.arg(format!("--root-path={}", builder.src.display()));1353        cmd.arg(format!("--cargo-path={}", builder.initial_cargo.display()));1354        cmd.arg(format!("--output-dir={}", builder.out.display()));1355        // Tidy is heavily IO constrained. Still respect `-j`, but use a higher limit if `jobs` hasn't been configured.1356        let jobs = builder.config.jobs.unwrap_or_else(|| {1357            8 * std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get) as u321358        });1359        cmd.arg(format!("--concurrency={jobs}"));1360        // pass the path to the yarn command used for installing js deps.1361        if let Some(yarn) = &builder.config.yarn {1362            cmd.arg(format!("--npm-path={}", yarn.display()));1363        } else {1364            cmd.arg("--npm-path=yarn");1365        }1366        if builder.is_verbose() {1367            cmd.arg("--verbose");1368        }1369        if builder.config.cmd.bless() {1370            cmd.arg("--bless");1371        }1372        if builder.config.is_running_on_ci() {1373            cmd.arg("--ci=true");1374        }1375        if let Some(s) =1376            builder.config.cmd.extra_checks().or(builder.config.tidy_extra_checks.as_deref())1377        {1378            cmd.arg(format!("--extra-checks={s}"));1379        }1380        let mut args = std::env::args_os();1381        if args.any(|arg| arg == OsStr::new("--")) {1382            cmd.arg("--");1383            cmd.args(args);1384        }13851386        if builder.config.channel == "dev" || builder.config.channel == "nightly" {1387            if !builder.config.json_output {1388                builder.info("fmt check");1389                if builder.config.initial_rustfmt.is_none() {1390                    let inferred_rustfmt_dir = builder.initial_sysroot.join("bin");1391                    eprintln!(1392                        "\1393ERROR: no `rustfmt` binary found in {PATH}1394INFO: `rust.channel` is currently set to \"{CHAN}\"1395HELP: if you are testing a beta branch, set `rust.channel` to \"beta\" in the `bootstrap.toml` file1396HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to `x.py test`",1397                        PATH = inferred_rustfmt_dir.display(),1398                        CHAN = builder.config.channel,1399                    );1400                    crate::exit!(1);1401                }1402                let all = false;1403                crate::core::build_steps::format::format(1404                    builder,1405                    !builder.config.cmd.bless(),1406                    all,1407                    &[],1408                );1409            } else {1410                eprintln!(1411                    "WARNING: `--json-output` is not supported on rustfmt, formatting will be skipped"1412                );1413            }1414        }14151416        builder.info("tidy check");1417        cmd.delay_failure().run(builder);14181419        builder.info("x.py completions check");1420        let completion_paths = get_completion_paths(builder);1421        if builder.config.cmd.bless() {1422            builder.ensure(crate::core::build_steps::run::GenerateCompletions);1423        } else if completion_paths1424            .into_iter()1425            .any(|(shell, path)| get_completion(shell, &path).is_some())1426        {1427            eprintln!(1428                "x.py completions were changed; run `x.py run generate-completions` to update them"1429            );1430            crate::exit!(1);1431        }14321433        builder.info("x.py help check");1434        if builder.config.cmd.bless() {1435            builder.ensure(crate::core::build_steps::run::GenerateHelp);1436        } else {1437            let help_path = get_help_path(builder);1438            let cur_help = std::fs::read_to_string(&help_path).unwrap_or_else(|err| {1439                eprintln!("couldn't read {}: {}", help_path.display(), err);1440                crate::exit!(1);1441            });1442            let new_help = top_level_help();14431444            if new_help != cur_help {1445                eprintln!("x.py help was changed; run `x.py run generate-help` to update it");1446                crate::exit!(1);1447            }1448        }1449    }14501451    fn metadata(&self) -> Option<StepMetadata> {1452        Some(StepMetadata::test("tidy", TargetSelection::default()))1453    }1454}14551456/// Runs `cargo test` on the `src/tools/run-make-support` crate.1457/// That crate is used by run-make tests.1458#[derive(Debug, Clone, PartialEq, Eq, Hash)]1459pub struct CrateRunMakeSupport {1460    host: TargetSelection,1461}14621463impl Step for CrateRunMakeSupport {1464    type Output = ();1465    const IS_HOST: bool = true;14661467    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1468        run.path("src/tools/run-make-support")1469    }14701471    fn make_run(run: RunConfig<'_>) {1472        run.builder.ensure(CrateRunMakeSupport { host: run.target });1473    }14741475    /// Runs `cargo test` for run-make-support.1476    fn run(self, builder: &Builder<'_>) {1477        let host = self.host;1478        let compiler = builder.compiler(0, host);14791480        let mut cargo = tool::prepare_tool_cargo(1481            builder,1482            compiler,1483            Mode::ToolBootstrap,1484            host,1485            Kind::Test,1486            "src/tools/run-make-support",1487            SourceType::InTree,1488            &[],1489        );1490        cargo.allow_features("test");1491        run_cargo_test(cargo, &[], &[], "run-make-support self test", host, builder);1492    }1493}14941495#[derive(Debug, Clone, PartialEq, Eq, Hash)]1496pub struct CrateBuildHelper {1497    host: TargetSelection,1498}14991500impl Step for CrateBuildHelper {1501    type Output = ();1502    const IS_HOST: bool = true;15031504    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1505        run.path("src/build_helper")1506    }15071508    fn make_run(run: RunConfig<'_>) {1509        run.builder.ensure(CrateBuildHelper { host: run.target });1510    }15111512    /// Runs `cargo test` for build_helper.1513    fn run(self, builder: &Builder<'_>) {1514        let host = self.host;1515        let compiler = builder.compiler(0, host);15161517        let mut cargo = tool::prepare_tool_cargo(1518            builder,1519            compiler,1520            Mode::ToolBootstrap,1521            host,1522            Kind::Test,1523            "src/build_helper",1524            SourceType::InTree,1525            &[],1526        );1527        cargo.allow_features("test");1528        run_cargo_test(cargo, &[], &[], "build_helper self test", host, builder);1529    }1530}15311532fn testdir(builder: &Builder<'_>, host: TargetSelection) -> PathBuf {1533    builder.out.join(host).join("test")1534}15351536/// Declares a test step that invokes compiletest on a particular test suite.1537macro_rules! test {1538    (1539        $( #[$attr:meta] )* // allow docstrings and attributes1540        $name:ident {1541            path: $path:expr,1542            mode: $mode:expr,1543            suite: $suite:expr,1544            default: $default:expr1545            $( , IS_HOST: $IS_HOST:expr )? // default: false1546            $( , compare_mode: $compare_mode:expr )? // default: None1547            $( , )? // optional trailing comma1548        }1549    ) => {1550        $( #[$attr] )*1551        #[derive(Debug, Clone, PartialEq, Eq, Hash)]1552        pub struct $name {1553            test_compiler: Compiler,1554            target: TargetSelection,1555        }15561557        impl Step for $name {1558            type Output = ();1559            const IS_HOST: bool = (const {1560                #[allow(unused_assignments, unused_mut)]1561                let mut value = false;1562                $( value = $IS_HOST; )?1563                value1564            });15651566            fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1567                run.suite_path($path)1568            }15691570            fn is_default_step(_builder: &Builder<'_>) -> bool {1571                const { $default }1572            }15731574            fn make_run(run: RunConfig<'_>) {1575                let test_compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());15761577                run.builder.ensure($name { test_compiler, target: run.target });1578            }15791580            fn run(self, builder: &Builder<'_>) {1581                builder.ensure(Compiletest {1582                    test_compiler: self.test_compiler,1583                    target: self.target,1584                    mode: const { $mode },1585                    suite: $suite,1586                    path: $path,1587                    compare_mode: (const {1588                        #[allow(unused_assignments, unused_mut)]1589                        let mut value = None;1590                        $( value = $compare_mode; )?1591                        value1592                    }),1593                })1594            }1595        }1596    };1597}15981599test!(Ui { path: "tests/ui", mode: CompiletestMode::Ui, suite: "ui", default: true });16001601test!(Crashes {1602    path: "tests/crashes",1603    mode: CompiletestMode::Crashes,1604    suite: "crashes",1605    default: true,1606});16071608test!(CodegenLlvm {1609    path: "tests/codegen-llvm",1610    mode: CompiletestMode::Codegen,1611    suite: "codegen-llvm",1612    default: true1613});16141615test!(CodegenUnits {1616    path: "tests/codegen-units",1617    mode: CompiletestMode::CodegenUnits,1618    suite: "codegen-units",1619    default: true,1620});16211622test!(Incremental {1623    path: "tests/incremental",1624    mode: CompiletestMode::Incremental,1625    suite: "incremental",1626    default: true,1627});16281629test!(Debuginfo {1630    path: "tests/debuginfo",1631    mode: CompiletestMode::Debuginfo,1632    suite: "debuginfo",1633    default: true,1634    compare_mode: Some("split-dwarf"),1635});16361637test!(UiFullDeps {1638    path: "tests/ui-fulldeps",1639    mode: CompiletestMode::Ui,1640    suite: "ui-fulldeps",1641    default: true,1642    IS_HOST: true,1643});16441645test!(RustdocHtml {1646    path: "tests/rustdoc-html",1647    mode: CompiletestMode::RustdocHtml,1648    suite: "rustdoc-html",1649    default: true,1650    IS_HOST: true,1651});1652test!(RustdocUi {1653    path: "tests/rustdoc-ui",1654    mode: CompiletestMode::Ui,1655    suite: "rustdoc-ui",1656    default: true,1657    IS_HOST: true,1658});16591660test!(RustdocJson {1661    path: "tests/rustdoc-json",1662    mode: CompiletestMode::RustdocJson,1663    suite: "rustdoc-json",1664    default: true,1665    IS_HOST: true,1666});16671668test!(Pretty {1669    path: "tests/pretty",1670    mode: CompiletestMode::Pretty,1671    suite: "pretty",1672    default: true,1673    IS_HOST: true,1674});16751676test!(RunMake {1677    path: "tests/run-make",1678    mode: CompiletestMode::RunMake,1679    suite: "run-make",1680    default: true,1681});1682test!(RunMakeCargo {1683    path: "tests/run-make-cargo",1684    mode: CompiletestMode::RunMake,1685    suite: "run-make-cargo",1686    default: true1687});1688test!(BuildStd {1689    path: "tests/build-std",1690    mode: CompiletestMode::RunMake,1691    suite: "build-std",1692    default: false1693});16941695test!(AssemblyLlvm {1696    path: "tests/assembly-llvm",1697    mode: CompiletestMode::Assembly,1698    suite: "assembly-llvm",1699    default: true1700});17011702/// Runs the coverage test suite at `tests/coverage` in some or all of the1703/// coverage test modes.1704#[derive(Debug, Clone, PartialEq, Eq, Hash)]1705pub struct Coverage {1706    pub compiler: Compiler,1707    pub target: TargetSelection,1708    pub(crate) mode: CompiletestMode,1709}17101711impl Coverage {1712    const PATH: &'static str = "tests/coverage";1713    const SUITE: &'static str = "coverage";1714    const ALL_MODES: &[CompiletestMode] =1715        &[CompiletestMode::CoverageMap, CompiletestMode::CoverageRun];1716}17171718impl Step for Coverage {1719    type Output = ();1720    /// Compiletest will automatically skip the "coverage-run" tests if necessary.1721    const IS_HOST: bool = false;17221723    fn should_run(mut run: ShouldRun<'_>) -> ShouldRun<'_> {1724        // Support various invocation styles, including:1725        // - `./x test coverage`1726        // - `./x test tests/coverage/trivial.rs`1727        // - `./x test coverage-map`1728        // - `./x test coverage-run -- tests/coverage/trivial.rs`1729        run = run.suite_path(Self::PATH);1730        for mode in Self::ALL_MODES {1731            run = run.alias(mode.as_str());1732        }1733        run1734    }17351736    fn is_default_step(_builder: &Builder<'_>) -> bool {1737        true1738    }17391740    fn make_run(run: RunConfig<'_>) {1741        let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());1742        let target = run.target;17431744        // List of (coverage) test modes that the coverage test suite will be1745        // run in. It's OK for this to contain duplicates, because the call to1746        // `Builder::ensure` below will take care of deduplication.1747        let mut modes = vec![];17481749        // From the pathsets that were selected on the command-line (or by default),1750        // determine which modes to run in.1751        for path in &run.paths {1752            match path {1753                PathSet::Set(_) => {1754                    for &mode in Self::ALL_MODES {1755                        if path.assert_single_path().path == Path::new(mode.as_str()) {1756                            modes.push(mode);1757                            break;1758                        }1759                    }1760                }1761                PathSet::Suite(_) => {1762                    modes.extend_from_slice(Self::ALL_MODES);1763                    break;1764                }1765            }1766        }17671768        // Skip any modes that were explicitly skipped/excluded on the command-line.1769        // FIXME(Zalathar): Integrate this into central skip handling somehow?1770        modes.retain(|mode| {1771            !run.builder.config.skip.iter().any(|skip| skip == Path::new(mode.as_str()))1772        });17731774        // FIXME(Zalathar): Make these commands skip all coverage tests, as expected:1775        // - `./x test --skip=tests`1776        // - `./x test --skip=tests/coverage`1777        // - `./x test --skip=coverage`1778        // Skip handling currently doesn't have a way to know that skipping the coverage1779        // suite should also skip the `coverage-map` and `coverage-run` aliases.17801781        for mode in modes {1782            run.builder.ensure(Coverage { compiler, target, mode });1783        }1784    }17851786    fn run(self, builder: &Builder<'_>) {1787        let Self { compiler, target, mode } = self;1788        // Like other compiletest suite test steps, delegate to an internal1789        // compiletest task to actually run the tests.1790        builder.ensure(Compiletest {1791            test_compiler: compiler,1792            target,1793            mode,1794            suite: Self::SUITE,1795            path: Self::PATH,1796            compare_mode: None,1797        });1798    }1799}18001801test!(CoverageRunRustdoc {1802    path: "tests/coverage-run-rustdoc",1803    mode: CompiletestMode::CoverageRun,1804    suite: "coverage-run-rustdoc",1805    default: true,1806    IS_HOST: true,1807});18081809// For the mir-opt suite we do not use macros, as we need custom behavior when blessing.1810#[derive(Debug, Clone, PartialEq, Eq, Hash)]1811pub struct MirOpt {1812    pub compiler: Compiler,1813    pub target: TargetSelection,1814}18151816impl Step for MirOpt {1817    type Output = ();18181819    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1820        run.suite_path("tests/mir-opt")1821    }18221823    fn is_default_step(_builder: &Builder<'_>) -> bool {1824        true1825    }18261827    fn make_run(run: RunConfig<'_>) {1828        let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());1829        run.builder.ensure(MirOpt { compiler, target: run.target });1830    }18311832    fn run(self, builder: &Builder<'_>) {1833        let run = |target| {1834            builder.ensure(Compiletest {1835                test_compiler: self.compiler,1836                target,1837                mode: CompiletestMode::MirOpt,1838                suite: "mir-opt",1839                path: "tests/mir-opt",1840                compare_mode: None,1841            })1842        };18431844        run(self.target);18451846        // Run more targets with `--bless`. But we always run the host target first, since some1847        // tests use very specific `only` clauses that are not covered by the target set below.1848        if builder.config.cmd.bless() {1849            // All that we really need to do is cover all combinations of 32/64-bit and unwind/abort,1850            // but while we're at it we might as well flex our cross-compilation support. This1851            // selection covers all our tier 1 operating systems and architectures using only tier1852            // 1 targets.18531854            for target in ["aarch64-unknown-linux-gnu", "i686-pc-windows-msvc"] {1855                run(TargetSelection::from_user(target));1856            }18571858            for target in ["x86_64-apple-darwin", "i686-unknown-linux-musl"] {1859                let target = TargetSelection::from_user(target);1860                let panic_abort_target = builder.ensure(MirOptPanicAbortSyntheticTarget {1861                    compiler: self.compiler,1862                    base: target,1863                });1864                run(panic_abort_target);1865            }1866        }1867    }1868}18691870/// Executes the `compiletest` tool to run a suite of tests.1871///1872/// Compiles all tests with `test_compiler` for `target` with the specified1873/// compiletest `mode` and `suite` arguments. For example `mode` can be1874/// "mir-opt" and `suite` can be something like "debuginfo".1875#[derive(Debug, Clone, PartialEq, Eq, Hash)]1876struct Compiletest {1877    /// The compiler that we're testing.1878    test_compiler: Compiler,1879    target: TargetSelection,1880    mode: CompiletestMode,1881    suite: &'static str,1882    path: &'static str,1883    compare_mode: Option<&'static str>,1884}18851886impl Step for Compiletest {1887    type Output = ();18881889    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1890        run.never()1891    }18921893    fn run(self, builder: &Builder<'_>) {1894        if builder.test_target == TestTarget::DocOnly {1895            return;1896        }18971898        if builder.top_stage == 0 && !builder.config.compiletest_allow_stage0 {1899            eprintln!("\1900ERROR: `--stage 0` runs compiletest on the stage0 (precompiled) compiler, not your local changes, and will almost always cause tests to fail1901HELP: to test the compiler or standard library, omit the stage or explicitly use `--stage 1` instead1902NOTE: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `--set build.compiletest-allow-stage0=true`."1903            );1904            crate::exit!(1);1905        }19061907        let mut test_compiler = self.test_compiler;1908        let target = self.target;1909        let mode = self.mode;1910        let suite = self.suite;19111912        // Path for test suite1913        let suite_path = self.path;19141915        // Skip codegen tests if they aren't enabled in configuration.1916        if !builder.config.codegen_tests && mode == CompiletestMode::Codegen {1917            return;1918        }19191920        // Support stage 1 ui-fulldeps. This is somewhat complicated: ui-fulldeps tests for the most1921        // part test the *API* of the compiler, not how it compiles a given file. As a result, we1922        // can run them against the stage 1 sources as long as we build them with the stage 01923        // bootstrap compiler.1924        // NOTE: Only stage 1 is special cased because we need the rustc_private artifacts to match the1925        // running compiler in stage 2 when plugins run.1926        let query_compiler;1927        let (stage, stage_id) = if suite == "ui-fulldeps" && test_compiler.stage == 1 {1928            // Even when using the stage 0 compiler, we also need to provide the stage 1 compiler1929            // so that compiletest can query it for target information.1930            query_compiler = Some(test_compiler);1931            // At stage 0 (stage - 1) we are using the stage0 compiler. Using `self.target` can lead1932            // finding an incorrect compiler path on cross-targets, as the stage 0 is always equal to1933            // `build.build` in the configuration.1934            let build = builder.build.host_target;1935            test_compiler = builder.compiler(test_compiler.stage - 1, build);1936            let test_stage = test_compiler.stage + 1;1937            (test_stage, format!("stage{test_stage}-{build}"))1938        } else {1939            query_compiler = None;1940            let stage = test_compiler.stage;1941            (stage, format!("stage{stage}-{target}"))1942        };19431944        if suite.ends_with("fulldeps") {1945            builder.ensure(compile::Rustc::new(test_compiler, target));1946        }19471948        if suite == "debuginfo" {1949            builder.ensure(dist::DebuggerScripts {1950                sysroot: builder.sysroot(test_compiler).to_path_buf(),1951                target,1952            });1953        }1954        if mode == CompiletestMode::RunMake {1955            builder.tool_exe(Tool::RunMakeSupport);1956        }19571958        // ensure that `libproc_macro` is available on the host.1959        if suite == "mir-opt" {1960            builder.ensure(1961                compile::Std::new(test_compiler, test_compiler.host).is_for_mir_opt_tests(true),1962            );1963        } else {1964            builder.std(test_compiler, test_compiler.host);1965        }19661967        let mut cmd = builder.tool_cmd(Tool::Compiletest);19681969        if suite == "mir-opt" {1970            builder.ensure(compile::Std::new(test_compiler, target).is_for_mir_opt_tests(true));1971        } else {1972            builder.std(test_compiler, target);1973        }19741975        builder.ensure(RemoteCopyLibs { build_compiler: test_compiler, target });19761977        // compiletest currently has... a lot of arguments, so let's just pass all1978        // of them!19791980        cmd.arg("--stage").arg(stage.to_string());1981        cmd.arg("--stage-id").arg(stage_id);19821983        cmd.arg("--compile-lib-path").arg(builder.rustc_libdir(test_compiler));1984        cmd.arg("--run-lib-path").arg(builder.sysroot_target_libdir(test_compiler, target));1985        cmd.arg("--rustc-path").arg(builder.rustc(test_compiler));1986        if let Some(query_compiler) = query_compiler {1987            cmd.arg("--query-rustc-path").arg(builder.rustc(query_compiler));1988        }19891990        // Minicore auxiliary lib for `no_core` tests that need `core` stubs in cross-compilation1991        // scenarios.1992        cmd.arg("--minicore-path")1993            .arg(builder.src.join("tests").join("auxiliary").join("minicore.rs"));19941995        let is_rustdoc = suite == "rustdoc-ui" || suite == "rustdoc-js";19961997        // There are (potentially) 2 `cargo`s to consider:1998        //1999        // - A "bootstrap" cargo, which is the same cargo used to build bootstrap itself, and is2000        //   used to build the `run-make` test recipes and the `run-make-support` test library. All

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.