From 622c48e4f1a5bc3727f8ead89767c8a9e367a77e Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 10 Oct 2020 14:27:52 -0400 Subject: [PATCH] Allow making `RUSTC_BOOTSTRAP` conditional on the crate name 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` There is a user-facing change here: things like `RUSTC_BOOTSTRAP=0` no longer active 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. - Add tests Check against `Cheat`, not whether nightly features are allowed. Nightly features are always allowed on the nightly channel. - Only call `is_nightly_build()` once within a function - Use booleans consistently for rustc_incremental Sessions can't be passed through threads, so `read_file` couldn't take a session. To be consistent, also take a boolean in `write_file_header`. --- compiler/rustc_ast_lowering/src/lib.rs | 4 +- compiler/rustc_codegen_llvm/src/llvm_util.rs | 13 +++--- compiler/rustc_driver/src/lib.rs | 21 +++++----- compiler/rustc_feature/src/lib.rs | 42 +++++++++++++++++-- .../src/persist/file_format.rs | 12 +++--- .../rustc_incremental/src/persist/load.rs | 19 ++++++--- .../rustc_incremental/src/persist/save.rs | 2 +- .../src/transform/check_consts/ops.rs | 3 +- .../src/thir/pattern/check_match.rs | 3 +- compiler/rustc_passes/src/check_const.rs | 3 +- .../rustc_resolve/src/late/diagnostics.rs | 5 +-- compiler/rustc_session/src/config.rs | 22 ++++++---- compiler/rustc_session/src/parse.rs | 2 +- compiler/rustc_session/src/session.rs | 3 ++ .../rustc_trait_selection/src/opaque_types.rs | 3 +- .../rustc_typeck/src/check/method/probe.rs | 3 +- src/librustdoc/clean/types.rs | 4 +- src/librustdoc/config.rs | 16 +++++-- src/librustdoc/core.rs | 2 +- src/librustdoc/doctest.rs | 3 +- src/librustdoc/externalfiles.rs | 4 +- src/librustdoc/html/render/mod.rs | 4 +- src/librustdoc/markdown.rs | 5 +-- src/librustdoc/passes/doc_test_lints.rs | 4 +- src/librustdoc/passes/html_tags.rs | 3 +- src/librustdoc/passes/non_autolinks.rs | 3 +- 26 files changed, 128 insertions(+), 80 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 599599f415f1c..3fa578874cc67 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -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; @@ -1395,8 +1394,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", diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 9c1e1b8fac06f..2e54784d85694 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -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; @@ -154,13 +153,11 @@ pub fn target_features(sess: &Session) -> Vec { 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(); diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index f434673c39e10..12e8006c86a4f 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -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 { 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 { 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; } diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index 68ac2841fed70..f965f7fdefe4a 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -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)); + } +} diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs index 048a81b81bab3..e185ee24d171b 100644 --- a/compiler/rustc_incremental/src/persist/file_format.rs +++ b/compiler/rustc_incremental/src/persist/file_format.rs @@ -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, 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(); } diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index 966faa9639d72..578c045a2b4e5 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -53,8 +53,12 @@ impl LoadResult<(PreviousDepGraph, WorkProductMap)> { } } -fn load_data(report_incremental_info: bool, path: &Path) -> LoadResult<(Vec, usize)> { - match file_format::read_file(report_incremental_info, path) { +fn load_data( + report_incremental_info: bool, + path: &Path, + nightly_build: bool, +) -> LoadResult<(Vec, 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()), } diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index 45cef479a4f43..102a77e8e79a7 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -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 diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index bd51136b8db58..d2e65abfbc7ee 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -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", diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 30b700a1d4f63..c64bdaab3edec 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -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; @@ -498,7 +497,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", diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index b24c62b971a46..e37c6418eb81c 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -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", diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 14f8c7b09f8e1..e7420558586cd 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -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 { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index b632bfbed301c..e9399dac6284c 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1247,7 +1247,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!( @@ -1544,7 +1544,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 \ @@ -1833,10 +1835,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(), @@ -1957,17 +1959,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 { diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 6f10d0c4b89ea..e3d24ccb85fa0 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -150,7 +150,7 @@ impl ParseSess { pub fn with_span_handler(handler: Handler, source_map: Lrc) -> 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()), diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 0b7c35a8afd50..67ed21d1d56bf 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -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 diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 914fa1e52c269..37538e7aac495 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -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"); } diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index d403e25939893..38ea69bdc6873 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -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 `{}`", diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 32b3f69ecd4f0..5f5deebca6516 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -681,7 +681,9 @@ impl Attributes { } Some(&(_, _, ExternalLocation::Remote(ref s))) => s.to_string(), Some(&(_, _, ExternalLocation::Unknown)) | None => String::from( - if UnstableFeatures::from_environment().is_nightly_build() { + // NOTE: intentionally doesn't pass crate name to avoid having + // different primitive links between crates + if UnstableFeatures::from_environment(None).is_nightly_build() { "https://doc.rust-lang.org/nightly" } else { "https://doc.rust-lang.org" diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 02885f519363c..b7db665147e7c 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -253,6 +253,7 @@ pub struct RenderOptions { pub document_private: bool, /// Document items that have `doc(hidden)`. pub document_hidden: bool, + pub unstable_features: rustc_feature::UnstableFeatures, } /// Temporary storage for data obtained during `RustdocVisitor::clean()`. @@ -295,7 +296,7 @@ impl Options { println_condition(p.condition); } - if nightly_options::is_nightly_build() { + if nightly_options::match_is_nightly_build(matches) { println!("\nPasses run with `--show-coverage`:"); for p in passes::COVERAGE_PASSES { print!("{:>20}", p.pass.name); @@ -479,6 +480,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), &diag, &mut id_map, edition, @@ -535,7 +537,9 @@ impl Options { let output_format = match matches.opt_str("output-format") { Some(s) => match OutputFormat::try_from(s.as_str()) { Ok(o) => { - if o.is_json() && !(show_coverage || nightly_options::is_nightly_build()) { + if o.is_json() + && !(show_coverage || nightly_options::match_is_nightly_build(matches)) + { diag.struct_err("json output format isn't supported for doc generation") .emit(); return Err(1); @@ -586,7 +590,6 @@ impl Options { Ok(Options { input, - crate_name, proc_macro_crate, error_format, libs, @@ -637,7 +640,11 @@ impl Options { generate_search_filter, document_private, document_hidden, + unstable_features: rustc_feature::UnstableFeatures::from_environment( + crate_name.as_deref(), + ), }, + crate_name, output_format, }) } @@ -655,7 +662,8 @@ fn check_deprecated_options(matches: &getopts::Matches, diag: &rustc_errors::Han for flag in deprecated_flags.iter() { if matches.opt_present(flag) { if *flag == "output-format" - && (matches.opt_present("show-coverage") || nightly_options::is_nightly_build()) + && (matches.opt_present("show-coverage") + || nightly_options::match_is_nightly_build(matches)) { continue; } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 5eca54199d6c8..4cfc0a10c00cf 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -370,7 +370,7 @@ pub fn run_core( cg: codegen_options, externs, target_triple: target, - unstable_features: UnstableFeatures::from_environment(), + unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()), actually_rustdoc: true, debugging_opts, error_format, diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index eb33890fb5fce..5e40e6b151d30 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -1,7 +1,6 @@ use rustc_ast as ast; use rustc_data_structures::sync::Lrc; use rustc_errors::ErrorReported; -use rustc_feature::UnstableFeatures; use rustc_hir as hir; use rustc_hir::intravisit; use rustc_hir::{HirId, CRATE_HIR_ID}; @@ -70,7 +69,7 @@ pub fn run(options: Options) -> Result<(), ErrorReported> { lint_cap: Some(options.lint_cap.clone().unwrap_or_else(|| lint::Forbid)), cg: options.codegen_options.clone(), externs: options.externs.clone(), - unstable_features: UnstableFeatures::from_environment(), + unstable_features: options.render_options.unstable_features, actually_rustdoc: true, debugging_opts: config::DebuggingOptions { ..config::basic_debugging_options() }, edition: options.edition, diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs index c8121d39d0f8f..900821dbf4a6b 100644 --- a/src/librustdoc/externalfiles.rs +++ b/src/librustdoc/externalfiles.rs @@ -1,6 +1,5 @@ use crate::html::markdown::{ErrorCodes, IdMap, Markdown, Playground}; use crate::rustc_span::edition::Edition; -use rustc_feature::UnstableFeatures; use std::fs; use std::path::Path; use std::str; @@ -25,12 +24,13 @@ impl ExternalHtml { after_content: &[String], md_before_content: &[String], md_after_content: &[String], + nightly_build: bool, diag: &rustc_errors::Handler, id_map: &mut IdMap, edition: Edition, playground: &Option, ) -> Option { - let codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()); + let codes = ErrorCodes::from(nightly_build); let ih = load_external_files(in_header, diag)?; let bc = load_external_files(before_content, diag)?; let m_bc = load_external_files(md_before_content, diag)?; diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 5ac0ffcfbf1c2..b3bfa7138a028 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -52,7 +52,6 @@ use rustc_ast_pretty::pprust; use rustc_attr::StabilityLevel; use rustc_data_structures::flock; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_feature::UnstableFeatures; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::Mutability; @@ -397,6 +396,7 @@ impl FormatRenderer for Context { resource_suffix, static_root_path, generate_search_filter, + unstable_features, .. } = options; @@ -466,7 +466,7 @@ impl FormatRenderer for Context { static_root_path, fs: DocFS::new(sender), edition, - codes: ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()), + codes: ErrorCodes::from(unstable_features.is_nightly_build()), playground, }; diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 3a87e1c46a615..33bd57223b8e9 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -2,7 +2,6 @@ use std::fs::{create_dir_all, read_to_string, File}; use std::io::prelude::*; use std::path::Path; -use rustc_feature::UnstableFeatures; use rustc_span::edition::Edition; use rustc_span::source_map::DUMMY_SP; @@ -66,7 +65,7 @@ pub fn render>( let title = metadata[0]; let mut ids = IdMap::new(); - let error_codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()); + let error_codes = ErrorCodes::from(options.unstable_features.is_nightly_build()); let text = if !options.markdown_no_toc { MarkdownWithToc(text, &mut ids, error_codes, edition, &playground).into_string() } else { @@ -131,7 +130,7 @@ pub fn test(mut options: Options) -> Result<(), String> { options.enable_per_target_ignores, ); collector.set_position(DUMMY_SP); - let codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()); + let codes = ErrorCodes::from(options.render_options.unstable_features.is_nightly_build()); find_testable_code(&input_str, &mut collector, codes, options.enable_per_target_ignores, None); diff --git a/src/librustdoc/passes/doc_test_lints.rs b/src/librustdoc/passes/doc_test_lints.rs index 686ec51fb0604..5fd7f5f81f7e0 100644 --- a/src/librustdoc/passes/doc_test_lints.rs +++ b/src/librustdoc/passes/doc_test_lints.rs @@ -92,9 +92,7 @@ pub fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) { find_testable_code(&dox, &mut tests, ErrorCodes::No, false, None); - if tests.found_tests == 0 - && rustc_feature::UnstableFeatures::from_environment().is_nightly_build() - { + if tests.found_tests == 0 && cx.tcx.sess.is_nightly_build() { if should_have_doc_example(cx, &item) { debug!("reporting error for {:?} (hir_id={:?})", item, hir_id); let sp = span_of_attrs(&item.attrs).unwrap_or(item.source.span()); diff --git a/src/librustdoc/passes/html_tags.rs b/src/librustdoc/passes/html_tags.rs index 1d9be619ec91a..26b64b4905ea7 100644 --- a/src/librustdoc/passes/html_tags.rs +++ b/src/librustdoc/passes/html_tags.rs @@ -5,7 +5,6 @@ use crate::fold::DocFolder; use crate::html::markdown::opts; use core::ops::Range; use pulldown_cmark::{Event, Parser}; -use rustc_feature::UnstableFeatures; use rustc_session::lint; use std::iter::Peekable; use std::str::CharIndices; @@ -27,7 +26,7 @@ impl<'a, 'tcx> InvalidHtmlTagsLinter<'a, 'tcx> { } pub fn check_invalid_html_tags(krate: Crate, cx: &DocContext<'_>) -> Crate { - if !UnstableFeatures::from_environment().is_nightly_build() { + if !cx.tcx.sess.is_nightly_build() { krate } else { let mut coll = InvalidHtmlTagsLinter::new(cx); diff --git a/src/librustdoc/passes/non_autolinks.rs b/src/librustdoc/passes/non_autolinks.rs index 4a8fc7fc6181e..964773dc0554b 100644 --- a/src/librustdoc/passes/non_autolinks.rs +++ b/src/librustdoc/passes/non_autolinks.rs @@ -7,7 +7,6 @@ use core::ops::Range; use pulldown_cmark::{Event, LinkType, Parser, Tag}; use regex::Regex; use rustc_errors::Applicability; -use rustc_feature::UnstableFeatures; use rustc_session::lint; pub const CHECK_NON_AUTOLINKS: Pass = Pass { @@ -54,7 +53,7 @@ impl<'a, 'tcx> NonAutolinksLinter<'a, 'tcx> { } pub fn check_non_autolinks(krate: Crate, cx: &DocContext<'_>) -> Crate { - if !UnstableFeatures::from_environment().is_nightly_build() { + if !cx.tcx.sess.is_nightly_build() { krate } else { let mut coll = NonAutolinksLinter::new(cx);