1
Fork 0

Rollup merge of #77802 - jyn514:bootstrap-specific, r=nikomatsakis

Allow making `RUSTC_BOOTSTRAP` conditional on the crate name

Motivation: This came up in the [Zulip stream](208403962) for https://github.com/rust-lang/compiler-team/issues/350.
See also https://github.com/rust-lang/cargo/pull/6608#issuecomment-458546258; this implements https://github.com/rust-lang/cargo/issues/6627.
The goal is for this to eventually allow prohibiting setting `RUSTC_BOOTSTRAP` in build.rs (https://github.com/rust-lang/cargo/issues/7088).

## User-facing changes

- `RUSTC_BOOTSTRAP=1` still works; there is no current plan to remove this.
- Things like `RUSTC_BOOTSTRAP=0` no longer activate nightly features. In practice this shouldn't be a big deal, since `RUSTC_BOOTSTRAP` is the opposite of stable and everyone uses `RUSTC_BOOTSTRAP=1` anyway.
- `RUSTC_BOOTSTRAP=x` will enable nightly features only for crate `x`.
- `RUSTC_BOOTSTRAP=x,y` will enable nightly features only for crates `x` and `y`.

## Implementation changes

The main change is that `UnstableOptions::from_environment` now requires
an (optional) crate name. If the crate name is unknown (`None`), then the new feature is not available and you still have to use `RUSTC_BOOTSTRAP=1`. In practice this means the feature is only available for `--crate-name`, not for `#![crate_name]`; I'm interested in supporting the second but I'm not sure how.

Other major changes:

- Added `Session::is_nightly_build()`, which uses the `crate_name` of
the session
- Added `nightly_options::match_is_nightly_build`, a convenience method
for looking up `--crate-name` from CLI arguments.
`Session::is_nightly_build()`should be preferred where possible, since
it will take into account `#![crate_name]` (I think).
- Added `unstable_features` to `rustdoc::RenderOptions`

I'm not sure whether this counts as T-compiler or T-lang; _technically_ RUSTC_BOOTSTRAP is an implementation detail, but it's been used so much it seems like this counts as a language change too.

r? `@joshtriplett`
cc `@Mark-Simulacrum` `@hsivonen`
This commit is contained in:
Jonas Schievink 2020-11-15 13:39:43 +01:00 committed by GitHub
commit 8825942e86
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 128 additions and 80 deletions

View file

@ -53,7 +53,6 @@ use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
use rustc_hir::intravisit;
use rustc_hir::{ConstArg, GenericArg, ParamName};
use rustc_index::vec::{Idx, IndexVec};
use rustc_session::config::nightly_options;
use rustc_session::lint::{builtin::BARE_TRAIT_OBJECTS, BuiltinLintDiagnostics, LintBuffer};
use rustc_session::parse::ParseSess;
use rustc_session::Session;
@ -1398,8 +1397,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
"`impl Trait` not allowed outside of {}",
allowed_in,
);
if pos == ImplTraitPosition::Binding && nightly_options::is_nightly_build()
{
if pos == ImplTraitPosition::Binding && self.sess.is_nightly_build() {
err.help(
"add `#![feature(impl_trait_in_bindings)]` to the crate \
attributes to enable",

View file

@ -3,7 +3,6 @@ use crate::llvm;
use libc::c_int;
use rustc_codegen_ssa::target_features::supported_target_features;
use rustc_data_structures::fx::FxHashSet;
use rustc_feature::UnstableFeatures;
use rustc_middle::bug;
use rustc_session::config::PrintRequest;
use rustc_session::Session;
@ -147,13 +146,11 @@ pub fn target_features(sess: &Session) -> Vec<Symbol> {
let target_machine = create_informational_target_machine(sess);
supported_target_features(sess)
.iter()
.filter_map(|&(feature, gate)| {
if UnstableFeatures::from_environment().is_nightly_build() || gate.is_none() {
Some(feature)
} else {
None
}
})
.filter_map(
|&(feature, gate)| {
if sess.is_nightly_build() || gate.is_none() { Some(feature) } else { None }
},
)
.filter(|feature| {
let llvm_feature = to_llvm_feature(sess, feature);
let cstr = CString::new(llvm_feature).unwrap();

View file

@ -20,7 +20,7 @@ use rustc_data_structures::profiling::print_time_passes_entry;
use rustc_data_structures::sync::SeqCst;
use rustc_errors::registry::{InvalidErrorCode, Registry};
use rustc_errors::{ErrorReported, PResult};
use rustc_feature::{find_gated_cfg, UnstableFeatures};
use rustc_feature::find_gated_cfg;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_interface::util::{self, collect_crate_types, get_builtin_codegen_backend};
use rustc_interface::{interface, Queries};
@ -746,9 +746,6 @@ impl RustcDefaultCalls {
}
}
Cfg => {
let allow_unstable_cfg =
UnstableFeatures::from_environment().is_nightly_build();
let mut cfgs = sess
.parse_sess
.config
@ -763,7 +760,7 @@ impl RustcDefaultCalls {
// it, this is intended to get into Cargo and then go
// through to build scripts.
if (name != sym::target_feature || value != Some(sym::crt_dash_static))
&& !allow_unstable_cfg
&& !sess.is_nightly_build()
&& find_gated_cfg(|cfg_sym| cfg_sym == name).is_some()
{
return None;
@ -814,14 +811,14 @@ pub fn version(binary: &str, matches: &getopts::Matches) {
}
}
fn usage(verbose: bool, include_unstable_options: bool) {
fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) {
let groups = if verbose { config::rustc_optgroups() } else { config::rustc_short_optgroups() };
let mut options = getopts::Options::new();
for option in groups.iter().filter(|x| include_unstable_options || x.is_stable()) {
(option.apply)(&mut options);
}
let message = "Usage: rustc [OPTIONS] INPUT";
let nightly_help = if nightly_options::is_nightly_build() {
let nightly_help = if nightly_build {
"\n -Z help Print unstable compiler options"
} else {
""
@ -831,7 +828,7 @@ fn usage(verbose: bool, include_unstable_options: bool) {
} else {
"\n --help -v Print the full set of options rustc accepts"
};
let at_path = if verbose && nightly_options::is_nightly_build() {
let at_path = if verbose && nightly_build {
" @path Read newline separated options from `path`\n"
} else {
""
@ -1034,7 +1031,9 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
if args.is_empty() {
// user did not write `-v` nor `-Z unstable-options`, so do not
// include that extra information.
usage(false, false);
let nightly_build =
rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build();
usage(false, false, nightly_build);
return None;
}
@ -1063,7 +1062,9 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
if matches.opt_present("h") || matches.opt_present("help") {
// Only show unstable options in --help if we accept unstable options.
usage(matches.opt_present("verbose"), nightly_options::is_unstable_enabled(&matches));
let unstable_enabled = nightly_options::is_unstable_enabled(&matches);
let nightly_build = nightly_options::match_is_nightly_build(&matches);
usage(matches.opt_present("verbose"), unstable_enabled, nightly_build);
return None;
}

View file

@ -59,7 +59,7 @@ pub enum Stability {
Deprecated(&'static str, Option<&'static str>),
}
#[derive(Clone, Copy, Hash)]
#[derive(Clone, Copy, Debug, Hash)]
pub enum UnstableFeatures {
/// Hard errors for unstable features are active, as on beta/stable channels.
Disallow,
@ -73,11 +73,20 @@ pub enum UnstableFeatures {
}
impl UnstableFeatures {
pub fn from_environment() -> 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.
let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
// Returns whether `krate` should be counted as unstable
let is_unstable_crate = |var: &str| {
krate.map_or(false, |name| var.split(',').any(|new_krate| new_krate == name))
};
// `true` if we should enable unstable features for bootstrapping.
let bootstrap = std::env::var("RUSTC_BOOTSTRAP").is_ok();
let bootstrap = std::env::var("RUSTC_BOOTSTRAP")
.map_or(false, |var| var == "1" || is_unstable_crate(&var));
match (disable_unstable_features, bootstrap) {
(_, true) => UnstableFeatures::Cheat,
(true, _) => UnstableFeatures::Disallow,
@ -140,3 +149,30 @@ pub use builtin_attrs::{
AttributeType, BuiltinAttribute, GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
};
pub use removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES};
#[cfg(test)]
mod test {
use super::UnstableFeatures;
#[test]
fn rustc_bootstrap_parsing() {
let is_bootstrap = |env, krate| {
std::env::set_var("RUSTC_BOOTSTRAP", env);
matches!(UnstableFeatures::from_environment(krate), UnstableFeatures::Cheat)
};
assert!(is_bootstrap("1", None));
assert!(is_bootstrap("1", Some("x")));
// RUSTC_BOOTSTRAP allows specifying a specific crate
assert!(is_bootstrap("x", Some("x")));
// RUSTC_BOOTSTRAP allows multiple comma-delimited crates
assert!(is_bootstrap("x,y,z", Some("x")));
assert!(is_bootstrap("x,y,z", Some("y")));
// Crate that aren't specified do not get unstable features
assert!(!is_bootstrap("x", Some("a")));
assert!(!is_bootstrap("x,y,z", Some("a")));
assert!(!is_bootstrap("x,y,z", None));
// this is technically a breaking change, but there are no stability guarantees for RUSTC_BOOTSTRAP
assert!(!is_bootstrap("0", None));
}
}

View file

@ -15,7 +15,6 @@ use std::io::{self, Read};
use std::path::Path;
use rustc_serialize::opaque::Encoder;
use rustc_session::config::nightly_options;
/// The first few bytes of files generated by incremental compilation.
const FILE_MAGIC: &[u8] = b"RSIC";
@ -28,12 +27,12 @@ const HEADER_FORMAT_VERSION: u16 = 0;
/// the Git commit hash.
const RUSTC_VERSION: Option<&str> = option_env!("CFG_VERSION");
pub fn write_file_header(stream: &mut Encoder) {
pub fn write_file_header(stream: &mut Encoder, nightly_build: bool) {
stream.emit_raw_bytes(FILE_MAGIC);
stream
.emit_raw_bytes(&[(HEADER_FORMAT_VERSION >> 0) as u8, (HEADER_FORMAT_VERSION >> 8) as u8]);
let rustc_version = rustc_version();
let rustc_version = rustc_version(nightly_build);
assert_eq!(rustc_version.len(), (rustc_version.len() as u8) as usize);
stream.emit_raw_bytes(&[rustc_version.len() as u8]);
stream.emit_raw_bytes(rustc_version.as_bytes());
@ -51,6 +50,7 @@ pub fn write_file_header(stream: &mut Encoder) {
pub fn read_file(
report_incremental_info: bool,
path: &Path,
nightly_build: bool,
) -> io::Result<Option<(Vec<u8>, usize)>> {
if !path.exists() {
return Ok(None);
@ -93,7 +93,7 @@ pub fn read_file(
let mut buffer = vec![0; rustc_version_str_len];
file.read_exact(&mut buffer)?;
if buffer != rustc_version().as_bytes() {
if buffer != rustc_version(nightly_build).as_bytes() {
report_format_mismatch(report_incremental_info, path, "Different compiler version");
return Ok(None);
}
@ -115,8 +115,8 @@ fn report_format_mismatch(report_incremental_info: bool, file: &Path, message: &
}
}
fn rustc_version() -> String {
if nightly_options::is_nightly_build() {
fn rustc_version(nightly_build: bool) -> String {
if nightly_build {
if let Some(val) = env::var_os("RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER") {
return val.to_string_lossy().into_owned();
}

View file

@ -53,8 +53,12 @@ impl LoadResult<(PreviousDepGraph, WorkProductMap)> {
}
}
fn load_data(report_incremental_info: bool, path: &Path) -> LoadResult<(Vec<u8>, usize)> {
match file_format::read_file(report_incremental_info, path) {
fn load_data(
report_incremental_info: bool,
path: &Path,
nightly_build: bool,
) -> LoadResult<(Vec<u8>, usize)> {
match file_format::read_file(report_incremental_info, path, nightly_build) {
Ok(Some(data_and_pos)) => LoadResult::Ok { data: data_and_pos },
Ok(None) => {
// The file either didn't exist or was produced by an incompatible
@ -111,13 +115,14 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
let expected_hash = sess.opts.dep_tracking_hash();
let mut prev_work_products = FxHashMap::default();
let nightly_build = sess.is_nightly_build();
// If we are only building with -Zquery-dep-graph but without an actual
// incr. comp. session directory, we skip this. Otherwise we'd fail
// when trying to load work products.
if sess.incr_comp_session_dir_opt().is_some() {
let work_products_path = work_products_path(sess);
let load_result = load_data(report_incremental_info, &work_products_path);
let load_result = load_data(report_incremental_info, &work_products_path, nightly_build);
if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result {
// Decode the list of work_products
@ -163,7 +168,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
MaybeAsync::Async(std::thread::spawn(move || {
let _prof_timer = prof.generic_activity("incr_comp_load_dep_graph");
match load_data(report_incremental_info, &path) {
match load_data(report_incremental_info, &path, nightly_build) {
LoadResult::DataOutOfDate => LoadResult::DataOutOfDate,
LoadResult::Error { message } => LoadResult::Error { message },
LoadResult::Ok { data: (bytes, start_pos) } => {
@ -201,7 +206,11 @@ pub fn load_query_result_cache(sess: &Session) -> OnDiskCache<'_> {
let _prof_timer = sess.prof.generic_activity("incr_comp_load_query_result_cache");
match load_data(sess.opts.debugging_opts.incremental_info, &query_cache_path(sess)) {
match load_data(
sess.opts.debugging_opts.incremental_info,
&query_cache_path(sess),
sess.is_nightly_build(),
) {
LoadResult::Ok { data: (bytes, start_pos) } => OnDiskCache::new(sess, bytes, start_pos),
_ => OnDiskCache::new_empty(sess.source_map()),
}

View file

@ -119,7 +119,7 @@ where
// generate the data in a memory buffer
let mut encoder = Encoder::new(Vec::new());
file_format::write_file_header(&mut encoder);
file_format::write_file_header(&mut encoder, sess.is_nightly_build());
encode(&mut encoder);
// write the data out

View file

@ -4,7 +4,6 @@ use rustc_errors::{struct_span_err, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_middle::mir;
use rustc_session::config::nightly_options;
use rustc_session::parse::feature_err;
use rustc_span::symbol::sym;
use rustc_span::{Span, Symbol};
@ -104,7 +103,7 @@ impl NonConstOp for FnCallUnstable {
if ccx.is_const_stable_const_fn() {
err.help("Const-stable functions can only call other const-stable functions");
} else if nightly_options::is_nightly_build() {
} else if ccx.tcx.sess.is_nightly_build() {
if let Some(feature) = feature {
err.help(&format!(
"add `#![feature({})]` to the crate attributes to enable",

View file

@ -12,7 +12,6 @@ use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::{HirId, Pat};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::config::nightly_options;
use rustc_session::lint::builtin::BINDINGS_WITH_VARIANT_NAME;
use rustc_session::lint::builtin::{IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS};
use rustc_session::parse::feature_err;
@ -502,7 +501,7 @@ fn check_exhaustive<'p, 'tcx>(
so a wildcard `_` is necessary to match exhaustively",
scrut_ty,
));
if nightly_options::is_nightly_build() {
if cx.tcx.sess.is_nightly_build() {
err.help(&format!(
"add `#![feature(precise_pointer_size_matching)]` \
to the crate attributes to enable precise `{}` matching",

View file

@ -15,7 +15,6 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_middle::hir::map::Map;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::nightly_options;
use rustc_session::parse::feature_err;
use rustc_span::{sym, Span, Symbol};
@ -145,7 +144,7 @@ impl<'tcx> CheckConstVisitor<'tcx> {
//
// FIXME(ecstaticmorse): Maybe this could be incorporated into `feature_err`? This
// is a pretty narrow case, however.
if nightly_options::is_nightly_build() {
if tcx.sess.is_nightly_build() {
for gate in missing_secondary {
let note = format!(
"add `#![feature({})]` to the crate attributes to enable",

View file

@ -16,7 +16,6 @@ use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::PrimTy;
use rustc_session::config::nightly_options;
use rustc_session::parse::feature_err;
use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
@ -890,7 +889,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
}
(Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => {
err.span_label(span, "type aliases cannot be used as traits");
if nightly_options::is_nightly_build() {
if self.r.session.is_nightly_build() {
let msg = "you might have meant to use `#![feature(trait_alias)]` instead of a \
`type` alias";
if let Some(span) = self.def_span(def_id) {
@ -1675,7 +1674,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
_ => {}
}
}
if nightly_options::is_nightly_build()
if self.tcx.sess.is_nightly_build()
&& !self.tcx.features().in_band_lifetimes
&& suggests_in_band
{

View file

@ -1250,7 +1250,7 @@ fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
None => DEFAULT_EDITION,
};
if !edition.is_stable() && !nightly_options::is_nightly_build() {
if !edition.is_stable() && !nightly_options::match_is_nightly_build(matches) {
early_error(
ErrorOutputType::default(),
&format!(
@ -1547,7 +1547,9 @@ fn parse_libs(
);
}
};
if kind == NativeLibKind::StaticNoBundle && !nightly_options::is_nightly_build() {
if kind == NativeLibKind::StaticNoBundle
&& !nightly_options::match_is_nightly_build(matches)
{
early_error(
error_format,
"the library kind 'static-nobundle' is only \
@ -1836,10 +1838,10 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
cg,
error_format,
externs,
unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
crate_name,
alt_std_name: None,
libs,
unstable_features: UnstableFeatures::from_environment(),
debug_assertions,
actually_rustdoc: false,
trimmed_def_paths: TrimmedDefPaths::default(),
@ -1960,17 +1962,21 @@ pub mod nightly_options {
use rustc_feature::UnstableFeatures;
pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
is_nightly_build() && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
match_is_nightly_build(matches)
&& matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
}
pub fn is_nightly_build() -> bool {
UnstableFeatures::from_environment().is_nightly_build()
pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
is_nightly_build(matches.opt_str("crate-name").as_deref())
}
pub fn is_nightly_build(krate: Option<&str>) -> bool {
UnstableFeatures::from_environment(krate).is_nightly_build()
}
pub fn check_nightly_options(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 =
UnstableFeatures::from_environment().is_nightly_build();
let really_allows_unstable_options = match_is_nightly_build(matches);
for opt in flags.iter() {
if opt.stability == OptionStability::Stable {

View file

@ -150,7 +150,7 @@ impl ParseSess {
pub fn with_span_handler(handler: Handler, source_map: Lrc<SourceMap>) -> Self {
Self {
span_diagnostic: handler,
unstable_features: UnstableFeatures::from_environment(),
unstable_features: UnstableFeatures::from_environment(None),
config: FxHashSet::default(),
edition: ExpnId::root().expn_data().edition,
raw_identifier_spans: Lock::new(Vec::new()),

View file

@ -745,6 +745,9 @@ impl Session {
pub fn unstable_options(&self) -> bool {
self.opts.debugging_opts.unstable_options
}
pub fn is_nightly_build(&self) -> bool {
self.opts.unstable_features.is_nightly_build()
}
pub fn overflow_checks(&self) -> bool {
self.opts
.cg

View file

@ -12,7 +12,6 @@ use rustc_infer::infer::{self, InferCtxt, InferOk};
use rustc_middle::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor};
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::config::nightly_options;
use rustc_span::Span;
use std::ops::ControlFlow;
@ -602,7 +601,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
};
err.span_label(span, label);
if nightly_options::is_nightly_build() {
if self.tcx.sess.is_nightly_build() {
err.help("add #![feature(member_constraints)] to the crate attributes to enable");
}

View file

@ -25,7 +25,6 @@ use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::ty::{
self, ParamEnvAnd, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
};
use rustc_session::config::nightly_options;
use rustc_session::lint;
use rustc_span::def_id::LocalDefId;
use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP};
@ -1272,7 +1271,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
self.tcx.def_path_str(stable_pick.item.def_id),
));
if nightly_options::is_nightly_build() {
if self.tcx.sess.is_nightly_build() {
for (candidate, feature) in unstable_candidates {
diag.help(&format!(
"add `#![feature({})]` to the crate attributes to enable `{}`",