Skip to content

Commit

Permalink
Introduce and use Feature type for feature gates
Browse files Browse the repository at this point in the history
This replaces the ad-hoc tuples used in the different feature gate files
and unifies their content into a common type, leading to more readable
matches and other good stuff that comes from having named fields. It
also contains the description of each feature as extracted from the doc
comment.
  • Loading branch information
Pascal Hertleif committed Aug 24, 2019
1 parent c9619a4 commit 6ffc834
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 43 deletions.
16 changes: 13 additions & 3 deletions src/libsyntax/feature_gate/accepted.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
//! List of the accepted feature gates.
use crate::symbol::{Symbol, sym};
use crate::symbol::sym;
use super::{State, Feature};

macro_rules! declare_features {
($(
$(#[doc = $doc:tt])* (accepted, $feature:ident, $ver:expr, $issue:expr, None),
)+) => {
/// Those language feature has since been Accepted (it was once Active)
pub const ACCEPTED_FEATURES: &[(Symbol, &str, Option<u32>, Option<&str>)] = &[
$((sym::$feature, $ver, $issue, None)),+
pub const ACCEPTED_FEATURES: &[Feature] = &[
$(
Feature {
state: State::Accepted,
name: sym::$feature,
since: $ver,
issue: $issue,
edition: None,
description: concat!($($doc,)*),
}
),+
];
}
}
Expand Down
10 changes: 10 additions & 0 deletions src/libsyntax/feature_gate/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,16 @@ macro_rules! declare_features {
};
}

impl Feature {
/// Set this feature in `Features`. Panics if called on a non-active feature.
pub fn set(&self, features: &mut Features, span: Span) {
match self.state {
State::Active { set } => set(features, span),
_ => panic!("Called `set` on feature `{}` which is not `active`", self.name)
}
}
}

// If you change this, please modify `src/doc/unstable-book` as well.
//
// Don't ever remove anything from this list; move them to `removed.rs`.
Expand Down
79 changes: 44 additions & 35 deletions src/libsyntax/feature_gate/check.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::active::{ACTIVE_FEATURES, Features};
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, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
Expand Down Expand Up @@ -127,17 +127,16 @@ pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features:
}

fn find_lang_feature_issue(feature: Symbol) -> Option<u32> {
if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) {
let issue = info.2;
if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.name == feature) {
// FIXME (#28244): enforce that active features have issue numbers
// assert!(issue.is_some())
issue
// 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.0 == feature);
.find(|t| t.name == feature);
match found {
Some(&(_, _, issue, _)) => issue,
Some(&Feature { issue, .. }) => issue,
None => panic!("Feature `{}` is not declared anywhere", feature),
}
}
Expand Down Expand Up @@ -733,14 +732,11 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
}
}

for &(name, .., f_edition, set) in ACTIVE_FEATURES {
if let Some(f_edition) = f_edition {
if f_edition <= crate_edition {
set(&mut features, DUMMY_SP);
edition_enabled_features.insert(name, crate_edition);
}
}
}
active_features_up_to(crate_edition)
.for_each(|f| {
f.set(&mut features, DUMMY_SP);
edition_enabled_features.insert(f.name, crate_edition);
});

// Process the edition umbrella feature-gates first, to ensure
// `edition_enabled_features` is completed before it's queried.
Expand All @@ -761,21 +757,19 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],

let name = mi.name_or_empty();

if let Some(edition) = ALL_EDITIONS.iter().find(|e| name == e.feature_name()) {
if *edition <= crate_edition {
if let Some(edition) = ALL_EDITIONS.iter().find(|e| name == e.feature_name()).copied() {
if edition <= crate_edition {
continue;
}

for &(name, .., f_edition, set) in ACTIVE_FEATURES {
if let Some(f_edition) = f_edition {
if f_edition <= *edition {
// FIXME(Manishearth) there is currently no way to set
// lib features by edition
set(&mut features, DUMMY_SP);
edition_enabled_features.insert(name, *edition);
}
}
}
active_features_up_to(edition)
.for_each(|f| {
// FIXME(Manishearth) there is currently no way to set
// lib features by edition

f.set(&mut features, DUMMY_SP);
edition_enabled_features.insert(name, edition);
});
}
}
}
Expand Down Expand Up @@ -829,14 +823,18 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
continue;
}

let removed = REMOVED_FEATURES.iter().find(|f| name == f.0);
let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.0);
if let Some((.., reason)) = removed.or(stable_removed) {
feature_removed(span_handler, mi.span(), *reason);
continue;
let removed = REMOVED_FEATURES.iter().find(|f| name == f.name);
let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.name);
if let Some(Feature { state, .. }) = removed.or(stable_removed) {
if let FeatureState::Removed { reason }
| FeatureState::Stabilized { reason } = state
{
feature_removed(span_handler, mi.span(), *reason);
continue;
}
}

if let Some((_, since, ..)) = ACCEPTED_FEATURES.iter().find(|f| name == f.0) {
if let Some(Feature { since, .. }) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) {
let since = Some(Symbol::intern(since));
features.declared_lang_features.push((name, mi.span(), since));
continue;
Expand All @@ -851,8 +849,8 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
}
}

if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) {
set(&mut features, mi.span());
if let Some(f) = ACTIVE_FEATURES.iter().find(|f| name == f.name) {
f.set(&mut features, mi.span());
features.declared_lang_features.push((name, mi.span(), None));
continue;
}
Expand All @@ -864,6 +862,17 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
features
}

fn active_features_up_to(edition: Edition) -> impl Iterator<Item=&'static Feature> {
ACTIVE_FEATURES.iter()
.filter(move |feature| {
if let Some(feature_edition) = feature.edition {
feature_edition <= edition
} else {
false
}
})
}

pub fn check_crate(krate: &ast::Crate,
sess: &ParseSess,
features: &Features,
Expand Down
33 changes: 33 additions & 0 deletions src/libsyntax/feature_gate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,39 @@ mod active;
mod builtin_attrs;
mod check;

use std::fmt;
use crate::{edition::Edition, symbol::Symbol};
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<u32>,
edition: Option<Edition>,
description: &'static str,
}

pub use active::{Features, INCOMPLETE_FEATURES};
pub use builtin_attrs::{
AttributeGate, AttributeType, GatedCfg,
Expand Down
29 changes: 24 additions & 5 deletions src/libsyntax/feature_gate/removed.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,42 @@
//! List of the removed feature gates.
use crate::symbol::{Symbol, sym};
use crate::symbol::sym;
use super::{State, Feature};

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: &[(Symbol, &str, Option<u32>, Option<&str>)] = &[
$((sym::$feature, $ver, $issue, $reason)),+
pub const REMOVED_FEATURES: &[Feature] = &[
$(
Feature {
state: State::Removed { reason: $reason },
name: sym::$feature,
since: $ver,
issue: $issue,
edition: None,
description: concat!($($doc,)*),
}
),+
];
};

($(
$(#[doc = $doc:tt])* (stable_removed, $feature:ident, $ver:expr, $issue:expr, None),
)+) => {
/// Represents stable features which have since been removed (it was once Accepted)
pub const STABLE_REMOVED_FEATURES: &[(Symbol, &str, Option<u32>, Option<&str>)] = &[
$((sym::$feature, $ver, $issue, None)),+
pub const STABLE_REMOVED_FEATURES: &[Feature] = &[
$(
Feature {
state: State::Stabilized { reason: None },
name: sym::$feature,
since: $ver,
issue: $issue,
edition: None,
description: concat!($($doc,)*),
}
),+
];
};
}
Expand Down

0 comments on commit 6ffc834

Please sign in to comment.