diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index 4ba50d03d707b..bfefa17d28904 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -48,12 +48,20 @@ pub enum UnstableFeatures { } impl UnstableFeatures { + /// This takes into account `RUSTC_BOOTSTRAP` and whether the input is in the sysroot. + /// + /// If `krate` is [`Some`], then setting `RUSTC_BOOTSTRAP=krate` will enable the nightly + /// features. Otherwise, only `RUSTC_BOOTSTRAP=1` or `input_in_sysroot` will work. + pub fn from_environment_check_in_sysroot(krate: Option<&str>, input_in_sysroot: bool) -> Self { + Self::from_environment_value(krate, std::env::var("RUSTC_BOOTSTRAP"), input_in_sysroot) + } + /// This takes into account `RUSTC_BOOTSTRAP`. /// /// If `krate` is [`Some`], then setting `RUSTC_BOOTSTRAP=krate` will enable the nightly /// features. Otherwise, only `RUSTC_BOOTSTRAP=1` will work. pub fn from_environment(krate: Option<&str>) -> Self { - Self::from_environment_value(krate, std::env::var("RUSTC_BOOTSTRAP")) + Self::from_environment_value(krate, std::env::var("RUSTC_BOOTSTRAP"), false) } /// Avoid unsafe `std::env::set_var()` by allowing tests to inject @@ -62,10 +70,8 @@ impl UnstableFeatures { fn from_environment_value( krate: Option<&str>, env_var_rustc_bootstrap: Result, + input_in_sysroot: bool, ) -> Self { - // `true` if this is a feature-staged build, i.e., on the beta or stable channel. - let disable_unstable_features = - option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some_and(|s| s != "0"); // Returns whether `krate` should be counted as unstable let is_unstable_crate = |var: &str| krate.is_some_and(|name| var.split(',').any(|new_krate| new_krate == name)); @@ -81,6 +87,14 @@ impl UnstableFeatures { } } + if input_in_sysroot { + return UnstableFeatures::Cheat; + } + + // `true` if this is a feature-staged build, i.e., on the beta or stable channel. + let disable_unstable_features = + option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some_and(|s| s != "0"); + if disable_unstable_features { UnstableFeatures::Disallow } else { UnstableFeatures::Allow } } diff --git a/compiler/rustc_feature/src/tests.rs b/compiler/rustc_feature/src/tests.rs index a5d589171d105..ba83bdd3d6211 100644 --- a/compiler/rustc_feature/src/tests.rs +++ b/compiler/rustc_feature/src/tests.rs @@ -4,7 +4,7 @@ use super::UnstableFeatures; fn rustc_bootstrap_parsing() { let is_bootstrap = |env: &str, krate: Option<&str>| { matches!( - UnstableFeatures::from_environment_value(krate, Ok(env.to_string())), + UnstableFeatures::from_environment_value(krate, Ok(env.to_string()), false), UnstableFeatures::Cheat ) }; @@ -23,10 +23,22 @@ fn rustc_bootstrap_parsing() { // `RUSTC_BOOTSTRAP=0` is not recognized. assert!(!is_bootstrap("0", None)); + let is_bootstrap = |env: &str, krate: Option<&str>, input_in_sysroot: bool| { + matches!( + UnstableFeatures::from_environment_value(krate, Ok(env.to_string()), input_in_sysroot), + UnstableFeatures::Cheat + ) + }; + // Whether RUSTC_BOOTSTRAP is set or unset, when input_in_sysroot is_bootstrap should be true + assert!(is_bootstrap("1", None, true)); + assert!(is_bootstrap("0", None, true)); + // Even when input_in_sysroot, disabling RUSTC_BOOTSTRAP is honoured. + assert!(!is_bootstrap("-1", None, true)); + // `RUSTC_BOOTSTRAP=-1` is force-stable, no unstable features allowed. let is_force_stable = |krate: Option<&str>| { matches!( - UnstableFeatures::from_environment_value(krate, Ok("-1".to_string())), + UnstableFeatures::from_environment_value(krate, Ok("-1".to_string()), false), UnstableFeatures::Disallow ) }; diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index f8b9ae040568a..b0492784bf6b4 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -9,7 +9,7 @@ use std::collections::btree_map::{ use std::collections::{BTreeMap, BTreeSet}; use std::ffi::OsStr; use std::hash::Hash; -use std::path::{Path, PathBuf}; +use std::path::{Path, PathBuf, absolute}; use std::str::{self, FromStr}; use std::sync::LazyLock; use std::{cmp, fmt, fs, iter}; @@ -2434,7 +2434,10 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M let edition = parse_crate_edition(early_dcx, matches); let crate_name = matches.opt_str("crate-name"); - let unstable_features = UnstableFeatures::from_environment(crate_name.as_deref()); + let unstable_features = UnstableFeatures::from_environment_check_in_sysroot( + crate_name.as_deref(), + input_in_sysroot(matches), + ); let JsonConfig { json_rendered, json_color, @@ -2863,10 +2866,26 @@ pub fn parse_crate_types_from_list(list_list: Vec) -> Result bool { + let sysroot = Sysroot::new(matches.opt_str("sysroot").map(PathBuf::from)); + // Input parsing derived from the make_input function. If there are multiple files, or stdin input, then + // input_in_sysroot is either irrelevant, or false. + let Some((Ok(input), Ok(sysroot))) = matches + .free + .as_slice() + .first() + .map(|path| (absolute(Path::new(path)), absolute(sysroot.path()))) + else { + return false; + }; + + input.starts_with(sysroot) +} + pub mod nightly_options { use rustc_feature::UnstableFeatures; - use super::{OptionStability, RustcOptGroup}; + use super::{OptionStability, RustcOptGroup, input_in_sysroot}; use crate::EarlyDiagCtxt; pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool { @@ -2875,11 +2894,12 @@ pub mod nightly_options { } pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool { - is_nightly_build(matches.opt_str("crate-name").as_deref()) + is_nightly_build(matches.opt_str("crate-name").as_deref(), input_in_sysroot(matches)) } - fn is_nightly_build(krate: Option<&str>) -> bool { - UnstableFeatures::from_environment(krate).is_nightly_build() + fn is_nightly_build(krate: Option<&str>, input_in_sysroot: bool) -> bool { + UnstableFeatures::from_environment_check_in_sysroot(krate, input_in_sysroot) + .is_nightly_build() } pub fn check_nightly_options(