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:
parent
c9619a4202
commit
c9d9616e82
5 changed files with 98 additions and 23 deletions
|
@ -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,)*),
|
||||
}
|
||||
),+
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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};
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
@ -829,14 +828,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;
|
||||
|
@ -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) {
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -1,14 +1,24 @@
|
|||
//! 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,)*),
|
||||
}
|
||||
),+
|
||||
];
|
||||
};
|
||||
|
||||
|
@ -16,8 +26,17 @@ macro_rules! declare_features {
|
|||
$(#[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,)*),
|
||||
}
|
||||
),+
|
||||
];
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue