Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature gating *declarations* => new crate rustc_feature #66895

Merged
merged 14 commits into from
Dec 1, 2019
Merged
21 changes: 8 additions & 13 deletions src/librustc_driver/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ 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::feature_gate::{find_gated_cfg, UnstableFeatures};
use syntax_pos::symbol::sym;
use syntax_pos::FileName;

pub mod pretty;
mod args;
Expand Down Expand Up @@ -677,12 +677,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
Expand All @@ -693,10 +687,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 {
Expand Down
24 changes: 17 additions & 7 deletions src/libsyntax/attr/builtin.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! Parsing and validation of builtin attributes

use crate::ast::{self, Attribute, MetaItem, NestedMetaItem};
use crate::feature_gate::{find_gated_cfg, emit_feature_err, GatedCfg, GateIssue};
use crate::print::pprust;
use crate::feature_gate::GatedCfg;
use crate::sess::ParseSess;

use errors::{Applicability, Handler};
Expand Down Expand Up @@ -531,8 +531,9 @@ pub fn find_crate_name(attrs: &[Attribute]) -> Option<Symbol> {
/// 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 {
Expand Down Expand Up @@ -561,12 +562,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);
emit_feature_err(sess, *feature, cfg_span, GateIssue::Language, &explain);
}
}

/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
/// evaluate individual items.
pub fn eval_condition<F>(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() {
Expand Down
36 changes: 6 additions & 30 deletions src/libsyntax/feature_gate/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,15 @@
use AttributeType::*;
use AttributeGate::*;

use super::check::{emit_feature_err, GateIssue};
use super::check::{EXPLAIN_ALLOW_INTERNAL_UNSAFE, EXPLAIN_ALLOW_INTERNAL_UNSTABLE};
use rustc_feature::{Features, Stability};

use crate::ast;
use crate::sess::ParseSess;

use syntax_pos::symbol::{Symbol, sym};
use syntax_pos::Span;
use rustc_data_structures::fx::FxHashMap;
use lazy_static::lazy_static;


type GateFn = fn(&Features) -> bool;

macro_rules! cfg_fn {
Expand All @@ -24,39 +20,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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why move away from a struct with field names to a tuple?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you look above, the constant contains the tuples already -- I'm introducing a type alias for that. The struct GatedCfg with span and index was actively harmful; imo it became clearly cleaner using .find(...) instead. Ostensibly we could store the constant as a list of structs instead, but it doesn't seem worth it given the number of times the type is referenced and used?

span: Span,
index: usize,
}

impl GatedCfg {
pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
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
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ pub mod feature_gate {
};
mod builtin_attrs;
pub use builtin_attrs::{
AttributeGate, AttributeTemplate, AttributeType, GatedCfg,
AttributeGate, AttributeTemplate, AttributeType, find_gated_cfg, GatedCfg,
BuiltinAttribute, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
deprecated_attributes, is_builtin_attr, is_builtin_attr_name,
};
Expand Down