Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make RUSTC_BOOTSTRAP read the crate name from CARGO_CRATE_NAME #133202

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions compiler/rustc_driver_impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1211,9 +1211,7 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option<geto
if args.is_empty() {
// user did not write `-v` nor `-Z unstable-options`, so do not
// include that extra information.
let nightly_build =
rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build();
usage(false, false, nightly_build);
usage(false, false, nightly_options::is_nightly_build());
return None;
}

Expand Down Expand Up @@ -1265,7 +1263,7 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option<geto
if matches.opt_present("h") || matches.opt_present("help") {
// Only show unstable options in --help if we accept unstable options.
let unstable_enabled = nightly_options::is_unstable_enabled(&matches);
let nightly_build = nightly_options::match_is_nightly_build(&matches);
let nightly_build = nightly_options::is_nightly_build();
usage(matches.opt_present("verbose"), unstable_enabled, nightly_build);
return None;
}
Expand Down Expand Up @@ -1337,7 +1335,7 @@ fn ice_path_with_config(config: Option<&UnstableOptions>) -> &'static Option<Pat
}

ICE_PATH.get_or_init(|| {
if !rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build() {
if !nightly_options::is_nightly_build() {
return None;
}
let mut path = match std::env::var_os("RUSTC_ICE") {
Expand Down Expand Up @@ -1493,7 +1491,7 @@ fn report_ice(
dcx.emit_note(session_diagnostics::IceBugReport { bug_report_url });

// Only emit update nightly hint for users on nightly builds.
if rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build() {
if nightly_options::is_nightly_build() {
dcx.emit_note(session_diagnostics::UpdateNightlyNote);
}
}
Expand Down
65 changes: 44 additions & 21 deletions compiler/rustc_feature/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ mod unstable;
#[cfg(test)]
mod tests;

use std::env;
use std::num::NonZero;

use rustc_span::symbol::Symbol;
Expand Down Expand Up @@ -63,30 +64,52 @@ pub enum UnstableFeatures {
}

impl UnstableFeatures {
/// 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 {
// `true` if this is a feature-staged build, i.e., on the beta or stable channel.
/// 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(
env_var: impl Fn(&str) -> Result<String, env::VarError>, // std::env::var
) -> Self {
// 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 = std::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 <https://github.com/rust-lang/rust/pull/77802> 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 {
Expand Down
22 changes: 15 additions & 7 deletions compiler/rustc_feature/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
use std::env;

use super::UnstableFeatures;

fn unstable_features(rustc_bootstrap: &str, crate_name: Option<&str>) -> UnstableFeatures {
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),
})
}

#[test]
fn rustc_bootstrap_parsing() {
let is_bootstrap = |env, krate| {
std::env::set_var("RUSTC_BOOTSTRAP", env);
matches!(UnstableFeatures::from_environment(krate), UnstableFeatures::Cheat)
let is_bootstrap = |rustc_bootstrap, crate_name| {
matches!(unstable_features(rustc_bootstrap, crate_name), UnstableFeatures::Cheat)
};
assert!(is_bootstrap("1", None));
assert!(is_bootstrap("1", Some("x")));
Expand All @@ -13,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")));
Expand All @@ -22,10 +32,8 @@ fn rustc_bootstrap_parsing() {
assert!(!is_bootstrap("0", None));

// `RUSTC_BOOTSTRAP=-1` is force-stable, no unstable features allowed.
let is_force_stable = |krate| {
std::env::set_var("RUSTC_BOOTSTRAP", "-1");
matches!(UnstableFeatures::from_environment(krate), UnstableFeatures::Disallow)
};
let is_force_stable =
|crate_name| matches!(unstable_features("-1", crate_name), UnstableFeatures::Disallow);
assert!(is_force_stable(None));
// Does not support specifying any crate.
assert!(is_force_stable(Some("x")));
Expand Down
76 changes: 3 additions & 73 deletions compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ use crate::{EarlyDiagCtxt, HashStableContext, Session, filesearch, lint};

mod cfg;
mod native_libs;
pub mod nightly_options;
pub mod sigpipe;

/// The different settings that the `-C strip` flag can have.
Expand Down Expand Up @@ -1824,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}"
Expand Down Expand Up @@ -2509,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);

Expand Down Expand Up @@ -2689,77 +2690,6 @@ pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateTy
Ok(crate_types)
}

pub mod nightly_options {
use rustc_feature::UnstableFeatures;

use super::{OptionStability, RustcOptGroup};
use crate::EarlyDiagCtxt;

pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
match_is_nightly_build(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())
}

fn is_nightly_build(krate: Option<&str>) -> bool {
UnstableFeatures::from_environment(krate).is_nightly_build()
}

pub fn check_nightly_options(
early_dcx: &EarlyDiagCtxt,
matches: &getopts::Matches,
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 mut nightly_options_on_stable = 0;

for opt in flags.iter() {
if opt.stability == OptionStability::Stable {
continue;
}
if !matches.opt_present(opt.name) {
continue;
}
if opt.name != "Z" && !has_z_unstable_option {
early_dcx.early_fatal(format!(
"the `-Z unstable-options` flag must also be passed to enable \
the flag `{}`",
opt.name
));
}
if really_allows_unstable_options {
continue;
}
match opt.stability {
OptionStability::Unstable => {
nightly_options_on_stable += 1;
let msg = format!(
"the option `{}` is only accepted on the nightly compiler",
opt.name
);
let _ = early_dcx.early_err(msg);
}
OptionStability::Stable => {}
}
}
if nightly_options_on_stable > 0 {
early_dcx
.early_help("consider switching to a nightly toolchain: `rustup default nightly`");
early_dcx.early_note("selecting a toolchain with `+toolchain` arguments require a rustup proxy; see <https://rust-lang.github.io/rustup/concepts/index.html>");
early_dcx.early_note("for more information about Rust's stability policy, see <https://doc.rust-lang.org/book/appendix-07-nightly-rust.html#unstable-features>");
early_dcx.early_fatal(format!(
"{} nightly option{} were parsed",
nightly_options_on_stable,
if nightly_options_on_stable > 1 { "s" } else { "" }
));
}
}
}

impl fmt::Display for CrateType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Expand Down
59 changes: 59 additions & 0 deletions compiler/rustc_session/src/config/nightly_options.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use rustc_feature::UnstableFeatures;

use crate::EarlyDiagCtxt;
use crate::config::{OptionStability, RustcOptGroup};

pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
is_nightly_build() && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
}

pub fn is_nightly_build() -> bool {
UnstableFeatures::from_environment().is_nightly_build()
}

pub fn check_nightly_options(
early_dcx: &EarlyDiagCtxt,
matches: &getopts::Matches,
flags: &[RustcOptGroup],
) {
let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
let really_allows_unstable_options = is_nightly_build();
let mut nightly_options_on_stable = 0;

for opt in flags.iter() {
if opt.stability == OptionStability::Stable {
continue;
}
if !matches.opt_present(opt.name) {
continue;
}
if opt.name != "Z" && !has_z_unstable_option {
early_dcx.early_fatal(format!(
"the `-Z unstable-options` flag must also be passed to enable the flag `{}`",
opt.name
));
}
if really_allows_unstable_options {
continue;
}
match opt.stability {
OptionStability::Unstable => {
nightly_options_on_stable += 1;
let msg =
format!("the option `{}` is only accepted on the nightly compiler", opt.name);
let _ = early_dcx.early_err(msg);
}
OptionStability::Stable => {}
}
}
if nightly_options_on_stable > 0 {
early_dcx.early_help("consider switching to a nightly toolchain: `rustup default nightly`");
early_dcx.early_note("selecting a toolchain with `+toolchain` arguments require a rustup proxy; see <https://rust-lang.github.io/rustup/concepts/index.html>");
early_dcx.early_note("for more information about Rust's stability policy, see <https://doc.rust-lang.org/book/appendix-07-nightly-rust.html#unstable-features>");
early_dcx.early_fatal(format!(
"{} nightly option{} were parsed",
nightly_options_on_stable,
if nightly_options_on_stable > 1 { "s" } else { "" }
));
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_session/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ impl ParseSess {
pub fn with_dcx(dcx: DiagCtxt, source_map: Lrc<SourceMap>) -> 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,
Expand Down
7 changes: 3 additions & 4 deletions src/librustdoc/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading