From 824062852772eefc601aaaee5e040ea522f6ff4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 2 Oct 2026 14:25:10 +0200 Subject: [PATCH 1/7] Add `RUSTC_BOOTSTRAP=-2` as a way of simulating a stable rustc in UI tests --- compiler/rustc_driver_impl/src/lib.rs | 2 +- compiler/rustc_feature/src/lib.rs | 36 +++++++++++++++++-- compiler/rustc_feature/src/tests.rs | 7 ++++ compiler/rustc_session/src/config.rs | 30 +++++++++------- src/doc/rustc-dev-guide/src/tests/misc.md | 28 +++++++-------- src/librustdoc/config.rs | 2 +- ..._bootstrap.force_stable_allow_flags.stderr | 9 +++++ tests/ui/bootstrap/rustc_bootstrap.rs | 10 ++++-- 8 files changed, 88 insertions(+), 36 deletions(-) create mode 100644 tests/ui/bootstrap/rustc_bootstrap.force_stable_allow_flags.stderr diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 9b1f43156522e..ea62f1545f633 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -1304,7 +1304,7 @@ pub fn handle_help(matches: &getopts::Matches, args: &[String]) -> bool { let chelp_pos = opt_help_pos("C"); let print_help = || { // Only show unstable options in --help if we accept unstable options. - let unstable_enabled = nightly_options::is_unstable_enabled(&matches); + let unstable_enabled = nightly_options::unstable_options_enabled(&matches); let nightly_build = nightly_options::match_is_nightly_build(&matches); usage(matches.opt_present("verbose"), unstable_enabled, nightly_build); }; diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index 83bf4f47a8ac9..e2eadaa66b0f0 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -36,15 +36,34 @@ pub struct Feature { #[derive(Clone, Copy, Debug, Hash)] pub enum UnstableFeatures { - /// Disallow use of unstable features, as on beta/stable channels. + /// Disallow use of unstable features and unstable compiler flags. + /// + /// Used by default by beta/stable channels. Disallow, - /// Allow use of unstable features, as on nightly. + /// Allow use of unstable features and unstable compiler flags. + /// + /// Used by default by the nightly channel. Allow, + /// Allow use of unstable features and unstable compiler flags, even if it is not the default + /// behavior. + /// + /// Can be used to make a beta/stable channel act like a nightly channel. + /// /// Errors are bypassed for bootstrapping. This is required any time /// during the build that feature-related lints are set to warn or above /// because the build turns on warnings-as-errors and uses lots of unstable /// features. As a result, this is always required for building Rust itself. Cheat, + /// Allow the use of *unstable compiler flags*, but disallow the use of + /// *unstable language features*. + /// And in general, try to treat everything except for compiler flags as if we were on stable. + /// + /// **This mode is designed only for internal testing of rustc.** + /// + /// Specifically, we need it when we want to test how rustc behaves on the stable channel, + /// but at the same time we need to be able to pass it some unstable `-Z` compiler flags + /// required for the testing infrastructure itself to work. + ActAsStableForTesting, } impl UnstableFeatures { @@ -76,6 +95,8 @@ impl UnstableFeatures { // Hypnotize ourselves so that we think we are a stable compiler and thus don't // allow any unstable features. "-1" => return UnstableFeatures::Disallow, + // Act as stable, but still accept unstable compiler flags required by compiletest + "-2" => return UnstableFeatures::ActAsStableForTesting, _ => {} } } @@ -83,10 +104,19 @@ impl UnstableFeatures { if disable_unstable_features { UnstableFeatures::Disallow } else { UnstableFeatures::Allow } } + pub fn allow_unstable_compiler_flags(&self) -> bool { + match *self { + UnstableFeatures::Allow + | UnstableFeatures::Cheat + | UnstableFeatures::ActAsStableForTesting => true, + UnstableFeatures::Disallow => false, + } + } + pub fn is_nightly_build(&self) -> bool { match *self { UnstableFeatures::Allow | UnstableFeatures::Cheat => true, - UnstableFeatures::Disallow => false, + UnstableFeatures::Disallow | UnstableFeatures::ActAsStableForTesting => false, } } } diff --git a/compiler/rustc_feature/src/tests.rs b/compiler/rustc_feature/src/tests.rs index a5d589171d105..9280a9de7e506 100644 --- a/compiler/rustc_feature/src/tests.rs +++ b/compiler/rustc_feature/src/tests.rs @@ -34,4 +34,11 @@ fn rustc_bootstrap_parsing() { // Does not support specifying any crate. assert!(is_force_stable(Some("x"))); assert!(is_force_stable(Some("x,y,z"))); + + // `RUSTC_BOOTSTRAP=-2` simulates the stable toolchain, while allowing unstable compiler flags + // to be passed. + std::assert_matches!( + UnstableFeatures::from_environment_value(None, Ok("-2".to_string())), + UnstableFeatures::ActAsStableForTesting + ); } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 7e274c66f6f75..a4f8bcf2dab6c 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2411,7 +2411,7 @@ pub fn parse_crate_edition( } }; - if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) { + if !edition.is_stable() && !nightly_options::unstable_options_enabled(matches) { let msg = if !is_nightly { format!( "the crate requires edition {edition}, but the latest edition supported by this \ @@ -2429,10 +2429,10 @@ pub fn parse_crate_edition( fn check_error_format_stability( early_dcx: &EarlyDiagCtxt, unstable_opts: &UnstableOptions, - is_nightly_build: bool, + unstable_flags_enabled: bool, format: ErrorOutputType, ) { - if unstable_opts.unstable_options || is_nightly_build { + if unstable_opts.unstable_options || unstable_flags_enabled { return; } let format = match format { @@ -2792,7 +2792,7 @@ pub fn build_session_options( check_error_format_stability( early_dcx, &unstable_opts, - unstable_features.is_nightly_build(), + unstable_features.allow_unstable_compiler_flags(), error_format, ); @@ -2888,7 +2888,7 @@ pub fn build_session_options( } } - let unstable_options_enabled = nightly_options::is_unstable_enabled(matches); + let unstable_options_enabled = nightly_options::unstable_options_enabled(matches); if !unstable_options_enabled && cg.force_frame_pointers == FramePointer::NonLeaf { early_dcx.early_fatal( "`-Cforce-frame-pointers=non-leaf` or `always` also requires `-Zunstable-options` \ @@ -2896,7 +2896,7 @@ pub fn build_session_options( ) } - if !nightly_options::is_unstable_enabled(matches) && !unstable_opts.offload.is_empty() { + if !unstable_options_enabled && !unstable_opts.offload.is_empty() { early_dcx.early_fatal( "`-Zoffload=Enable` also requires `-Zunstable-options` and a nightly compiler", ) @@ -3199,17 +3199,21 @@ pub mod nightly_options { use super::{OptionStability, RustcOptGroup}; use crate::EarlyDiagCtxt; - pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool { - match_is_nightly_build(matches) + /// Are we allowed to use -Z compiler flags *and* -Zunstable-options was passed? + pub fn unstable_options_enabled(matches: &getopts::Matches) -> bool { + unstable_compiler_flags_allowed(matches) && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options") } - pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool { - is_nightly_build(matches.opt_str("crate-name").as_deref()) + /// Are we allowed to use -Z compiler flags? + pub fn unstable_compiler_flags_allowed(matches: &getopts::Matches) -> bool { + UnstableFeatures::from_environment(matches.opt_str("crate-name").as_deref()) + .allow_unstable_compiler_flags() } - fn is_nightly_build(krate: Option<&str>) -> bool { - UnstableFeatures::from_environment(krate).is_nightly_build() + pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool { + let krate = matches.opt_str("crate-name"); + UnstableFeatures::from_environment(krate.as_deref()).is_nightly_build() } pub fn check_nightly_options( @@ -3218,7 +3222,7 @@ pub mod nightly_options { flags: &[RustcOptGroup], ) { let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options"); - let really_allows_unstable_options = match_is_nightly_build(matches); + let really_allows_unstable_options = unstable_compiler_flags_allowed(matches); let mut nightly_options_on_stable = 0; for opt in flags.iter() { diff --git a/src/doc/rustc-dev-guide/src/tests/misc.md b/src/doc/rustc-dev-guide/src/tests/misc.md index e8671257a4144..167e57f757a3d 100644 --- a/src/doc/rustc-dev-guide/src/tests/misc.md +++ b/src/doc/rustc-dev-guide/src/tests/misc.md @@ -11,23 +11,19 @@ This is a bootstrap/compiler implementation detail, but it can also be useful fo even if it's actually a nightly `rustc`. This is useful because some behaviors of the compiler (e.g. diagnostics) can differ depending on whether the compiler is nightly or not. - -Note that setting `RUSTC_BOOTSTRAP` in ui tests (e.g. via `//@ rustc-env`) is pointless since ui +- `RUSTC_BOOTSTRAP=-2` will force a given `rustc` to pretend it is a stable + compiler, even if it's actually a nightly `rustc`. + However, the compiler will still accept unstable compiler flags. + This is useful for internal testing of the compiler, where we need to pass + unstable flags required by compiletest, but we also want to test the compiler's + behavior on the stable channel. + +Note that setting `RUSTC_BOOTSTRAP=-1` in ui tests (e.g. via `//@ rustc-env`) is pointless since ui tests inherit the bootstrap env var from bootstrap (so it's set to `1` by default), and since compiletest itself passes `-Z` flags (so `-1` breaks the test). -To test stable-only behavior, you need to write a `run-make` test instead. +To test stable-only behavior, use +`RUSTC_BOOTSTRAP=-2` instead. For `run-make`/`run-make-cargo` tests, `//@ rustc-env` is not supported. -You can do something like the following for individual `rustc` invocations. - -```rust,ignore -use run_make_support::rustc; - -fn main() { - rustc() - // Pretend that I am very stable - .env("RUSTC_BOOTSTRAP", "-1") - //... - .run(); -} -``` +You can do use the `run_make_support::stable_bare_rustc` function to create an instance of the compiler +that acts as the stable channel (this internally uses `RUSTC_BOOTSTRAP=-1`). diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 7604973739f08..6e988728858a8 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -452,7 +452,7 @@ impl Options { match ( output_format_s.as_ref().map(|_| output_format), show_coverage, - nightly_options::is_unstable_enabled(matches), + nightly_options::unstable_options_enabled(matches), ) { (None | Some(OutputFormat::CoverageJson), true, _) => {} (_, true, _) => { diff --git a/tests/ui/bootstrap/rustc_bootstrap.force_stable_allow_flags.stderr b/tests/ui/bootstrap/rustc_bootstrap.force_stable_allow_flags.stderr new file mode 100644 index 0000000000000..c4436ca5a1815 --- /dev/null +++ b/tests/ui/bootstrap/rustc_bootstrap.force_stable_allow_flags.stderr @@ -0,0 +1,9 @@ +error[E0554]: `#![feature]` may not be used on the nightly release channel + --> $DIR/rustc_bootstrap.rs:51:1 + | +LL | #![feature(rustc_attrs)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0554`. diff --git a/tests/ui/bootstrap/rustc_bootstrap.rs b/tests/ui/bootstrap/rustc_bootstrap.rs index fb72bba95a158..96a464e8e4dbe 100644 --- a/tests/ui/bootstrap/rustc_bootstrap.rs +++ b/tests/ui/bootstrap/rustc_bootstrap.rs @@ -6,11 +6,13 @@ //! - `1`: cheat, allow usage of unstable features even if rustc thinks it is a stable compiler. //! - `x,y,z`: comma-delimited list of crates. //! - `-1`: force rustc to think it is a stable compiler. +//! - `-2`: force rustc to think it is a stable compiler, while still allowing -Z flags. // ignore-tidy-linelength -//@ revisions: default_nightly cheat cheat_single_crate cheat_multi_crate force_stable invalid_zero invalid_junk +//@ revisions: default_nightly cheat cheat_single_crate cheat_multi_crate force_stable force_stable_allow_flags invalid_zero invalid_junk //@ only-nightly +//@ normalize-stderr: "dev release channel" -> "nightly release channel" //@[default_nightly] unset-rustc-env:RUSTC_BOOTSTRAP //@[default_nightly] check-pass @@ -39,10 +41,14 @@ //@[force_stable] rustc-env:RUSTC_BOOTSTRAP=-1 //@[force_stable] compile-flags: -Z unstable-options -#![crate_type = "lib"] +// Here rustc shouldn't complain about compiletest's -Z flags being passed. +//@[force_stable_allow_flags] rustc-env:RUSTC_BOOTSTRAP=-2 +//@[force_stable_allow_flags] compile-flags: -Z unstable-options +#![crate_type = "lib"] // Note: `rustc_attrs` is a perma-unstable internal feature that is unlikely to change, which is // used as a proxy to check `RUSTC_BOOTSTRAP` versus stability checking logic. #![feature(rustc_attrs)] +//[force_stable_allow_flags]~^ ERROR: `#![feature]` may not be used on the //[force_stable]~? RAW the option `Z` is only accepted on the nightly compiler From 94a6b12557e9af7c09eec7d292c00adcb03fb228 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 2 Oct 2026 16:12:41 +0200 Subject: [PATCH 2/7] Implement `act-as-stable` compiletest directive --- src/doc/rustc-dev-guide/src/tests/misc.md | 17 +++++++++++------ src/tools/compiletest/src/directives.rs | 1 + .../src/directives/directive_names.rs | 1 + .../compiletest/src/directives/handlers.rs | 6 ++++++ 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/misc.md b/src/doc/rustc-dev-guide/src/tests/misc.md index 167e57f757a3d..688be7e97fdca 100644 --- a/src/doc/rustc-dev-guide/src/tests/misc.md +++ b/src/doc/rustc-dev-guide/src/tests/misc.md @@ -18,12 +18,17 @@ This is a bootstrap/compiler implementation detail, but it can also be useful fo unstable flags required by compiletest, but we also want to test the compiler's behavior on the stable channel. +### UI tests + Note that setting `RUSTC_BOOTSTRAP=-1` in ui tests (e.g. via `//@ rustc-env`) is pointless since ui -tests inherit the bootstrap env var from bootstrap (so it's set to `1` by default), -and since compiletest itself passes `-Z` flags (so `-1` breaks the test). -To test stable-only behavior, use -`RUSTC_BOOTSTRAP=-2` instead. +tests inherit the bootstrap env var from bootstrap (so it's set to `1` by default), and since +compiletest itself passes `-Z` flags (so `-1` breaks the test). + +To test stable-only behavior, use the `act-as-stable` directive, which will set `RUSTC_BOOTSTRAP=-2` +for you. + +### Run-make tests -For `run-make`/`run-make-cargo` tests, `//@ rustc-env` is not supported. -You can do use the `run_make_support::stable_bare_rustc` function to create an instance of the compiler +For `run-make`/`run-make-cargo` tests, `//@ act-as-stable` is not supported. +You can use the `run_make_support::stable_bare_rustc` function to create an instance of the compiler that acts as the stable channel (this internally uses `RUSTC_BOOTSTRAP=-1`). diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index 1037b2c6375b7..4ef2b5fd46d65 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -222,6 +222,7 @@ pub(crate) struct TestProps { } mod directives { + pub(crate) const ACT_AS_STABLE: &str = "act-as-stable"; pub(crate) const ERROR_PATTERN: &str = "error-pattern"; pub(crate) const REGEX_ERROR_PATTERN: &str = "regex-error-pattern"; pub(crate) const COMPILE_FLAGS: &str = "compile-flags"; diff --git a/src/tools/compiletest/src/directives/directive_names.rs b/src/tools/compiletest/src/directives/directive_names.rs index 732f4ab275dd7..07ac09944379b 100644 --- a/src/tools/compiletest/src/directives/directive_names.rs +++ b/src/tools/compiletest/src/directives/directive_names.rs @@ -9,6 +9,7 @@ pub(crate) static KNOWN_DIRECTIVE_NAMES_SET: LazyLock> = /// a best-effort approximation for diagnostics. Add new directives to this list when needed. pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ // tidy-alphabetical-start + "act-as-stable", "add-minicore", "assembly-output", "aux-bin", diff --git a/src/tools/compiletest/src/directives/handlers.rs b/src/tools/compiletest/src/directives/handlers.rs index 4e86dcb308f0d..f33688180419f 100644 --- a/src/tools/compiletest/src/directives/handlers.rs +++ b/src/tools/compiletest/src/directives/handlers.rs @@ -64,6 +64,12 @@ fn make_directive_handlers_map() -> HashMap<&'static str, Handler> { // these handlers, e.g. by getting rid of now-redundant name checks. let handlers: Vec = vec![ + handler(ACT_AS_STABLE, |_config, ln, props| { + if ln.name == ACT_AS_STABLE { + // Simulate the stable toolchain, but allow unstable -Z flags passed by compiletest + props.rustc_env.push(("RUSTC_BOOTSTRAP".to_string(), "-2".to_string())); + } + }), handler(ERROR_PATTERN, |config, ln, props| { config.push_name_value_directive(ln, ERROR_PATTERN, &mut props.error_patterns, |r| r); }), From 522200b2e4a67362f10c9b4af13b88fe676c44d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 2 Oct 2026 16:12:54 +0200 Subject: [PATCH 3/7] Use `act-as-stable` in the `feature-gate-autodiff-use` test --- ... feature-gate-autodiff-use.nightly.stderr} | 4 ++-- .../feature-gate-autodiff-use.rs | 22 ++++++++++++------- .../feature-gate-autodiff-use.stable.stderr | 19 ++++++++++++++++ 3 files changed, 35 insertions(+), 10 deletions(-) rename tests/ui/feature-gates/{feature-gate-autodiff-use.stderr => feature-gate-autodiff-use.nightly.stderr} (91%) create mode 100644 tests/ui/feature-gates/feature-gate-autodiff-use.stable.stderr diff --git a/tests/ui/feature-gates/feature-gate-autodiff-use.stderr b/tests/ui/feature-gates/feature-gate-autodiff-use.nightly.stderr similarity index 91% rename from tests/ui/feature-gates/feature-gate-autodiff-use.stderr rename to tests/ui/feature-gates/feature-gate-autodiff-use.nightly.stderr index 94b9a065e491e..ca724632063d4 100644 --- a/tests/ui/feature-gates/feature-gate-autodiff-use.stderr +++ b/tests/ui/feature-gates/feature-gate-autodiff-use.nightly.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature `autodiff` - --> $DIR/feature-gate-autodiff-use.rs:11:3 + --> $DIR/feature-gate-autodiff-use.rs:16:3 | LL | #[autodiff_reverse(dfoo)] | ^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | #[autodiff_reverse(dfoo)] = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature `autodiff` - --> $DIR/feature-gate-autodiff-use.rs:5:5 + --> $DIR/feature-gate-autodiff-use.rs:9:5 | LL | use std::autodiff::autodiff_reverse; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/feature-gates/feature-gate-autodiff-use.rs b/tests/ui/feature-gates/feature-gate-autodiff-use.rs index 85608be4ac04a..d7336e50df1f3 100644 --- a/tests/ui/feature-gates/feature-gate-autodiff-use.rs +++ b/tests/ui/feature-gates/feature-gate-autodiff-use.rs @@ -1,16 +1,22 @@ +//@ revisions: nightly stable +//@[nightly] only-nightly +//@[stable] act-as-stable + // This checks that without enabling the autodiff feature, we can't import std::autodiff::autodiff; #![crate_type = "lib"] use std::autodiff::autodiff_reverse; -//~^ ERROR use of unstable library feature `autodiff` -//| NOTE see issue #124509 for more information -//| HELP add `#![feature(autodiff)]` to the crate attributes to enable -//| NOTE this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +//[stable]~^ ERROR use of unstable library feature `autodiff` +//[nightly]~^^ ERROR use of unstable library feature `autodiff` +//[nightly]~| NOTE see issue #124509 for more information +//[nightly]~| HELP add `#![feature(autodiff)]` to the crate attributes to enable +//[nightly]~| NOTE this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date #[autodiff_reverse(dfoo)] -//~^ ERROR use of unstable library feature `autodiff` [E0658] -//| NOTE see issue #124509 for more information -//| HELP add `#![feature(autodiff)]` to the crate attributes to enable -//| NOTE this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +//[stable]~^ ERROR use of unstable library feature `autodiff` [E0658] +//[nightly]~^^ ERROR use of unstable library feature `autodiff` [E0658] +//[nightly]~| NOTE see issue #124509 for more information +//[nightly]~| HELP add `#![feature(autodiff)]` to the crate attributes to enable +//[nightly]~| NOTE this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date fn foo() {} diff --git a/tests/ui/feature-gates/feature-gate-autodiff-use.stable.stderr b/tests/ui/feature-gates/feature-gate-autodiff-use.stable.stderr new file mode 100644 index 0000000000000..2ac3c82b644ef --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-autodiff-use.stable.stderr @@ -0,0 +1,19 @@ +error[E0658]: use of unstable library feature `autodiff` + --> $DIR/feature-gate-autodiff-use.rs:16:3 + | +LL | #[autodiff_reverse(dfoo)] + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #124509 for more information + +error[E0658]: use of unstable library feature `autodiff` + --> $DIR/feature-gate-autodiff-use.rs:9:5 + | +LL | use std::autodiff::autodiff_reverse; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #124509 for more information + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. From aa97b1bfb6a761c2de78e04d580f6753d7d0e944 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 2 Oct 2026 16:20:04 +0200 Subject: [PATCH 4/7] Migrate `const-destruct-stable-toolchain` from a run-make test to a UI test --- .../const-drop-stable.stderr | 11 -------- .../const-drop.rs | 3 -- .../const-destruct-stable-toolchain/rmake.rs | 28 ------------------- ...-destruct-stable-toolchain.nightly.stderr} | 2 +- .../consts/const-destruct-stable-toolchain.rs | 15 ++++++++++ ...st-destruct-stable-toolchain.stable.stderr | 11 ++++++++ 6 files changed, 27 insertions(+), 43 deletions(-) delete mode 100644 tests/run-make/const-destruct-stable-toolchain/const-drop-stable.stderr delete mode 100644 tests/run-make/const-destruct-stable-toolchain/const-drop.rs delete mode 100644 tests/run-make/const-destruct-stable-toolchain/rmake.rs rename tests/{run-make/const-destruct-stable-toolchain/const-drop-nightly.stderr => ui/consts/const-destruct-stable-toolchain.nightly.stderr} (91%) create mode 100644 tests/ui/consts/const-destruct-stable-toolchain.rs create mode 100644 tests/ui/consts/const-destruct-stable-toolchain.stable.stderr diff --git a/tests/run-make/const-destruct-stable-toolchain/const-drop-stable.stderr b/tests/run-make/const-destruct-stable-toolchain/const-drop-stable.stderr deleted file mode 100644 index dc37d840658fd..0000000000000 --- a/tests/run-make/const-destruct-stable-toolchain/const-drop-stable.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0493]: destructor of `T` cannot be evaluated at compile-time - --> const-drop.rs:1:24 - | -1 | const fn const_drop(_: T) {} - | ^ - value is dropped here - | | - | the destructor for this type cannot be evaluated in constant functions - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0493`. diff --git a/tests/run-make/const-destruct-stable-toolchain/const-drop.rs b/tests/run-make/const-destruct-stable-toolchain/const-drop.rs deleted file mode 100644 index 6479498281fe5..0000000000000 --- a/tests/run-make/const-destruct-stable-toolchain/const-drop.rs +++ /dev/null @@ -1,3 +0,0 @@ -const fn const_drop(_: T) {} - -fn main() {} diff --git a/tests/run-make/const-destruct-stable-toolchain/rmake.rs b/tests/run-make/const-destruct-stable-toolchain/rmake.rs deleted file mode 100644 index 47d66cf267ab9..0000000000000 --- a/tests/run-make/const-destruct-stable-toolchain/rmake.rs +++ /dev/null @@ -1,28 +0,0 @@ -//@ needs-target-std -//@ ignore-backends: gcc - -// Test that the suggestion to constrain a type parameter that is dropped in a const -// function with a `[const] Destruct` bound is only offered on nightly, since the bound -// requires an unstable feature. - -use run_make_support::{diff, rustc, stable_bare_rustc}; - -fn main() { - let out = stable_bare_rustc() - .input("const-drop.rs") - .edition("2015") - .run_fail() - .assert_stderr_not_contains("consider restricting type parameter `T`") - .stderr_utf8(); - diff().expected_file("const-drop-stable.stderr").actual_text("(rustc)", &out).run(); - let out = rustc() - .input("const-drop.rs") - .edition("2015") - .ui_testing() - .run_fail() - .assert_stderr_contains( - "consider restricting type parameter `T` with unstable trait `Destruct`", - ) - .stderr_utf8(); - diff().expected_file("const-drop-nightly.stderr").actual_text("(rustc)", &out).run(); -} diff --git a/tests/run-make/const-destruct-stable-toolchain/const-drop-nightly.stderr b/tests/ui/consts/const-destruct-stable-toolchain.nightly.stderr similarity index 91% rename from tests/run-make/const-destruct-stable-toolchain/const-drop-nightly.stderr rename to tests/ui/consts/const-destruct-stable-toolchain.nightly.stderr index 52f68743b6275..2d05a300165aa 100644 --- a/tests/run-make/const-destruct-stable-toolchain/const-drop-nightly.stderr +++ b/tests/ui/consts/const-destruct-stable-toolchain.nightly.stderr @@ -1,5 +1,5 @@ error[E0493]: destructor of `T` cannot be evaluated at compile-time - --> const-drop.rs:1:24 + --> $DIR/const-destruct-stable-toolchain.rs:12:24 | LL | const fn const_drop(_: T) {} | ^ - value is dropped here diff --git a/tests/ui/consts/const-destruct-stable-toolchain.rs b/tests/ui/consts/const-destruct-stable-toolchain.rs new file mode 100644 index 0000000000000..ad16a74508e4c --- /dev/null +++ b/tests/ui/consts/const-destruct-stable-toolchain.rs @@ -0,0 +1,15 @@ +// Test that the suggestion to constrain a type parameter that is dropped in a const +// function with a `[const] Destruct` bound is only offered on nightly, since the bound +// requires an unstable feature. +// +//@ needs-target-std +//@ ignore-backends: gcc +// +//@ revisions: stable nightly +// +//@[stable] act-as-stable +//@[nightly] only-nightly +const fn const_drop(_: T) {} +//~^ ERROR: destructor of `T` cannot be evaluated at compile-time [E0493] + +fn main() {} diff --git a/tests/ui/consts/const-destruct-stable-toolchain.stable.stderr b/tests/ui/consts/const-destruct-stable-toolchain.stable.stderr new file mode 100644 index 0000000000000..4755afcd3f1e3 --- /dev/null +++ b/tests/ui/consts/const-destruct-stable-toolchain.stable.stderr @@ -0,0 +1,11 @@ +error[E0493]: destructor of `T` cannot be evaluated at compile-time + --> $DIR/const-destruct-stable-toolchain.rs:12:24 + | +LL | const fn const_drop(_: T) {} + | ^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constant functions + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0493`. From 0c3b3bee4e044fbaf28ddbabadf646b8688e6f3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 2 Oct 2026 16:25:27 +0200 Subject: [PATCH 5/7] Migrate `print-request-help-stable-unstable` from a run-make test to a UI test --- .../help-diff.diff | 7 ---- .../rmake.rs | 33 ------------------- ...quest-help-stable-unstable.nightly.stderr} | 0 .../print-request-help-stable-unstable.rs | 12 +++++++ ...equest-help-stable-unstable.stable.stderr} | 0 5 files changed, 12 insertions(+), 40 deletions(-) delete mode 100644 tests/run-make/print-request-help-stable-unstable/help-diff.diff delete mode 100644 tests/run-make/print-request-help-stable-unstable/rmake.rs rename tests/{run-make/print-request-help-stable-unstable/unstable-invalid-print-request-help.err => ui/compile-flags/print-request-help-stable-unstable.nightly.stderr} (100%) create mode 100644 tests/ui/compile-flags/print-request-help-stable-unstable.rs rename tests/{run-make/print-request-help-stable-unstable/stable-invalid-print-request-help.err => ui/compile-flags/print-request-help-stable-unstable.stable.stderr} (100%) diff --git a/tests/run-make/print-request-help-stable-unstable/help-diff.diff b/tests/run-make/print-request-help-stable-unstable/help-diff.diff deleted file mode 100644 index 8a9c3d0cf46c1..0000000000000 --- a/tests/run-make/print-request-help-stable-unstable/help-diff.diff +++ /dev/null @@ -1,7 +0,0 @@ -@@ -1,5 +1,5 @@ - error: unknown print request: `xxx` - | -- = help: valid print requests are: `calling-conventions`, `cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `tls-models` -+ = help: valid print requests are: `all-target-specs-json`, `backend-has-mnemonic`, `backend-has-zstd`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `target-spec-json-schema`, `tls-models`, `wasm-proc-macro-tuple` - = help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information - diff --git a/tests/run-make/print-request-help-stable-unstable/rmake.rs b/tests/run-make/print-request-help-stable-unstable/rmake.rs deleted file mode 100644 index 49df84b353cd4..0000000000000 --- a/tests/run-make/print-request-help-stable-unstable/rmake.rs +++ /dev/null @@ -1,33 +0,0 @@ -//! Check that unstable print requests are omitted from help if compiler is in stable channel. -//! -//! Issue: - -//@ ignore-backends: gcc - -use run_make_support::{diff, rustc, similar, stable_bare_rustc}; - -fn main() { - let stable_invalid_print_request_help = - stable_bare_rustc().edition("2015").print("xxx").run_fail().stderr_utf8(); - assert!(!stable_invalid_print_request_help.contains("all-target-specs-json")); - diff() - .expected_file("stable-invalid-print-request-help.err") - .actual_text("stable_invalid_print_request_help", &stable_invalid_print_request_help) - .run(); - - let unstable_invalid_print_request_help = - rustc().edition("2015").print("xxx").run_fail().stderr_utf8(); - assert!(unstable_invalid_print_request_help.contains("all-target-specs-json")); - diff() - .expected_file("unstable-invalid-print-request-help.err") - .actual_text("unstable_invalid_print_request_help", &unstable_invalid_print_request_help) - .run(); - - let help_diff = similar::TextDiff::from_lines( - &stable_invalid_print_request_help, - &unstable_invalid_print_request_help, - ) - .unified_diff() - .to_string(); - diff().expected_file("help-diff.diff").actual_text("help_diff", help_diff).run(); -} diff --git a/tests/run-make/print-request-help-stable-unstable/unstable-invalid-print-request-help.err b/tests/ui/compile-flags/print-request-help-stable-unstable.nightly.stderr similarity index 100% rename from tests/run-make/print-request-help-stable-unstable/unstable-invalid-print-request-help.err rename to tests/ui/compile-flags/print-request-help-stable-unstable.nightly.stderr diff --git a/tests/ui/compile-flags/print-request-help-stable-unstable.rs b/tests/ui/compile-flags/print-request-help-stable-unstable.rs new file mode 100644 index 0000000000000..f75996f28e6bd --- /dev/null +++ b/tests/ui/compile-flags/print-request-help-stable-unstable.rs @@ -0,0 +1,12 @@ +//! Check that unstable print requests are omitted from help if compiler is in stable channel. +//! +//! Issue: + +//@ ignore-backends: gcc +//@ compile-flags: --print xxx +// +//@ revisions: stable nightly +//@[stable] act-as-stable +//@[nightly] only-nightly + +//~? ERROR unknown print request: `xxx` diff --git a/tests/run-make/print-request-help-stable-unstable/stable-invalid-print-request-help.err b/tests/ui/compile-flags/print-request-help-stable-unstable.stable.stderr similarity index 100% rename from tests/run-make/print-request-help-stable-unstable/stable-invalid-print-request-help.err rename to tests/ui/compile-flags/print-request-help-stable-unstable.stable.stderr From f6c3d62706c688007bd978034473e6328cf3fdf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 14 Oct 2026 13:42:34 +0200 Subject: [PATCH 6/7] Replace `RUSTC_BOOTSTRAP=-2` with `RUSTC_BOOTSTRAP=-allow-unstable-compiler-flags=` --- compiler/rustc_feature/src/lib.rs | 40 +++++++++----- compiler/rustc_feature/src/tests.rs | 15 ++++-- compiler/rustc_session/src/config.rs | 52 +++++++++++++++---- .../rustc_session/src/config/native_libs.rs | 2 +- src/doc/rustc-dev-guide/src/tests/misc.md | 15 ++++-- src/librustdoc/config.rs | 2 +- src/librustdoc/doctest.rs | 2 +- 7 files changed, 91 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index e2eadaa66b0f0..890142718fe92 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -34,7 +34,7 @@ pub struct Feature { issue: Option>, } -#[derive(Clone, Copy, Debug, Hash)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub enum UnstableFeatures { /// Disallow use of unstable features and unstable compiler flags. /// @@ -54,16 +54,18 @@ pub enum UnstableFeatures { /// because the build turns on warnings-as-errors and uses lots of unstable /// features. As a result, this is always required for building Rust itself. Cheat, - /// Allow the use of *unstable compiler flags*, but disallow the use of + /// Allow the use of selected *unstable compiler flags*, but disallow the use of /// *unstable language features*. - /// And in general, try to treat everything except for compiler flags as if we were on stable. /// /// **This mode is designed only for internal testing of rustc.** /// /// Specifically, we need it when we want to test how rustc behaves on the stable channel, /// but at the same time we need to be able to pass it some unstable `-Z` compiler flags /// required for the testing infrastructure itself to work. - ActAsStableForTesting, + AllowUnstableCompilerFlagsOnly { + /// Unstable compiler flags that we are allowed to use, without their `-Z` prefix. + allowed_flags: Vec, + }, } impl UnstableFeatures { @@ -89,14 +91,19 @@ impl UnstableFeatures { let is_unstable_crate = |var: &str| krate.is_some_and(|name| var.split(',').any(|new_krate| new_krate == name)); + let allow_unstable_flags_prefix = "-allow-unstable-compiler-flags="; if let Ok(val) = env_var_rustc_bootstrap.as_deref() { match val { + // Act as stable, but still accept unstable compiler flags required by compiletest + val if let Some(flags) = val.strip_prefix(allow_unstable_flags_prefix) => { + return UnstableFeatures::AllowUnstableCompilerFlagsOnly { + allowed_flags: flags.split(",").map(|s| s.trim().to_string()).collect(), + }; + } val if val == "1" || is_unstable_crate(val) => return UnstableFeatures::Cheat, // Hypnotize ourselves so that we think we are a stable compiler and thus don't // allow any unstable features. "-1" => return UnstableFeatures::Disallow, - // Act as stable, but still accept unstable compiler flags required by compiletest - "-2" => return UnstableFeatures::ActAsStableForTesting, _ => {} } } @@ -104,19 +111,26 @@ impl UnstableFeatures { if disable_unstable_features { UnstableFeatures::Disallow } else { UnstableFeatures::Allow } } - pub fn allow_unstable_compiler_flags(&self) -> bool { - match *self { - UnstableFeatures::Allow - | UnstableFeatures::Cheat - | UnstableFeatures::ActAsStableForTesting => true, - UnstableFeatures::Disallow => false, + /// Are we allowed to use the given unstable `flag`? + /// If it is a `-Z`, it should be passed without the `-Z` prefix. + pub fn allow_unstable_compiler_flag(&self, flag: &str) -> bool { + match self { + UnstableFeatures::Allow | UnstableFeatures::Cheat => true, + UnstableFeatures::AllowUnstableCompilerFlagsOnly { allowed_flags } + if allowed_flags.iter().any(|allowed_flag| allowed_flag == flag) => + { + true + } + UnstableFeatures::Disallow + | UnstableFeatures::AllowUnstableCompilerFlagsOnly { .. } => false, } } pub fn is_nightly_build(&self) -> bool { match *self { UnstableFeatures::Allow | UnstableFeatures::Cheat => true, - UnstableFeatures::Disallow | UnstableFeatures::ActAsStableForTesting => false, + UnstableFeatures::Disallow + | UnstableFeatures::AllowUnstableCompilerFlagsOnly { .. } => false, } } } diff --git a/compiler/rustc_feature/src/tests.rs b/compiler/rustc_feature/src/tests.rs index 9280a9de7e506..46e44f0ffc877 100644 --- a/compiler/rustc_feature/src/tests.rs +++ b/compiler/rustc_feature/src/tests.rs @@ -35,10 +35,15 @@ fn rustc_bootstrap_parsing() { assert!(is_force_stable(Some("x"))); assert!(is_force_stable(Some("x,y,z"))); - // `RUSTC_BOOTSTRAP=-2` simulates the stable toolchain, while allowing unstable compiler flags - // to be passed. - std::assert_matches!( - UnstableFeatures::from_environment_value(None, Ok("-2".to_string())), - UnstableFeatures::ActAsStableForTesting + // `RUSTC_BOOTSTRAP=-allow-unstable-compiler-flags` simulates the stable toolchain, while + // allowing unstable compiler flags to be passed. + std::assert_eq!( + UnstableFeatures::from_environment_value( + None, + Ok("-allow-unstable-compiler-flags=foo,bar".to_string()) + ), + UnstableFeatures::AllowUnstableCompilerFlagsOnly { + allowed_flags: vec!["foo".to_string(), "bar".to_string()] + } ); } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index a4f8bcf2dab6c..0ae95a822e70d 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2792,7 +2792,7 @@ pub fn build_session_options( check_error_format_stability( early_dcx, &unstable_opts, - unstable_features.allow_unstable_compiler_flags(), + unstable_features.allow_unstable_compiler_flag("error-format"), error_format, ); @@ -2974,7 +2974,7 @@ pub fn build_session_options( } // Parse any `-l` flags, which link to native libraries. - let libs = parse_native_libs(early_dcx, &unstable_opts, unstable_features, matches); + let libs = parse_native_libs(early_dcx, &unstable_opts, &unstable_features, matches); let test = matches.opt_present("test"); @@ -3201,16 +3201,12 @@ pub mod nightly_options { /// Are we allowed to use -Z compiler flags *and* -Zunstable-options was passed? pub fn unstable_options_enabled(matches: &getopts::Matches) -> bool { - unstable_compiler_flags_allowed(matches) + let unstable_features = + UnstableFeatures::from_environment(matches.opt_str("crate-name").as_deref()); + unstable_features.allow_unstable_compiler_flag("unstable-options") && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options") } - /// Are we allowed to use -Z compiler flags? - pub fn unstable_compiler_flags_allowed(matches: &getopts::Matches) -> bool { - UnstableFeatures::from_environment(matches.opt_str("crate-name").as_deref()) - .allow_unstable_compiler_flags() - } - pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool { let krate = matches.opt_str("crate-name"); UnstableFeatures::from_environment(krate.as_deref()).is_nightly_build() @@ -3222,7 +3218,8 @@ pub mod nightly_options { flags: &[RustcOptGroup], ) { let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options"); - let really_allows_unstable_options = unstable_compiler_flags_allowed(matches); + let unstable_features = + UnstableFeatures::from_environment(matches.opt_str("crate-name").as_deref()); let mut nightly_options_on_stable = 0; for opt in flags.iter() { @@ -3239,7 +3236,40 @@ pub mod nightly_options { opt.name )); } - if really_allows_unstable_options { + + // Check if the matched values are enabled + // If we're dealing with -Z, then check all the matched values (i.e. -Zfoo, -Zbar, etc.) + // If we're dealing with other flags, check their name directly + if opt.name == "Z" { + // For `-Zui-testing -Zfoo=bar -Zfoo=baz`, this returns + // ["ui-testing", "foo=bar", "foo=baz"]. + // Check that all of them are allowed + let values = matches.opt_strs(opt.name); + let disallowed_flags = values + .iter() + .map(|flag| flag.split_once("=").map(|s| s.0).unwrap_or(flag)) + .filter(|flag| !unstable_features.allow_unstable_compiler_flag(flag)) + .collect::>(); + if disallowed_flags.is_empty() { + continue; + } + + // At this point, check if we're using the "allow unstable flags only" mode. + // In this case, if the user allowed only foo and bar, but then -Zbaz was also + // passed, rustc would only print that `-Z` is not allowed, which doesn't tell the + // user the actual -Z flag value that was disallowed. So we try to provide better + // diagnostics here (solely for the use-case of debugging compiletest itself). + let unstable_features = + UnstableFeatures::from_environment(matches.opt_str("crate-name").as_deref()); + if matches!( + unstable_features, + UnstableFeatures::AllowUnstableCompilerFlagsOnly { .. } + ) { + for flag in disallowed_flags { + let _ = early_dcx.early_err(format!("the -Z{flag} option was not allowed through `-allow-unstable-compiler-flags`")); + } + } + } else if unstable_features.allow_unstable_compiler_flag(opt.name) { continue; } diff --git a/compiler/rustc_session/src/config/native_libs.rs b/compiler/rustc_session/src/config/native_libs.rs index 0733bd3ca4b78..1f159f8071323 100644 --- a/compiler/rustc_session/src/config/native_libs.rs +++ b/compiler/rustc_session/src/config/native_libs.rs @@ -18,7 +18,7 @@ mod tests; pub(crate) fn parse_native_libs( early_dcx: &EarlyDiagCtxt, unstable_opts: &UnstableOptions, - unstable_features: UnstableFeatures, + unstable_features: &UnstableFeatures, matches: &getopts::Matches, ) -> Vec { let cx = ParseNativeLibCx { diff --git a/src/doc/rustc-dev-guide/src/tests/misc.md b/src/doc/rustc-dev-guide/src/tests/misc.md index 688be7e97fdca..4f496860f2d3e 100644 --- a/src/doc/rustc-dev-guide/src/tests/misc.md +++ b/src/doc/rustc-dev-guide/src/tests/misc.md @@ -11,9 +11,12 @@ This is a bootstrap/compiler implementation detail, but it can also be useful fo even if it's actually a nightly `rustc`. This is useful because some behaviors of the compiler (e.g. diagnostics) can differ depending on whether the compiler is nightly or not. -- `RUSTC_BOOTSTRAP=-2` will force a given `rustc` to pretend it is a stable - compiler, even if it's actually a nightly `rustc`. - However, the compiler will still accept unstable compiler flags. +- `RUSTC_BOOTSTRAP=-allow-unstable-compiler-flags=` will force a given `rustc` to pretend it + is a stable compiler, even if it's actually a nightly `rustc`. + However, the compiler will still accept the passed unstable compiler flags `` (the allowed flag + should be separated by commas). + For example, if you use `RUSTC_BOOTSTRAP=-allow-unstable-compiler-flags=foo,bar`, it will be possible to + pass `-Zfoo` and `-Zbar` to the compiler. This is useful for internal testing of the compiler, where we need to pass unstable flags required by compiletest, but we also want to test the compiler's behavior on the stable channel. @@ -24,8 +27,10 @@ Note that setting `RUSTC_BOOTSTRAP=-1` in ui tests (e.g. via `//@ rustc-env`) is tests inherit the bootstrap env var from bootstrap (so it's set to `1` by default), and since compiletest itself passes `-Z` flags (so `-1` breaks the test). -To test stable-only behavior, use the `act-as-stable` directive, which will set `RUSTC_BOOTSTRAP=-2` -for you. +To test stable-only behavior, use the `act-as-stable` directive, which will set +`RUSTC_BOOTSTRAP=-allow-unstable-compiler-flags` with the flags required by compiletest for you. With this +directive, the compiler will not allow using unstable language features or unstable flags that are not set by +compiletest. ### Run-make tests diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 6e988728858a8..597c648c1106a 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -944,7 +944,7 @@ impl Options { output_format, json_unused_externs, scrape_examples_options, - unstable_features, + unstable_features: unstable_features.clone(), doctest_build_args, target_modifiers: collected_options.target_modifiers, }; diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 35b2af5370fff..ab55bcf239623 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -173,7 +173,7 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions lint_cap: Some(options.lint_cap.unwrap_or(lint::Forbid)), cg: options.codegen_options.clone(), externs: options.externs.clone(), - unstable_features: options.unstable_features, + unstable_features: options.unstable_features.clone(), actually_rustdoc: true, edition: options.edition, target_triple: options.target.clone(), From adbf2a534930e077fe2b7e334b80938d06d6c05e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 14 Oct 2026 13:43:12 +0200 Subject: [PATCH 7/7] Use `RUSTC_BOOTSTRAP=-allow-unstable-compiler-flags` in compiletest --- .../compiletest/src/directives/handlers.rs | 18 +++++++++++--- src/tools/compiletest/src/runtest.rs | 24 +++++++++++++++++++ ...ce_stable_disallow_additional_flags.stderr | 10 ++++++++ ..._stable_disallow_unstable_features.stderr} | 2 +- tests/ui/bootstrap/rustc_bootstrap.rs | 14 +++++++---- 5 files changed, 59 insertions(+), 9 deletions(-) create mode 100644 tests/ui/bootstrap/rustc_bootstrap.force_stable_disallow_additional_flags.stderr rename tests/ui/bootstrap/{rustc_bootstrap.force_stable_allow_flags.stderr => rustc_bootstrap.force_stable_disallow_unstable_features.stderr} (87%) diff --git a/src/tools/compiletest/src/directives/handlers.rs b/src/tools/compiletest/src/directives/handlers.rs index f33688180419f..0e80d6d865f22 100644 --- a/src/tools/compiletest/src/directives/handlers.rs +++ b/src/tools/compiletest/src/directives/handlers.rs @@ -1,12 +1,13 @@ use std::collections::HashMap; use std::sync::{Arc, LazyLock}; -use crate::common::{Config, PassFailMode, TestMode}; +use crate::common::{Config, PassFailMode, TestMode, TestSuite}; use crate::directives::{ DirectiveLine, NormalizeKind, NormalizeRule, TestProps, parse_and_update_aux, parse_edition_range, split_flags, }; use crate::errors::ErrorKind; +use crate::runtest::COMPILETEST_UI_SUITE_UNSTABLE_FLAGS; pub(crate) static DIRECTIVE_HANDLERS_MAP: LazyLock> = LazyLock::new(make_directive_handlers_map); @@ -64,10 +65,21 @@ fn make_directive_handlers_map() -> HashMap<&'static str, Handler> { // these handlers, e.g. by getting rid of now-redundant name checks. let handlers: Vec = vec![ - handler(ACT_AS_STABLE, |_config, ln, props| { + handler(ACT_AS_STABLE, |config, ln, props| { if ln.name == ACT_AS_STABLE { + if ![TestSuite::Ui, TestSuite::UiFullDeps].contains(&config.suite) { + panic!( + "The {ACT_AS_STABLE} directive is only usable in the ui and ui-fulldeps test suites" + ); + } // Simulate the stable toolchain, but allow unstable -Z flags passed by compiletest - props.rustc_env.push(("RUSTC_BOOTSTRAP".to_string(), "-2".to_string())); + props.rustc_env.push(( + "RUSTC_BOOTSTRAP".to_string(), + format!( + "-allow-unstable-compiler-flags={}", + COMPILETEST_UI_SUITE_UNSTABLE_FLAGS.join(",") + ), + )); } }), handler(ERROR_PATTERN, |config, ln, props| { diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 263c8d5aded54..860a69fca66b2 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -260,6 +260,27 @@ enum CompilerKind { Rustdoc, } +/// Unstable compiler flags that compiletest passes to UI tests on its own, i.e. without specific +/// tests opting into them explicitly. +/// This should include both flags that are always passed unconditionally (e.g. `-Zui-testing`) and +/// flags that are enabled across the whole test suite when compiletest is configured in a +/// certain way (e.g. a specific `-Zcodegen-backend` being used for all tests). +/// +/// Note: try to keep this up-to-date with [`TestCx::make_compile_args`]. +pub(crate) const COMPILETEST_UI_SUITE_UNSTABLE_FLAGS: &[&str] = &[ + "simulate-remapped-rust-src-base", + "translate-remapped-path-to-local-path", + "ignore-directory-in-diagnostics-source-blocks", + "deduplicate-diagnostics", + "write-long-types-to-disk", + "codegen-backend", + "next-solver", + "polonius", + "wasm-proc-macros", + "threads", + "ui-testing", +]; + impl<'test> TestCx<'test> { /// Code executed for each revision in turn (or, if there are no /// revisions, exactly once, with revision == None). @@ -1660,6 +1681,9 @@ impl<'test> TestCx<'test> { compiler.arg("-Zunstable-options").arg("--disable-minification"); } + // Note: when adding new unstable compile flags here, also update + // `COMPILETEST_UI_SUITE_UNSTABLE_FLAGS` + // Hide libstd sources from ui tests to make sure we generate the stderr // output that users will see. // Without this, we may be producing good diagnostics in-tree but users diff --git a/tests/ui/bootstrap/rustc_bootstrap.force_stable_disallow_additional_flags.stderr b/tests/ui/bootstrap/rustc_bootstrap.force_stable_disallow_additional_flags.stderr new file mode 100644 index 0000000000000..13d619cfc388f --- /dev/null +++ b/tests/ui/bootstrap/rustc_bootstrap.force_stable_disallow_additional_flags.stderr @@ -0,0 +1,10 @@ +error: the -Zmir-opt-level option was not allowed through `-allow-unstable-compiler-flags` + +error: the option `Z` is only accepted on the nightly compiler + +error: 1 nightly option was parsed + | + = help: consider switching to a nightly toolchain: `rustup default nightly` + = note: selecting a toolchain with `+toolchain` arguments require a rustup proxy; see + = note: for more information about Rust's stability policy, see + diff --git a/tests/ui/bootstrap/rustc_bootstrap.force_stable_allow_flags.stderr b/tests/ui/bootstrap/rustc_bootstrap.force_stable_disallow_unstable_features.stderr similarity index 87% rename from tests/ui/bootstrap/rustc_bootstrap.force_stable_allow_flags.stderr rename to tests/ui/bootstrap/rustc_bootstrap.force_stable_disallow_unstable_features.stderr index c4436ca5a1815..13627ce02eee3 100644 --- a/tests/ui/bootstrap/rustc_bootstrap.force_stable_allow_flags.stderr +++ b/tests/ui/bootstrap/rustc_bootstrap.force_stable_disallow_unstable_features.stderr @@ -1,5 +1,5 @@ error[E0554]: `#![feature]` may not be used on the nightly release channel - --> $DIR/rustc_bootstrap.rs:51:1 + --> $DIR/rustc_bootstrap.rs:55:1 | LL | #![feature(rustc_attrs)] | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/bootstrap/rustc_bootstrap.rs b/tests/ui/bootstrap/rustc_bootstrap.rs index 96a464e8e4dbe..6395a750718e8 100644 --- a/tests/ui/bootstrap/rustc_bootstrap.rs +++ b/tests/ui/bootstrap/rustc_bootstrap.rs @@ -10,7 +10,7 @@ // ignore-tidy-linelength -//@ revisions: default_nightly cheat cheat_single_crate cheat_multi_crate force_stable force_stable_allow_flags invalid_zero invalid_junk +//@ revisions: default_nightly cheat cheat_single_crate cheat_multi_crate force_stable force_stable_disallow_additional_flags force_stable_disallow_unstable_features invalid_zero invalid_junk //@ only-nightly //@ normalize-stderr: "dev release channel" -> "nightly release channel" @@ -41,14 +41,18 @@ //@[force_stable] rustc-env:RUSTC_BOOTSTRAP=-1 //@[force_stable] compile-flags: -Z unstable-options -// Here rustc shouldn't complain about compiletest's -Z flags being passed. -//@[force_stable_allow_flags] rustc-env:RUSTC_BOOTSTRAP=-2 -//@[force_stable_allow_flags] compile-flags: -Z unstable-options +// Here rustc shouldn't complain about the allowed compiletest -Z flags being passed, but should +// still complain about other unstable flags. +//@[force_stable_disallow_additional_flags] act-as-stable +//@[force_stable_disallow_additional_flags] compile-flags: -Z mir-opt-level=3 + +// Here rustc should not allow using unstable language features. +//@[force_stable_disallow_unstable_features] act-as-stable #![crate_type = "lib"] // Note: `rustc_attrs` is a perma-unstable internal feature that is unlikely to change, which is // used as a proxy to check `RUSTC_BOOTSTRAP` versus stability checking logic. #![feature(rustc_attrs)] -//[force_stable_allow_flags]~^ ERROR: `#![feature]` may not be used on the +//[force_stable_disallow_unstable_features]~^ ERROR: `#![feature]` may not be used on the //[force_stable]~? RAW the option `Z` is only accepted on the nightly compiler