Add feature gate + tests
This commit is contained in:
parent
4897a05ebf
commit
3c15405c25
5 changed files with 106 additions and 10 deletions
|
|
@ -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 @@ 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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
}
|
||||
|
|
|
|||
19
src/test/ui/feature-gate-macro_at_most_once_rep.rs
Normal file
19
src/test/ui/feature-gate-macro_at_most_once_rep.rs
Normal file
|
|
@ -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!();
|
||||
}
|
||||
11
src/test/ui/feature-gate-macro_at_most_once_rep.stderr
Normal file
11
src/test/ui/feature-gate-macro_at_most_once_rep.stderr
Normal file
|
|
@ -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
|
||||
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue