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.