Skip to content

Feature gate clean #32791

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

Merged
merged 5 commits into from
Apr 28, 2016
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 5 additions & 11 deletions src/librustc_driver/driver.rs
Original file line number Diff line number Diff line change
@@ -512,19 +512,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())
});
39 changes: 22 additions & 17 deletions src/librustc_plugin/load.rs
Original file line number Diff line number Diff line change
@@ -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);
}
}

67 changes: 37 additions & 30 deletions src/libsyntax/ext/expand.rs
Original file line number Diff line number Diff line change
@@ -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);
@@ -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);
@@ -367,6 +382,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) {
@@ -441,18 +458,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,
@@ -516,6 +521,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);

@@ -1063,7 +1072,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)
@@ -1072,13 +1081,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);
@@ -1345,14 +1352,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,
}
}

974 changes: 425 additions & 549 deletions src/libsyntax/feature_gate.rs

Large diffs are not rendered by default.

94 changes: 64 additions & 30 deletions src/libsyntax_ext/deriving/mod.rs
Original file line number Diff line number Diff line change
@@ -96,6 +96,36 @@ fn expand_derive(cx: &mut ExtCtxt,
let mut found_partial_eq = false;
let mut found_eq = false;

// This span is **very** sensitive and crucial to
// getting the stability behavior we want. What we are
// doing is marking the generated `#[derive_*]` with the
// span of the `#[deriving(...)]` attribute (the
// entire attribute, not just the `PartialEq` or `Eq`
// part), but with the current backtrace. The current
// backtrace will contain a topmost entry that IS this
// `#[deriving(...)]` attribute and with the
// "allow-unstable" flag set to true.
//
// Note that we do NOT use the span of the `Eq`
// text itself. You might think this is
// equivalent, because the `Eq` appears within the
// `#[deriving(Eq)]` attribute, and hence we would
// inherit the "allows unstable" from the
// backtrace. But in fact this is not always the
// case. The actual source text that led to
// deriving can be `#[$attr]`, for example, where
// `$attr == deriving(Eq)`. In that case, the
// "#[derive_*]" would be considered to
// originate not from the deriving call but from
// text outside the deriving call, and hence would
// be forbidden from using unstable
// content.
//
// See tests src/run-pass/rfc1445 for
// examples. --nmatsakis
let span = Span { expn_id: cx.backtrace(), .. span };
assert!(cx.parse_sess.codemap().span_allows_unstable(span));

for titem in traits.iter().rev() {
let tname = match titem.node {
MetaItemKind::Word(ref tname) => tname,
@@ -121,42 +151,13 @@ fn expand_derive(cx: &mut ExtCtxt,
}

// #[derive(Foo, Bar)] expands to #[derive_Foo] #[derive_Bar]
item.attrs.push(cx.attribute(titem.span, cx.meta_word(titem.span,
item.attrs.push(cx.attribute(span, cx.meta_word(titem.span,
intern_and_get_ident(&format!("derive_{}", tname)))));
}

// RFC #1445. `#[derive(PartialEq, Eq)]` adds a (trusted)
// `#[structural_match]` attribute.
if found_partial_eq && found_eq {
// This span is **very** sensitive and crucial to
// getting the stability behavior we want. What we are
// doing is marking `#[structural_match]` with the
// span of the `#[deriving(...)]` attribute (the
// entire attribute, not just the `PartialEq` or `Eq`
// part), but with the current backtrace. The current
// backtrace will contain a topmost entry that IS this
// `#[deriving(...)]` attribute and with the
// "allow-unstable" flag set to true.
//
// Note that we do NOT use the span of the `Eq`
// text itself. You might think this is
// equivalent, because the `Eq` appears within the
// `#[deriving(Eq)]` attribute, and hence we would
// inherit the "allows unstable" from the
// backtrace. But in fact this is not always the
// case. The actual source text that led to
// deriving can be `#[$attr]`, for example, where
// `$attr == deriving(Eq)`. In that case, the
// "#[structural_match]" would be considered to
// originate not from the deriving call but from
// text outside the deriving call, and hence would
// be forbidden from using unstable
// content.
//
// See tests src/run-pass/rfc1445 for
// examples. --nmatsakis
let span = Span { expn_id: cx.backtrace(), .. span };
assert!(cx.parse_sess.codemap().span_allows_unstable(span));
debug!("inserting structural_match with span {:?}", span);
let structural_match = intern_and_get_ident("structural_match");
item.attrs.push(cx.attribute(span,
@@ -188,6 +189,39 @@ macro_rules! derive_traits {
mitem: &MetaItem,
annotatable: &Annotatable,
push: &mut FnMut(Annotatable)) {
if !ecx.parse_sess.codemap().span_allows_unstable(sp)
&& !ecx.ecfg.features.unwrap().custom_derive {
// FIXME:
// https://github.com/rust-lang/rust/pull/32671#issuecomment-206245303
// This is just to avoid breakage with syntex.
// Remove that to spawn an error instead.
let cm = ecx.parse_sess.codemap();
let parent = cm.with_expn_info(ecx.backtrace(),
|info| info.unwrap().call_site.expn_id);
cm.with_expn_info(parent, |info| {
if info.is_some() {
let mut w = ecx.parse_sess.span_diagnostic.struct_span_warn(
sp, feature_gate::EXPLAIN_DERIVE_UNDERSCORE,
);
if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_none() {
w.fileline_help(
sp, &format!("add #![feature(custom_derive)] to \
the crate attributes to enable")
);
}
w.emit();
} else {
feature_gate::emit_feature_err(
&ecx.parse_sess.span_diagnostic,
"custom_derive", sp, feature_gate::GateIssue::Language,
feature_gate::EXPLAIN_DERIVE_UNDERSCORE
);

return;
}
})
}

warn_if_deprecated(ecx, sp, $name);
$func(ecx, sp, mitem, annotatable, push);
}
Original file line number Diff line number Diff line change
@@ -11,8 +11,8 @@
macro_rules! bar {
() => {
// more layers don't help:
#[allow_internal_unstable]
macro_rules! baz { //~ ERROR allow_internal_unstable side-steps
#[allow_internal_unstable] //~ ERROR allow_internal_unstable side-steps
macro_rules! baz {
() => {}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@@ -8,13 +8,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Test that the trace_macros feature gate is on.
// checks that this attribute is caught on non-macro items.
// this needs a different test since this is done after expansion

fn main() {
// (Infrastructure does not attempt to detect uses in macro definitions.)
macro_rules! expando {
($x: ident) => { trace_macros!($x) }
}
#[allow_internal_unstable] //~ ERROR allow_internal_unstable side-steps
struct S;

expando!(true); //~ ERROR `trace_macros` is not stable
}
fn main() {}
33 changes: 33 additions & 0 deletions src/test/compile-fail/issue-32655.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(dead_code)]
#![feature(rustc_attrs)]

macro_rules! foo (
() => (
#[derive_Clone] //~ WARN attributes of the form
struct T;
);
);

macro_rules! bar (
($e:item) => ($e)
);

foo!();

bar!(
#[derive_Clone] //~ WARN attributes of the form
struct S;
);

#[rustc_error]
fn main() {} //~ ERROR compilation successful
23 changes: 23 additions & 0 deletions src/test/compile-fail/issue-32782.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

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

macro_rules! foo (
() => (
#[allow_internal_unstable] //~ ERROR allow_internal_unstable side-steps
bar!();
);
);

foo!();
fn main() {}
2 changes: 1 addition & 1 deletion src/test/compile-fail/trace_macros-gate.rs
Original file line number Diff line number Diff line change
@@ -26,5 +26,5 @@ fn main() {
($x: ident) => { trace_macros!($x) }
}

expando!(true);
expando!(true); //~ ERROR `trace_macros` is not stable
}
20 changes: 0 additions & 20 deletions src/test/compile-fail/trace_macros-gate3.rs

This file was deleted.

14 changes: 7 additions & 7 deletions src/tools/tidy/src/features.rs
Original file line number Diff line number Diff line change
@@ -136,18 +136,18 @@ fn collect_lang_features(path: &Path) -> Vec<Feature> {

let mut features = Vec::new();
for line in contents.lines().map(|l| l.trim()) {
if !STATUSES.iter().any(|s| line.contains(s) && line.starts_with("(")) {
if !STATUSES.iter().any(|s| line.starts_with(&format!("({}", s))) {
continue
}
let mut parts = line.split(",");
let name = parts.next().unwrap().replace("\"", "").replace("(", "");
let since = parts.next().unwrap().trim().replace("\"", "");
let status = match parts.skip(1).next().unwrap() {
s if s.contains("Active") => "unstable",
s if s.contains("Removed") => "unstable",
s if s.contains("Accepted") => "stable",
let status = match &parts.next().unwrap().trim().replace("(", "")[..] {
"active" => "unstable",
"removed" => "unstable",
"accepted" => "stable",
s => panic!("unknown status: {}", s),
};
let name = parts.next().unwrap().trim().to_owned();
let since = parts.next().unwrap().trim().replace("\"", "");

features.push(Feature {
name: name,