Skip to content

Commit f911d87

Browse files
authored
Auto merge of #34272 - jseyfried:simplify_gated_cfg_checking, r=nrc
Simplify gated cfg checking r? @nrc
2 parents 18f2871 + 2cd6ccf commit f911d87

File tree

11 files changed

+113
-218
lines changed

11 files changed

+113
-218
lines changed

src/librustc_driver/driver.rs

+12-36
Original file line numberDiff line numberDiff line change
@@ -577,15 +577,13 @@ pub fn phase_2_configure_and_expand<'a>(sess: &Session,
577577
//
578578
// baz! should not use this definition unless foo is enabled.
579579

580-
let mut feature_gated_cfgs = vec![];
581-
krate = time(time_passes, "configuration 1", || {
582-
sess.track_errors(|| {
583-
syntax::config::strip_unconfigured_items(sess.diagnostic(),
584-
krate,
585-
sess.opts.test,
586-
&mut feature_gated_cfgs)
587-
})
588-
})?;
580+
krate = time(time_passes, "configuration", || {
581+
let (krate, features) =
582+
syntax::config::strip_unconfigured_items(krate, &sess.parse_sess, sess.opts.test);
583+
// these need to be set "early" so that expansion sees `quote` if enabled.
584+
*sess.features.borrow_mut() = features;
585+
krate
586+
});
589587

590588
*sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs);
591589
sess.crate_disambiguator.set(token::intern(&compute_crate_disambiguator(sess)));
@@ -594,13 +592,6 @@ pub fn phase_2_configure_and_expand<'a>(sess: &Session,
594592
middle::recursion_limit::update_recursion_limit(sess, &krate);
595593
});
596594

597-
// these need to be set "early" so that expansion sees `quote` if enabled.
598-
sess.track_errors(|| {
599-
*sess.features.borrow_mut() =
600-
syntax::feature_gate::get_features(&sess.parse_sess.span_diagnostic,
601-
&krate);
602-
})?;
603-
604595
krate = time(time_passes, "crate injection", || {
605596
let alt_std_name = sess.opts.alt_std_name.clone();
606597
syntax::std_inject::maybe_inject_crates_ref(&sess.parse_sess, krate, alt_std_name)
@@ -699,7 +690,6 @@ pub fn phase_2_configure_and_expand<'a>(sess: &Session,
699690
let mut ecx = syntax::ext::base::ExtCtxt::new(&sess.parse_sess,
700691
krate.config.clone(),
701692
cfg,
702-
&mut feature_gated_cfgs,
703693
&mut loader);
704694
syntax_ext::register_builtins(&mut ecx.syntax_env);
705695
let (ret, macro_names) = syntax::ext::expand::expand_crate(ecx,
@@ -712,19 +702,6 @@ pub fn phase_2_configure_and_expand<'a>(sess: &Session,
712702
ret
713703
});
714704

715-
krate = sess.track_errors(|| {
716-
time(time_passes, "gated configuration checking", || {
717-
let features = sess.features.borrow();
718-
feature_gated_cfgs.sort();
719-
feature_gated_cfgs.dedup();
720-
for cfg in &feature_gated_cfgs {
721-
cfg.check_and_emit(sess.diagnostic(), &features, sess.codemap());
722-
}
723-
});
724-
725-
krate
726-
})?;
727-
728705
krate = time(time_passes, "maybe building test harness", || {
729706
syntax::test::modify_for_testing(&sess.parse_sess,
730707
sess.opts.test,
@@ -739,12 +716,11 @@ pub fn phase_2_configure_and_expand<'a>(sess: &Session,
739716
// Needs to go *after* expansion to be able to check the results of macro expansion.
740717
time(time_passes, "complete gated feature checking", || {
741718
sess.track_errors(|| {
742-
let features = syntax::feature_gate::check_crate(sess.codemap(),
743-
&sess.parse_sess.span_diagnostic,
744-
&krate,
745-
&attributes,
746-
sess.opts.unstable_features);
747-
*sess.features.borrow_mut() = features;
719+
syntax::feature_gate::check_crate(&krate,
720+
&sess.parse_sess,
721+
&sess.features.borrow(),
722+
&attributes,
723+
sess.opts.unstable_features);
748724
})
749725
})?;
750726

src/libsyntax/attr.rs

+13-20
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,11 @@ use ast::{Stmt, StmtKind, DeclKind};
2020
use ast::{Expr, Item, Local, Decl};
2121
use codemap::{Span, Spanned, spanned, dummy_spanned};
2222
use codemap::BytePos;
23-
use config::CfgDiag;
2423
use errors::Handler;
25-
use feature_gate::{GatedCfg, GatedCfgAttr};
24+
use feature_gate::{Features, GatedCfg};
2625
use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
2726
use parse::token::InternedString;
28-
use parse::token;
27+
use parse::{ParseSess, token};
2928
use ptr::P;
3029

3130
use std::cell::{RefCell, Cell};
@@ -365,35 +364,29 @@ pub fn requests_inline(attrs: &[Attribute]) -> bool {
365364
}
366365

367366
/// Tests if a cfg-pattern matches the cfg set
368-
pub fn cfg_matches<T: CfgDiag>(cfgs: &[P<MetaItem>],
369-
cfg: &ast::MetaItem,
370-
diag: &mut T) -> bool {
367+
pub fn cfg_matches(cfgs: &[P<MetaItem>], cfg: &ast::MetaItem,
368+
sess: &ParseSess, features: Option<&Features>)
369+
-> bool {
371370
match cfg.node {
372371
ast::MetaItemKind::List(ref pred, ref mis) if &pred[..] == "any" =>
373-
mis.iter().any(|mi| cfg_matches(cfgs, &mi, diag)),
372+
mis.iter().any(|mi| cfg_matches(cfgs, &mi, sess, features)),
374373
ast::MetaItemKind::List(ref pred, ref mis) if &pred[..] == "all" =>
375-
mis.iter().all(|mi| cfg_matches(cfgs, &mi, diag)),
374+
mis.iter().all(|mi| cfg_matches(cfgs, &mi, sess, features)),
376375
ast::MetaItemKind::List(ref pred, ref mis) if &pred[..] == "not" => {
377376
if mis.len() != 1 {
378-
diag.emit_error(|diagnostic| {
379-
diagnostic.span_err(cfg.span, "expected 1 cfg-pattern");
380-
});
377+
sess.span_diagnostic.span_err(cfg.span, "expected 1 cfg-pattern");
381378
return false;
382379
}
383-
!cfg_matches(cfgs, &mis[0], diag)
380+
!cfg_matches(cfgs, &mis[0], sess, features)
384381
}
385382
ast::MetaItemKind::List(ref pred, _) => {
386-
diag.emit_error(|diagnostic| {
387-
diagnostic.span_err(cfg.span,
388-
&format!("invalid predicate `{}`", pred));
389-
});
383+
sess.span_diagnostic.span_err(cfg.span, &format!("invalid predicate `{}`", pred));
390384
false
391385
},
392386
ast::MetaItemKind::Word(_) | ast::MetaItemKind::NameValue(..) => {
393-
diag.flag_gated(|feature_gated_cfgs| {
394-
feature_gated_cfgs.extend(
395-
GatedCfg::gate(cfg).map(GatedCfgAttr::GatedCfg));
396-
});
387+
if let (Some(features), Some(gated_cfg)) = (features, GatedCfg::gate(cfg)) {
388+
gated_cfg.check_and_emit(sess, features);
389+
}
397390
contains(cfgs, cfg)
398391
}
399392
}

src/libsyntax/config.rs

+48-60
Original file line numberDiff line numberDiff line change
@@ -9,36 +9,24 @@
99
// except according to those terms.
1010

1111
use attr::{AttrMetaMethods, HasAttrs};
12-
use errors::Handler;
13-
use feature_gate::GatedCfgAttr;
12+
use feature_gate::{emit_feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features, GateIssue};
1413
use fold::Folder;
1514
use {ast, fold, attr};
1615
use codemap::{Spanned, respan};
17-
use parse::token;
16+
use parse::{ParseSess, token};
1817
use ptr::P;
1918

2019
use util::small_vector::SmallVector;
2120

2221
/// A folder that strips out items that do not belong in the current configuration.
2322
pub struct StripUnconfigured<'a> {
24-
diag: CfgDiagReal<'a, 'a>,
25-
should_test: bool,
26-
config: &'a ast::CrateConfig,
23+
pub config: &'a ast::CrateConfig,
24+
pub should_test: bool,
25+
pub sess: &'a ParseSess,
26+
pub features: Option<&'a Features>,
2727
}
2828

2929
impl<'a> StripUnconfigured<'a> {
30-
pub fn new(config: &'a ast::CrateConfig,
31-
should_test: bool,
32-
diagnostic: &'a Handler,
33-
feature_gated_cfgs: &'a mut Vec<GatedCfgAttr>)
34-
-> Self {
35-
StripUnconfigured {
36-
config: config,
37-
should_test: should_test,
38-
diag: CfgDiagReal { diag: diagnostic, feature_gated_cfgs: feature_gated_cfgs },
39-
}
40-
}
41-
4230
fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
4331
let node = self.process_cfg_attrs(node);
4432
if self.in_cfg(node.attrs()) { Some(node) } else { None }
@@ -59,20 +47,20 @@ impl<'a> StripUnconfigured<'a> {
5947
Some(attr_list) => attr_list,
6048
None => {
6149
let msg = "expected `#[cfg_attr(<cfg pattern>, <attr>)]`";
62-
self.diag.diag.span_err(attr.span, msg);
50+
self.sess.span_diagnostic.span_err(attr.span, msg);
6351
return None;
6452
}
6553
};
6654
let (cfg, mi) = match (attr_list.len(), attr_list.get(0), attr_list.get(1)) {
6755
(2, Some(cfg), Some(mi)) => (cfg, mi),
6856
_ => {
6957
let msg = "expected `#[cfg_attr(<cfg pattern>, <attr>)]`";
70-
self.diag.diag.span_err(attr.span, msg);
58+
self.sess.span_diagnostic.span_err(attr.span, msg);
7159
return None;
7260
}
7361
};
7462

75-
if attr::cfg_matches(self.config, &cfg, &mut self.diag) {
63+
if attr::cfg_matches(self.config, &cfg, self.sess, self.features) {
7664
self.process_cfg_attr(respan(mi.span, ast::Attribute_ {
7765
id: attr::mk_attr_id(),
7866
style: attr.node.style,
@@ -98,41 +86,55 @@ impl<'a> StripUnconfigured<'a> {
9886
};
9987

10088
if mis.len() != 1 {
101-
self.diag.emit_error(|diagnostic| {
102-
diagnostic.span_err(attr.span, "expected 1 cfg-pattern");
103-
});
89+
self.sess.span_diagnostic.span_err(attr.span, "expected 1 cfg-pattern");
10490
return true;
10591
}
10692

107-
attr::cfg_matches(self.config, &mis[0], &mut self.diag)
93+
attr::cfg_matches(self.config, &mis[0], self.sess, self.features)
10894
})
10995
}
11096

11197
// Visit attributes on expression and statements (but not attributes on items in blocks).
11298
fn visit_stmt_or_expr_attrs(&mut self, attrs: &[ast::Attribute]) {
11399
// flag the offending attributes
114100
for attr in attrs.iter() {
115-
self.diag.feature_gated_cfgs.push(GatedCfgAttr::GatedAttr(attr.span));
116-
}
117-
}
118-
119-
// Visit unremovable (non-optional) expressions -- c.f. `fold_expr` vs `fold_opt_expr`.
120-
fn visit_unremovable_expr(&mut self, expr: &ast::Expr) {
121-
if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a) || is_test_or_bench(a)) {
122-
let msg = "removing an expression is not supported in this position";
123-
self.diag.diag.span_err(attr.span, msg);
101+
if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) {
102+
emit_feature_err(&self.sess.span_diagnostic,
103+
"stmt_expr_attributes",
104+
attr.span,
105+
GateIssue::Language,
106+
EXPLAIN_STMT_ATTR_SYNTAX);
107+
}
124108
}
125109
}
126110
}
127111

128112
// Support conditional compilation by transforming the AST, stripping out
129113
// any items that do not belong in the current configuration
130-
pub fn strip_unconfigured_items(diagnostic: &Handler, krate: ast::Crate, should_test: bool,
131-
feature_gated_cfgs: &mut Vec<GatedCfgAttr>)
132-
-> ast::Crate
133-
{
134-
let config = &krate.config.clone();
135-
StripUnconfigured::new(config, should_test, diagnostic, feature_gated_cfgs).fold_crate(krate)
114+
pub fn strip_unconfigured_items(mut krate: ast::Crate, sess: &ParseSess, should_test: bool)
115+
-> (ast::Crate, Features) {
116+
let features;
117+
{
118+
let mut strip_unconfigured = StripUnconfigured {
119+
config: &krate.config.clone(),
120+
should_test: should_test,
121+
sess: sess,
122+
features: None,
123+
};
124+
125+
let err_count = sess.span_diagnostic.err_count();
126+
let krate_attrs = strip_unconfigured.process_cfg_attrs(krate.attrs.clone());
127+
features = get_features(&sess.span_diagnostic, &krate_attrs);
128+
if err_count < sess.span_diagnostic.err_count() {
129+
krate.attrs = krate_attrs.clone(); // Avoid reconfiguring malformed `cfg_attr`s
130+
}
131+
132+
strip_unconfigured.features = Some(&features);
133+
krate = strip_unconfigured.fold_crate(krate);
134+
krate.attrs = krate_attrs;
135+
}
136+
137+
(krate, features)
136138
}
137139

138140
impl<'a> fold::Folder for StripUnconfigured<'a> {
@@ -188,14 +190,19 @@ impl<'a> fold::Folder for StripUnconfigured<'a> {
188190

189191
fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
190192
self.visit_stmt_or_expr_attrs(expr.attrs());
193+
191194
// If an expr is valid to cfg away it will have been removed by the
192195
// outer stmt or expression folder before descending in here.
193196
// Anything else is always required, and thus has to error out
194197
// in case of a cfg attr.
195198
//
196199
// NB: This is intentionally not part of the fold_expr() function
197200
// in order for fold_opt_expr() to be able to avoid this check
198-
self.visit_unremovable_expr(&expr);
201+
if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a) || is_test_or_bench(a)) {
202+
let msg = "removing an expression is not supported in this position";
203+
self.sess.span_diagnostic.span_err(attr.span, msg);
204+
}
205+
199206
let expr = self.process_cfg_attrs(expr);
200207
fold_expr(self, expr)
201208
}
@@ -273,22 +280,3 @@ fn is_cfg(attr: &ast::Attribute) -> bool {
273280
fn is_test_or_bench(attr: &ast::Attribute) -> bool {
274281
attr.check_name("test") || attr.check_name("bench")
275282
}
276-
277-
pub trait CfgDiag {
278-
fn emit_error<F>(&mut self, f: F) where F: FnMut(&Handler);
279-
fn flag_gated<F>(&mut self, f: F) where F: FnMut(&mut Vec<GatedCfgAttr>);
280-
}
281-
282-
pub struct CfgDiagReal<'a, 'b> {
283-
pub diag: &'a Handler,
284-
pub feature_gated_cfgs: &'b mut Vec<GatedCfgAttr>,
285-
}
286-
287-
impl<'a, 'b> CfgDiag for CfgDiagReal<'a, 'b> {
288-
fn emit_error<F>(&mut self, mut f: F) where F: FnMut(&Handler) {
289-
f(self.diag)
290-
}
291-
fn flag_gated<F>(&mut self, mut f: F) where F: FnMut(&mut Vec<GatedCfgAttr>) {
292-
f(self.feature_gated_cfgs)
293-
}
294-
}

src/libsyntax/ext/base.rs

-4
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use errors::DiagnosticBuilder;
1818
use ext;
1919
use ext::expand;
2020
use ext::tt::macro_rules;
21-
use feature_gate::GatedCfgAttr;
2221
use parse;
2322
use parse::parser;
2423
use parse::token;
@@ -556,7 +555,6 @@ pub struct ExtCtxt<'a> {
556555
pub backtrace: ExpnId,
557556
pub ecfg: expand::ExpansionConfig<'a>,
558557
pub crate_root: Option<&'static str>,
559-
pub feature_gated_cfgs: &'a mut Vec<GatedCfgAttr>,
560558
pub loader: &'a mut MacroLoader,
561559

562560
pub mod_path: Vec<ast::Ident> ,
@@ -573,7 +571,6 @@ pub struct ExtCtxt<'a> {
573571
impl<'a> ExtCtxt<'a> {
574572
pub fn new(parse_sess: &'a parse::ParseSess, cfg: ast::CrateConfig,
575573
ecfg: expand::ExpansionConfig<'a>,
576-
feature_gated_cfgs: &'a mut Vec<GatedCfgAttr>,
577574
loader: &'a mut MacroLoader)
578575
-> ExtCtxt<'a> {
579576
let env = initial_syntax_expander_table(&ecfg);
@@ -584,7 +581,6 @@ impl<'a> ExtCtxt<'a> {
584581
mod_path: Vec::new(),
585582
ecfg: ecfg,
586583
crate_root: None,
587-
feature_gated_cfgs: feature_gated_cfgs,
588584
exported_macros: Vec::new(),
589585
loader: loader,
590586
syntax_env: env,

0 commit comments

Comments
 (0)