From a57cdb46d83defc4ce64cb3f343c11927424068e Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Mon, 28 Jul 2025 14:12:20 +0800 Subject: [PATCH 1/4] Remove ability to check/build/test `compiletest` as stage 0 bootstrap tool Instead, consider this as an `ToolStd` tool until `compiletest`'s dependency in the unstable `#![feature(internal_output_capture)]` is replaced by a stable implementation. --- bootstrap.example.toml | 3 -- src/bootstrap/defaults/bootstrap.dist.toml | 2 - src/bootstrap/src/core/build_steps/check.rs | 44 +++++++++------------ src/bootstrap/src/core/build_steps/tool.rs | 3 +- src/bootstrap/src/core/config/config.rs | 4 -- src/bootstrap/src/core/config/toml/build.rs | 1 - 6 files changed, 20 insertions(+), 37 deletions(-) diff --git a/bootstrap.example.toml b/bootstrap.example.toml index 73e93ccbe4202..c02359adafb1d 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -465,9 +465,6 @@ # What custom diff tool to use for displaying compiletest tests. #build.compiletest-diff-tool = -# Whether to use the precompiled stage0 libtest with compiletest. -#build.compiletest-use-stage0-libtest = true - # Default value for the `--extra-checks` flag of tidy. # # See `./x test tidy --help` for details. diff --git a/src/bootstrap/defaults/bootstrap.dist.toml b/src/bootstrap/defaults/bootstrap.dist.toml index 9daf9faac14a2..eb7ed451abf9f 100644 --- a/src/bootstrap/defaults/bootstrap.dist.toml +++ b/src/bootstrap/defaults/bootstrap.dist.toml @@ -7,8 +7,6 @@ test-stage = 2 doc-stage = 2 # When compiling from source, you usually want all tools. extended = true -# Use libtest built from the source tree instead of the precompiled one from stage 0. -compiletest-use-stage0-libtest = false # Most users installing from source want to build all parts of the project from source. [llvm] diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index cfe090b22dc32..e0e8e5779b6cd 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -376,7 +376,7 @@ macro_rules! tool_check_step { // The part of this path after the final '/' is also used as a display name. path: $path:literal $(, alt_path: $alt_path:literal )* - // Closure that returns `Mode` based on the passed `&Builder<'_>` + // Under which tool mode should the tool be checked with? , mode: $mode:expr // Subset of nightly features that are allowed to be used when checking $(, allow_features: $allow_features:expr )? @@ -404,8 +404,7 @@ macro_rules! tool_check_step { fn make_run(run: RunConfig<'_>) { let target = run.target; - let builder = run.builder; - let mode = $mode(builder); + let mode = $mode; let build_compiler = prepare_compiler_for_check(run.builder, target, mode); @@ -426,7 +425,7 @@ macro_rules! tool_check_step { _value }; let extra_features: &[&str] = &[$($($enable_features),*)?]; - let mode = $mode(builder); + let mode = $mode; run_tool_check_step(builder, build_compiler, target, $path, mode, allow_features, extra_features); } @@ -493,54 +492,50 @@ fn run_tool_check_step( tool_check_step!(Rustdoc { path: "src/tools/rustdoc", alt_path: "src/librustdoc", - mode: |_builder| Mode::ToolRustc + mode: Mode::ToolRustc }); // Clippy, miri and Rustfmt are hybrids. They are external tools, but use a git subtree instead // of a submodule. Since the SourceType only drives the deny-warnings // behavior, treat it as in-tree so that any new warnings in clippy will be // rejected. -tool_check_step!(Clippy { path: "src/tools/clippy", mode: |_builder| Mode::ToolRustc }); -tool_check_step!(Miri { path: "src/tools/miri", mode: |_builder| Mode::ToolRustc }); -tool_check_step!(CargoMiri { path: "src/tools/miri/cargo-miri", mode: |_builder| Mode::ToolRustc }); -tool_check_step!(Rustfmt { path: "src/tools/rustfmt", mode: |_builder| Mode::ToolRustc }); +tool_check_step!(Clippy { path: "src/tools/clippy", mode: Mode::ToolRustc }); +tool_check_step!(Miri { path: "src/tools/miri", mode: Mode::ToolRustc }); +tool_check_step!(CargoMiri { path: "src/tools/miri/cargo-miri", mode: Mode::ToolRustc }); +tool_check_step!(Rustfmt { path: "src/tools/rustfmt", mode: Mode::ToolRustc }); tool_check_step!(RustAnalyzer { path: "src/tools/rust-analyzer", - mode: |_builder| Mode::ToolRustc, + mode: Mode::ToolRustc, allow_features: tool::RustAnalyzer::ALLOW_FEATURES, enable_features: ["in-rust-tree"], }); tool_check_step!(MiroptTestTools { path: "src/tools/miropt-test-tools", - mode: |_builder| Mode::ToolBootstrap + mode: Mode::ToolBootstrap }); // We want to test the local std tool_check_step!(TestFloatParse { path: "src/tools/test-float-parse", - mode: |_builder| Mode::ToolStd, + mode: Mode::ToolStd, allow_features: tool::TestFloatParse::ALLOW_FEATURES }); tool_check_step!(FeaturesStatusDump { path: "src/tools/features-status-dump", - mode: |_builder| Mode::ToolBootstrap + mode: Mode::ToolBootstrap }); -tool_check_step!(Bootstrap { - path: "src/bootstrap", - mode: |_builder| Mode::ToolBootstrap, - default: false -}); +tool_check_step!(Bootstrap { path: "src/bootstrap", mode: Mode::ToolBootstrap, default: false }); // `run-make-support` will be built as part of suitable run-make compiletest test steps, but support // check to make it easier to work on. tool_check_step!(RunMakeSupport { path: "src/tools/run-make-support", - mode: |_builder| Mode::ToolBootstrap, + mode: Mode::ToolBootstrap, default: false }); tool_check_step!(CoverageDump { path: "src/tools/coverage-dump", - mode: |_builder| Mode::ToolBootstrap, + mode: Mode::ToolBootstrap, default: false }); @@ -548,11 +543,10 @@ tool_check_step!(CoverageDump { // so this is mainly for people working on compiletest to run locally. tool_check_step!(Compiletest { path: "src/tools/compiletest", - mode: |builder: &Builder<'_>| if builder.config.compiletest_use_stage0_libtest { - Mode::ToolBootstrap - } else { - Mode::ToolStd - }, + // Note: compiletest currently still depends on `#![feature(internal_output_capture)]`, so + // should be considered a `ToolStd` tool for robustness, as it is *possible* for that internal + // library feature to be changed. + mode: Mode::ToolStd, allow_features: COMPILETEST_ALLOW_FEATURES, default: false, }); diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index f5fa33b98f3bf..e11dfe82a45c6 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -491,13 +491,12 @@ macro_rules! bootstrap_tool { )* let is_unstable = false $(|| $unstable)*; - let compiletest_wants_stage0 = $tool_name == "compiletest" && builder.config.compiletest_use_stage0_libtest; builder.ensure(ToolBuild { build_compiler: self.compiler, target: self.target, tool: $tool_name, - mode: if is_unstable && !compiletest_wants_stage0 { + mode: if is_unstable { // use in-tree libraries for unstable features Mode::ToolStd } else { diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 6e04f11542438..f93b3f5569e6a 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -296,8 +296,6 @@ pub struct Config { /// Command for visual diff display, e.g. `diff-tool --color=always`. pub compiletest_diff_tool: Option, - /// Whether to use the precompiled stage0 libtest with compiletest. - pub compiletest_use_stage0_libtest: bool, /// Default value for `--extra-checks` pub tidy_extra_checks: Option, pub is_running_on_ci: bool, @@ -747,7 +745,6 @@ impl Config { optimized_compiler_builtins, jobs, compiletest_diff_tool, - compiletest_use_stage0_libtest, tidy_extra_checks, ccache, exclude, @@ -1013,7 +1010,6 @@ impl Config { config.optimized_compiler_builtins = optimized_compiler_builtins.unwrap_or(config.channel != "dev"); config.compiletest_diff_tool = compiletest_diff_tool; - config.compiletest_use_stage0_libtest = compiletest_use_stage0_libtest.unwrap_or(true); config.tidy_extra_checks = tidy_extra_checks; let download_rustc = config.download_rustc_commit.is_some(); diff --git a/src/bootstrap/src/core/config/toml/build.rs b/src/bootstrap/src/core/config/toml/build.rs index 4d29691f38b66..4397e6c30eb38 100644 --- a/src/bootstrap/src/core/config/toml/build.rs +++ b/src/bootstrap/src/core/config/toml/build.rs @@ -68,7 +68,6 @@ define_config! { optimized_compiler_builtins: Option = "optimized-compiler-builtins", jobs: Option = "jobs", compiletest_diff_tool: Option = "compiletest-diff-tool", - compiletest_use_stage0_libtest: Option = "compiletest-use-stage0-libtest", tidy_extra_checks: Option = "tidy-extra-checks", ccache: Option = "ccache", exclude: Option> = "exclude", From 357f79a55cc5a2caddf64f28c3e91e607beba8da Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Mon, 28 Jul 2025 14:14:50 +0800 Subject: [PATCH 2/4] Check/test `compiletest` normally as a staged `ToolStd` tool But remove `python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true` from `pr-check-1` and move `./x test compiletest` to the last (and test `compiletest` unit tests against staged compiler/library), as this will require a stage 1 (compiler, library) build to build `compiletest` itself as well. --- src/ci/citool/tests/test-jobs.yml | 2 +- src/ci/docker/host-x86_64/pr-check-1/Dockerfile | 5 ++--- src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile | 2 +- src/ci/github-actions/jobs.yml | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/ci/citool/tests/test-jobs.yml b/src/ci/citool/tests/test-jobs.yml index d82b3e7648e17..512c806285746 100644 --- a/src/ci/citool/tests/test-jobs.yml +++ b/src/ci/citool/tests/test-jobs.yml @@ -27,7 +27,7 @@ runners: <<: *base-job envs: env-x86_64-apple-tests: &env-x86_64-apple-tests - SCRIPT: ./x.py check compiletest --set build.compiletest-use-stage0-libtest=true && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact + SCRIPT: ./x.py check compiletest && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 # Ensure that host tooling is tested on our minimum supported macOS version. diff --git a/src/ci/docker/host-x86_64/pr-check-1/Dockerfile b/src/ci/docker/host-x86_64/pr-check-1/Dockerfile index f7d51fba861e1..8e1b173eb541f 100644 --- a/src/ci/docker/host-x86_64/pr-check-1/Dockerfile +++ b/src/ci/docker/host-x86_64/pr-check-1/Dockerfile @@ -43,10 +43,9 @@ ENV SCRIPT \ python3 ../x.py check bootstrap && \ /scripts/check-default-config-profiles.sh && \ python3 ../x.py build src/tools/build-manifest && \ - python3 ../x.py test --stage 0 src/tools/compiletest && \ - python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \ python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \ python3 ../x.py check --set build.optimized-compiler-builtins=false core alloc std --target=aarch64-unknown-linux-gnu,i686-pc-windows-msvc,i686-unknown-linux-gnu,x86_64-apple-darwin,x86_64-pc-windows-gnu,x86_64-pc-windows-msvc && \ /scripts/validate-toolstate.sh && \ reuse --include-submodules lint && \ - python3 ../x.py test collect-license-metadata + python3 ../x.py test collect-license-metadata && \ + python3 ../x.py test src/tools/compiletest diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index 95357d229374c..60873ad636046 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -90,5 +90,5 @@ ENV HOST_TARGET x86_64-unknown-linux-gnu COPY scripts/shared.sh /scripts/ ENV SCRIPT /tmp/checktools.sh ../x.py && \ - python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \ + python3 ../x.py check compiletest && \ python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args "'--jobs 1'" diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 011688487b447..5746394dce8d1 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -78,7 +78,7 @@ runners: envs: env-x86_64-apple-tests: &env-x86_64-apple-tests - SCRIPT: ./x.py check compiletest --set build.compiletest-use-stage0-libtest=true && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact + SCRIPT: ./x.py check compiletest && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc # Ensure that host tooling is tested on our minimum supported macOS version. MACOSX_DEPLOYMENT_TARGET: 10.12 From 372e25df973c0aa989db6a77942e8cf4af16e950 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Mon, 28 Jul 2025 15:07:40 +0800 Subject: [PATCH 3/4] Introduce first-class `compiletest-force-stage0` override Instead of the ad-hoc `COMPILETEST_FORCE_STAGE0` env var. However, explicitly do not test this configuration under CI, as tests are most certainly not guaranteed to pass against stage 0 (compiler, library). --- bootstrap.example.toml | 8 ++++++ src/bootstrap/src/core/build_steps/test.rs | 26 +++++++++++------- src/bootstrap/src/core/build_steps/tool.rs | 2 +- src/bootstrap/src/core/builder/tests.rs | 30 ++++++++++++++------- src/bootstrap/src/core/config/config.rs | 8 ++++++ src/bootstrap/src/core/config/toml/build.rs | 1 + 6 files changed, 55 insertions(+), 20 deletions(-) diff --git a/bootstrap.example.toml b/bootstrap.example.toml index c02359adafb1d..7a0d7f783ffeb 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -462,6 +462,14 @@ # passed to cargo invocations. #build.jobs = 0 +# Whether to force `compiletest` to be built and run against the stage 0 +# toolchain (i.e. stage 0 compiler and library). +# +# Both `compiletest`-managed test suites and `compiletest`'s own unit tests are +# **not an explicitly supported configuration**, and almost certainly will incur +# test failures against the stage 0 compiler and library. +#build.compiletest-force-stage0 = false + # What custom diff tool to use for displaying compiletest tests. #build.compiletest-diff-tool = diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 0f9268097d7b7..5ad4897df71fa 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -8,6 +8,8 @@ use std::ffi::{OsStr, OsString}; use std::path::{Path, PathBuf}; use std::{env, fs, iter}; +use build_helper::exit; + use crate::core::build_steps::compile::{Std, run_cargo}; use crate::core::build_steps::doc::DocumentationFormat; use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags}; @@ -714,17 +716,24 @@ impl Step for CompiletestTest { /// Runs `cargo test` for compiletest. fn run(self, builder: &Builder<'_>) { + if builder.top_stage == 0 && !builder.config.compiletest_force_stage0 { + eprintln!( + "`compiletest` unit tests cannot be run against stage 0 unless `build.compiletest-force-stage0` override is specified" + ); + exit!(1); + } + let host = self.host; let compiler = builder.compiler(builder.top_stage, host); - // We need `ToolStd` for the locally-built sysroot because - // compiletest uses unstable features of the `test` crate. + // We need `ToolStd` for the locally-built sysroot because compiletest uses unstable + // features of the `test` crate. builder.std(compiler, host); let mut cargo = tool::prepare_tool_cargo( builder, compiler, - // compiletest uses libtest internals; make it use the in-tree std to make sure it never breaks - // when std sources change. + // compiletest uses libtest internals; make it use the in-tree std to make sure it never + // breaks when std sources change. Mode::ToolStd, host, Kind::Test, @@ -1612,12 +1621,11 @@ impl Step for Compiletest { return; } - if builder.top_stage == 0 && env::var("COMPILETEST_FORCE_STAGE0").is_err() { + if builder.top_stage == 0 && !builder.config.compiletest_force_stage0 { eprintln!("\ -ERROR: `--stage 0` runs compiletest on the stage0 (precompiled) compiler, not your local changes, and will almost always cause tests to fail -HELP: to test the compiler, use `--stage 1` instead -HELP: to test the standard library, use `--stage 0 library/std` instead -NOTE: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `COMPILETEST_FORCE_STAGE0=1`." +ERROR: `--stage 0` runs `compiletest` on the stage0 (precompiled) compiler, not your local changes, and will almost always cause tests to fail +HELP: to test the staged compiler/library, use `--stage 1` instead +NOTE: 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-force-stage0=true`." ); crate::exit!(1); } diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index e11dfe82a45c6..43fd112d7b83d 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -496,7 +496,7 @@ macro_rules! bootstrap_tool { build_compiler: self.compiler, target: self.target, tool: $tool_name, - mode: if is_unstable { + mode: if is_unstable || !builder.config.compiletest_force_stage0 { // use in-tree libraries for unstable features Mode::ToolStd } else { diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 6ea5d4e655328..6f13182d8f487 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1531,16 +1531,6 @@ mod snapshot { insta::assert_snapshot!( ctx.config("check") .path("compiletest") - .render_steps(), @"[check] rustc 0 -> Compiletest 1 "); - } - - #[test] - fn check_compiletest_stage1_libtest() { - let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("check") - .path("compiletest") - .args(&["--set", "build.compiletest-use-stage0-libtest=false"]) .render_steps(), @r" [build] llvm [build] rustc 0 -> rustc 1 @@ -1549,6 +1539,26 @@ mod snapshot { "); } + #[test] + #[should_panic] + fn test_compiletest_stage0_no_force() { + let ctx = TestCtx::new(); + ctx.config("test").path("compiletest").stage(0).run(); + } + + #[test] + fn test_compiletest_force_stage0() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("test") + .path("compiletest") + .stage(0) + .args(&[ + "--set", "build.compiletest-force-stage0=true" + ]) + .render_steps(), @"[build] rustdoc 0 "); + } + #[test] fn check_codegen() { let ctx = TestCtx::new(); diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index f93b3f5569e6a..7e05c29d242ba 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -293,6 +293,10 @@ pub struct Config { /// `paths=["foo", "bar"]`. pub paths: Vec, + /// Force `compiletest` to be built and tested with stage 0 (compiler, library). Note that + /// `compiletest`'s own unit tests are not guaranteed to pass against stage 0 (compiler, + /// library)! + pub compiletest_force_stage0: bool, /// Command for visual diff display, e.g. `diff-tool --color=always`. pub compiletest_diff_tool: Option, @@ -744,6 +748,7 @@ impl Config { android_ndk, optimized_compiler_builtins, jobs, + compiletest_force_stage0, compiletest_diff_tool, tidy_extra_checks, ccache, @@ -1009,7 +1014,10 @@ impl Config { config.optimized_compiler_builtins = optimized_compiler_builtins.unwrap_or(config.channel != "dev"); + + config.compiletest_force_stage0 = compiletest_force_stage0.unwrap_or(false); config.compiletest_diff_tool = compiletest_diff_tool; + config.tidy_extra_checks = tidy_extra_checks; let download_rustc = config.download_rustc_commit.is_some(); diff --git a/src/bootstrap/src/core/config/toml/build.rs b/src/bootstrap/src/core/config/toml/build.rs index 4397e6c30eb38..b3b0754005ca8 100644 --- a/src/bootstrap/src/core/config/toml/build.rs +++ b/src/bootstrap/src/core/config/toml/build.rs @@ -67,6 +67,7 @@ define_config! { android_ndk: Option = "android-ndk", optimized_compiler_builtins: Option = "optimized-compiler-builtins", jobs: Option = "jobs", + compiletest_force_stage0: Option = "compiletest-force-stage0", compiletest_diff_tool: Option = "compiletest-diff-tool", tidy_extra_checks: Option = "tidy-extra-checks", ccache: Option = "ccache", From 1a97eec0ea9788d473009ebe3e428a005e3af3a0 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Mon, 28 Jul 2025 15:57:53 +0800 Subject: [PATCH 4/4] Add change tracker entry --- src/bootstrap/src/utils/change_tracker.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 4b0c482136485..b930f89578b18 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -486,4 +486,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "Removed `rust.description` and `llvm.ccache` as it was deprecated in #137723 and #136941 long time ago.", }, + ChangeInfo { + change_id: 144563, + severity: ChangeSeverity::Warning, + summary: "Removed `build.compiletest-use-stage0-libtest` as `compiletest` is now considered a staged `ToolStd` tool. The possibility to run `compiletest`-managed test suites or `compiletest` unit tests against a stage 0 compiler is retained, but instead of `COMPILETEST_FORCE_STAGE0` env var, it is now a proper config option `build.compiletest-force-stage0`.", + }, ];