diff --git a/Cargo.lock b/Cargo.lock index d27eec893b0af..67259aed8ebee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3199,6 +3199,7 @@ dependencies = [ "rustc_data_structures", "rustc_error_codes", "rustc_errors", + "rustc_feature", "rustc_fs_util", "rustc_index", "rustc_macros", @@ -3574,6 +3575,7 @@ dependencies = [ "rustc_data_structures", "rustc_error_codes", "rustc_errors", + "rustc_feature", "rustc_interface", "rustc_lint", "rustc_metadata", @@ -3607,6 +3609,15 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "rustc_feature" +version = "0.0.0" +dependencies = [ + "lazy_static 1.3.0", + "rustc_data_structures", + "syntax_pos", +] + [[package]] name = "rustc_fs_util" version = "0.0.0" @@ -3682,6 +3693,7 @@ dependencies = [ "rustc", "rustc_data_structures", "rustc_error_codes", + "rustc_feature", "rustc_index", "rustc_target", "syntax", @@ -3786,6 +3798,7 @@ dependencies = [ "rustc_data_structures", "rustc_error_codes", "rustc_errors", + "rustc_feature", "rustc_lexer", "rustc_target", "smallvec 1.0.0", @@ -3802,6 +3815,7 @@ dependencies = [ "rustc_data_structures", "rustc_error_codes", "rustc_errors", + "rustc_feature", "rustc_index", "rustc_parse", "rustc_target", @@ -3844,6 +3858,7 @@ dependencies = [ "rustc_data_structures", "rustc_error_codes", "rustc_errors", + "rustc_feature", "rustc_metadata", "smallvec 1.0.0", "syntax", @@ -4442,6 +4457,7 @@ dependencies = [ "rustc_data_structures", "rustc_error_codes", "rustc_errors", + "rustc_feature", "rustc_index", "rustc_lexer", "rustc_macros", @@ -4458,6 +4474,7 @@ dependencies = [ "log", "rustc_data_structures", "rustc_errors", + "rustc_feature", "rustc_lexer", "rustc_parse", "serialize", @@ -4475,6 +4492,7 @@ dependencies = [ "rustc_data_structures", "rustc_error_codes", "rustc_errors", + "rustc_feature", "rustc_parse", "rustc_target", "smallvec 1.0.0", diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 6c1695a4eac09..fb30d6c519c90 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -22,6 +22,7 @@ rustc-rayon = "0.3.0" rustc-rayon-core = "0.3.0" polonius-engine = "0.10.0" rustc_apfloat = { path = "../librustc_apfloat" } +rustc_feature = { path = "../librustc_feature" } rustc_target = { path = "../librustc_target" } rustc_macros = { path = "../librustc_macros" } rustc_data_structures = { path = "../librustc_data_structures" } diff --git a/src/librustc/arena.rs b/src/librustc/arena.rs index 193b04eabb3fb..1d6a3420ed952 100644 --- a/src/librustc/arena.rs +++ b/src/librustc/arena.rs @@ -101,7 +101,7 @@ macro_rules! arena_types { [few] resolve_lifetimes: rustc::middle::resolve_lifetime::ResolveLifetimes, [few] lint_levels: rustc::lint::LintLevelMap, [few] stability_index: rustc::middle::stability::Index<'tcx>, - [few] features: syntax::feature_gate::Features, + [few] features: rustc_feature::Features, [few] all_traits: Vec, [few] privacy_access_levels: rustc::middle::privacy::AccessLevels, [few] target_features_whitelist: rustc_data_structures::fx::FxHashMap< diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 144980c53eb5f..6499e56325a42 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -4,7 +4,6 @@ use crate::ich::StableHashingContext; use syntax::ast; -use syntax::feature_gate; use syntax_pos::SourceFile; use crate::hir::def_id::{DefId, CrateNum, CRATE_DEF_INDEX}; @@ -156,7 +155,7 @@ fn stable_normalized_pos(np: ::syntax_pos::NormalizedPos, } -impl<'tcx> HashStable> for feature_gate::Features { +impl<'tcx> HashStable> for rustc_feature::Features { fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) { // Unfortunately we cannot exhaustively list fields here, since the // struct is macro generated. diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs index 27bf9649324b4..619ca724214c8 100644 --- a/src/librustc/lint/levels.rs +++ b/src/librustc/lint/levels.rs @@ -232,13 +232,13 @@ impl<'a> LintLevelsBuilder<'a> { // don't have any lint names (`#[level(reason = "foo")]`) if let ast::LitKind::Str(rationale, _) = name_value.kind { if !self.sess.features_untracked().lint_reasons { - feature_gate::emit_feature_err( + feature_gate::feature_err( &self.sess.parse_sess, sym::lint_reasons, item.span, - feature_gate::GateIssue::Language, "lint reasons are experimental" - ); + ) + .emit(); } reason = Some(rationale); } else { diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 411a47423c5aa..54aafe2114dac 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -13,11 +13,12 @@ use crate::ty::query::Providers; use crate::middle::privacy::AccessLevels; use crate::session::{DiagnosticMessageId, Session}; use errors::DiagnosticBuilder; +use rustc_feature::GateIssue; use syntax::symbol::{Symbol, sym}; use syntax_pos::{Span, MultiSpan}; use syntax::ast::{Attribute, CRATE_NODE_ID}; use syntax::errors::Applicability; -use syntax::feature_gate::{GateIssue, emit_feature_err}; +use syntax::feature_gate::{feature_err, feature_err_issue}; use syntax::attr::{self, Stability, Deprecation, RustcDeprecation}; use crate::ty::{self, TyCtxt}; use crate::util::nodemap::{FxHashSet, FxHashMap}; @@ -512,9 +513,8 @@ pub fn report_unstable( if is_soft { soft_handler(lint::builtin::SOFT_UNSTABLE, span, &msg) } else { - emit_feature_err( - &sess.parse_sess, feature, span, GateIssue::Library(issue), &msg - ); + feature_err_issue(&sess.parse_sess, feature, span, GateIssue::Library(issue), &msg) + .emit(); } } } @@ -842,15 +842,19 @@ impl Visitor<'tcx> for Checker<'tcx> { let ty = self.tcx.type_of(def_id); if adt_def.has_dtor(self.tcx) { - emit_feature_err(&self.tcx.sess.parse_sess, - sym::untagged_unions, item.span, GateIssue::Language, - "unions with `Drop` implementations are unstable"); + feature_err( + &self.tcx.sess.parse_sess, sym::untagged_unions, item.span, + "unions with `Drop` implementations are unstable" + ) + .emit(); } else { let param_env = self.tcx.param_env(def_id); if !param_env.can_type_implement_copy(self.tcx, ty).is_ok() { - emit_feature_err(&self.tcx.sess.parse_sess, - sym::untagged_unions, item.span, GateIssue::Language, - "unions with non-`Copy` fields are unstable"); + feature_err( + &self.tcx.sess.parse_sess, sym::untagged_unions, item.span, + "unions with non-`Copy` fields are unstable" + ) + .emit(); } } } diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index cd93fed8e1e0e..d715ddb1b81de 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -1130,7 +1130,7 @@ rustc_queries! { desc { |tcx| "estimating size for `{}`", tcx.def_path_str(def.def_id()) } } - query features_query(_: CrateNum) -> &'tcx feature_gate::Features { + query features_query(_: CrateNum) -> &'tcx rustc_feature::Features { eval_always desc { "looking up enabled feature gates" } } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 6733250e1e8d8..fbfae721bbe91 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -7,6 +7,7 @@ use crate::session::{early_error, early_warn, Session}; use crate::session::search_paths::SearchPath; use rustc_data_structures::fx::FxHashSet; +use rustc_feature::UnstableFeatures; use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel}; use rustc_target::spec::{Target, TargetTriple}; @@ -16,7 +17,6 @@ use syntax::ast; use syntax::source_map::{FileName, FilePathMapping}; use syntax::edition::{Edition, EDITION_NAME_LIST, DEFAULT_EDITION}; use syntax::symbol::{sym, Symbol}; -use syntax::feature_gate::UnstableFeatures; use errors::emitter::HumanReadableErrorType; use errors::{ColorConfig, FatalError, Handler}; @@ -2701,7 +2701,7 @@ pub fn parse_crate_types_from_list(list_list: Vec) -> Result, - features: Once, + features: Once, /// The maximum recursion limit for potentially infinitely recursive /// operations such as auto-dereference and monomorphization. @@ -470,11 +469,11 @@ impl Session { /// DO NOT USE THIS METHOD if there is a TyCtxt available, as it circumvents /// dependency tracking. Use tcx.features() instead. #[inline] - pub fn features_untracked(&self) -> &feature_gate::Features { + pub fn features_untracked(&self) -> &rustc_feature::Features { self.features.get() } - pub fn init_features(&self, features: feature_gate::Features) { + pub fn init_features(&self, features: rustc_feature::Features) { self.features.set(features); } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 0b6937975aae1..776ae7dc141ce 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -72,7 +72,6 @@ use rustc_macros::HashStable; use syntax::ast; use syntax::attr; use syntax::source_map::MultiSpan; -use syntax::feature_gate; use syntax::symbol::{Symbol, kw, sym}; use syntax_pos::Span; use syntax::expand::allocator::AllocatorKind; @@ -1312,7 +1311,7 @@ impl<'tcx> TyCtxt<'tcx> { self.cstore.allocator_kind() } - pub fn features(self) -> &'tcx feature_gate::Features { + pub fn features(self) -> &'tcx rustc_feature::Features { self.features_query(LOCAL_CRATE) } diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index a1eb1c43335b1..5b4a6ac8a2d3c 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -56,7 +56,6 @@ use std::any::type_name; use syntax_pos::{Span, DUMMY_SP}; use syntax::attr; use syntax::ast; -use syntax::feature_gate; use syntax::symbol::Symbol; #[macro_use] diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index e7562c399b222..acc221f0657c9 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -30,6 +30,7 @@ extern crate libc; #[macro_use] extern crate rustc; extern crate rustc_target; #[macro_use] extern crate rustc_data_structures; +extern crate rustc_feature; extern crate rustc_index; extern crate rustc_incremental; extern crate rustc_codegen_utils; diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs index 290ca40926104..7bff9e69dd52e 100644 --- a/src/librustc_codegen_llvm/llvm_util.rs +++ b/src/librustc_codegen_llvm/llvm_util.rs @@ -6,7 +6,7 @@ use rustc::session::config::PrintRequest; use rustc_target::spec::{MergeFunctions, PanicStrategy}; use libc::c_int; use std::ffi::CString; -use syntax::feature_gate::UnstableFeatures; +use rustc_feature::UnstableFeatures; use syntax::symbol::sym; use std::str; diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index 2b7e4d35248e6..d1cb4cbeb9b31 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -19,6 +19,7 @@ rustc_target = { path = "../librustc_target" } rustc_lint = { path = "../librustc_lint" } rustc_data_structures = { path = "../librustc_data_structures" } errors = { path = "../librustc_errors", package = "rustc_errors" } +rustc_feature = { path = "../librustc_feature" } rustc_metadata = { path = "../librustc_metadata" } rustc_mir = { path = "../librustc_mir" } rustc_parse = { path = "../librustc_parse" } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index c945de8f1e1dc..8b04d3d46d04a 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -44,7 +44,7 @@ use errors::{PResult, registry::Registry}; use rustc_interface::interface; use rustc_interface::util::get_codegen_sysroot; use rustc_data_structures::sync::SeqCst; - +use rustc_feature::{find_gated_cfg, UnstableFeatures}; use rustc_serialize::json::ToJson; use std::borrow::Cow; @@ -61,10 +61,9 @@ use std::str; use std::time::Instant; use syntax::ast; -use syntax::source_map::FileLoader; -use syntax::feature_gate::{GatedCfg, UnstableFeatures}; -use syntax::symbol::sym; -use syntax_pos::{DUMMY_SP, FileName}; +use syntax_pos::source_map::FileLoader; +use syntax_pos::symbol::sym; +use syntax_pos::FileName; pub mod pretty; mod args; @@ -684,12 +683,6 @@ impl RustcDefaultCalls { .is_nightly_build(); let mut cfgs = sess.parse_sess.config.iter().filter_map(|&(name, ref value)| { - let gated_cfg = GatedCfg::gate(&ast::MetaItem { - path: ast::Path::from_ident(ast::Ident::with_dummy_span(name)), - kind: ast::MetaItemKind::Word, - span: DUMMY_SP, - }); - // Note that crt-static is a specially recognized cfg // directive that's printed out here as part of // rust-lang/rust#37406, but in general the @@ -700,10 +693,11 @@ impl RustcDefaultCalls { // through to build scripts. let value = value.as_ref().map(|s| s.as_str()); let value = value.as_ref().map(|s| s.as_ref()); - if name != sym::target_feature || value != Some("crt-static") { - if !allow_unstable_cfg && gated_cfg.is_some() { - return None - } + if (name != sym::target_feature || value != Some("crt-static")) + && !allow_unstable_cfg + && find_gated_cfg(|cfg_sym| cfg_sym == name).is_some() + { + return None; } if let Some(value) = value { diff --git a/src/librustc_feature/Cargo.toml b/src/librustc_feature/Cargo.toml new file mode 100644 index 0000000000000..40ce922947bcb --- /dev/null +++ b/src/librustc_feature/Cargo.toml @@ -0,0 +1,15 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_feature" +version = "0.0.0" +edition = "2018" + +[lib] +name = "rustc_feature" +path = "lib.rs" +doctest = false + +[dependencies] +rustc_data_structures = { path = "../librustc_data_structures" } +lazy_static = "1.0.0" +syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/libsyntax/feature_gate/accepted.rs b/src/librustc_feature/accepted.rs similarity index 99% rename from src/libsyntax/feature_gate/accepted.rs rename to src/librustc_feature/accepted.rs index dab83f48a03ae..fec5a7f1a4501 100644 --- a/src/libsyntax/feature_gate/accepted.rs +++ b/src/librustc_feature/accepted.rs @@ -1,7 +1,7 @@ //! List of the accepted feature gates. -use crate::symbol::sym; use super::{State, Feature}; +use syntax_pos::symbol::sym; macro_rules! declare_features { ($( diff --git a/src/libsyntax/feature_gate/active.rs b/src/librustc_feature/active.rs similarity index 97% rename from src/libsyntax/feature_gate/active.rs rename to src/librustc_feature/active.rs index b04b30aa6bc18..7c0d39965fc00 100644 --- a/src/libsyntax/feature_gate/active.rs +++ b/src/librustc_feature/active.rs @@ -2,10 +2,9 @@ use super::{State, Feature}; -use crate::edition::Edition; -use crate::symbol::{Symbol, sym}; - +use syntax_pos::edition::Edition; use syntax_pos::Span; +use syntax_pos::symbol::{Symbol, sym}; macro_rules! set { ($field: ident) => {{ @@ -37,7 +36,7 @@ macro_rules! declare_features { ),+]; /// A set of features to be used by later passes. - #[derive(Clone)] + #[derive(Clone, Default)] pub struct Features { /// `#![feature]` attrs for language features, for error reporting. pub declared_lang_features: Vec<(Symbol, Span, Option)>, @@ -50,17 +49,7 @@ macro_rules! declare_features { } impl Features { - pub fn new() -> Features { - Features { - declared_lang_features: Vec::new(), - declared_lib_features: Vec::new(), - $($feature: false),+ - } - } - - pub fn walk_feature_fields(&self, mut f: F) - where F: FnMut(&str, bool) - { + pub fn walk_feature_fields(&self, mut f: impl FnMut(&str, bool)) { $(f(stringify!($feature), self.$feature);)+ } } diff --git a/src/libsyntax/feature_gate/builtin_attrs.rs b/src/librustc_feature/builtin_attrs.rs similarity index 93% rename from src/libsyntax/feature_gate/builtin_attrs.rs rename to src/librustc_feature/builtin_attrs.rs index a9f41633f30fd..f72df00a8e821 100644 --- a/src/libsyntax/feature_gate/builtin_attrs.rs +++ b/src/librustc_feature/builtin_attrs.rs @@ -3,17 +3,10 @@ use AttributeType::*; use AttributeGate::*; -use super::check::{emit_feature_err, GateIssue}; -use super::check::{Stability, EXPLAIN_ALLOW_INTERNAL_UNSAFE, EXPLAIN_ALLOW_INTERNAL_UNSTABLE}; -use super::active::Features; +use crate::{Features, Stability}; -use crate::ast; -use crate::attr::AttributeTemplate; -use crate::sess::ParseSess; -use crate::symbol::{Symbol, sym}; - -use syntax_pos::Span; use rustc_data_structures::fx::FxHashMap; +use syntax_pos::symbol::{Symbol, sym}; use lazy_static::lazy_static; type GateFn = fn(&Features) -> bool; @@ -24,39 +17,19 @@ macro_rules! cfg_fn { } } +pub type GatedCfg = (Symbol, Symbol, GateFn); + /// `cfg(...)`'s that are feature gated. -const GATED_CFGS: &[(Symbol, Symbol, GateFn)] = &[ +const GATED_CFGS: &[GatedCfg] = &[ // (name in cfg, feature, function to check if the feature is enabled) (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)), (sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), (sym::target_has_atomic_load_store, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), ]; -#[derive(Debug)] -pub struct GatedCfg { - span: Span, - index: usize, -} - -impl GatedCfg { - pub fn gate(cfg: &ast::MetaItem) -> Option { - GATED_CFGS.iter() - .position(|info| cfg.check_name(info.0)) - .map(|idx| { - GatedCfg { - span: cfg.span, - index: idx - } - }) - } - - pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) { - let (cfg, feature, has_feature) = GATED_CFGS[self.index]; - if !has_feature(features) && !self.span.allows_unstable(feature) { - let explain = format!("`cfg({})` is experimental and subject to change", cfg); - emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain); - } - } +/// Find a gated cfg determined by the `pred`icate which is given the cfg's name. +pub fn find_gated_cfg(pred: impl Fn(Symbol) -> bool) -> Option<&'static GatedCfg> { + GATED_CFGS.iter().find(|(cfg_sym, ..)| pred(*cfg_sym)) } // If you change this, please modify `src/doc/unstable-book` as well. You must @@ -108,6 +81,21 @@ impl AttributeGate { } } +/// A template that the attribute input must match. +/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now. +#[derive(Clone, Copy)] +pub struct AttributeTemplate { + pub word: bool, + pub list: Option<&'static str>, + pub name_value_str: Option<&'static str>, +} + +impl AttributeTemplate { + pub fn only_word() -> Self { + Self { word: true, list: None, name_value_str: None } + } +} + /// A convenience macro for constructing attribute templates. /// E.g., `template!(Word, List: "description")` means that the attribute /// supports forms `#[attr]` and `#[attr(description)]`. @@ -361,9 +349,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), gated!( allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), - EXPLAIN_ALLOW_INTERNAL_UNSTABLE, + "allow_internal_unstable side-steps feature gating and stability checks", + ), + gated!( + allow_internal_unsafe, Normal, template!(Word), + "allow_internal_unsafe side-steps the unsafe_code lint", ), - gated!(allow_internal_unsafe, Normal, template!(Word), EXPLAIN_ALLOW_INTERNAL_UNSAFE), // ========================================================================== // Internal attributes: Type system related: @@ -587,14 +578,10 @@ pub fn deprecated_attributes() -> Vec<&'static BuiltinAttribute> { BUILTIN_ATTRIBUTES.iter().filter(|(.., gate)| gate.is_deprecated()).collect() } -pub fn is_builtin_attr_name(name: ast::Name) -> bool { +pub fn is_builtin_attr_name(name: Symbol) -> bool { BUILTIN_ATTRIBUTE_MAP.get(&name).is_some() } -pub fn is_builtin_attr(attr: &ast::Attribute) -> bool { - attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).is_some() -} - lazy_static! { pub static ref BUILTIN_ATTRIBUTE_MAP: FxHashMap = { let mut map = FxHashMap::default(); diff --git a/src/librustc_feature/lib.rs b/src/librustc_feature/lib.rs new file mode 100644 index 0000000000000..c38bb3740af3a --- /dev/null +++ b/src/librustc_feature/lib.rs @@ -0,0 +1,137 @@ +//! # Feature gates +//! +//! This crate declares the set of past and present unstable features in the compiler. +//! Feature gate checking itself is done in `libsyntax/feature_gate/check.rs` at the moment. +//! +//! Features are enabled in programs via the crate-level attributes of +//! `#![feature(...)]` with a comma-separated list of features. +//! +//! For the purpose of future feature-tracking, once a feature gate is added, +//! even if it is stabilized or removed, *do not remove it*. Instead, move the +//! symbol to the `accepted` or `removed` modules respectively. + +mod accepted; +mod removed; +mod active; +mod builtin_attrs; + +use std::fmt; +use std::num::NonZeroU32; +use syntax_pos::{Span, edition::Edition, symbol::Symbol}; + +#[derive(Clone, Copy)] +pub enum State { + Accepted, + Active { set: fn(&mut Features, Span) }, + Removed { reason: Option<&'static str> }, + Stabilized { reason: Option<&'static str> }, +} + +impl fmt::Debug for State { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + State::Accepted { .. } => write!(f, "accepted"), + State::Active { .. } => write!(f, "active"), + State::Removed { .. } => write!(f, "removed"), + State::Stabilized { .. } => write!(f, "stabilized"), + } + } +} + +#[derive(Debug, Clone)] +pub struct Feature { + pub state: State, + pub name: Symbol, + pub since: &'static str, + issue: Option, // FIXME: once #58732 is done make this an Option + pub edition: Option, + description: &'static str, +} + +impl Feature { + fn issue(&self) -> Option { + self.issue.and_then(|i| NonZeroU32::new(i)) + } +} + +#[derive(Copy, Clone, Debug)] +pub enum Stability { + Unstable, + // First argument is tracking issue link; second argument is an optional + // help message, which defaults to "remove this attribute". + Deprecated(&'static str, Option<&'static str>), +} + +#[derive(Clone, Copy, Hash)] +pub enum UnstableFeatures { + /// Hard errors for unstable features are active, as on beta/stable channels. + Disallow, + /// Allow features to be activated, as on nightly. + Allow, + /// Errors are bypassed for bootstrapping. This is required any time + /// during the build that feature-related lints are set to warn or above + /// because the build turns on warnings-as-errors and uses lots of unstable + /// features. As a result, this is always required for building Rust itself. + Cheat +} + +impl UnstableFeatures { + pub fn from_environment() -> UnstableFeatures { + // `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(); + // `true` if we should enable unstable features for bootstrapping. + let bootstrap = std::env::var("RUSTC_BOOTSTRAP").is_ok(); + match (disable_unstable_features, bootstrap) { + (_, true) => UnstableFeatures::Cheat, + (true, _) => UnstableFeatures::Disallow, + (false, _) => UnstableFeatures::Allow + } + } + + pub fn is_nightly_build(&self) -> bool { + match *self { + UnstableFeatures::Allow | UnstableFeatures::Cheat => true, + UnstableFeatures::Disallow => false, + } + } +} + +fn find_lang_feature_issue(feature: Symbol) -> Option { + if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.name == feature) { + // FIXME (#28244): enforce that active features have issue numbers + // assert!(info.issue().is_some()) + info.issue() + } else { + // search in Accepted, Removed, or Stable Removed features + let found = ACCEPTED_FEATURES + .iter() + .chain(REMOVED_FEATURES) + .chain(STABLE_REMOVED_FEATURES) + .find(|t| t.name == feature); + match found { + Some(found) => found.issue(), + None => panic!("feature `{}` is not declared anywhere", feature), + } + } +} + +pub enum GateIssue { + Language, + Library(Option) +} + +pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option { + match issue { + GateIssue::Language => find_lang_feature_issue(feature), + GateIssue::Library(lib) => lib, + } +} + +pub use accepted::ACCEPTED_FEATURES; +pub use active::{ACTIVE_FEATURES, Features, INCOMPLETE_FEATURES}; +pub use removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES}; +pub use builtin_attrs::{ + AttributeGate, AttributeTemplate, AttributeType, find_gated_cfg, GatedCfg, + BuiltinAttribute, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP, + deprecated_attributes, is_builtin_attr_name, +}; diff --git a/src/libsyntax/feature_gate/removed.rs b/src/librustc_feature/removed.rs similarity index 99% rename from src/libsyntax/feature_gate/removed.rs rename to src/librustc_feature/removed.rs index f0aa74c65df62..340bd32fb8a46 100644 --- a/src/libsyntax/feature_gate/removed.rs +++ b/src/librustc_feature/removed.rs @@ -1,7 +1,7 @@ //! List of the removed feature gates. -use crate::symbol::sym; use super::{State, Feature}; +use syntax_pos::symbol::sym; macro_rules! declare_features { ($( diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml index d26d8791f6669..ed38243581b1a 100644 --- a/src/librustc_lint/Cargo.toml +++ b/src/librustc_lint/Cargo.toml @@ -15,5 +15,6 @@ rustc_target = { path = "../librustc_target" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_feature = { path = "../librustc_feature" } rustc_index = { path = "../librustc_index" } rustc_error_codes = { path = "../librustc_error_codes" } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 38624034022f0..5d3a6cccc4e73 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -34,15 +34,15 @@ use lint::{LateContext, LintContext, LintArray}; use lint::{LintPass, LateLintPass, EarlyLintPass, EarlyContext}; use rustc::util::nodemap::FxHashSet; +use rustc_feature::{AttributeGate, AttributeTemplate, AttributeType, deprecated_attributes}; +use rustc_feature::Stability; use syntax::tokenstream::{TokenTree, TokenStream}; use syntax::ast::{self, Expr}; use syntax::ptr::P; -use syntax::attr::{self, HasAttrs, AttributeTemplate}; +use syntax::attr::{self, HasAttrs}; use syntax::source_map::Spanned; use syntax::edition::Edition; -use syntax::feature_gate::{self, AttributeGate, AttributeType}; -use syntax::feature_gate::{Stability, deprecated_attributes}; use syntax_pos::{BytePos, Span}; use syntax::symbol::{Symbol, kw, sym}; use syntax::errors::{Applicability, DiagnosticBuilder}; @@ -1850,7 +1850,7 @@ impl EarlyLintPass for IncompleteFeatures { features.declared_lang_features .iter().map(|(name, span, _)| (name, span)) .chain(features.declared_lib_features.iter().map(|(name, span)| (name, span))) - .filter(|(name, _)| feature_gate::INCOMPLETE_FEATURES.iter().any(|f| name == &f)) + .filter(|(name, _)| rustc_feature::INCOMPLETE_FEATURES.iter().any(|f| name == &f)) .for_each(|(name, &span)| { cx.struct_span_lint( INCOMPLETE_FEATURES, diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 9f293bdaa105e..f7de7ec7e18f4 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -1,3 +1,4 @@ +use rustc::hir; use rustc::hir::def::{Res, DefKind}; use rustc::hir::def_id::DefId; use rustc::lint; @@ -7,19 +8,17 @@ use rustc::ty::adjustment; use rustc_data_structures::fx::FxHashMap; use lint::{LateContext, EarlyContext, LintContext, LintArray}; use lint::{LintPass, EarlyLintPass, LateLintPass}; +use rustc_feature::{AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use syntax::ast; use syntax::attr; use syntax::errors::{Applicability, pluralize}; -use syntax::feature_gate::{AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use syntax::print::pprust; use syntax::symbol::{kw, sym}; use syntax::symbol::Symbol; use syntax::util::parser; use syntax_pos::{Span, BytePos}; -use rustc::hir; - use log::debug; declare_lint! { diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs index e577b238c8684..425e5d1d821bf 100644 --- a/src/librustc_metadata/native_libs.rs +++ b/src/librustc_metadata/native_libs.rs @@ -7,7 +7,7 @@ use rustc::util::nodemap::FxHashSet; use rustc_target::spec::abi::Abi; use syntax::attr; use syntax::source_map::Span; -use syntax::feature_gate::{self, GateIssue}; +use syntax::feature_gate::feature_err; use syntax::symbol::{kw, sym, Symbol}; use syntax::{span_err, struct_span_err}; @@ -158,27 +158,29 @@ impl Collector<'tcx> { } } if lib.cfg.is_some() && !self.tcx.features().link_cfg { - feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, - sym::link_cfg, - span.unwrap(), - GateIssue::Language, - "is unstable"); + feature_err(&self.tcx.sess.parse_sess, sym::link_cfg, span.unwrap(), "is unstable") + .emit(); } if lib.kind == cstore::NativeStaticNobundle && - !self.tcx.features().static_nobundle { - feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, - sym::static_nobundle, - span.unwrap_or_else(|| syntax_pos::DUMMY_SP), - GateIssue::Language, - "kind=\"static-nobundle\" is unstable"); + !self.tcx.features().static_nobundle + { + feature_err( + &self.tcx.sess.parse_sess, + sym::static_nobundle, + span.unwrap_or_else(|| syntax_pos::DUMMY_SP), + "kind=\"static-nobundle\" is unstable" + ) + .emit(); } if lib.kind == cstore::NativeRawDylib && !self.tcx.features().raw_dylib { - feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, - sym::raw_dylib, - span.unwrap_or_else(|| syntax_pos::DUMMY_SP), - GateIssue::Language, - "kind=\"raw-dylib\" is unstable"); + feature_err( + &self.tcx.sess.parse_sess, + sym::raw_dylib, + span.unwrap_or_else(|| syntax_pos::DUMMY_SP), + "kind=\"raw-dylib\" is unstable" + ) + .emit(); } self.libs.push(lib); } diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs index acad56be60403..a4f12a4e54fa7 100644 --- a/src/librustc_mir/transform/check_consts/ops.rs +++ b/src/librustc_mir/transform/check_consts/ops.rs @@ -4,7 +4,7 @@ use rustc::hir::def_id::DefId; use rustc::mir::BorrowKind; use rustc::session::config::nightly_options; use rustc::ty::TyCtxt; -use syntax::feature_gate::{emit_feature_err, GateIssue}; +use syntax::feature_gate::feature_err; use syntax::symbol::sym; use syntax_pos::{Span, Symbol}; @@ -222,13 +222,13 @@ impl NonConstOp for Panic { } fn emit_error(&self, item: &Item<'_, '_>, span: Span) { - emit_feature_err( + feature_err( &item.tcx.sess.parse_sess, sym::const_panic, span, - GateIssue::Language, &format!("panicking in {}s is unstable", item.const_kind()), - ); + ) + .emit(); } } @@ -240,13 +240,13 @@ impl NonConstOp for RawPtrComparison { } fn emit_error(&self, item: &Item<'_, '_>, span: Span) { - emit_feature_err( + feature_err( &item.tcx.sess.parse_sess, sym::const_compare_raw_pointers, span, - GateIssue::Language, &format!("comparing raw pointers inside {}", item.const_kind()), - ); + ) + .emit(); } } @@ -258,14 +258,14 @@ impl NonConstOp for RawPtrDeref { } fn emit_error(&self, item: &Item<'_, '_>, span: Span) { - emit_feature_err( - &item.tcx.sess.parse_sess, sym::const_raw_ptr_deref, - span, GateIssue::Language, + feature_err( + &item.tcx.sess.parse_sess, sym::const_raw_ptr_deref, span, &format!( "dereferencing raw pointers in {}s is unstable", item.const_kind(), ), - ); + ) + .emit(); } } @@ -277,14 +277,14 @@ impl NonConstOp for RawPtrToIntCast { } fn emit_error(&self, item: &Item<'_, '_>, span: Span) { - emit_feature_err( - &item.tcx.sess.parse_sess, sym::const_raw_ptr_to_usize_cast, - span, GateIssue::Language, + feature_err( + &item.tcx.sess.parse_sess, sym::const_raw_ptr_to_usize_cast, span, &format!( "casting pointers to integers in {}s is unstable", item.const_kind(), ), - ); + ) + .emit(); } } @@ -334,11 +334,11 @@ impl NonConstOp for Transmute { } fn emit_error(&self, item: &Item<'_, '_>, span: Span) { - emit_feature_err( - &item.tcx.sess.parse_sess, sym::const_transmute, - span, GateIssue::Language, - &format!("The use of std::mem::transmute() \ - is gated in {}s", item.const_kind())); + feature_err( + &item.tcx.sess.parse_sess, sym::const_transmute, span, + &format!("The use of std::mem::transmute() is gated in {}s", item.const_kind()) + ) + .emit(); } } @@ -355,10 +355,10 @@ impl NonConstOp for UnionAccess { } fn emit_error(&self, item: &Item<'_, '_>, span: Span) { - emit_feature_err( - &item.tcx.sess.parse_sess, sym::const_fn_union, - span, GateIssue::Language, + feature_err( + &item.tcx.sess.parse_sess, sym::const_fn_union, span, "unions in const fn are unstable", - ); + ) + .emit(); } } diff --git a/src/librustc_parse/Cargo.toml b/src/librustc_parse/Cargo.toml index a9175487a75f9..95b3256f53a38 100644 --- a/src/librustc_parse/Cargo.toml +++ b/src/librustc_parse/Cargo.toml @@ -16,6 +16,7 @@ syntax_pos = { path = "../libsyntax_pos" } syntax = { path = "../libsyntax" } errors = { path = "../librustc_errors", package = "rustc_errors" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_feature = { path = "../librustc_feature" } rustc_lexer = { path = "../librustc_lexer" } rustc_target = { path = "../librustc_target" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_parse/config.rs b/src/librustc_parse/config.rs index 7ce555ed57a3d..26e51e83d625a 100644 --- a/src/librustc_parse/config.rs +++ b/src/librustc_parse/config.rs @@ -9,14 +9,9 @@ //! [#64197]: https://github.com/rust-lang/rust/issues/64197 use crate::validate_attr; +use rustc_feature::Features; use syntax::attr::HasAttrs; -use syntax::feature_gate::{ - feature_err, - EXPLAIN_STMT_ATTR_SYNTAX, - Features, - get_features, - GateIssue, -}; +use syntax::feature_gate::{feature_err, get_features}; use syntax::attr; use syntax::ast; use syntax::edition::Edition; @@ -52,7 +47,7 @@ pub fn features(mut krate: ast::Crate, sess: &ParseSess, edition: Edition, } else { // the entire crate is unconfigured krate.attrs = Vec::new(); krate.module.items = Vec::new(); - return (krate, Features::new()); + return (krate, Features::default()); } features = get_features(&sess.span_diagnostic, &krate.attrs, edition, allow_features); @@ -217,8 +212,7 @@ impl<'a> StripUnconfigured<'a> { let mut err = feature_err(self.sess, sym::stmt_expr_attributes, attr.span, - GateIssue::Language, - EXPLAIN_STMT_ATTR_SYNTAX); + "attributes on expressions are experimental"); if attr.is_doc_comment() { err.help("`///` is for documentation comments. For a plain comment, use `//`."); diff --git a/src/librustc_parse/validate_attr.rs b/src/librustc_parse/validate_attr.rs index bbe0dc1c35f1b..a3c9e2665930d 100644 --- a/src/librustc_parse/validate_attr.rs +++ b/src/librustc_parse/validate_attr.rs @@ -1,10 +1,10 @@ //! Meta-syntax validation logic of attributes for post-expansion. use errors::{PResult, Applicability}; -use syntax::ast::{self, Attribute, AttrKind, Ident, MetaItem}; -use syntax::attr::{AttributeTemplate, mk_name_value_item_str}; +use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP}; +use syntax::ast::{self, Attribute, AttrKind, Ident, MetaItem, MetaItemKind}; +use syntax::attr::mk_name_value_item_str; use syntax::early_buffered_lints::BufferedEarlyLintId; -use syntax::feature_gate::BUILTIN_ATTRIBUTE_MAP; use syntax::token; use syntax::tokenstream::TokenTree; use syntax::sess::ParseSess; @@ -41,6 +41,16 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta }) } +/// Checks that the given meta-item is compatible with this `AttributeTemplate`. +fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaItemKind) -> bool { + match meta { + MetaItemKind::Word => template.word, + MetaItemKind::List(..) => template.list.is_some(), + MetaItemKind::NameValue(lit) if lit.kind.is_str() => template.name_value_str.is_some(), + MetaItemKind::NameValue(..) => false, + } +} + pub fn check_builtin_attribute( sess: &ParseSess, attr: &Attribute, @@ -57,7 +67,7 @@ pub fn check_builtin_attribute( name == sym::test || name == sym::bench; match parse_meta(sess, attr) { - Ok(meta) => if !should_skip(name) && !template.compatible(&meta.kind) { + Ok(meta) => if !should_skip(name) && !is_attr_template_compatible(&template, &meta.kind) { let error_msg = format!("malformed `{}` attribute input", name); let mut msg = "attribute must be of the form ".to_owned(); let mut suggestions = vec![]; diff --git a/src/librustc_passes/Cargo.toml b/src/librustc_passes/Cargo.toml index 7a98734bdbe3d..bb2f7c6741824 100644 --- a/src/librustc_passes/Cargo.toml +++ b/src/librustc_passes/Cargo.toml @@ -12,6 +12,7 @@ path = "lib.rs" log = "0.4" rustc = { path = "../librustc" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_feature = { path = "../librustc_feature" } rustc_index = { path = "../librustc_index" } rustc_parse = { path = "../librustc_parse" } rustc_target = { path = "../librustc_target" } diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index e189b7175f91d..5a29a56ad5472 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -14,7 +14,6 @@ use rustc_parse::validate_attr; use syntax::ast::*; use syntax::attr; use syntax::expand::is_proc_macro_attr; -use syntax::feature_gate::is_builtin_attr; use syntax::print::pprust; use syntax::source_map::Spanned; use syntax::symbol::{kw, sym}; @@ -257,7 +256,7 @@ impl<'a> AstValidator<'a> { .flat_map(|i| i.attrs.as_ref()) .filter(|attr| { let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn]; - !arr.contains(&attr.name_or_empty()) && is_builtin_attr(attr) + !arr.contains(&attr.name_or_empty()) && attr::is_builtin_attr(attr) }) .for_each(|attr| if attr.is_doc_comment() { let mut err = self.err_handler().struct_span_err( diff --git a/src/librustc_passes/check_const.rs b/src/librustc_passes/check_const.rs index 24bc088e24a70..63c6e60de7954 100644 --- a/src/librustc_passes/check_const.rs +++ b/src/librustc_passes/check_const.rs @@ -13,8 +13,9 @@ use rustc::hir::map::Map; use rustc::hir; use rustc::ty::TyCtxt; use rustc::ty::query::Providers; +use rustc_feature::Features; use syntax::ast::Mutability; -use syntax::feature_gate::{emit_feature_err, Features, GateIssue}; +use syntax::feature_gate::feature_err; use syntax::span_err; use syntax_pos::{sym, Span}; use rustc_error_codes::*; @@ -140,13 +141,7 @@ impl<'tcx> CheckConstVisitor<'tcx> { | NonConstExpr::Match(hir::MatchSource::Normal) | NonConstExpr::Match(hir::MatchSource::IfDesugar { .. }) | NonConstExpr::Match(hir::MatchSource::IfLetDesugar { .. }) - => emit_feature_err( - &self.tcx.sess.parse_sess, - sym::const_if_match, - span, - GateIssue::Language, - &msg - ), + => feature_err(&self.tcx.sess.parse_sess, sym::const_if_match, span, &msg).emit(), _ => span_err!(self.tcx.sess, span, E0744, "{}", msg), } diff --git a/src/librustc_resolve/Cargo.toml b/src/librustc_resolve/Cargo.toml index 6cce893f8ecdd..caca20e4221e5 100644 --- a/src/librustc_resolve/Cargo.toml +++ b/src/librustc_resolve/Cargo.toml @@ -20,6 +20,7 @@ arena = { path = "../libarena" } errors = { path = "../librustc_errors", package = "rustc_errors" } syntax_pos = { path = "../libsyntax_pos" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_feature = { path = "../librustc_feature" } rustc_metadata = { path = "../librustc_metadata" } rustc_error_codes = { path = "../librustc_error_codes" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index eb7265cb9ccd1..04e233c597310 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -29,10 +29,8 @@ use errors::Applicability; use syntax::ast::{Name, Ident}; use syntax::attr; - use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, NodeId}; use syntax::ast::{MetaItemKind, StmtKind, TraitItem, TraitItemKind}; -use syntax::feature_gate::is_builtin_attr; use syntax::token::{self, Token}; use syntax::print::pprust; use syntax::{span_err, struct_span_err}; @@ -1231,7 +1229,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { } fn visit_attribute(&mut self, attr: &'b ast::Attribute) { - if !attr.is_doc_comment() && is_builtin_attr(attr) { + if !attr.is_doc_comment() && attr::is_builtin_attr(attr) { self.r.builtin_attrs.push( (attr.get_normal_item().path.segments[0].ident, self.parent_scope) ); diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index e134b8b92ac2e..4dcafb6d2798c 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -9,8 +9,8 @@ use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::session::Session; use rustc::ty::{self, DefIdTree}; use rustc::util::nodemap::FxHashSet; +use rustc_feature::BUILTIN_ATTRIBUTES; use syntax::ast::{self, Ident, Path}; -use syntax::feature_gate::BUILTIN_ATTRIBUTES; use syntax::source_map::SourceMap; use syntax::struct_span_err; use syntax::symbol::{Symbol, kw}; diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 21c24f9da1c16..9e7098da49f32 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -12,18 +12,18 @@ use rustc::middle::stability; use rustc::session::Session; use rustc::util::nodemap::FxHashSet; use rustc::{ty, lint, span_bug}; +use rustc_feature::is_builtin_attr_name; use syntax::ast::{self, NodeId, Ident}; use syntax::attr::{self, StabilityLevel}; use syntax::edition::Edition; -use syntax::feature_gate::{emit_feature_err, is_builtin_attr_name}; -use syntax::feature_gate::GateIssue; +use syntax::feature_gate::feature_err; use syntax::print::pprust; -use syntax::symbol::{Symbol, kw, sym}; use syntax_expand::base::{self, InvocationRes, Indeterminate}; use syntax_expand::base::SyntaxExtension; use syntax_expand::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind}; use syntax_expand::compile_declarative_macro; use syntax_pos::hygiene::{self, ExpnId, ExpnData, ExpnKind}; +use syntax_pos::symbol::{Symbol, kw, sym}; use syntax_pos::{Span, DUMMY_SP}; use std::{mem, ptr}; @@ -346,13 +346,8 @@ impl<'a> Resolver<'a> { segment.ident.as_str().starts_with("rustc") { let msg = "attributes starting with `rustc` are reserved for use by the `rustc` compiler"; - emit_feature_err( - &self.session.parse_sess, - sym::rustc_attrs, - segment.ident.span, - GateIssue::Language, - msg, - ); + feature_err(&self.session.parse_sess, sym::rustc_attrs, segment.ident.span, msg) + .emit(); } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index fdbf729a773aa..af978d5095eaa 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -23,7 +23,7 @@ use crate::require_c_abi_if_c_variadic; use smallvec::SmallVec; use syntax::ast; use syntax::errors::pluralize; -use syntax::feature_gate::{GateIssue, emit_feature_err}; +use syntax::feature_gate::feature_err; use syntax::util::lev_distance::find_best_match_for_name; use syntax::symbol::sym; use syntax_pos::{DUMMY_SP, Span, MultiSpan}; @@ -914,8 +914,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } else { "parenthetical notation is only stable when used with `Fn`-family traits" }; - emit_feature_err(&self.tcx().sess.parse_sess, sym::unboxed_closures, - span, GateIssue::Language, msg); + feature_err(&self.tcx().sess.parse_sess, sym::unboxed_closures, span, msg).emit(); } self.create_substs_for_ast_path(span, diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 871acb2726a21..901a2192e20dd 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -644,11 +644,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion { - feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, - sym::unsized_tuple_coercion, - self.cause.span, - feature_gate::GateIssue::Language, - feature_gate::EXPLAIN_UNSIZED_TUPLE_COERCION); + feature_gate::feature_err( + &self.tcx.sess.parse_sess, + sym::unsized_tuple_coercion, + self.cause.span, + "unsized tuple coercion is not stable enough for use and is subject to change", + ) + .emit(); } Ok(coercion) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 3a4a4a50bf273..c7a0190a1d1b4 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -125,7 +125,7 @@ use syntax_pos::{self, BytePos, Span, MultiSpan}; use syntax_pos::hygiene::DesugaringKind; use syntax::ast; use syntax::attr; -use syntax::feature_gate::{GateIssue, emit_feature_err}; +use syntax::feature_gate::feature_err; use syntax::source_map::{DUMMY_SP, original_sp}; use syntax::symbol::{kw, sym, Ident}; use syntax::util::parser::ExprPrecedence; @@ -2373,13 +2373,13 @@ fn check_transparent(tcx: TyCtxt<'_>, sp: Span, def_id: DefId) { if adt.is_enum() { if !tcx.features().transparent_enums { - emit_feature_err( + feature_err( &tcx.sess.parse_sess, sym::transparent_enums, sp, - GateIssue::Language, "transparent enums are unstable", - ); + ) + .emit(); } if adt.variants.len() != 1 { bad_variant_count(tcx, adt, sp, def_id); @@ -2391,11 +2391,13 @@ fn check_transparent(tcx: TyCtxt<'_>, sp: Span, def_id: DefId) { } if adt.is_union() && !tcx.features().transparent_unions { - emit_feature_err(&tcx.sess.parse_sess, - sym::transparent_unions, - sp, - GateIssue::Language, - "transparent unions are unstable"); + feature_err( + &tcx.sess.parse_sess, + sym::transparent_unions, + sp, + "transparent unions are unstable", + ) + .emit(); } // For each field, figure out if it's known to be a ZST and align(1) @@ -2452,11 +2454,13 @@ pub fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, vs: &'tcx [hir::Variant], i let repr_type_ty = def.repr.discr_type().to_ty(tcx); if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 { if !tcx.features().repr128 { - emit_feature_err(&tcx.sess.parse_sess, - sym::repr128, - sp, - GateIssue::Language, - "repr with 128-bit type is unstable"); + feature_err( + &tcx.sess.parse_sess, + sym::repr128, + sp, + "repr with 128-bit type is unstable", + ) + .emit(); } } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index b491b10331356..20b6b01de57b2 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -10,7 +10,7 @@ use rustc::middle::lang_items; use rustc::infer::opaque_types::may_define_opaque_type; use syntax::ast; -use syntax::feature_gate::{self, GateIssue}; +use syntax::feature_gate; use syntax_pos::Span; use syntax::symbol::sym; use errors::DiagnosticBuilder; @@ -830,13 +830,13 @@ fn check_method_receiver<'fcx, 'tcx>( &fcx.tcx.sess.parse_sess, sym::arbitrary_self_types, span, - GateIssue::Language, &format!( "`{}` cannot be used as the type of `self` without \ the `arbitrary_self_types` feature", receiver_ty, ), - ).help(HELP_FOR_SELF_TYPE) + ) + .help(HELP_FOR_SELF_TYPE) .emit(); } else { // Report error; would not have worked with `arbitrary_self_types`. diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 301b0ff350302..6d6e7685fa053 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1492,16 +1492,16 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { _ => None, }; if let Some(unsupported_type) = err { - feature_gate::emit_feature_err( + feature_gate::feature_err( &tcx.sess.parse_sess, sym::const_compare_raw_pointers, hir_ty.span, - feature_gate::GateIssue::Language, &format!( "using {} as const generic parameters is unstable", unsupported_type ), - ); + ) + .emit(); }; } if ty::search_for_structural_match_violation( @@ -2520,13 +2520,13 @@ fn from_target_feature( None => true, }; if !allowed && id.is_local() { - feature_gate::emit_feature_err( + feature_gate::feature_err( &tcx.sess.parse_sess, feature_gate.unwrap(), item.span(), - feature_gate::GateIssue::Language, &format!("the target feature `{}` is currently unstable", feature), - ); + ) + .emit(); } Some(Symbol::intern(feature)) })); diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 09f4873967ed5..078948cc63bd2 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -7,10 +7,10 @@ use std::mem; use std::fmt::{self, Write}; use std::ops; +use rustc_feature::Features; use syntax::symbol::{Symbol, sym}; use syntax::ast::{MetaItem, MetaItemKind, NestedMetaItem, LitKind}; use syntax::sess::ParseSess; -use syntax::feature_gate::Features; use syntax_pos::Span; diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 7d1f89079f808..b77b1c720cfdf 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -12,12 +12,12 @@ use rustc::session::DiagnosticOutput; use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc_interface::interface; use rustc_driver::abort_on_err; +use rustc_feature::UnstableFeatures; use rustc_resolve as resolve; use syntax::ast::CRATE_NODE_ID; use syntax::source_map; use syntax::attr; -use syntax::feature_gate::UnstableFeatures; use errors::json::JsonEmitter; use syntax::symbol::sym; use syntax_pos::DUMMY_SP; diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs index 56f1191feed0b..7945850ef08ac 100644 --- a/src/librustdoc/externalfiles.rs +++ b/src/librustdoc/externalfiles.rs @@ -2,7 +2,7 @@ use std::fs; use std::path::Path; use std::str; use errors; -use crate::syntax::feature_gate::UnstableFeatures; +use rustc_feature::UnstableFeatures; use crate::syntax::edition::Edition; use crate::html::markdown::{IdMap, ErrorCodes, Markdown, Playground}; diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index ba94cb82c00d2..b5c1a77a38742 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -45,7 +45,6 @@ use errors; use serialize::json::{ToJson, Json, as_json}; use syntax::ast; use syntax::edition::Edition; -use syntax::feature_gate::UnstableFeatures; use syntax::print::pprust; use syntax::source_map::FileName; use syntax::symbol::{Symbol, sym}; @@ -56,6 +55,7 @@ use rustc::middle::stability; use rustc::hir; use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::flock; +use rustc_feature::UnstableFeatures; use crate::clean::{self, AttributesExt, Deprecation, GetDefId, SelfTy, Mutability}; use crate::config::RenderOptions; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 69d9748bb8832..be3644ecf96a7 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -24,6 +24,7 @@ extern crate env_logger; extern crate rustc; extern crate rustc_data_structures; extern crate rustc_driver; +extern crate rustc_feature; extern crate rustc_error_codes; extern crate rustc_index; extern crate rustc_resolve; diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 8431271e62d56..7dc3df23a6d16 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -6,7 +6,7 @@ use errors; use testing; use syntax::edition::Edition; use syntax::source_map::DUMMY_SP; -use syntax::feature_gate::UnstableFeatures; +use rustc_feature::UnstableFeatures; use crate::externalfiles::{LoadStringError, load_string}; use crate::config::{Options, RenderOptions}; diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index d8f2dbca835d8..3c021ae746523 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -5,10 +5,10 @@ use rustc::hir; use rustc::lint as lint; use rustc::ty; use rustc_resolve::ParentScope; +use rustc_feature::UnstableFeatures; use syntax; use syntax::ast::{self, Ident}; use syntax_expand::base::SyntaxExtensionKind; -use syntax::feature_gate::UnstableFeatures; use syntax::symbol::Symbol; use syntax_pos::DUMMY_SP; diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index d09eb0b2fc263..5fd7ab03224a5 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -1,4 +1,5 @@ use rustc_data_structures::sync::Lrc; +use rustc_feature::UnstableFeatures; use rustc_interface::interface; use rustc_target::spec::TargetTriple; use rustc::hir; @@ -9,7 +10,6 @@ use syntax::ast; use syntax::with_globals; use syntax::source_map::SourceMap; use syntax::edition::Edition; -use syntax::feature_gate::UnstableFeatures; use std::env; use std::io::{self, Write}; use std::panic; diff --git a/src/libsyntax/Cargo.toml b/src/libsyntax/Cargo.toml index dff23076c82e6..085c1760c8027 100644 --- a/src/libsyntax/Cargo.toml +++ b/src/libsyntax/Cargo.toml @@ -18,6 +18,7 @@ lazy_static = "1.0.0" syntax_pos = { path = "../libsyntax_pos" } errors = { path = "../librustc_errors", package = "rustc_errors" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_feature = { path = "../librustc_feature" } rustc_index = { path = "../librustc_index" } rustc_lexer = { path = "../librustc_lexer" } rustc_macros = { path = "../librustc_macros" } diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index c10541c8c7e75..3c10f27b60ae9 100644 --- a/src/libsyntax/attr/builtin.rs +++ b/src/libsyntax/attr/builtin.rs @@ -1,7 +1,8 @@ //! Parsing and validation of builtin attributes +use super::{mark_used, MetaItemKind}; use crate::ast::{self, Attribute, MetaItem, NestedMetaItem}; -use crate::feature_gate::{Features, GatedCfg}; +use crate::feature_gate::feature_err; use crate::print::pprust; use crate::sess::ParseSess; @@ -9,12 +10,15 @@ use errors::{Applicability, Handler}; use std::num::NonZeroU32; use syntax_pos::hygiene::Transparency; use syntax_pos::{symbol::Symbol, symbol::sym, Span}; +use rustc_feature::{Features, find_gated_cfg, GatedCfg, is_builtin_attr_name}; use rustc_macros::HashStable_Generic; -use super::{mark_used, MetaItemKind}; - use rustc_error_codes::*; +pub fn is_builtin_attr(attr: &Attribute) -> bool { + attr.ident().filter(|ident| is_builtin_attr_name(ident.name)).is_some() +} + enum AttrError { MultipleItem(String), UnknownMetaItem(String, &'static [&'static str]), @@ -24,31 +28,6 @@ enum AttrError { UnsupportedLiteral(&'static str, /* is_bytestr */ bool), } -/// A template that the attribute input must match. -/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now. -#[derive(Clone, Copy)] -pub struct AttributeTemplate { - pub word: bool, - pub list: Option<&'static str>, - pub name_value_str: Option<&'static str>, -} - -impl AttributeTemplate { - pub fn only_word() -> Self { - Self { word: true, list: None, name_value_str: None } - } - - /// Checks that the given meta-item is compatible with this template. - pub fn compatible(&self, meta_item_kind: &ast::MetaItemKind) -> bool { - match meta_item_kind { - ast::MetaItemKind::Word => self.word, - ast::MetaItemKind::List(..) => self.list.is_some(), - ast::MetaItemKind::NameValue(lit) if lit.kind.is_str() => self.name_value_str.is_some(), - ast::MetaItemKind::NameValue(..) => false, - } - } -} - fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) { let diag = &sess.span_diagnostic; match error { @@ -555,8 +534,9 @@ pub fn find_crate_name(attrs: &[Attribute]) -> Option { /// Tests if a cfg-pattern matches the cfg set pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>) -> bool { eval_condition(cfg, sess, &mut |cfg| { - if let (Some(feats), Some(gated_cfg)) = (features, GatedCfg::gate(cfg)) { - gated_cfg.check_and_emit(sess, feats); + let gate = find_gated_cfg(|sym| cfg.check_name(sym)); + if let (Some(feats), Some(gated_cfg)) = (features, gate) { + gate_cfg(&gated_cfg, cfg.span, sess, feats); } let error = |span, msg| { sess.span_diagnostic.span_err(span, msg); true }; if cfg.path.segments.len() != 1 { @@ -585,12 +565,21 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat }) } +fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &ParseSess, features: &Features) { + let (cfg, feature, has_feature) = gated_cfg; + if !has_feature(features) && !cfg_span.allows_unstable(*feature) { + let explain = format!("`cfg({})` is experimental and subject to change", cfg); + feature_err(sess, *feature, cfg_span, &explain).emit() + } +} + /// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to /// evaluate individual items. -pub fn eval_condition(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F) - -> bool - where F: FnMut(&ast::MetaItem) -> bool -{ +pub fn eval_condition( + cfg: &ast::MetaItem, + sess: &ParseSess, + eval: &mut impl FnMut(&ast::MetaItem) -> bool, +) -> bool { match cfg.kind { ast::MetaItemKind::List(ref mis) => { for mi in mis.iter() { diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index ec0eaa568123a..3d2c3b1d4f901 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -1,7 +1,7 @@ -use super::{active::{ACTIVE_FEATURES, Features}, Feature, State as FeatureState}; -use super::accepted::ACCEPTED_FEATURES; -use super::removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES}; -use super::builtin_attrs::{AttributeGate, BUILTIN_ATTRIBUTE_MAP}; +use rustc_feature::{ACCEPTED_FEATURES, ACTIVE_FEATURES, REMOVED_FEATURES, STABLE_REMOVED_FEATURES}; +use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP}; +use rustc_feature::{Features, Feature, State as FeatureState, UnstableFeatures}; +use rustc_feature::{find_feature_issue, GateIssue}; use crate::ast::{self, AssocTyConstraint, AssocTyConstraintKind, NodeId}; use crate::ast::{GenericParam, GenericParamKind, PatKind, RangeEnd, VariantData}; @@ -19,18 +19,6 @@ use log::debug; use rustc_error_codes::*; - -use std::env; -use std::num::NonZeroU32; - -#[derive(Copy, Clone, Debug)] -pub enum Stability { - Unstable, - // First argument is tracking issue link; second argument is an optional - // help message, which defaults to "remove this attribute" - Deprecated(&'static str, Option<&'static str>), -} - macro_rules! gate_feature_fn { ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $level: expr) => {{ let (cx, has_feature, span, @@ -59,30 +47,6 @@ pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: PostExpansionVisitor { parse_sess, features }.visit_attribute(attr) } -fn find_lang_feature_issue(feature: Symbol) -> Option { - if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.name == feature) { - // FIXME (#28244): enforce that active features have issue numbers - // assert!(info.issue().is_some()) - info.issue() - } else { - // search in Accepted, Removed, or Stable Removed features - let found = ACCEPTED_FEATURES - .iter() - .chain(REMOVED_FEATURES) - .chain(STABLE_REMOVED_FEATURES) - .find(|t| t.name == feature); - match found { - Some(found) => found.issue(), - None => panic!("feature `{}` is not declared anywhere", feature), - } - } -} - -pub enum GateIssue { - Language, - Library(Option) -} - #[derive(Debug, Copy, Clone, PartialEq)] pub enum GateStrength { /// A hard error. (Most feature gates should use this.) @@ -91,41 +55,35 @@ pub enum GateStrength { Soft, } -pub fn emit_feature_err( - sess: &ParseSess, +pub fn feature_err<'a>( + sess: &'a ParseSess, feature: Symbol, - span: Span, - issue: GateIssue, + span: impl Into, explain: &str, -) { - feature_err(sess, feature, span, issue, explain).emit(); +) -> DiagnosticBuilder<'a> { + feature_err_issue(sess, feature, span, GateIssue::Language, explain) } -pub fn feature_err<'a, S: Into>( +pub fn feature_err_issue<'a>( sess: &'a ParseSess, feature: Symbol, - span: S, + span: impl Into, issue: GateIssue, explain: &str, ) -> DiagnosticBuilder<'a> { leveled_feature_err(sess, feature, span, issue, explain, GateStrength::Hard) } -fn leveled_feature_err<'a, S: Into>( +fn leveled_feature_err<'a>( sess: &'a ParseSess, feature: Symbol, - span: S, + span: impl Into, issue: GateIssue, explain: &str, level: GateStrength, ) -> DiagnosticBuilder<'a> { let diag = &sess.span_diagnostic; - let issue = match issue { - GateIssue::Language => find_lang_feature_issue(feature), - GateIssue::Library(lib) => lib, - }; - let mut err = match level { GateStrength::Hard => { diag.struct_span_err_with_code(span, explain, stringify_error_code!(E0658)) @@ -133,7 +91,7 @@ fn leveled_feature_err<'a, S: Into>( GateStrength::Soft => diag.struct_span_warn(span, explain), }; - if let Some(n) = issue { + if let Some(n) = find_feature_issue(feature, issue) { err.note(&format!( "for more information, see https://github.com/rust-lang/rust/issues/{}", n, @@ -156,20 +114,6 @@ fn leveled_feature_err<'a, S: Into>( } -const EXPLAIN_BOX_SYNTAX: &str = - "box expression syntax is experimental; you can call `Box::new` instead"; - -pub const EXPLAIN_STMT_ATTR_SYNTAX: &str = - "attributes on expressions are experimental"; - -pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &str = - "allow_internal_unstable side-steps feature gating and stability checks"; -pub const EXPLAIN_ALLOW_INTERNAL_UNSAFE: &str = - "allow_internal_unsafe side-steps the unsafe_code lint"; - -pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &str = - "unsized tuple coercion is not stable enough for use and is subject to change"; - struct PostExpansionVisitor<'a> { parse_sess: &'a ParseSess, features: &'a Features, @@ -282,7 +226,6 @@ impl<'a> PostExpansionVisitor<'a> { self.parse_sess, sym::arbitrary_enum_discriminant, discriminant_spans.clone(), - crate::feature_gate::GateIssue::Language, "custom discriminant values are not allowed in enums with tuple or struct variants", ); for sp in discriminant_spans { @@ -529,7 +472,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_expr(&mut self, e: &'a ast::Expr) { match e.kind { ast::ExprKind::Box(_) => { - gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX); + gate_feature_post!( + &self, box_syntax, e.span, + "box expression syntax is experimental; you can call `Box::new` instead" + ); } ast::ExprKind::Type(..) => { // To avoid noise about type ascription in common syntax errors, only emit if it @@ -695,7 +641,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], err.emit(); } - let mut features = Features::new(); + let mut features = Features::default(); let mut edition_enabled_features = FxHashMap::default(); for &edition in ALL_EDITIONS { @@ -900,40 +846,6 @@ pub fn check_crate(krate: &ast::Crate, visit::walk_crate(&mut visitor, krate); } -#[derive(Clone, Copy, Hash)] -pub enum UnstableFeatures { - /// Hard errors for unstable features are active, as on beta/stable channels. - Disallow, - /// Allow features to be activated, as on nightly. - Allow, - /// Errors are bypassed for bootstrapping. This is required any time - /// during the build that feature-related lints are set to warn or above - /// because the build turns on warnings-as-errors and uses lots of unstable - /// features. As a result, this is always required for building Rust itself. - Cheat -} - -impl UnstableFeatures { - pub fn from_environment() -> UnstableFeatures { - // `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(); - // `true` if we should enable unstable features for bootstrapping. - let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok(); - match (disable_unstable_features, bootstrap) { - (_, true) => UnstableFeatures::Cheat, - (true, _) => UnstableFeatures::Disallow, - (false, _) => UnstableFeatures::Allow - } - } - - pub fn is_nightly_build(&self) -> bool { - match *self { - UnstableFeatures::Allow | UnstableFeatures::Cheat => true, - UnstableFeatures::Disallow => false, - } - } -} - fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate, unstable: UnstableFeatures) { if !unstable.is_nightly_build() { for attr in krate.attrs.iter().filter(|attr| attr.check_name(sym::feature)) { diff --git a/src/libsyntax/feature_gate/mod.rs b/src/libsyntax/feature_gate/mod.rs deleted file mode 100644 index c4418c0f0f632..0000000000000 --- a/src/libsyntax/feature_gate/mod.rs +++ /dev/null @@ -1,71 +0,0 @@ -//! # Feature gating -//! -//! This module implements the gating necessary for preventing certain compiler -//! features from being used by default. This module will crawl a pre-expanded -//! AST to ensure that there are no features which are used that are not -//! enabled. -//! -//! Features are enabled in programs via the crate-level attributes of -//! `#![feature(...)]` with a comma-separated list of features. -//! -//! For the purpose of future feature-tracking, once code for detection of feature -//! gate usage is added, *do not remove it again* even once the feature -//! becomes stable. - -mod accepted; -mod removed; -mod active; -mod builtin_attrs; -mod check; - -use crate::{edition::Edition, symbol::Symbol}; -use std::fmt; -use std::num::NonZeroU32; -use syntax_pos::Span; - -#[derive(Clone, Copy)] -pub enum State { - Accepted, - Active { set: fn(&mut Features, Span) }, - Removed { reason: Option<&'static str> }, - Stabilized { reason: Option<&'static str> }, -} - -impl fmt::Debug for State { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - State::Accepted { .. } => write!(f, "accepted"), - State::Active { .. } => write!(f, "active"), - State::Removed { .. } => write!(f, "removed"), - State::Stabilized { .. } => write!(f, "stabilized"), - } - } -} - -#[derive(Debug, Clone)] -pub struct Feature { - state: State, - name: Symbol, - since: &'static str, - issue: Option, // FIXME: once #58732 is done make this an Option - edition: Option, - description: &'static str, -} - -impl Feature { - fn issue(&self) -> Option { - self.issue.and_then(|i| NonZeroU32::new(i)) - } -} - -pub use active::{Features, INCOMPLETE_FEATURES}; -pub use builtin_attrs::{ - AttributeGate, AttributeType, GatedCfg, - BuiltinAttribute, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP, - deprecated_attributes, is_builtin_attr, is_builtin_attr_name, -}; -pub use check::{ - check_crate, check_attribute, get_features, feature_err, emit_feature_err, - Stability, GateIssue, UnstableFeatures, - EXPLAIN_STMT_ATTR_SYNTAX, EXPLAIN_UNSIZED_TUPLE_COERCION, -}; diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 22b49862f4965..3d4a5d624c119 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -92,7 +92,10 @@ pub mod attr; pub mod expand; pub use syntax_pos::source_map; pub mod entry; -pub mod feature_gate; +pub mod feature_gate { + mod check; + pub use check::{check_crate, check_attribute, get_features, feature_err, feature_err_issue}; +} pub mod mut_visit; pub mod ptr; pub mod show_span; diff --git a/src/libsyntax/sess.rs b/src/libsyntax/sess.rs index 740e9dfe45935..aa9217c1b69a8 100644 --- a/src/libsyntax/sess.rs +++ b/src/libsyntax/sess.rs @@ -3,15 +3,15 @@ use crate::ast::{CrateConfig, NodeId}; use crate::early_buffered_lints::{BufferedEarlyLint, BufferedEarlyLintId}; -use crate::source_map::{SourceMap, FilePathMapping}; -use crate::feature_gate::UnstableFeatures; use errors::{Applicability, emitter::SilentEmitter, Handler, ColorConfig, DiagnosticBuilder}; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use rustc_data_structures::sync::{Lrc, Lock, Once}; +use rustc_feature::UnstableFeatures; use syntax_pos::{Symbol, Span, MultiSpan}; use syntax_pos::edition::Edition; use syntax_pos::hygiene::ExpnId; +use syntax_pos::source_map::{SourceMap, FilePathMapping}; use std::path::PathBuf; use std::str; diff --git a/src/libsyntax_expand/Cargo.toml b/src/libsyntax_expand/Cargo.toml index 653b87f0d8213..897d5a65ba3de 100644 --- a/src/libsyntax_expand/Cargo.toml +++ b/src/libsyntax_expand/Cargo.toml @@ -16,6 +16,7 @@ log = "0.4" syntax_pos = { path = "../libsyntax_pos" } errors = { path = "../librustc_errors", package = "rustc_errors" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_feature = { path = "../librustc_feature" } rustc_lexer = { path = "../librustc_lexer" } rustc_parse = { path = "../librustc_parse" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/libsyntax_expand/expand.rs b/src/libsyntax_expand/expand.rs index 4f05b0147bff4..a6ced1439c5d9 100644 --- a/src/libsyntax_expand/expand.rs +++ b/src/libsyntax_expand/expand.rs @@ -4,16 +4,17 @@ use crate::hygiene::{ExpnId, SyntaxContext, ExpnData, ExpnKind}; use crate::mbe::macro_rules::annotate_err_with_kind; use crate::placeholders::{placeholder, PlaceholderExpander}; use crate::config::StripUnconfigured; -use rustc_parse::configure; +use rustc_feature::Features; +use rustc_parse::configure; use rustc_parse::DirectoryOwnership; use rustc_parse::parser::Parser; use rustc_parse::validate_attr; use syntax::ast::{self, AttrItem, Block, Ident, LitKind, NodeId, PatKind, Path}; use syntax::ast::{MacStmtStyle, StmtKind, ItemKind}; -use syntax::attr::{self, HasAttrs}; +use syntax::attr::{self, HasAttrs, is_builtin_attr}; use syntax::source_map::respan; -use syntax::feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feature_err}; +use syntax::feature_gate::{self, feature_err}; use syntax::mut_visit::*; use syntax::print::pprust; use syntax::ptr::P; @@ -726,13 +727,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> { if self.cx.ecfg.proc_macro_hygiene() { return } - emit_feature_err( + feature_err( self.cx.parse_sess, sym::proc_macro_hygiene, span, - GateIssue::Language, &format!("custom attributes cannot be applied to {}", kind), - ); + ) + .emit(); } fn gate_proc_macro_input(&self, annotatable: &Annotatable) { @@ -744,13 +745,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fn visit_item(&mut self, item: &'ast ast::Item) { match &item.kind { ast::ItemKind::Mod(module) if !module.inline => { - emit_feature_err( + feature_err( self.parse_sess, sym::proc_macro_hygiene, item.span, - GateIssue::Language, "non-inline modules in proc macro input are unstable", - ); + ) + .emit(); } _ => {} } @@ -789,13 +790,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> { if self.cx.ecfg.proc_macro_hygiene() { return } - emit_feature_err( + feature_err( self.cx.parse_sess, sym::proc_macro_hygiene, span, - GateIssue::Language, &format!("procedural macros cannot be expanded to {}", kind), - ); + ) + .emit(); } fn parse_ast_fragment( @@ -991,9 +992,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { if let Some(attr) = &attr { if !self.cx.ecfg.custom_inner_attributes() && attr.style == ast::AttrStyle::Inner && !attr.has_name(sym::test) { - emit_feature_err(&self.cx.parse_sess, sym::custom_inner_attributes, - attr.span, GateIssue::Language, - "non-builtin inner attributes are unstable"); + feature_err( + &self.cx.parse_sess, sym::custom_inner_attributes, attr.span, + "non-builtin inner attributes are unstable" + ) + .emit(); } } attr diff --git a/src/libsyntax_expand/mbe/macro_rules.rs b/src/libsyntax_expand/mbe/macro_rules.rs index a1d8b5a53386a..b191527df1991 100644 --- a/src/libsyntax_expand/mbe/macro_rules.rs +++ b/src/libsyntax_expand/mbe/macro_rules.rs @@ -8,12 +8,12 @@ use crate::mbe::macro_parser::{Error, Failure, Success}; use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedParseResult}; use crate::mbe::transcribe::transcribe; +use rustc_feature::Features; use rustc_parse::parser::Parser; use rustc_parse::Directory; use syntax::ast; use syntax::attr::{self, TransparencyError}; use syntax::edition::Edition; -use syntax::feature_gate::Features; use syntax::print::pprust; use syntax::sess::ParseSess; use syntax::symbol::{kw, sym, Symbol}; diff --git a/src/libsyntax_ext/Cargo.toml b/src/libsyntax_ext/Cargo.toml index 2ebdac8ef7c58..d73a9ea6cdbc1 100644 --- a/src/libsyntax_ext/Cargo.toml +++ b/src/libsyntax_ext/Cargo.toml @@ -14,6 +14,7 @@ errors = { path = "../librustc_errors", package = "rustc_errors" } fmt_macros = { path = "../libfmt_macros" } log = "0.4" rustc_data_structures = { path = "../librustc_data_structures" } +rustc_feature = { path = "../librustc_feature" } rustc_parse = { path = "../librustc_parse" } rustc_target = { path = "../librustc_target" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/libsyntax_ext/test_harness.rs b/src/libsyntax_ext/test_harness.rs index 659780d7a434b..4c1eec38c6e5d 100644 --- a/src/libsyntax_ext/test_harness.rs +++ b/src/libsyntax_ext/test_harness.rs @@ -2,13 +2,13 @@ use log::debug; use smallvec::{smallvec, SmallVec}; +use rustc_feature::Features; use rustc_target::spec::PanicStrategy; use syntax::ast::{self, Ident}; use syntax::attr; use syntax::entry::{self, EntryPointType}; use syntax_expand::base::{ExtCtxt, Resolver}; use syntax_expand::expand::{AstFragment, ExpansionConfig}; -use syntax::feature_gate::Features; use syntax::mut_visit::{*, ExpectOne}; use syntax::ptr::P; use syntax::sess::ParseSess; diff --git a/src/libsyntax_ext/util.rs b/src/libsyntax_ext/util.rs index e59daab177083..f7bd9a0560461 100644 --- a/src/libsyntax_ext/util.rs +++ b/src/libsyntax_ext/util.rs @@ -1,7 +1,7 @@ use rustc_parse::validate_attr; +use rustc_feature::AttributeTemplate; use syntax_pos::Symbol; use syntax::ast::MetaItem; -use syntax::attr::AttributeTemplate; use syntax_expand::base::ExtCtxt; pub fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, name: Symbol) { diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index defe85ef46a23..4ea101296b738 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -231,7 +231,7 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { } fn collect_lang_features_in(base: &Path, file: &str, bad: &mut bool) -> Features { - let path = base.join("libsyntax/feature_gate").join(file); + let path = base.join("librustc_feature").join(file); let contents = t!(fs::read_to_string(&path)); // We allow rustc-internal features to omit a tracking issue.