From 41b689948736cc79f35b6002c040513291dcd7c2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 5 Oct 2023 18:59:01 +1100 Subject: [PATCH] Remove `rustc_feature::State`. `State` is used to distinguish active vs accepted vs removed features. However, these can also be distinguished by their location, in `ACTIVE_FEATURES`, `ACCEPTED_FEATURES`, and `REMOVED_FEATURES`. So this commit removes `State` and moves the internals of its variants next to the `Feature` in each element of `*_FEATURES`, introducing new types `ActiveFeature` and `RemovedFeature`. (There is no need for `AcceptedFeature` because `State::Accepted` had no fields.) This is a tighter type representation, avoids the need for some runtime checks, and makes the code a bit shorter. --- compiler/rustc_expand/src/config.rs | 48 ++++++++++---------------- compiler/rustc_feature/src/accepted.rs | 17 ++++----- compiler/rustc_feature/src/active.rs | 36 ++++++++----------- compiler/rustc_feature/src/lib.rs | 38 +++++--------------- compiler/rustc_feature/src/removed.rs | 19 ++++++---- 5 files changed, 61 insertions(+), 97 deletions(-) diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 4b213ff1922..9909a9ade8b 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -14,12 +14,12 @@ use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem use rustc_attr as attr; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_data_structures::fx::FxHashSet; -use rustc_feature::{Feature, Features, State as FeatureState}; +use rustc_feature::Features; use rustc_feature::{ACCEPTED_FEATURES, ACTIVE_FEATURES, REMOVED_FEATURES}; use rustc_parse::validate_attr; use rustc_session::parse::feature_err; use rustc_session::Session; -use rustc_span::edition::{Edition, ALL_EDITIONS}; +use rustc_span::edition::ALL_EDITIONS; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; use thin_vec::ThinVec; @@ -36,16 +36,6 @@ pub struct StripUnconfigured<'a> { } pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features { - fn active_features_up_to(edition: Edition) -> impl Iterator { - ACTIVE_FEATURES.iter().filter(move |feature| { - if let Some(feature_edition) = feature.edition { - feature_edition <= edition - } else { - false - } - }) - } - fn feature_list(attr: &Attribute) -> ThinVec { if attr.has_name(sym::feature) && let Some(list) = attr.meta_item_list() @@ -83,11 +73,13 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features { // Enable edition-dependent features based on `features_edition`. // - E.g. enable `test_2018_feature` if `features_edition` is 2018 or higher let mut edition_enabled_features = FxHashSet::default(); - for feature in active_features_up_to(features_edition) { - // FIXME(Manishearth) there is currently no way to set lib features by - // edition. - edition_enabled_features.insert(feature.name); - feature.set(&mut features); + for f in ACTIVE_FEATURES { + if let Some(edition) = f.feature.edition && edition <= features_edition { + // FIXME(Manishearth) there is currently no way to set lib features by + // edition. + edition_enabled_features.insert(f.feature.name); + (f.set_enabled)(&mut features); + } } // Process all features declared in the code. @@ -147,19 +139,17 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features { } // If the declared feature has been removed, issue an error. - if let Some(Feature { state, .. }) = REMOVED_FEATURES.iter().find(|f| name == f.name) { - if let FeatureState::Removed { reason } = state { - sess.emit_err(FeatureRemoved { - span: mi.span(), - reason: reason.map(|reason| FeatureRemovedReason { reason }), - }); - continue; - } + if let Some(f) = REMOVED_FEATURES.iter().find(|f| name == f.feature.name) { + sess.emit_err(FeatureRemoved { + span: mi.span(), + reason: f.reason.map(|reason| FeatureRemovedReason { reason }), + }); + continue; } // If the declared feature is stable, record it. - if let Some(Feature { since, .. }) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) { - let since = Some(Symbol::intern(since)); + if let Some(f) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) { + let since = Some(Symbol::intern(f.since)); features.set_declared_lang_feature(name, mi.span(), since); continue; } @@ -175,8 +165,8 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features { } // If the declared feature is unstable, record it. - if let Some(f) = ACTIVE_FEATURES.iter().find(|f| name == f.name) { - f.set(&mut features); + if let Some(f) = ACTIVE_FEATURES.iter().find(|f| name == f.feature.name) { + (f.set_enabled)(&mut features); features.set_declared_lang_feature(name, mi.span(), None); continue; } diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index b198876b05c..46ff43fa9aa 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -1,6 +1,6 @@ //! List of the accepted feature gates. -use super::{to_nonzero, Feature, State}; +use super::{to_nonzero, Feature}; use rustc_span::symbol::sym; macro_rules! declare_features { @@ -9,15 +9,12 @@ macro_rules! declare_features { )+) => { /// Those language feature has since been Accepted (it was once Active) pub const ACCEPTED_FEATURES: &[Feature] = &[ - $( - Feature { - state: State::Accepted, - name: sym::$feature, - since: $ver, - issue: to_nonzero($issue), - edition: None, - } - ),+ + $(Feature { + name: sym::$feature, + since: $ver, + issue: to_nonzero($issue), + edition: None, + }),+ ]; } } diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index ef672487b98..95ddd19fcb2 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -1,12 +1,17 @@ //! List of the active feature gates. -use super::{to_nonzero, Feature, State}; +use super::{to_nonzero, Feature}; use rustc_data_structures::fx::FxHashSet; use rustc_span::edition::Edition; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; +pub struct ActiveFeature { + pub feature: Feature, + pub set_enabled: fn(&mut Features), +} + #[derive(PartialEq)] enum FeatureStatus { Default, @@ -32,21 +37,18 @@ macro_rules! declare_features { )+) => { /// Represents active features that are currently being implemented or /// currently being considered for addition/removal. - pub const ACTIVE_FEATURES: - &[Feature] = - &[$( - // (sym::$feature, $ver, $issue, $edition, set!($feature)) - Feature { - state: State::Active { - // Sets this feature's corresponding bool within `features`. - set: |features| features.$feature = true, - }, + pub const ACTIVE_FEATURES: &[ActiveFeature] = &[ + $(ActiveFeature { + feature: Feature { name: sym::$feature, since: $ver, issue: to_nonzero($issue), edition: $edition, - } - ),+]; + }, + // Sets this feature's corresponding bool within `features`. + set_enabled: |features| features.$feature = true, + }),+ + ]; /// A set of features to be used by later passes. #[derive(Clone, Default, Debug)] @@ -134,16 +136,6 @@ macro_rules! declare_features { }; } -impl Feature { - /// Sets this feature in `Features`. Panics if called on a non-active feature. - pub fn set(&self, features: &mut Features) { - match self.state { - State::Active { set } => set(features), - _ => panic!("called `set` on feature `{}` which is not `active`", self.name), - } - } -} - // See https://rustc-dev-guide.rust-lang.org/feature-gates.html#feature-gates for more // documentation about handling feature gates. // diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index 4721bff0ec7..42bf15262d7 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -24,29 +24,10 @@ mod removed; mod tests; use rustc_span::{edition::Edition, symbol::Symbol}; -use std::fmt; use std::num::NonZeroU32; -#[derive(Clone, Copy)] -pub enum State { - Accepted, - Active { set: fn(&mut Features) }, - Removed { 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"), - } - } -} - #[derive(Debug, Clone)] pub struct Feature { - pub state: State, pub name: Symbol, pub since: &'static str, issue: Option, @@ -106,17 +87,16 @@ impl UnstableFeatures { fn find_lang_feature_issue(feature: Symbol) -> Option { // Search in all the feature lists. - let found = [] - .iter() - .chain(ACTIVE_FEATURES) - .chain(ACCEPTED_FEATURES) - .chain(REMOVED_FEATURES) - .find(|t| t.name == feature); - - match found { - Some(found) => found.issue, - None => panic!("feature `{feature}` is not declared anywhere"), + if let Some(f) = ACTIVE_FEATURES.iter().find(|f| f.feature.name == feature) { + return f.feature.issue; } + if let Some(f) = ACCEPTED_FEATURES.iter().find(|f| f.name == feature) { + return f.issue; + } + if let Some(f) = REMOVED_FEATURES.iter().find(|f| f.feature.name == feature) { + return f.feature.issue; + } + panic!("feature `{feature}` is not declared anywhere"); } const fn to_nonzero(n: Option) -> Option { diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 1697e929eda..91c556dc465 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -1,23 +1,28 @@ //! List of the removed feature gates. -use super::{to_nonzero, Feature, State}; +use super::{to_nonzero, Feature}; use rustc_span::symbol::sym; +pub struct RemovedFeature { + pub feature: Feature, + pub reason: Option<&'static str>, +} + macro_rules! declare_features { ($( $(#[doc = $doc:tt])* (removed, $feature:ident, $ver:expr, $issue:expr, None, $reason:expr), )+) => { /// Represents unstable features which have since been removed (it was once Active) - pub const REMOVED_FEATURES: &[Feature] = &[ - $( - Feature { - state: State::Removed { reason: $reason }, + pub const REMOVED_FEATURES: &[RemovedFeature] = &[ + $(RemovedFeature { + feature: Feature { name: sym::$feature, since: $ver, issue: to_nonzero($issue), edition: None, - } - ),+ + }, + reason: $reason + }),+ ]; }; }