src/bootstrap/src/core/build_steps/test.rs RUST 4,431 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 4,431.
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::test::failed_tests::{RecordFailedTests, SetupFailedTestsFile};25use crate::core::build_steps::tool::{26    self, RustcPrivateCompilers, SourceType, TEST_FLOAT_PARSE_ALLOW_FEATURES, Tool,27    ToolTargetBuildMode, get_tool_target_compiler,28};29use crate::core::build_steps::toolstate::ToolState;30use crate::core::build_steps::{compile, dist, llvm};31use crate::core::builder::{32    self, Alias, Builder, Compiler, Kind, RunConfig, ShouldRun, Step, StepMetadata,33    crate_description,34};35use crate::core::config::TargetSelection;36use crate::core::config::flags::{Subcommand, get_completion, top_level_help};37use crate::core::{android, debuggers};38use crate::utils::build_stamp::{self, BuildStamp};39use crate::utils::exec::{BootstrapCommand, command};40use crate::utils::helpers::{41    self, LldThreads, TestFilterCategory, add_dylib_path, add_rustdoc_cargo_linker_args,42    dylib_path, dylib_path_var, linker_args, linker_flags, t, target_supports_cranelift_backend,43    up_to_date,44};45use crate::utils::render_tests::{add_flags_and_try_run_tests, try_run_tests};46use crate::{CLang, CodegenBackendKind, GitRepo, Mode, PathSet, TestTarget, envify};4748mod compiletest;49pub mod failed_tests;5051/// Runs `cargo test` on various internal tools used by bootstrap.52#[derive(Debug, Clone, PartialEq, Eq, Hash)]53pub struct CrateBootstrap {54    path: PathBuf,55    host: TargetSelection,56}5758impl Step for CrateBootstrap {59    type Output = ();60    const IS_HOST: bool = true;6162    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {63        // This step is responsible for several different tool paths.64        //65        // By default, it will test all of them, but requesting specific tools on the command-line66        // (e.g. `./x test src/tools/coverage-dump`) will test only the specified tools.67        run.path("src/tools/jsondoclint")68            .path("src/tools/replace-version-placeholder")69            .path("src/tools/coverage-dump")70            // We want `./x test tidy` to _run_ the tidy tool, not its tests.71            // So we need a separate alias to test the tidy tool itself.72            .alias("tidyselftest")73    }7475    fn is_default_step(_builder: &Builder<'_>) -> bool {76        true77    }7879    fn make_run(run: RunConfig<'_>) {80        // Create and ensure a separate instance of this step for each path81        // that was selected on the command-line (or selected by default).82        for path in run.paths {83            let path = path.assert_single_path().path.clone();84            run.builder.ensure(CrateBootstrap { host: run.target, path });85        }86    }8788    fn run(self, builder: &Builder<'_>) {89        let bootstrap_host = builder.config.host_target;90        let compiler = builder.compiler(0, bootstrap_host);91        let record_failed_tests = builder.ensure(SetupFailedTestsFile);92        let mut path = self.path.to_str().unwrap();9394        // Map alias `tidyselftest` back to the actual crate path of tidy.95        if path == "tidyselftest" {96            path = "src/tools/tidy";97        }9899        let cargo = tool::prepare_tool_cargo(100            builder,101            compiler,102            Mode::ToolBootstrap,103            bootstrap_host,104            Kind::Test,105            path,106            SourceType::InTree,107            &[],108        );109110        let crate_name = path.rsplit_once('/').unwrap().1;111        run_cargo_test(cargo, &[], &[], crate_name, bootstrap_host, builder, record_failed_tests);112    }113114    fn metadata(&self) -> Option<StepMetadata> {115        Some(116            StepMetadata::test("crate-bootstrap", self.host)117                .with_metadata(self.path.as_path().to_string_lossy().to_string()),118        )119    }120}121122#[derive(Debug, Clone, PartialEq, Eq, Hash)]123pub struct Linkcheck {124    host: TargetSelection,125}126127impl Step for Linkcheck {128    type Output = ();129    const IS_HOST: bool = true;130131    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {132        run.path("src/tools/linkchecker")133    }134135    fn is_default_step(builder: &Builder<'_>) -> bool {136        builder.config.docs137    }138139    fn make_run(run: RunConfig<'_>) {140        run.builder.ensure(Linkcheck { host: run.target });141    }142143    /// Runs the `linkchecker` tool as compiled in `stage` by the `host` compiler.144    ///145    /// This tool in `src/tools` will verify the validity of all our links in the146    /// documentation to ensure we don't have a bunch of dead ones.147    fn run(self, builder: &Builder<'_>) {148        let host = self.host;149        let hosts = &builder.hosts;150        let targets = &builder.targets;151152        // if we have different hosts and targets, some things may be built for153        // the host (e.g. rustc) and others for the target (e.g. std). The154        // documentation built for each will contain broken links to155        // docs built for the other platform (e.g. rustc linking to cargo)156        if (hosts != targets) && !hosts.is_empty() && !targets.is_empty() {157            panic!(158                "Linkcheck currently does not support builds with different hosts and targets.159You can skip linkcheck with --skip src/tools/linkchecker"160            );161        }162163        builder.info(&format!("Linkcheck ({host})"));164165        // Test the linkchecker itself.166        let bootstrap_host = builder.config.host_target;167        let compiler = builder.compiler(0, bootstrap_host);168        let record_failed_tests = builder.ensure(SetupFailedTestsFile);169170        let cargo = tool::prepare_tool_cargo(171            builder,172            compiler,173            Mode::ToolBootstrap,174            bootstrap_host,175            Kind::Test,176            "src/tools/linkchecker",177            SourceType::InTree,178            &[],179        );180        run_cargo_test(181            cargo,182            &[],183            &[],184            "linkchecker self tests",185            bootstrap_host,186            builder,187            record_failed_tests,188        );189190        if !builder.test_target.runs_doctests() {191            return;192        }193194        // Build all the default documentation.195        builder.run_default_doc_steps();196197        // Build the linkchecker before calling `msg`, since GHA doesn't support nested groups.198        let linkchecker = builder.tool_cmd(Tool::Linkchecker);199200        // Run the linkchecker.201        let _guard = builder.msg_test("Linkcheck", bootstrap_host, 1);202        let _time = helpers::timeit(builder);203        linkchecker.delay_failure().arg(builder.out.join(host).join("doc")).run(builder);204    }205206    fn metadata(&self) -> Option<StepMetadata> {207        Some(StepMetadata::test("link-check", self.host))208    }209}210211fn check_if_tidy_is_installed(builder: &Builder<'_>) -> bool {212    command("tidy")213        .allow_failure()214        .arg("--version")215        // Cache the output to avoid running this command more than once (per builder).216        .cached()217        .run_capture_stdout(builder)218        .is_success()219}220221#[derive(Debug, Clone, PartialEq, Eq, Hash)]222pub struct HtmlCheck {223    target: TargetSelection,224}225226impl Step for HtmlCheck {227    type Output = ();228    const IS_HOST: bool = true;229230    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {231        run.path("src/tools/html-checker")232    }233234    fn is_default_step(builder: &Builder<'_>) -> bool {235        check_if_tidy_is_installed(builder)236    }237238    fn make_run(run: RunConfig<'_>) {239        run.builder.ensure(HtmlCheck { target: run.target });240    }241242    fn run(self, builder: &Builder<'_>) {243        if !check_if_tidy_is_installed(builder) {244            eprintln!("not running HTML-check tool because `tidy` is missing");245            eprintln!(246                "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."247            );248            panic!("Cannot run html-check tests");249        }250        // Ensure that a few different kinds of documentation are available.251        builder.run_default_doc_steps();252        builder.ensure(crate::core::build_steps::doc::Rustc::for_stage(253            builder,254            builder.top_stage,255            self.target,256        ));257258        builder259            .tool_cmd(Tool::HtmlChecker)260            .delay_failure()261            .arg(builder.doc_out(self.target))262            .run(builder);263    }264265    fn metadata(&self) -> Option<StepMetadata> {266        Some(StepMetadata::test("html-check", self.target))267    }268}269270/// Builds cargo and then runs the `src/tools/cargotest` tool, which checks out271/// some representative crate repositories and runs `cargo test` on them, in272/// order to test cargo.273#[derive(Debug, Clone, PartialEq, Eq, Hash)]274pub struct Cargotest {275    build_compiler: Compiler,276    host: TargetSelection,277}278279impl Step for Cargotest {280    type Output = ();281    const IS_HOST: bool = true;282283    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {284        run.path("src/tools/cargotest")285    }286287    fn make_run(run: RunConfig<'_>) {288        if run.builder.top_stage == 0 {289            eprintln!(290                "ERROR: running cargotest with stage 0 is currently unsupported. Use at least stage 1."291            );292            exit!(1);293        }294        // We want to build cargo stage N (where N == top_stage), and rustc stage N,295        // and test both of these together.296        // So we need to get a build compiler stage N-1 to build the stage N components.297        run.builder.ensure(Cargotest {298            build_compiler: run.builder.compiler(run.builder.top_stage - 1, run.target),299            host: run.target,300        });301    }302303    /// Runs the `cargotest` tool as compiled in `stage` by the `host` compiler.304    ///305    /// This tool in `src/tools` will check out a few Rust projects and run `cargo306    /// test` to ensure that we don't regress the test suites there.307    fn run(self, builder: &Builder<'_>) {308        // cargotest's staging has several pieces:309        // consider ./x test cargotest --stage=2.310        //311        // The test goal is to exercise a (stage 2 cargo, stage 2 rustc) pair through a stage 2312        // cargotest tool.313        // To produce the stage 2 cargo and cargotest, we need to do so with the stage 1 rustc and std.314        // Importantly, the stage 2 rustc being tested (`tested_compiler`) via stage 2 cargotest is315        // the rustc built by an earlier stage 1 rustc (the build_compiler). These are two different316        // compilers!317        let cargo =318            builder.ensure(tool::Cargo::from_build_compiler(self.build_compiler, self.host));319        let tested_compiler = builder.compiler(self.build_compiler.stage + 1, self.host);320        builder.std(tested_compiler, self.host);321322        // Note that this is a short, cryptic, and not scoped directory name. This323        // is currently to minimize the length of path on Windows where we otherwise324        // quickly run into path name limit constraints.325        let out_dir = builder.out.join("ct");326        t!(fs::create_dir_all(&out_dir));327328        let _time = helpers::timeit(builder);329        let mut cmd = builder.tool_cmd(Tool::CargoTest);330        cmd.arg(&cargo.tool_path)331            .arg(&out_dir)332            .args(builder.config.test_args())333            .env("RUSTC", builder.rustc(tested_compiler))334            .env("RUSTDOC", builder.rustdoc_for_compiler(tested_compiler));335        add_rustdoc_cargo_linker_args(&mut cmd, builder, tested_compiler.host, LldThreads::No);336        cmd.delay_failure().run(builder);337    }338339    fn metadata(&self) -> Option<StepMetadata> {340        Some(StepMetadata::test("cargotest", self.host).stage(self.build_compiler.stage + 1))341    }342}343344/// Runs `cargo test` for cargo itself.345/// We label these tests as "cargo self-tests".346#[derive(Debug, Clone, PartialEq, Eq, Hash)]347pub struct Cargo {348    build_compiler: Compiler,349    host: TargetSelection,350}351352impl Cargo {353    const CRATE_PATH: &str = "src/tools/cargo";354}355356impl Step for Cargo {357    type Output = ();358    const IS_HOST: bool = true;359360    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {361        run.path(Self::CRATE_PATH)362    }363364    fn make_run(run: RunConfig<'_>) {365        run.builder.ensure(Cargo {366            build_compiler: get_tool_target_compiler(367                run.builder,368                ToolTargetBuildMode::Build(run.target),369            ),370            host: run.target,371        });372    }373374    /// Runs `cargo test` for `cargo` packaged with Rust.375    fn run(self, builder: &Builder<'_>) {376        // When we do a "stage 1 cargo self-test", it means that we test the stage 1 rustc377        // using stage 1 cargo. So we actually build cargo using the stage 0 compiler, and then378        // run its tests against the stage 1 compiler (called `tested_compiler` below).379        builder.ensure(tool::Cargo::from_build_compiler(self.build_compiler, self.host));380        let record_failed_tests = builder.ensure(SetupFailedTestsFile);381382        let tested_compiler = builder.compiler(self.build_compiler.stage + 1, self.host);383        builder.std(tested_compiler, self.host);384        // We also need to build rustdoc for cargo tests385        // It will be located in the bindir of `tested_compiler`, so we don't need to explicitly386        // pass its path to Cargo.387        builder.rustdoc_for_compiler(tested_compiler);388389        let cargo = tool::prepare_tool_cargo(390            builder,391            self.build_compiler,392            Mode::ToolTarget,393            self.host,394            Kind::Test,395            Self::CRATE_PATH,396            SourceType::Submodule,397            &[],398        );399400        // NOTE: can't use `run_cargo_test` because we need to overwrite `PATH`401        let mut cargo = prepare_cargo_test(cargo, &[], &[], self.host, builder);402403        // Don't run cross-compile tests, we may not have cross-compiled libstd libs404        // available.405        cargo.env("CFG_DISABLE_CROSS_TESTS", "1");406        // Forcibly disable tests using nightly features since any changes to407        // those features won't be able to land.408        cargo.env("CARGO_TEST_DISABLE_NIGHTLY", "1");409410        // Configure PATH to find the right rustc. NB. we have to use PATH411        // and not RUSTC because the Cargo test suite has tests that will412        // fail if rustc is not spelled `rustc`.413        cargo.env("PATH", bin_path_for_cargo(builder, tested_compiler));414415        // The `cargo` command configured above has dylib dir path set to the `build_compiler`'s416        // libdir. That causes issues in cargo test, because the programs that cargo compiles are417        // incorrectly picking that libdir, even though they should be picking the418        // `tested_compiler`'s libdir. We thus have to override the precedence here.419        let mut existing_dylib_paths = cargo420            .get_envs()421            .find(|(k, _)| *k == OsStr::new(dylib_path_var()))422            .and_then(|(_, v)| v)423            .map(|value| split_paths(value).collect::<Vec<PathBuf>>())424            .unwrap_or_default();425        existing_dylib_paths.insert(0, builder.rustc_libdir(tested_compiler));426        add_dylib_path(existing_dylib_paths, &mut cargo);427428        // Cargo's test suite uses `CARGO_RUSTC_CURRENT_DIR` to determine the path that `file!` is429        // relative to. Cargo no longer sets this env var, so we have to do that. This has to be the430        // same value as `-Zroot-dir`.431        cargo.env("CARGO_RUSTC_CURRENT_DIR", builder.src.display().to_string());432433        #[cfg(feature = "build-metrics")]434        builder.metrics.begin_test_suite(435            build_helper::metrics::TestSuiteMetadata::CargoPackage {436                crates: vec!["cargo".into()],437                target: self.host.triple.to_string(),438                host: self.host.triple.to_string(),439                stage: self.build_compiler.stage + 1,440            },441            builder,442        );443444        let _time = helpers::timeit(builder);445        add_flags_and_try_run_tests(builder, &mut cargo, record_failed_tests);446    }447448    fn metadata(&self) -> Option<StepMetadata> {449        Some(StepMetadata::test("cargo", self.host).built_by(self.build_compiler))450    }451}452453#[derive(Debug, Clone, PartialEq, Eq, Hash)]454pub struct RustAnalyzer {455    compilers: RustcPrivateCompilers,456}457458impl Step for RustAnalyzer {459    type Output = ();460    const IS_HOST: bool = true;461462    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {463        run.path("src/tools/rust-analyzer")464    }465466    fn is_default_step(_builder: &Builder<'_>) -> bool {467        true468    }469470    fn make_run(run: RunConfig<'_>) {471        run.builder.ensure(Self {472            compilers: RustcPrivateCompilers::new(473                run.builder,474                run.builder.top_stage,475                run.builder.host_target,476            ),477        });478    }479480    /// Runs `cargo test` for rust-analyzer481    fn run(self, builder: &Builder<'_>) {482        let build_compiler = self.compilers.build_compiler();483        let target = self.compilers.target();484        let record_failed_tests = builder.ensure(SetupFailedTestsFile);485486        // NOTE: rust-analyzer repo currently (as of 2025-12-11) does not run tests against 32-bit487        // targets, so we also don't run them in rust-lang/rust CI (because that will just mean that488        // subtree syncs will keep getting 32-bit-specific failures that are not observed in489        // rust-analyzer repo CI).490        //491        // Some 32-bit specific failures include e.g. target pointer width specific hashes.492493        // FIXME: eventually, we should probably reduce the amount of target tuple substring494        // matching in bootstrap.495        if target.starts_with("i686") {496            return;497        }498499        let suite = "src/tools/rust-analyzer";500        let mut cargo = tool::prepare_tool_cargo(501            builder,502            build_compiler,503            Mode::ToolRustcPrivate,504            target,505            Kind::Test,506            suite,507            SourceType::InTree,508            &["in-rust-tree".to_owned()],509        );510        cargo.allow_features(tool::RustAnalyzer::ALLOW_FEATURES);511512        // N.B. it turns out _setting_ `CARGO_WORKSPACE_DIR` actually somehow breaks `expect-test`,513        // even though previously we actually needed to set that hack to allow `expect-test` to514        // correctly discover the r-a workspace instead of the outer r-l/r workspace.515516        // FIXME: RA's test suite tries to write to the source directory, that can't work in Rust CI517        // without properly wiring up the writable test dir.518        cargo.env("SKIP_SLOW_TESTS", "1");519520        // NOTE: we need to skip `src/tools/rust-analyzer/xtask` as they seem to exercise rustup /521        // stable rustfmt.522        //523        // NOTE: you can only skip a specific workspace package via `--exclude=...` if you *also*524        // specify `--workspace`.525        cargo.arg("--workspace");526        cargo.arg("--exclude=xtask");527528        if build_compiler.stage == 0 {529            // This builds a proc macro against the bootstrap libproc_macro, which is not ABI530            // compatible with the ABI proc-macro-srv expects to load.531            cargo.arg("--exclude=proc-macro-srv");532            cargo.arg("--exclude=proc-macro-srv-cli");533        }534535        let mut skip_tests = vec![];536537        // NOTE: the following test skips is a bit cheeky in that it assumes there are no538        // identically named tests across different r-a packages, where we want to run the539        // identically named test in one package but not another. If we want to support that use540        // case, we'd have to run the r-a tests in two batches (with one excluding the package that541        // we *don't* want to run the test for, and the other batch including).542543        // Across all platforms.544        skip_tests.extend_from_slice(&[545            // FIXME: this test wants to find a `rustc`. We need to provide it with a path to staged546            // in-tree `rustc`, but setting `RUSTC` env var requires some reworking of bootstrap.547            "tests::smoke_test_real_sysroot_cargo",548            // NOTE: part of `smol-str` test suite; this tries to access a stable rustfmt from the549            // environment, which is not something we want to do.550            "check_code_formatting",551        ]);552553        let skip_tests = skip_tests.iter().map(|name| format!("--skip={name}")).collect::<Vec<_>>();554        let skip_tests = skip_tests.iter().map(|s| s.as_str()).collect::<Vec<_>>();555556        cargo.add_rustc_lib_path(builder);557        run_cargo_test(558            cargo,559            skip_tests.as_slice(),560            &[],561            "rust-analyzer",562            target,563            builder,564            record_failed_tests,565        );566    }567568    fn metadata(&self) -> Option<StepMetadata> {569        Some(570            StepMetadata::test("rust-analyzer", self.compilers.target())571                .built_by(self.compilers.build_compiler()),572        )573    }574}575576/// Runs `cargo test` for rustfmt.577#[derive(Debug, Clone, PartialEq, Eq, Hash)]578pub struct Rustfmt {579    compilers: RustcPrivateCompilers,580}581582impl Step for Rustfmt {583    type Output = ();584    const IS_HOST: bool = true;585586    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {587        run.path("src/tools/rustfmt")588    }589590    fn make_run(run: RunConfig<'_>) {591        run.builder.ensure(Rustfmt {592            compilers: RustcPrivateCompilers::new(593                run.builder,594                run.builder.top_stage,595                run.builder.host_target,596            ),597        });598    }599600    /// Runs `cargo test` for rustfmt.601    fn run(self, builder: &Builder<'_>) {602        let build_compiler = self.compilers.build_compiler();603        let target = self.compilers.target();604        let record_failed_tests = builder.ensure(SetupFailedTestsFile);605606        // FIXME(#156525): `compile::Sysroot::run` intentionally do not copy `rustc-dev` artifacts607        // until they're requested with `builder.ensure(Rustc)`, relevant for `download-rustc`608        // flows.609        builder.ensure(compile::Rustc::new(build_compiler, target));610611        let mut cargo = tool::prepare_tool_cargo(612            builder,613            build_compiler,614            Mode::ToolRustcPrivate,615            target,616            Kind::Test,617            "src/tools/rustfmt",618            SourceType::InTree,619            &[],620        );621622        let dir = testdir(builder, target);623        t!(fs::create_dir_all(&dir));624        cargo.env("RUSTFMT_TEST_DIR", dir);625626        cargo.add_rustc_lib_path(builder);627628        run_cargo_test(cargo, &[], &[], "rustfmt", target, builder, record_failed_tests);629    }630631    fn metadata(&self) -> Option<StepMetadata> {632        Some(633            StepMetadata::test("rustfmt", self.compilers.target())634                .built_by(self.compilers.build_compiler()),635        )636    }637}638639#[derive(Debug, Clone, PartialEq, Eq, Hash)]640pub struct Miri {641    target: TargetSelection,642}643644impl Miri {645    /// Run `cargo miri setup` for the given target, return where the Miri sysroot was put.646    pub fn build_miri_sysroot(647        builder: &Builder<'_>,648        compiler: Compiler,649        target: TargetSelection,650    ) -> PathBuf {651        let miri_sysroot = builder.out.join(compiler.host).join("miri-sysroot");652        let mut cargo = builder::Cargo::new(653            builder,654            compiler,655            Mode::Std,656            SourceType::Submodule,657            target,658            Kind::MiriSetup,659        );660661        // Tell `cargo miri setup` where to find the sources.662        cargo.env("MIRI_LIB_SRC", builder.src.join("library"));663        // Tell it where to put the sysroot.664        cargo.env("MIRI_SYSROOT", &miri_sysroot);665666        let mut cargo = BootstrapCommand::from(cargo);667        let _guard =668            builder.msg(Kind::Build, "miri sysroot", Mode::ToolRustcPrivate, compiler, target);669        cargo.run(builder);670671        // # Determine where Miri put its sysroot.672        // To this end, we run `cargo miri setup --print-sysroot` and capture the output.673        // (We do this separately from the above so that when the setup actually674        // happens we get some output.)675        // We re-use the `cargo` from above.676        cargo.arg("--print-sysroot");677678        builder.do_if_verbose(|| println!("running: {cargo:?}"));679        let stdout = cargo.run_capture_stdout(builder).stdout();680        // Output is "<sysroot>\n".681        let sysroot = stdout.trim_end();682        builder.do_if_verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}"));683        PathBuf::from(sysroot)684    }685}686687impl Step for Miri {688    type Output = ();689690    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {691        run.path("src/tools/miri")692    }693694    fn make_run(run: RunConfig<'_>) {695        run.builder.ensure(Miri { target: run.target });696    }697698    /// Runs `cargo test` for miri.699    fn run(self, builder: &Builder<'_>) {700        let host = builder.build.host_target;701        let target = self.target;702        let stage = builder.top_stage;703        if stage == 0 {704            eprintln!("miri cannot be tested at stage 0");705            std::process::exit(1);706        }707708        // This compiler runs on the host, we'll just use it for the target.709        let compilers = RustcPrivateCompilers::new(builder, stage, host);710711        // Build our tools.712        let miri = builder.ensure(tool::Miri::from_compilers(compilers));713        // the ui tests also assume cargo-miri has been built714        builder.ensure(tool::CargoMiri::from_compilers(compilers));715716        let target_compiler = compilers.target_compiler();717718        // We also need sysroots, for Miri and for the host (the latter for build scripts).719        // This is for the tests so everything is done with the target compiler.720        let miri_sysroot = Miri::build_miri_sysroot(builder, target_compiler, target);721        builder.std(target_compiler, host);722        let host_sysroot = builder.sysroot(target_compiler);723724        // Miri has its own "target dir" for ui test dependencies. Make sure it gets cleared when725        // the sysroot gets rebuilt, to avoid "found possibly newer version of crate `std`" errors.726        if !builder.config.dry_run() {727            // This has to match `CARGO_TARGET_TMPDIR` in Miri's `ui.rs`.728            // This means we need `host` here as that's the target `ui.rs` is built for.729            let ui_test_dep_dir = builder730                .stage_out(miri.build_compiler, Mode::ToolStd)731                .join(host)732                .join("tmp")733                .join("miri_ui");734            // The mtime of `miri_sysroot` changes when the sysroot gets rebuilt (also see735            // <https://github.com/RalfJung/rustc-build-sysroot/commit/10ebcf60b80fe2c3dc765af0ff19fdc0da4b7466>).736            // We can hence use that directly as a signal to clear the ui test dir.737            build_stamp::clear_if_dirty(builder, &ui_test_dep_dir, &miri_sysroot);738        }739740        // Run `cargo test`.741        // This is with the Miri crate, so it uses the host compiler.742        let mut cargo = tool::prepare_tool_cargo(743            builder,744            miri.build_compiler,745            Mode::ToolRustcPrivate,746            host,747            Kind::Test,748            "src/tools/miri",749            SourceType::InTree,750            &[],751        );752753        cargo.add_rustc_lib_path(builder);754755        // We can NOT use `run_cargo_test` since Miri's integration tests do not use the usual test756        // harness and therefore do not understand the flags added by `add_flags_and_try_run_test`.757        let mut cargo = prepare_cargo_test(cargo, &[], &[], host, builder);758759        // miri tests need to know about the stage sysroot760        cargo.env("MIRI_SYSROOT", &miri_sysroot);761        cargo.env("MIRI_HOST_SYSROOT", &host_sysroot);762763        // Set the target.764        cargo.env("MIRI_TEST_TARGET", target.rustc_target_arg());765766        {767            let _guard = builder.msg_test("miri", target, target_compiler.stage);768            let _time = helpers::timeit(builder);769            cargo.run(builder);770        }771772        // Run it again for mir-opt-level 4 to catch some miscompilations.773        if builder.config.test_args().is_empty() {774            cargo.env(775                "MIRIFLAGS",776                format!(777                    "{} -O -Zmir-opt-level=4 -Cdebug-assertions=yes",778                    env::var("MIRIFLAGS").unwrap_or_default()779                ),780            );781            // Optimizations can change backtraces782            cargo.env("MIRI_SKIP_UI_CHECKS", "1");783            // `MIRI_SKIP_UI_CHECKS` and `RUSTC_BLESS` are incompatible784            cargo.env_remove("RUSTC_BLESS");785            // Optimizations can change error locations and remove UB so don't run `fail` tests.786            cargo.args(["tests/pass", "tests/panic"]);787788            {789                let _guard =790                    builder.msg_test("miri (mir-opt-level 4)", target, target_compiler.stage);791                let _time = helpers::timeit(builder);792                cargo.run(builder);793            }794        }795    }796}797798/// Runs `cargo miri test` to demonstrate that `src/tools/miri/cargo-miri`799/// works and that libtest works under miri.800#[derive(Debug, Clone, PartialEq, Eq, Hash)]801pub struct CargoMiri {802    target: TargetSelection,803}804805impl Step for CargoMiri {806    type Output = ();807808    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {809        run.path("src/tools/miri/cargo-miri")810    }811812    fn make_run(run: RunConfig<'_>) {813        run.builder.ensure(CargoMiri { target: run.target });814    }815816    /// Tests `cargo miri test`.817    fn run(self, builder: &Builder<'_>) {818        let host = builder.build.host_target;819        let target = self.target;820        let stage = builder.top_stage;821        if stage == 0 {822            eprintln!("cargo-miri cannot be tested at stage 0");823            std::process::exit(1);824        }825826        // This compiler runs on the host, we'll just use it for the target.827        let build_compiler = builder.compiler(stage, host);828829        // Run `cargo miri test`.830        // This is just a smoke test (Miri's own CI invokes this in a bunch of different ways and ensures831        // that we get the desired output), but that is sufficient to make sure that the libtest harness832        // itself executes properly under Miri, and that all the logic in `cargo-miri` does not explode.833        let mut cargo = tool::prepare_tool_cargo(834            builder,835            build_compiler,836            Mode::ToolStd, // it's unclear what to use here, we're not building anything just doing a smoke test!837            target,838            Kind::MiriTest,839            "src/tools/miri/test-cargo-miri",840            SourceType::Submodule,841            &[],842        );843844        // If we are testing stage 2+ cargo miri, make sure that it works with the in-tree cargo.845        // We want to do this *somewhere* to ensure that Miri + nightly cargo actually works.846        if stage >= 2 {847            let built_cargo = builder848                .ensure(tool::Cargo::from_build_compiler(849                    // Build stage 1 cargo here, we don't need it to be built in any special way,850                    // just that it is built from in-tree sources.851                    builder.compiler(0, builder.host_target),852                    builder.host_target,853                ))854                .tool_path;855            cargo.env("CARGO", built_cargo);856        }857858        // We're not using `prepare_cargo_test` so we have to do this ourselves.859        // (We're not using that as the test-cargo-miri crate is not known to bootstrap.)860        match builder.test_target {861            TestTarget::AllTargets => {862                cargo.args(["--lib", "--bins", "--examples", "--tests", "--benches"])863            }864            TestTarget::Default => &mut cargo,865            TestTarget::DocOnly => cargo.arg("--doc"),866            TestTarget::Tests => cargo.arg("--tests"),867        };868        cargo.arg("--").args(builder.config.test_args());869870        // Finally, run everything.871        let mut cargo = BootstrapCommand::from(cargo);872        {873            let _guard = builder.msg_test("cargo-miri", target, stage);874            let _time = helpers::timeit(builder);875            cargo.run(builder);876        }877    }878}879880#[derive(Debug, Clone, PartialEq, Eq, Hash)]881pub struct CompiletestTest {882    host: TargetSelection,883}884885impl Step for CompiletestTest {886    type Output = ();887888    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {889        run.path("src/tools/compiletest")890    }891892    fn make_run(run: RunConfig<'_>) {893        run.builder.ensure(CompiletestTest { host: run.target });894    }895896    /// Runs `cargo test` for compiletest.897    fn run(self, builder: &Builder<'_>) {898        let host = self.host;899        let record_failed_tests = builder.ensure(SetupFailedTestsFile);900901        // Now that compiletest uses only stable Rust, building it always uses902        // the stage 0 compiler. However, some of its unit tests need to be able903        // to query information from an in-tree compiler, so we treat `--stage`904        // as selecting the stage of that secondary compiler.905906        if builder.top_stage == 0 && !builder.config.compiletest_allow_stage0 {907            eprintln!("\908ERROR: `--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 inappropriately909NOTE: 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`."910            );911            crate::exit!(1);912        }913914        let bootstrap_compiler = builder.compiler(0, host);915        let staged_compiler = builder.compiler(builder.top_stage, host);916917        let mut cargo = tool::prepare_tool_cargo(918            builder,919            bootstrap_compiler,920            Mode::ToolBootstrap,921            host,922            Kind::Test,923            "src/tools/compiletest",924            SourceType::InTree,925            &[],926        );927928        // Used for `compiletest` self-tests to have the path to the *staged* compiler. Getting this929        // right is important, as `compiletest` is intended to only support one target spec JSON930        // format, namely that of the staged compiler.931        cargo.env("TEST_RUSTC", builder.rustc(staged_compiler));932933        run_cargo_test(934            cargo,935            &[],936            &[],937            "compiletest self test",938            host,939            builder,940            record_failed_tests,941        );942    }943}944945/// Runs `library/stdarch/crates/stdarch-verify`'s tests which cross-check the946/// `core::arch` intrinsics for x86, Arm, and MIPS against the corresponding947/// vendor references (signatures, target features, and `assert_instr` mappings).948#[derive(Debug, Clone, PartialEq, Eq, Hash)]949pub struct StdarchVerify;950951impl Step for StdarchVerify {952    type Output = ();953    const IS_HOST: bool = true;954955    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {956        run.path("library/stdarch/crates/stdarch-verify")957    }958959    fn is_default_step(_builder: &Builder<'_>) -> bool {960        true961    }962963    fn make_run(run: RunConfig<'_>) {964        run.builder.ensure(StdarchVerify);965    }966967    fn run(self, builder: &Builder<'_>) {968        let host = builder.config.host_target;969        let record_failed_tests = builder.ensure(SetupFailedTestsFile);970        let build_compiler = builder.compiler(0, host);971972        let cargo = tool::prepare_tool_cargo(973            builder,974            build_compiler,975            Mode::ToolBootstrap,976            host,977            Kind::Test,978            "library/stdarch/crates/stdarch-verify",979            SourceType::InTree,980            &[],981        );982983        run_cargo_test(984            cargo,985            &[],986            &["stdarch-verify".to_string()],987            Some("stdarch-verify"),988            host,989            builder,990            record_failed_tests,991        );992    }993}994995#[derive(Debug, Clone, PartialEq, Eq, Hash)]996pub struct Clippy {997    compilers: RustcPrivateCompilers,998}9991000impl Step for Clippy {1001    type Output = ();1002    const IS_HOST: bool = true;10031004    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1005        run.suite_path("src/tools/clippy/tests").path("src/tools/clippy")1006    }10071008    fn is_default_step(_builder: &Builder<'_>) -> bool {1009        false1010    }10111012    fn make_run(run: RunConfig<'_>) {1013        run.builder.ensure(Clippy {1014            compilers: RustcPrivateCompilers::new(1015                run.builder,1016                run.builder.top_stage,1017                run.builder.host_target,1018            ),1019        });1020    }10211022    /// Runs `cargo test` for clippy.1023    fn run(self, builder: &Builder<'_>) {1024        let target = self.compilers.target();10251026        // We need to carefully distinguish the compiler that builds clippy, and the compiler1027        // that is linked into the clippy being tested. `target_compiler` is the latter,1028        // and it must also be used by clippy's test runner to build tests and their dependencies.1029        let target_compiler = self.compilers.target_compiler();1030        let build_compiler = self.compilers.build_compiler();10311032        // FIXME(#156525): `compile::Sysroot::run` intentionally do not copy `rustc-dev` artifacts1033        // until they're requested with `builder.ensure(Rustc)`, relevant for `download-rustc`1034        // flows.1035        builder.ensure(compile::Rustc::new(build_compiler, target));10361037        let mut cargo = tool::prepare_tool_cargo(1038            builder,1039            build_compiler,1040            Mode::ToolRustcPrivate,1041            target,1042            Kind::Test,1043            "src/tools/clippy",1044            SourceType::InTree,1045            &[],1046        );10471048        cargo.env("RUSTC_TEST_SUITE", builder.rustc(build_compiler));1049        cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(build_compiler));1050        let host_libs = builder1051            .stage_out(build_compiler, Mode::ToolRustcPrivate)1052            .join(builder.cargo_dir(Mode::ToolRustcPrivate));1053        cargo.env("HOST_LIBS", host_libs);10541055        // Build the standard library that the tests can use.1056        builder.std(target_compiler, target);1057        cargo.env("TEST_SYSROOT", builder.sysroot(target_compiler));1058        cargo.env("TEST_RUSTC", builder.rustc(target_compiler));1059        cargo.env("TEST_RUSTC_LIB", builder.rustc_libdir(target_compiler));10601061        // Collect paths of tests to run1062        'partially_test: {1063            let paths = &builder.config.paths[..];1064            let mut test_names = Vec::new();1065            for path in paths {1066                match helpers::is_valid_test_suite_arg(path, "src/tools/clippy/tests", builder) {1067                    TestFilterCategory::Arg(path) => {1068                        test_names.push(path);1069                    }1070                    TestFilterCategory::Fullsuite => {1071                        // When src/tools/clippy is called directly, all tests should be run.1072                        break 'partially_test;1073                    }1074                    TestFilterCategory::Uninteresting => {}1075                }1076            }1077            cargo.env("TESTNAME", test_names.join(","));1078        }10791080        cargo.add_rustc_lib_path(builder);1081        let cargo = prepare_cargo_test(cargo, &[], &[], target, builder);10821083        let _guard = builder.msg_test("clippy", target, target_compiler.stage);10841085        // Clippy reports errors if it blessed the outputs1086        if cargo.allow_failure().run(builder) {1087            // The tests succeeded; nothing to do.1088            return;1089        }10901091        if !builder.config.cmd.bless() {1092            crate::exit!(1);1093        }1094    }10951096    fn metadata(&self) -> Option<StepMetadata> {1097        Some(1098            StepMetadata::test("clippy", self.compilers.target())1099                .built_by(self.compilers.build_compiler()),1100        )1101    }1102}11031104fn bin_path_for_cargo(builder: &Builder<'_>, compiler: Compiler) -> OsString {1105    let path = builder.sysroot(compiler).join("bin");1106    let old_path = env::var_os("PATH").unwrap_or_default();1107    env::join_paths(iter::once(path).chain(env::split_paths(&old_path))).expect("")1108}11091110/// Run the rustdoc-themes tool to test a given compiler.1111#[derive(Debug, Clone, Hash, PartialEq, Eq)]1112pub struct RustdocTheme {1113    /// The compiler (more accurately, its rustdoc) that we test.1114    test_compiler: Compiler,1115}11161117impl Step for RustdocTheme {1118    type Output = ();1119    const IS_HOST: bool = true;11201121    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1122        run.path("src/tools/rustdoc-themes")1123    }11241125    fn is_default_step(_builder: &Builder<'_>) -> bool {1126        true1127    }11281129    fn make_run(run: RunConfig<'_>) {1130        let test_compiler = run.builder.compiler(run.builder.top_stage, run.target);11311132        run.builder.ensure(RustdocTheme { test_compiler });1133    }11341135    fn run(self, builder: &Builder<'_>) {1136        let rustdoc = builder.bootstrap_out.join("rustdoc");1137        let mut cmd = builder.tool_cmd(Tool::RustdocTheme);1138        cmd.arg(rustdoc.to_str().unwrap())1139            .arg(builder.src.join("src/librustdoc/html/static/css/rustdoc.css").to_str().unwrap())1140            .env("RUSTC_STAGE", self.test_compiler.stage.to_string())1141            .env("RUSTC_SYSROOT", builder.sysroot(self.test_compiler))1142            .env(1143                "RUSTDOC_LIBDIR",1144                builder.sysroot_target_libdir(self.test_compiler, self.test_compiler.host),1145            )1146            .env("CFG_RELEASE_CHANNEL", &builder.config.channel)1147            .env("RUSTDOC_REAL", builder.rustdoc_for_compiler(self.test_compiler))1148            .env("RUSTC_BOOTSTRAP", "1");1149        cmd.args(linker_args(builder, self.test_compiler.host, LldThreads::No));11501151        cmd.delay_failure().run(builder);1152    }11531154    fn metadata(&self) -> Option<StepMetadata> {1155        Some(1156            StepMetadata::test("rustdoc-theme", self.test_compiler.host)1157                .stage(self.test_compiler.stage),1158        )1159    }1160}11611162/// Test rustdoc JS for the standard library.1163#[derive(Debug, Clone, Hash, PartialEq, Eq)]1164pub struct RustdocJSStd {1165    /// Compiler that will build the standary library.1166    build_compiler: Compiler,1167    target: TargetSelection,1168}11691170impl Step for RustdocJSStd {1171    type Output = ();1172    const IS_HOST: bool = true;11731174    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1175        run.suite_path("tests/rustdoc-js-std")1176    }11771178    fn is_default_step(builder: &Builder<'_>) -> bool {1179        builder.config.nodejs.is_some()1180    }11811182    fn make_run(run: RunConfig<'_>) {1183        run.builder.ensure(RustdocJSStd {1184            build_compiler: run.builder.compiler(run.builder.top_stage, run.builder.host_target),1185            target: run.target,1186        });1187    }11881189    fn run(self, builder: &Builder<'_>) {1190        let nodejs =1191            builder.config.nodejs.as_ref().expect("need nodejs to run rustdoc-js-std tests");1192        let mut command = command(nodejs);1193        command1194            .arg(builder.src.join("src/tools/rustdoc-js/tester.js"))1195            .arg("--crate-name")1196            .arg("std")1197            .arg("--resource-suffix")1198            .arg(&builder.version)1199            .arg("--doc-folder")1200            .arg(builder.doc_out(self.target))1201            .arg("--test-folder")1202            .arg(builder.src.join("tests/rustdoc-js-std"));12031204        let full_suite = builder.paths.iter().any(|path| {1205            matches!(1206                helpers::is_valid_test_suite_arg(path, "tests/rustdoc-js-std", builder),1207                TestFilterCategory::Fullsuite1208            )1209        });12101211        // If we have to also run the full suite, don't worry about the individual arguments.1212        // They will be covered by running the entire suite1213        if !full_suite {1214            for path in &builder.paths {1215                if let TestFilterCategory::Arg(p) =1216                    helpers::is_valid_test_suite_arg(path, "tests/rustdoc-js-std", builder)1217                {1218                    if !p.ends_with(".js") {1219                        eprintln!("A non-js file was given: `{}`", path.display());1220                        panic!("Cannot run rustdoc-js-std tests");1221                    }1222                    command.arg("--test-file").arg(path);1223                }1224            }1225        }12261227        builder.ensure(crate::core::build_steps::doc::Std::from_build_compiler(1228            self.build_compiler,1229            self.target,1230            DocumentationFormat::Html,1231        ));1232        let _guard = builder.msg_test("rustdoc-js-std", self.target, self.build_compiler.stage);1233        command.run(builder);1234    }12351236    fn metadata(&self) -> Option<StepMetadata> {1237        Some(StepMetadata::test("rustdoc-js-std", self.target).stage(self.build_compiler.stage))1238    }1239}12401241#[derive(Debug, Clone, Hash, PartialEq, Eq)]1242pub struct RustdocJSNotStd {1243    pub target: TargetSelection,1244    pub compiler: Compiler,1245}12461247impl Step for RustdocJSNotStd {1248    type Output = ();1249    const IS_HOST: bool = true;12501251    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1252        run.suite_path("tests/rustdoc-js")1253    }12541255    fn is_default_step(builder: &Builder<'_>) -> bool {1256        builder.config.nodejs.is_some()1257    }12581259    fn make_run(run: RunConfig<'_>) {1260        let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());1261        run.builder.ensure(RustdocJSNotStd { target: run.target, compiler });1262    }12631264    fn run(self, builder: &Builder<'_>) {1265        builder.ensure(Compiletest {1266            test_compiler: self.compiler,1267            target: self.target,1268            mode: CompiletestMode::RustdocJs,1269            suite: "rustdoc-js",1270            path: "tests/rustdoc-js",1271            compare_mode: None,1272        });1273    }1274}12751276fn get_browser_ui_test_version_inner(1277    builder: &Builder<'_>,1278    yarn: &Path,1279    global: bool,1280) -> Option<String> {1281    let mut command = command(yarn);1282    command1283        .arg("--cwd")1284        .arg(&builder.build.out)1285        .arg("list")1286        .arg("--parseable")1287        .arg("--long")1288        .arg("--depth=0");1289    if global {1290        command.arg("--global");1291    }1292    // Cache the command output so that `test::RustdocGUI` only performs these1293    // command-line probes once.1294    let lines = command.allow_failure().cached().run_capture(builder).stdout();1295    lines1296        .lines()1297        .find_map(|l| l.split(':').nth(1)?.strip_prefix("browser-ui-test@"))1298        .map(|v| v.to_owned())1299}13001301fn get_browser_ui_test_version(builder: &Builder<'_>) -> Option<String> {1302    let yarn = builder.config.yarn.as_deref()?;1303    get_browser_ui_test_version_inner(builder, yarn, false)1304        .or_else(|| get_browser_ui_test_version_inner(builder, yarn, true))1305}13061307/// Run GUI tests on a given rustdoc.1308#[derive(Debug, Clone, Hash, PartialEq, Eq)]1309pub struct RustdocGUI {1310    /// The compiler whose rustdoc we are testing.1311    test_compiler: Compiler,1312    target: TargetSelection,1313}13141315impl Step for RustdocGUI {1316    type Output = ();1317    const IS_HOST: bool = true;13181319    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1320        run.suite_path("tests/rustdoc-gui")1321    }13221323    fn is_default_step(builder: &Builder<'_>) -> bool {1324        builder.config.nodejs.is_some()1325            && builder.test_target != TestTarget::DocOnly1326            && get_browser_ui_test_version(builder).is_some()1327    }13281329    fn make_run(run: RunConfig<'_>) {1330        let test_compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());1331        run.builder.ensure(RustdocGUI { test_compiler, target: run.target });1332    }13331334    fn run(self, builder: &Builder<'_>) {1335        builder.std(self.test_compiler, self.target);1336        let record_failed_tests = builder.ensure(SetupFailedTestsFile);13371338        let mut cmd = builder.tool_cmd(Tool::RustdocGUITest);13391340        let out_dir = builder.test_out(self.target).join("rustdoc-gui");1341        build_stamp::clear_if_dirty(1342            builder,1343            &out_dir,1344            &builder.rustdoc_for_compiler(self.test_compiler),1345        );13461347        if let Some(src) = builder.config.src.to_str() {1348            cmd.arg("--rust-src").arg(src);1349        }13501351        if let Some(out_dir) = out_dir.to_str() {1352            cmd.arg("--out-dir").arg(out_dir);1353        }13541355        if let Some(initial_cargo) = builder.config.initial_cargo.to_str() {1356            cmd.arg("--initial-cargo").arg(initial_cargo);1357        }13581359        cmd.arg("--jobs").arg(builder.jobs().to_string());13601361        cmd.env("RUSTDOC", builder.rustdoc_for_compiler(self.test_compiler))1362            .env("RUSTC", builder.rustc(self.test_compiler));13631364        add_rustdoc_cargo_linker_args(&mut cmd, builder, self.test_compiler.host, LldThreads::No);13651366        let full_suite = builder.paths.iter().any(|path| {1367            matches!(1368                helpers::is_valid_test_suite_arg(path, "tests/rustdoc-js-std", builder),1369                TestFilterCategory::Fullsuite1370            )1371        });13721373        // If we have to also run the full suite, don't worry about the individual arguments.1374        // They will be covered by running the entire suite1375        if !full_suite {1376            for path in &builder.paths {1377                if let TestFilterCategory::Arg(p) =1378                    helpers::is_valid_test_suite_arg(path, "tests/rustdoc-gui", builder)1379                {1380                    if !p.ends_with(".goml") {1381                        eprintln!("A non-goml file was given: `{}`", path.display());1382                        panic!("Cannot run rustdoc-gui tests");1383                    }1384                    if let Some(name) = path.file_name().and_then(|f| f.to_str()) {1385                        cmd.arg("--goml-file").arg(name);1386                    }1387                }1388            }1389        }13901391        for test_arg in builder.config.test_args() {1392            cmd.arg("--test-arg").arg(test_arg);1393        }13941395        if let Some(ref nodejs) = builder.config.nodejs {1396            cmd.arg("--nodejs").arg(nodejs);1397        }13981399        if let Some(ref yarn) = builder.config.yarn {1400            cmd.arg("--yarn").arg(yarn);1401        }14021403        let _time = helpers::timeit(builder);1404        let _guard = builder.msg_test("rustdoc-gui", self.target, self.test_compiler.stage);1405        try_run_tests(builder, &mut cmd, true, record_failed_tests);1406    }14071408    fn metadata(&self) -> Option<StepMetadata> {1409        Some(StepMetadata::test("rustdoc-gui", self.target).stage(self.test_compiler.stage))1410    }1411}14121413/// Runs `src/tools/tidy` and `cargo fmt --check` to detect various style1414/// problems in the repository.1415///1416/// (To run the tidy tool's internal tests, use the alias "tidyselftest" instead.)1417#[derive(Debug, Clone, PartialEq, Eq, Hash)]1418pub struct Tidy;14191420impl Step for Tidy {1421    type Output = ();1422    const IS_HOST: bool = true;14231424    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1425        run.path("src/tools/tidy")1426    }14271428    fn is_default_step(builder: &Builder<'_>) -> bool {1429        builder.test_target != TestTarget::DocOnly1430    }14311432    fn make_run(run: RunConfig<'_>) {1433        run.builder.ensure(Tidy);1434    }14351436    /// Runs the `tidy` tool.1437    ///1438    /// This tool in `src/tools` checks up on various bits and pieces of style and1439    /// otherwise just implements a few lint-like checks that are specific to the1440    /// compiler itself.1441    ///1442    /// Once tidy passes, this step also runs `fmt --check` if tests are being run1443    /// for the `dev` or `nightly` channels.1444    fn run(self, builder: &Builder<'_>) {1445        let mut cmd = builder.tool_cmd(Tool::Tidy);1446        cmd.arg(format!("--root-path={}", builder.src.display()));1447        cmd.arg(format!("--cargo-path={}", builder.initial_cargo.display()));1448        cmd.arg(format!("--output-dir={}", builder.out.display()));1449        // Tidy is heavily IO constrained. Still respect `-j`, but use a higher limit if `jobs` hasn't been configured.1450        let jobs = builder.config.jobs.unwrap_or_else(|| {1451            8 * std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get) as u321452        });1453        cmd.arg(format!("--concurrency={jobs}"));1454        // pass the path to the yarn command used for installing js deps.1455        if let Some(yarn) = &builder.config.yarn {1456            cmd.arg(format!("--npm-path={}", yarn.display()));1457        } else {1458            cmd.arg("--npm-path=yarn");1459        }1460        if builder.is_verbose() {1461            cmd.arg("--verbose");1462        }1463        if builder.config.cmd.bless() {1464            cmd.arg("--bless");1465        }1466        if builder.config.is_running_on_ci() {1467            cmd.arg("--ci=true");1468        }1469        if let Some(s) =1470            builder.config.cmd.extra_checks().or(builder.config.tidy_extra_checks.as_deref())1471        {1472            cmd.arg(format!("--extra-checks={s}"));1473        }1474        let mut args = std::env::args_os();1475        if args.any(|arg| arg == OsStr::new("--")) {1476            cmd.arg("--");1477            cmd.args(args);1478        }14791480        if builder.config.channel == "dev" || builder.config.channel == "nightly" {1481            if !builder.config.json_output {1482                builder.info("fmt check");1483                if builder.config.initial_rustfmt.is_none() {1484                    let inferred_rustfmt_dir = builder.initial_sysroot.join("bin");1485                    eprintln!(1486                        "\1487ERROR: no `rustfmt` binary found in {PATH}1488INFO: `rust.channel` is currently set to \"{CHAN}\"1489HELP: if you are testing a beta branch, set `rust.channel` to \"beta\" in the `bootstrap.toml` file1490HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to `x.py test`",1491                        PATH = inferred_rustfmt_dir.display(),1492                        CHAN = builder.config.channel,1493                    );1494                    crate::exit!(1);1495                }1496                let all = false;1497                crate::core::build_steps::format::format(1498                    builder,1499                    !builder.config.cmd.bless(),1500                    all,1501                    &[],1502                );1503            } else {1504                eprintln!(1505                    "WARNING: `--json-output` is not supported on rustfmt, formatting will be skipped"1506                );1507            }1508        }15091510        builder.info("tidy check");1511        cmd.delay_failure().run(builder);15121513        builder.info("x.py completions check");1514        let completion_paths = get_completion_paths(builder);1515        if builder.config.cmd.bless() {1516            builder.ensure(crate::core::build_steps::run::GenerateCompletions);1517        } else if completion_paths1518            .into_iter()1519            .any(|(shell, path)| get_completion(shell, &path).is_some())1520        {1521            eprintln!(1522                "x.py completions were changed; run `x.py run generate-completions` to update them"1523            );1524            crate::exit!(1);1525        }15261527        builder.info("x.py help check");1528        if builder.config.cmd.bless() {1529            builder.ensure(crate::core::build_steps::run::GenerateHelp);1530        } else {1531            let help_path = get_help_path(builder);1532            let cur_help = std::fs::read_to_string(&help_path).unwrap_or_else(|err| {1533                eprintln!("couldn't read {}: {}", help_path.display(), err);1534                crate::exit!(1);1535            });1536            let new_help = top_level_help();15371538            if new_help != cur_help {1539                eprintln!("x.py help was changed; run `x.py run generate-help` to update it");1540                crate::exit!(1);1541            }1542        }1543    }15441545    fn metadata(&self) -> Option<StepMetadata> {1546        Some(StepMetadata::test("tidy", TargetSelection::default()))1547    }1548}15491550/// Runs `cargo test` on the `src/tools/run-make-support` crate.1551/// That crate is used by run-make tests.1552#[derive(Debug, Clone, PartialEq, Eq, Hash)]1553pub struct CrateRunMakeSupport {1554    host: TargetSelection,1555}15561557impl Step for CrateRunMakeSupport {1558    type Output = ();1559    const IS_HOST: bool = true;15601561    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1562        run.path("src/tools/run-make-support")1563    }15641565    fn make_run(run: RunConfig<'_>) {1566        run.builder.ensure(CrateRunMakeSupport { host: run.target });1567    }15681569    /// Runs `cargo test` for run-make-support.1570    fn run(self, builder: &Builder<'_>) {1571        let host = self.host;1572        let compiler = builder.compiler(0, host);1573        let record_failed_tests = builder.ensure(SetupFailedTestsFile);15741575        let mut cargo = tool::prepare_tool_cargo(1576            builder,1577            compiler,1578            Mode::ToolBootstrap,1579            host,1580            Kind::Test,1581            "src/tools/run-make-support",1582            SourceType::InTree,1583            &[],1584        );1585        cargo.allow_features("test");1586        run_cargo_test(1587            cargo,1588            &[],1589            &[],1590            "run-make-support self test",1591            host,1592            builder,1593            record_failed_tests,1594        );1595    }1596}15971598#[derive(Debug, Clone, PartialEq, Eq, Hash)]1599pub struct CrateBuildHelper {1600    host: TargetSelection,1601}16021603impl Step for CrateBuildHelper {1604    type Output = ();1605    const IS_HOST: bool = true;16061607    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1608        run.path("src/build_helper")1609    }16101611    fn make_run(run: RunConfig<'_>) {1612        run.builder.ensure(CrateBuildHelper { host: run.target });1613    }16141615    /// Runs `cargo test` for build_helper.1616    fn run(self, builder: &Builder<'_>) {1617        let host = self.host;1618        let compiler = builder.compiler(0, host);1619        let record_failed_tests = builder.ensure(SetupFailedTestsFile);16201621        let mut cargo = tool::prepare_tool_cargo(1622            builder,1623            compiler,1624            Mode::ToolBootstrap,1625            host,1626            Kind::Test,1627            "src/build_helper",1628            SourceType::InTree,1629            &[],1630        );1631        cargo.allow_features("test");1632        run_cargo_test(1633            cargo,1634            &[],1635            &[],1636            "build_helper self test",1637            host,1638            builder,1639            record_failed_tests,1640        );1641    }1642}16431644fn testdir(builder: &Builder<'_>, host: TargetSelection) -> PathBuf {1645    builder.out.join(host).join("test")1646}16471648/// Declares a test step that invokes compiletest on a particular test suite.1649macro_rules! test {1650    (1651        $( #[$attr:meta] )* // allow docstrings and attributes1652        $name:ident {1653            path: $path:expr,1654            mode: $mode:expr,1655            suite: $suite:expr,1656            default: $default:expr1657            $( , IS_HOST: $IS_HOST:expr )? // default: false1658            $( , compare_mode: $compare_mode:expr )? // default: None1659            $( , )? // optional trailing comma1660        }1661    ) => {1662        $( #[$attr] )*1663        #[derive(Debug, Clone, PartialEq, Eq, Hash)]1664        pub struct $name {1665            test_compiler: Compiler,1666            target: TargetSelection,1667        }16681669        impl Step for $name {1670            type Output = ();1671            const IS_HOST: bool = (const {1672                #[allow(unused_assignments, unused_mut)]1673                let mut value = false;1674                $( value = $IS_HOST; )?1675                value1676            });16771678            fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1679                run.suite_path($path)1680            }16811682            fn is_default_step(_builder: &Builder<'_>) -> bool {1683                const { $default }1684            }16851686            fn make_run(run: RunConfig<'_>) {1687                let test_compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());16881689                run.builder.ensure($name { test_compiler, target: run.target });1690            }16911692            fn run(self, builder: &Builder<'_>) {1693                builder.ensure(Compiletest {1694                    test_compiler: self.test_compiler,1695                    target: self.target,1696                    mode: const { $mode },1697                    suite: $suite,1698                    path: $path,1699                    compare_mode: (const {1700                        #[allow(unused_assignments, unused_mut)]1701                        let mut value = None;1702                        $( value = $compare_mode; )?1703                        value1704                    }),1705                })1706            }1707        }1708    };1709}17101711test!(Ui { path: "tests/ui", mode: CompiletestMode::Ui, suite: "ui", default: true });17121713test!(Crashes {1714    path: "tests/crashes",1715    mode: CompiletestMode::Crashes,1716    suite: "crashes",1717    default: true,1718});17191720test!(CodegenLlvm {1721    path: "tests/codegen-llvm",1722    mode: CompiletestMode::Codegen,1723    suite: "codegen-llvm",1724    default: true1725});17261727test!(CodegenUnits {1728    path: "tests/codegen-units",1729    mode: CompiletestMode::CodegenUnits,1730    suite: "codegen-units",1731    default: true,1732});17331734test!(Incremental {1735    path: "tests/incremental",1736    mode: CompiletestMode::Incremental,1737    suite: "incremental",1738    default: true,1739});17401741test!(Debuginfo {1742    path: "tests/debuginfo",1743    mode: CompiletestMode::Debuginfo,1744    suite: "debuginfo",1745    default: true,1746    compare_mode: Some("split-dwarf"),1747});17481749test!(UiFullDeps {1750    path: "tests/ui-fulldeps",1751    mode: CompiletestMode::Ui,1752    suite: "ui-fulldeps",1753    default: true,1754    IS_HOST: true,1755});17561757test!(RustdocHtml {1758    path: "tests/rustdoc-html",1759    mode: CompiletestMode::RustdocHtml,1760    suite: "rustdoc-html",1761    default: true,1762    IS_HOST: true,1763});1764test!(RustdocUi {1765    path: "tests/rustdoc-ui",1766    mode: CompiletestMode::Ui,1767    suite: "rustdoc-ui",1768    default: true,1769    IS_HOST: true,1770});17711772test!(RustdocJson {1773    path: "tests/rustdoc-json",1774    mode: CompiletestMode::RustdocJson,1775    suite: "rustdoc-json",1776    default: true,1777    IS_HOST: true,1778});17791780test!(Pretty {1781    path: "tests/pretty",1782    mode: CompiletestMode::Pretty,1783    suite: "pretty",1784    default: true,1785    IS_HOST: true,1786});17871788test!(RunMake {1789    path: "tests/run-make",1790    mode: CompiletestMode::RunMake,1791    suite: "run-make",1792    default: true,1793});1794test!(RunMakeCargo {1795    path: "tests/run-make-cargo",1796    mode: CompiletestMode::RunMake,1797    suite: "run-make-cargo",1798    default: true1799});1800test!(BuildStd {1801    path: "tests/build-std",1802    mode: CompiletestMode::RunMake,1803    suite: "build-std",1804    default: false1805});18061807test!(AssemblyLlvm {1808    path: "tests/assembly-llvm",1809    mode: CompiletestMode::Assembly,1810    suite: "assembly-llvm",1811    default: true1812});18131814/// Runs the coverage test suite at `tests/coverage` in some or all of the1815/// coverage test modes.1816#[derive(Debug, Clone, PartialEq, Eq, Hash)]1817pub struct Coverage {1818    pub compiler: Compiler,1819    pub target: TargetSelection,1820    pub(crate) mode: CompiletestMode,1821}18221823impl Coverage {1824    const PATH: &'static str = "tests/coverage";1825    const SUITE: &'static str = "coverage";1826    const ALL_MODES: &[CompiletestMode] =1827        &[CompiletestMode::CoverageMap, CompiletestMode::CoverageRun];1828}18291830impl Step for Coverage {1831    type Output = ();1832    /// Compiletest will automatically skip the "coverage-run" tests if necessary.1833    const IS_HOST: bool = false;18341835    fn should_run(mut run: ShouldRun<'_>) -> ShouldRun<'_> {1836        // Support various invocation styles, including:1837        // - `./x test coverage`1838        // - `./x test tests/coverage/trivial.rs`1839        // - `./x test coverage-map`1840        // - `./x test coverage-run -- tests/coverage/trivial.rs`1841        run = run.suite_path(Self::PATH);1842        for mode in Self::ALL_MODES {1843            run = run.alias(mode.as_str());1844        }1845        run1846    }18471848    fn is_default_step(_builder: &Builder<'_>) -> bool {1849        true1850    }18511852    fn make_run(run: RunConfig<'_>) {1853        let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());1854        let target = run.target;18551856        // List of (coverage) test modes that the coverage test suite will be1857        // run in. It's OK for this to contain duplicates, because the call to1858        // `Builder::ensure` below will take care of deduplication.1859        let mut modes = vec![];18601861        // From the pathsets that were selected on the command-line (or by default),1862        // determine which modes to run in.1863        for path in &run.paths {1864            match path {1865                PathSet::Set(_) => {1866                    for &mode in Self::ALL_MODES {1867                        if path.assert_single_path().path == Path::new(mode.as_str()) {1868                            modes.push(mode);1869                            break;1870                        }1871                    }1872                }1873                PathSet::Suite(_) => {1874                    modes.extend_from_slice(Self::ALL_MODES);1875                    break;1876                }1877            }1878        }18791880        // Skip any modes that were explicitly skipped/excluded on the command-line.1881        // FIXME(Zalathar): Integrate this into central skip handling somehow?1882        modes.retain(|mode| {1883            !run.builder.config.skip.iter().any(|skip| skip == Path::new(mode.as_str()))1884        });18851886        // FIXME(Zalathar): Make these commands skip all coverage tests, as expected:1887        // - `./x test --skip=tests`1888        // - `./x test --skip=tests/coverage`1889        // - `./x test --skip=coverage`1890        // Skip handling currently doesn't have a way to know that skipping the coverage1891        // suite should also skip the `coverage-map` and `coverage-run` aliases.18921893        for mode in modes {1894            run.builder.ensure(Coverage { compiler, target, mode });1895        }1896    }18971898    fn run(self, builder: &Builder<'_>) {1899        let Self { compiler, target, mode } = self;1900        // Like other compiletest suite test steps, delegate to an internal1901        // compiletest task to actually run the tests.1902        builder.ensure(Compiletest {1903            test_compiler: compiler,1904            target,1905            mode,1906            suite: Self::SUITE,1907            path: Self::PATH,1908            compare_mode: None,1909        });1910    }1911}19121913test!(CoverageRunRustdoc {1914    path: "tests/coverage-run-rustdoc",1915    mode: CompiletestMode::CoverageRun,1916    suite: "coverage-run-rustdoc",1917    default: true,1918    IS_HOST: true,1919});19201921// For the mir-opt suite we do not use macros, as we need custom behavior when blessing.1922#[derive(Debug, Clone, PartialEq, Eq, Hash)]1923pub struct MirOpt {1924    pub compiler: Compiler,1925    pub target: TargetSelection,1926}19271928impl Step for MirOpt {1929    type Output = ();19301931    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {1932        run.suite_path("tests/mir-opt")1933    }19341935    fn is_default_step(_builder: &Builder<'_>) -> bool {1936        true1937    }19381939    fn make_run(run: RunConfig<'_>) {1940        let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());1941        run.builder.ensure(MirOpt { compiler, target: run.target });1942    }19431944    fn run(self, builder: &Builder<'_>) {1945        let run = |target| {1946            builder.ensure(Compiletest {1947                test_compiler: self.compiler,1948                target,1949                mode: CompiletestMode::MirOpt,1950                suite: "mir-opt",1951                path: "tests/mir-opt",1952                compare_mode: None,1953            })1954        };19551956        run(self.target);19571958        // Run more targets with `--bless`. But we always run the host target first, since some1959        // tests use very specific `only` clauses that are not covered by the target set below.1960        if builder.config.cmd.bless() {1961            // All that we really need to do is cover all combinations of 32/64-bit and unwind/abort,1962            // but while we're at it we might as well flex our cross-compilation support. This1963            // selection covers all our tier 1 operating systems and architectures using only tier1964            // 1 targets.19651966            for target in ["aarch64-unknown-linux-gnu", "i686-pc-windows-msvc"] {1967                run(TargetSelection::from_user(target));1968            }19691970            for target in ["x86_64-apple-darwin", "i686-unknown-linux-musl"] {1971                let target = TargetSelection::from_user(target);1972                let panic_abort_target = builder.ensure(MirOptPanicAbortSyntheticTarget {1973                    compiler: self.compiler,1974                    base: target,1975                });1976                run(panic_abort_target);1977            }1978        }1979    }1980}19811982/// Executes the `compiletest` tool to run a suite of tests.1983///1984/// Compiles all tests with `test_compiler` for `target` with the specified1985/// compiletest `mode` and `suite` arguments. For example `mode` can be1986/// "mir-opt" and `suite` can be something like "debuginfo".1987#[derive(Debug, Clone, PartialEq, Eq, Hash)]1988struct Compiletest {1989    /// The compiler that we're testing.1990    test_compiler: Compiler,1991    target: TargetSelection,1992    mode: CompiletestMode,1993    suite: &'static str,1994    path: &'static str,1995    compare_mode: Option<&'static str>,1996}19971998impl Step for Compiletest {1999    type Output = ();

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.