1
Fork 0

Introduce and use Feature type for feature gates

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.
This commit is contained in:
Pascal Hertleif 2019-08-24 17:50:21 +02:00
parent c9619a4202
commit c9d9616e82
5 changed files with 98 additions and 23 deletions

View file

@ -1,14 +1,24 @@
//! List of the accepted feature gates. //! List of the accepted feature gates.
use crate::symbol::{Symbol, sym}; use crate::symbol::sym;
use super::{State, Feature};
macro_rules! declare_features { macro_rules! declare_features {
($( ($(
$(#[doc = $doc:tt])* (accepted, $feature:ident, $ver:expr, $issue:expr, None), $(#[doc = $doc:tt])* (accepted, $feature:ident, $ver:expr, $issue:expr, None),
)+) => { )+) => {
/// Those language feature has since been Accepted (it was once Active) /// Those language feature has since been Accepted (it was once Active)
pub const ACCEPTED_FEATURES: &[(Symbol, &str, Option<u32>, Option<&str>)] = &[ pub const ACCEPTED_FEATURES: &[Feature] = &[
$((sym::$feature, $ver, $issue, None)),+ $(
Feature {
state: State::Accepted,
name: sym::$feature,
since: $ver,
issue: $issue,
edition: None,
description: concat!($($doc,)*),
}
),+
]; ];
} }
} }

View file

@ -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. // 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`. // Don't ever remove anything from this list; move them to `removed.rs`.

View file

@ -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::accepted::ACCEPTED_FEATURES;
use super::removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES}; use super::removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES};
use super::builtin_attrs::{AttributeGate, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use super::builtin_attrs::{AttributeGate, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
@ -127,17 +127,16 @@ pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features:
} }
fn find_lang_feature_issue(feature: Symbol) -> Option<u32> { fn find_lang_feature_issue(feature: Symbol) -> Option<u32> {
if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) { if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.name == feature) {
let issue = info.2;
// FIXME (#28244): enforce that active features have issue numbers // FIXME (#28244): enforce that active features have issue numbers
// assert!(issue.is_some()) // assert!(info.issue.is_some())
issue info.issue
} else { } else {
// search in Accepted, Removed, or Stable Removed features // search in Accepted, Removed, or Stable Removed features
let found = ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES).chain(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 { match found {
Some(&(_, _, issue, _)) => issue, Some(&Feature { issue, .. }) => issue,
None => panic!("Feature `{}` is not declared anywhere", feature), None => panic!("Feature `{}` is not declared anywhere", feature),
} }
} }
@ -829,14 +828,18 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
continue; continue;
} }
let removed = REMOVED_FEATURES.iter().find(|f| name == f.0); let removed = REMOVED_FEATURES.iter().find(|f| name == f.name);
let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.0); let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.name);
if let Some((.., reason)) = removed.or(stable_removed) { if let Some(Feature { state, .. }) = removed.or(stable_removed) {
feature_removed(span_handler, mi.span(), *reason); if let FeatureState::Removed { reason }
continue; | 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)); let since = Some(Symbol::intern(since));
features.declared_lang_features.push((name, mi.span(), since)); features.declared_lang_features.push((name, mi.span(), since));
continue; continue;
@ -851,8 +854,8 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
} }
} }
if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) { if let Some(f) = ACTIVE_FEATURES.iter().find(|f| name == f.name) {
set(&mut features, mi.span()); f.set(&mut features, mi.span());
features.declared_lang_features.push((name, mi.span(), None)); features.declared_lang_features.push((name, mi.span(), None));
continue; continue;
} }

View file

@ -18,6 +18,39 @@ mod active;
mod builtin_attrs; mod builtin_attrs;
mod check; 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 active::{Features, INCOMPLETE_FEATURES};
pub use builtin_attrs::{ pub use builtin_attrs::{
AttributeGate, AttributeType, GatedCfg, AttributeGate, AttributeType, GatedCfg,

View file

@ -1,14 +1,24 @@
//! List of the removed feature gates. //! List of the removed feature gates.
use crate::symbol::{Symbol, sym}; use crate::symbol::sym;
use super::{State, Feature};
macro_rules! declare_features { macro_rules! declare_features {
($( ($(
$(#[doc = $doc:tt])* (removed, $feature:ident, $ver:expr, $issue:expr, None, $reason:expr), $(#[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) /// Represents unstable features which have since been removed (it was once Active)
pub const REMOVED_FEATURES: &[(Symbol, &str, Option<u32>, Option<&str>)] = &[ pub const REMOVED_FEATURES: &[Feature] = &[
$((sym::$feature, $ver, $issue, $reason)),+ $(
Feature {
state: State::Removed { reason: $reason },
name: sym::$feature,
since: $ver,
issue: $issue,
edition: None,
description: concat!($($doc,)*),
}
),+
]; ];
}; };
@ -16,8 +26,17 @@ macro_rules! declare_features {
$(#[doc = $doc:tt])* (stable_removed, $feature:ident, $ver:expr, $issue:expr, None), $(#[doc = $doc:tt])* (stable_removed, $feature:ident, $ver:expr, $issue:expr, None),
)+) => { )+) => {
/// Represents stable features which have since been removed (it was once Accepted) /// Represents stable features which have since been removed (it was once Accepted)
pub const STABLE_REMOVED_FEATURES: &[(Symbol, &str, Option<u32>, Option<&str>)] = &[ pub const STABLE_REMOVED_FEATURES: &[Feature] = &[
$((sym::$feature, $ver, $issue, None)),+ $(
Feature {
state: State::Stabilized { reason: None },
name: sym::$feature,
since: $ver,
issue: $issue,
edition: None,
description: concat!($($doc,)*),
}
),+
]; ];
}; };
} }