diff options
| author | Mark Mansi <markm@cs.wisc.edu> | 2018-01-26 16:16:43 -0600 |
|---|---|---|
| committer | Mark Mansi <markm@cs.wisc.edu> | 2018-01-30 12:42:51 -0600 |
| commit | 3c15405c2571e03226b98f2d6eddec51967f0a18 (patch) | |
| tree | 544446df2609b2afcaa16ec39e6d6cd8b369c464 | |
| parent | 4897a05ebf862f694f8b276e6c540ba30af4326a (diff) | |
| download | rust-3c15405c2571e03226b98f2d6eddec51967f0a18.tar.gz rust-3c15405c2571e03226b98f2d6eddec51967f0a18.zip | |
Add feature gate + tests
| -rw-r--r-- | src/libsyntax/ext/tt/macro_rules.rs | 6 | ||||
| -rw-r--r-- | src/libsyntax/ext/tt/quoted.rs | 72 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate.rs | 8 | ||||
| -rw-r--r-- | src/test/ui/feature-gate-macro_at_most_once_rep.rs | 19 | ||||
| -rw-r--r-- | src/test/ui/feature-gate-macro_at_most_once_rep.stderr | 11 |
5 files changed, 106 insertions, 10 deletions
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 9efb4faa635..5254c751e6b 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -237,7 +237,8 @@ pub fn compile(sess: &ParseSess, features: &RefCell<Features>, def: &ast::Item) s.iter().map(|m| { if let MatchedNonterminal(ref nt) = *m { if let NtTT(ref tt) = **nt { - let tt = quoted::parse(tt.clone().into(), true, sess).pop().unwrap(); + let tt = quoted::parse(tt.clone().into(), true, sess, features, &def.attrs) + .pop().unwrap(); valid &= check_lhs_nt_follows(sess, features, &def.attrs, &tt); return tt; } @@ -253,7 +254,8 @@ pub fn compile(sess: &ParseSess, features: &RefCell<Features>, def: &ast::Item) s.iter().map(|m| { if let MatchedNonterminal(ref nt) = *m { if let NtTT(ref tt) = **nt { - return quoted::parse(tt.clone().into(), false, sess).pop().unwrap(); + return quoted::parse(tt.clone().into(), false, sess, features, &def.attrs) + .pop().unwrap(); } } sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs") diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs index 670d3614604..8e05a6ccc47 100644 --- a/src/libsyntax/ext/tt/quoted.rs +++ b/src/libsyntax/ext/tt/quoted.rs @@ -8,14 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ast; +use {ast, attr}; use ext::tt::macro_parser; +use feature_gate::{self, emit_feature_err, Features, GateIssue}; use parse::{token, ParseSess}; use print::pprust; use symbol::keywords; use syntax_pos::{BytePos, Span, DUMMY_SP}; use tokenstream; +use std::cell::RefCell; use std::iter::Peekable; use std::rc::Rc; @@ -179,6 +181,8 @@ pub fn parse( input: tokenstream::TokenStream, expect_matchers: bool, sess: &ParseSess, + features: &RefCell<Features>, + attrs: &[ast::Attribute], ) -> Vec<TokenTree> { // Will contain the final collection of `self::TokenTree` let mut result = Vec::new(); @@ -187,10 +191,9 @@ pub fn parse( // additional trees if need be. let mut trees = input.trees().peekable(); while let Some(tree) = trees.next() { - let tree = parse_tree(tree, &mut trees, expect_matchers, sess); - // Given the parsed tree, if there is a metavar and we are expecting matchers, actually // parse out the matcher (i.e. in `$id:ident` this would parse the `:` and `ident`). + let tree = parse_tree(tree, &mut trees, expect_matchers, sess, features, attrs); match tree { TokenTree::MetaVar(start_sp, ident) if expect_matchers => { let span = match trees.next() { @@ -244,6 +247,8 @@ fn parse_tree<I>( trees: &mut Peekable<I>, expect_matchers: bool, sess: &ParseSess, + features: &RefCell<Features>, + attrs: &[ast::Attribute], ) -> TokenTree where I: Iterator<Item = tokenstream::TokenTree>, @@ -262,9 +267,9 @@ where sess.span_diagnostic.span_err(span, &msg); } // Parse the contents of the sequence itself - let sequence = parse(delimited.tts.into(), expect_matchers, sess); + let sequence = parse(delimited.tts.into(), expect_matchers, sess, features, attrs); // Get the Kleene operator and optional separator - let (separator, op) = parse_sep_and_kleene_op(trees, span, sess); + let (separator, op) = parse_sep_and_kleene_op(trees, span, sess, features, attrs); // Count the number of captured "names" (i.e. named metavars) let name_captures = macro_parser::count_names(&sequence); TokenTree::Sequence( @@ -317,7 +322,7 @@ where span, Rc::new(Delimited { delim: delimited.delim, - tts: parse(delimited.tts.into(), expect_matchers, sess), + tts: parse(delimited.tts.into(), expect_matchers, sess, features, attrs), }), ), } @@ -373,6 +378,8 @@ fn parse_sep_and_kleene_op<I>( input: &mut Peekable<I>, span: Span, sess: &ParseSess, + features: &RefCell<Features>, + attrs: &[ast::Attribute], ) -> (Option<token::Token>, KleeneOp) where I: Iterator<Item = tokenstream::TokenTree>, @@ -401,6 +408,21 @@ where // (N.B. We need to advance the input iterator.) match parse_kleene_op(input, span) { // #2 is a KleeneOp (this is the only valid option) :) + Ok(Ok(op)) if op == KleeneOp::ZeroOrOne => { + if !features.borrow().macro_at_most_once_rep + && !attr::contains_name(attrs, "allow_internal_unstable") + { + let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP; + emit_feature_err( + sess, + "macro_at_most_once_rep", + span, + GateIssue::Language, + explain, + ); + } + return (Some(token::Question), op); + } Ok(Ok(op)) => return (Some(token::Question), op), // #2 is a random token (this is an error) :( @@ -410,6 +432,19 @@ where Err(span) => span, } } else { + if !features.borrow().macro_at_most_once_rep + && !attr::contains_name(attrs, "allow_internal_unstable") + { + let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP; + emit_feature_err( + sess, + "macro_at_most_once_rep", + span, + GateIssue::Language, + explain, + ); + } + // #2 is a random tree and #1 is KleeneOp::ZeroOrOne return (None, op); } @@ -418,6 +453,21 @@ where // #1 is a separator followed by #2, a KleeneOp Ok(Err((tok, span))) => match parse_kleene_op(input, span) { // #2 is a KleeneOp :D + Ok(Ok(op)) if op == KleeneOp::ZeroOrOne => { + if !features.borrow().macro_at_most_once_rep + && !attr::contains_name(attrs, "allow_internal_unstable") + { + let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP; + emit_feature_err( + sess, + "macro_at_most_once_rep", + span, + GateIssue::Language, + explain, + ); + } + return (Some(tok), op); + } Ok(Ok(op)) => return (Some(tok), op), // #2 is a random token :( @@ -431,7 +481,13 @@ where Err(span) => span, }; - sess.span_diagnostic - .span_err(span, "expected one of: `*`, `+`, or `?`"); + if !features.borrow().macro_at_most_once_rep + && !attr::contains_name(attrs, "allow_internal_unstable") + { + sess.span_diagnostic + .span_err(span, "expected one of: `*`, `+`, or `?`"); + } else { + sess.span_diagnostic.span_err(span, "expected `*` or `+`"); + } (None, KleeneOp::ZeroOrMore) } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 9a2560b0458..9358511018a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -452,6 +452,11 @@ declare_features! ( // Allows `#[repr(transparent)]` attribute on newtype structs (active, repr_transparent, "1.25.0", Some(43036)), + + // Use `?` as the Kleene "at most one" operator + // FIXME(mark-i-m): make sure we use the correct issue number when there is + // a tracking issue... + (active, macro_at_most_once_rep, "1.25.0", None), ); declare_features! ( @@ -1250,6 +1255,9 @@ pub const EXPLAIN_PLACEMENT_IN: &'static str = pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &'static str = "Unsized tuple coercion is not stable enough for use and is subject to change"; +pub const EXPLAIN_MACRO_AT_MOST_ONCE_REP: &'static str = + "Using the `?` macro Kleene operator for \"at most one\" repetition is unstable"; + struct PostExpansionVisitor<'a> { context: &'a Context<'a>, } diff --git a/src/test/ui/feature-gate-macro_at_most_once_rep.rs b/src/test/ui/feature-gate-macro_at_most_once_rep.rs new file mode 100644 index 00000000000..13b2a8e217a --- /dev/null +++ b/src/test/ui/feature-gate-macro_at_most_once_rep.rs @@ -0,0 +1,19 @@ +// Copyright 2017 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. + +// Test that the MSP430 interrupt ABI cannot be used when msp430_interrupt +// feature gate is not used. + +macro_rules! m { ($(a)?) => {} } +//~^ ERROR Using the `?` macro Kleene operator for "at most one" repetition is unstable + +fn main() { + m!(); +} diff --git a/src/test/ui/feature-gate-macro_at_most_once_rep.stderr b/src/test/ui/feature-gate-macro_at_most_once_rep.stderr new file mode 100644 index 00000000000..f470399ffef --- /dev/null +++ b/src/test/ui/feature-gate-macro_at_most_once_rep.stderr @@ -0,0 +1,11 @@ +error[E0658]: Using the `?` macro Kleene operator for "at most one" repetition is unstable + --> $DIR/feature-gate-macro_at_most_once_rep.rs:14:19 + | +14 | macro_rules! m { ($(a)?) => {} } + | ^^^^^ + | + = help: add #![feature(macro_at_most_once_rep)] to the crate attributes to enable + +error: aborting due to previous error + + |
