From d47b57b069c2c430288ddb0088fb2c5f5b1f310e Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 19 Nov 2024 14:51:10 +1100 Subject: [PATCH] Make `RUSTC_BOOTSTRAP` read the crate name from `CARGO_CRATE_NAME` --- compiler/rustc_driver_impl/src/lib.rs | 10 ++-- compiler/rustc_feature/src/lib.rs | 60 ++++++++++++------- compiler/rustc_feature/src/tests.rs | 4 +- compiler/rustc_session/src/config.rs | 4 +- .../src/config/nightly_options.rs | 13 ++-- compiler/rustc_session/src/parse.rs | 2 +- src/librustdoc/config.rs | 7 +-- src/librustdoc/core.rs | 2 +- 8 files changed, 55 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index b6f7abed6f3c9..eaeadc03b5dd6 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -1211,9 +1211,7 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option Option) -> &'static Option) -> Self { - Self::from_environment_inner(krate, |name| env::var(name)) + /// Determines whether this compiler allows unstable options/features, + /// according to whether it was built as a stable/beta compiler or a nightly + /// compiler, and taking `RUSTC_BOOTSTRAP` into account. + #[inline(never)] + pub fn from_environment() -> Self { + Self::from_environment_inner(|name| env::var(name)) } /// Unit tests can pass a mock `std::env::var` instead of modifying the real environment. fn from_environment_inner( - krate: Option<&str>, env_var: impl Fn(&str) -> Result, // std::env::var ) -> Self { - // `true` if this is a feature-staged build, i.e., on the beta or stable channel. + // If `CFG_DISABLE_UNSTABLE_FEATURES` was true when this compiler was + // built, it is a stable/beta compiler that forbids unstable features. 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)); - - let bootstrap = env_var("RUSTC_BOOTSTRAP").ok(); - if let Some(val) = bootstrap.as_deref() { - match val { - 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, - _ => {} - } + let default_answer = if disable_unstable_features { + UnstableFeatures::Disallow + } else { + UnstableFeatures::Allow + }; + + // Returns true if the given list of comma-separated crate names + // contains `CARGO_CRATE_NAME`. + // + // This is not actually used by bootstrap; it only exists so that when + // cargo sees a third-party crate trying to set `RUSTC_BOOTSTRAP=1` in + // build.rs, it can suggest a somewhat less horrifying alternative. + // + // See for context. + let includes_current_crate = |names: &str| -> bool { + let Ok(crate_name) = env_var("CARGO_CRATE_NAME") else { return false }; + // Normalize `-` in crate names to `_`. + let crate_name = crate_name.replace('-', "_"); + names.replace('-', "_").split(',').any(|name| name == crate_name) + }; + + match env_var("RUSTC_BOOTSTRAP").as_deref() { + // Force the compiler to act as nightly, even if it's stable. + Ok("1") => UnstableFeatures::Cheat, + // Force the compiler to act as stable, even if it's nightly. + Ok("-1") => UnstableFeatures::Disallow, + // Force nightly if `RUSTC_BOOTSTRAP` contains the current crate name. + Ok(names) if includes_current_crate(names) => UnstableFeatures::Cheat, + _ => default_answer, } - - if disable_unstable_features { UnstableFeatures::Disallow } else { UnstableFeatures::Allow } } pub fn is_nightly_build(&self) -> bool { diff --git a/compiler/rustc_feature/src/tests.rs b/compiler/rustc_feature/src/tests.rs index dd6c57f247899..a105d358f8d38 100644 --- a/compiler/rustc_feature/src/tests.rs +++ b/compiler/rustc_feature/src/tests.rs @@ -3,8 +3,9 @@ use std::env; use super::UnstableFeatures; fn unstable_features(rustc_bootstrap: &str, crate_name: Option<&str>) -> UnstableFeatures { - UnstableFeatures::from_environment_inner(crate_name, |name| match name { + UnstableFeatures::from_environment_inner(|name| match name { "RUSTC_BOOTSTRAP" => Ok(rustc_bootstrap.to_owned()), + "CARGO_CRATE_NAME" => crate_name.map(str::to_owned).ok_or(env::VarError::NotPresent), _ => Err(env::VarError::NotPresent), }) } @@ -21,6 +22,7 @@ fn rustc_bootstrap_parsing() { // RUSTC_BOOTSTRAP allows multiple comma-delimited crates assert!(is_bootstrap("x,y,z", Some("x"))); assert!(is_bootstrap("x,y,z", Some("y"))); + assert!(is_bootstrap("x,y-utils", Some("y_utils"))); // Crate that aren't specified do not get unstable features assert!(!is_bootstrap("x", Some("a"))); assert!(!is_bootstrap("x,y,z", Some("a"))); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index bcc97d61ad212..4b22ae7b5b439 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1825,7 +1825,7 @@ pub fn parse_crate_edition(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches }; if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) { - let is_nightly = nightly_options::match_is_nightly_build(matches); + let is_nightly = nightly_options::is_nightly_build(); let msg = if !is_nightly { format!( "the crate requires edition {edition}, but the latest edition supported by this Rust version is {LATEST_STABLE_EDITION}" @@ -2510,7 +2510,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M let debuginfo_compression = unstable_opts.debuginfo_compression; let crate_name = matches.opt_str("crate-name"); - let unstable_features = UnstableFeatures::from_environment(crate_name.as_deref()); + let unstable_features = UnstableFeatures::from_environment(); // Parse any `-l` flags, which link to native libraries. let libs = parse_native_libs(early_dcx, &unstable_opts, unstable_features, matches); diff --git a/compiler/rustc_session/src/config/nightly_options.rs b/compiler/rustc_session/src/config/nightly_options.rs index ab65b2100da47..b6ce00823d04b 100644 --- a/compiler/rustc_session/src/config/nightly_options.rs +++ b/compiler/rustc_session/src/config/nightly_options.rs @@ -4,16 +4,11 @@ use crate::EarlyDiagCtxt; use crate::config::{OptionStability, RustcOptGroup}; pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool { - match_is_nightly_build(matches) - && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options") + is_nightly_build() && 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()) -} - -fn is_nightly_build(krate: Option<&str>) -> bool { - UnstableFeatures::from_environment(krate).is_nightly_build() +pub fn is_nightly_build() -> bool { + UnstableFeatures::from_environment().is_nightly_build() } pub fn check_nightly_options( @@ -22,7 +17,7 @@ pub fn check_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 = is_nightly_build(); let mut nightly_options_on_stable = 0; for opt in flags.iter() { diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 21c1165511099..e3616e53bb02d 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -251,7 +251,7 @@ impl ParseSess { pub fn with_dcx(dcx: DiagCtxt, source_map: Lrc) -> Self { Self { dcx, - unstable_features: UnstableFeatures::from_environment(None), + unstable_features: UnstableFeatures::from_environment(), config: Cfg::default(), check_config: CheckCfg::default(), edition: ExpnId::root().expn_data().edition, diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 5071ed1c47faa..db7753a80d8ac 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -409,7 +409,7 @@ impl Options { println_condition(p.condition); } - if nightly_options::match_is_nightly_build(matches) { + if nightly_options::is_nightly_build() { println!("\nPasses run with `--show-coverage`:"); for p in passes::COVERAGE_PASSES { print!("{:>20}", p.pass.name); @@ -653,7 +653,7 @@ impl Options { &matches.opt_strs("html-after-content"), &matches.opt_strs("markdown-before-content"), &matches.opt_strs("markdown-after-content"), - nightly_options::match_is_nightly_build(matches), + nightly_options::is_nightly_build(), dcx, &mut id_map, edition, @@ -775,8 +775,7 @@ impl Options { let with_examples = matches.opt_strs("with-examples"); let call_locations = crate::scrape_examples::load_call_locations(with_examples, dcx); - let unstable_features = - rustc_feature::UnstableFeatures::from_environment(crate_name.as_deref()); + let unstable_features = rustc_feature::UnstableFeatures::from_environment(); let options = Options { bin_crate, proc_macro_crate, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index a562a9eee717b..ffbb10aa3f2a2 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -260,7 +260,7 @@ pub(crate) fn create_config( cg: codegen_options, externs, target_triple: target, - unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()), + unstable_features: UnstableFeatures::from_environment(), actually_rustdoc: true, resolve_doc_links, unstable_opts,