Skip to content

Commit

Permalink
Auto merge of #32791 - LeoTestard:feature-gate-clean, r=nikomatsakis
Browse files Browse the repository at this point in the history
Feature gate clean

This PR does a bit of cleaning in the feature-gate-handling code of libsyntax. It also fixes two bugs (#32782 and #32648). Changes include:

* Change the way the existing features are declared in `feature_gate.rs`. The array of features and the `Features` struct are now defined together by a single macro. `featureck.py` has been updated accordingly. Note: there are now three different arrays for active, removed and accepted features instead of a single one with a `Status` item to tell wether a feature is active, removed, or accepted. This is mainly due to the way I implemented my macro in the first time and I can switch back to a single array if needed. But an advantage of the way it is now is that when an active feature is used, the parser only searches through the list of active features. It goes through the other arrays only if the feature is not found. I like to think that error checking (in this case, checking that an used feature is active) does not slow down compilation of valid code. :) But this is not very important...
* Feature-gate checking pass now use the `Features` structure instead of looking through a string vector. This should speed them up a bit. The construction of the `Features` struct should be faster too since it is build directly when parsing features instead of calling `has_feature` dozens of times.
* The MacroVisitor pass has been removed, it was mostly useless since the `#[cfg]-stripping` phase happens before (fixes #32648). The features that must actually be checked before expansion are now checked at the time they are used. This also allows us to check attributes that are generated by macro expansion and not visible to MacroVisitor, but are also removed by macro expansion and thus not visible to PostExpansionVisitor either. This fixes #32782. Note that in order for `#[derive_*]` to be feature-gated but still accepted when generated by `#[derive(Trait)]`, I had to do a little bit of trickery with spans that I'm not totally confident into. Please review that part carefully. (It's in `libsyntax_ext/deriving/mod.rs`.)::

Note: this is a [breaking change], since programs with feature-gated attributes on macro-generated macro invocations were not rejected before. For example:

```rust
macro_rules! bar (
    () => ()
);

macro_rules! foo (
    () => (
        #[allow_internal_unstable] //~ ERROR allow_internal_unstable side-steps
        bar!();
    );
);
```
foo!();
  • Loading branch information
bors committed Apr 28, 2016
2 parents cda7c1c + fa23d10 commit 435095f
Show file tree
Hide file tree
Showing 12 changed files with 625 additions and 676 deletions.
16 changes: 5 additions & 11 deletions src/librustc_driver/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -528,19 +528,13 @@ pub fn phase_2_configure_and_expand(sess: &Session,
middle::recursion_limit::update_recursion_limit(sess, &krate);
});

time(time_passes, "gated macro checking", || {
sess.track_errors(|| {
let features =
syntax::feature_gate::check_crate_macros(sess.codemap(),
&sess.parse_sess.span_diagnostic,
&krate);

// these need to be set "early" so that expansion sees `quote` if enabled.
*sess.features.borrow_mut() = features;
})
// these need to be set "early" so that expansion sees `quote` if enabled.
sess.track_errors(|| {
*sess.features.borrow_mut() =
syntax::feature_gate::get_features(&sess.parse_sess.span_diagnostic,
&krate);
})?;


krate = time(time_passes, "crate injection", || {
syntax::std_inject::maybe_inject_crates_ref(krate, sess.opts.alt_std_name.clone())
});
Expand Down
39 changes: 22 additions & 17 deletions src/librustc_plugin/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,27 +51,32 @@ pub fn load_plugins(sess: &Session,
addl_plugins: Option<Vec<String>>) -> Vec<PluginRegistrar> {
let mut loader = PluginLoader::new(sess, cstore, crate_name);

for attr in &krate.attrs {
if !attr.check_name("plugin") {
continue;
}

let plugins = match attr.meta_item_list() {
Some(xs) => xs,
None => {
call_malformed_plugin_attribute(sess, attr.span);
// do not report any error now. since crate attributes are
// not touched by expansion, every use of plugin without
// the feature enabled will result in an error later...
if sess.features.borrow().plugin {
for attr in &krate.attrs {
if !attr.check_name("plugin") {
continue;
}
};

for plugin in plugins {
if plugin.value_str().is_some() {
call_malformed_plugin_attribute(sess, attr.span);
continue;
let plugins = match attr.meta_item_list() {
Some(xs) => xs,
None => {
call_malformed_plugin_attribute(sess, attr.span);
continue;
}
};

for plugin in plugins {
if plugin.value_str().is_some() {
call_malformed_plugin_attribute(sess, attr.span);
continue;
}

let args = plugin.meta_item_list().map(ToOwned::to_owned).unwrap_or_default();
loader.load_plugin(plugin.span, &plugin.name(), args);
}

let args = plugin.meta_item_list().map(ToOwned::to_owned).unwrap_or_default();
loader.load_plugin(plugin.span, &plugin.name(), args);
}
}

Expand Down
67 changes: 37 additions & 30 deletions src/libsyntax/ext/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,26 @@ use std_inject;
use std::collections::HashSet;
use std::env;

// this function is called to detect use of feature-gated or invalid attributes
// on macro invoations since they will not be detected after macro expansion
fn check_attributes(attrs: &[ast::Attribute], fld: &MacroExpander) {
for attr in attrs.iter() {
feature_gate::check_attribute(&attr, &fld.cx.parse_sess.span_diagnostic,
&fld.cx.parse_sess.codemap(),
&fld.cx.ecfg.features.unwrap());
}
}

pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
let expr_span = e.span;
return e.and_then(|ast::Expr {id, node, span, attrs}| match node {

// expr_mac should really be expr_ext or something; it's the
// entry-point for all syntax extensions.
ast::ExprKind::Mac(mac) => {
if let Some(ref attrs) = attrs {
check_attributes(attrs, fld);
}

// Assert that we drop any macro attributes on the floor here
drop(attrs);
Expand Down Expand Up @@ -70,10 +83,12 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {

ast::ExprKind::InPlace(placer, value_expr) => {
// Ensure feature-gate is enabled
feature_gate::check_for_placement_in(
fld.cx.ecfg.features,
&fld.cx.parse_sess.span_diagnostic,
expr_span);
if !fld.cx.ecfg.features.unwrap().placement_in_syntax {
feature_gate::emit_feature_err(
&fld.cx.parse_sess.span_diagnostic, "placement_in_syntax", expr_span,
feature_gate::GateIssue::Language, feature_gate::EXPLAIN_PLACEMENT_IN
);
}

let placer = fld.fold_expr(placer);
let value_expr = fld.fold_expr(value_expr);
Expand Down Expand Up @@ -370,6 +385,8 @@ pub fn expand_item_mac(it: P<ast::Item>,
_ => fld.cx.span_bug(it.span, "invalid item macro invocation")
});

check_attributes(&attrs, fld);

let fm = fresh_mark();
let items = {
let expanded = match fld.cx.syntax_env.find(extname) {
Expand Down Expand Up @@ -444,18 +461,6 @@ pub fn expand_item_mac(it: P<ast::Item>,
let allow_internal_unstable = attr::contains_name(&attrs,
"allow_internal_unstable");

// ensure any #[allow_internal_unstable]s are
// detected (including nested macro definitions
// etc.)
if allow_internal_unstable && !fld.cx.ecfg.enable_allow_internal_unstable() {
feature_gate::emit_feature_err(
&fld.cx.parse_sess.span_diagnostic,
"allow_internal_unstable",
span,
feature_gate::GateIssue::Language,
feature_gate::EXPLAIN_ALLOW_INTERNAL_UNSTABLE)
}

let export = attr::contains_name(&attrs, "macro_export");
let def = ast::MacroDef {
ident: ident,
Expand Down Expand Up @@ -519,6 +524,10 @@ fn expand_stmt(stmt: Stmt, fld: &mut MacroExpander) -> SmallVector<Stmt> {
_ => return expand_non_macro_stmt(stmt, fld)
};

if let Some(ref attrs) = attrs {
check_attributes(attrs, fld);
}

// Assert that we drop any macro attributes on the floor here
drop(attrs);

Expand Down Expand Up @@ -1066,7 +1075,7 @@ fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander)
attrs: ii.attrs,
vis: ii.vis,
defaultness: ii.defaultness,
node: match ii.node {
node: match ii.node {
ast::ImplItemKind::Method(sig, body) => {
let (sig, body) = expand_and_rename_method(sig, body, fld);
ast::ImplItemKind::Method(sig, body)
Expand All @@ -1075,13 +1084,11 @@ fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander)
},
span: fld.new_span(ii.span)
}),
ast::ImplItemKind::Macro(_) => {
let (span, mac) = match ii.node {
ast::ImplItemKind::Macro(mac) => (ii.span, mac),
_ => unreachable!()
};
ast::ImplItemKind::Macro(mac) => {
check_attributes(&ii.attrs, fld);

let maybe_new_items =
expand_mac_invoc(mac, span,
expand_mac_invoc(mac, ii.span,
|r| r.make_impl_items(),
|meths, mark| meths.move_map(|m| mark_impl_item(m, mark)),
fld);
Expand Down Expand Up @@ -1348,14 +1355,14 @@ impl<'feat> ExpansionConfig<'feat> {
}

feature_tests! {
fn enable_quotes = allow_quote,
fn enable_asm = allow_asm,
fn enable_log_syntax = allow_log_syntax,
fn enable_concat_idents = allow_concat_idents,
fn enable_trace_macros = allow_trace_macros,
fn enable_quotes = quote,
fn enable_asm = asm,
fn enable_log_syntax = log_syntax,
fn enable_concat_idents = concat_idents,
fn enable_trace_macros = trace_macros,
fn enable_allow_internal_unstable = allow_internal_unstable,
fn enable_custom_derive = allow_custom_derive,
fn enable_pushpop_unsafe = allow_pushpop_unsafe,
fn enable_custom_derive = custom_derive,
fn enable_pushpop_unsafe = pushpop_unsafe,
}
}

Expand Down
Loading

0 comments on commit 435095f

Please sign in to comment.