提交 3c15405c 编写于 作者: M Mark Mansi

Add feature gate + tests

上级 4897a05e
......@@ -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")
......
......@@ -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 @@ fn parse_tree<I>(
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 @@ fn parse_tree<I>(
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 @@ fn parse_sep_and_kleene_op<I>(
// (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 @@ fn parse_sep_and_kleene_op<I>(
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 @@ fn parse_sep_and_kleene_op<I>(
// #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 @@ fn parse_sep_and_kleene_op<I>(
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)
}
......@@ -452,6 +452,11 @@ pub fn new() -> 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 @@ fn leveled_feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue
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>,
}
......
// 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!();
}
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
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册