From 3277a06f08bf112188c0f346f7ef28dd03961040 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Sun, 3 Jun 2018 21:21:04 -0500 Subject: [PATCH] undo #49719 for rust 2015 with feature flag --- src/libsyntax/ext/tt/macro_rules.rs | 20 ++++- src/libsyntax/ext/tt/quoted.rs | 114 ++++++++++++++++------------ 2 files changed, 83 insertions(+), 51 deletions(-) diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 2e6d590c333cf..8f615ee026461 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -240,8 +240,14 @@ pub fn compile(sess: &ParseSess, features: &Features, def: &ast::Item, edition: 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, features, &def.attrs) - .pop().unwrap(); + let tt = quoted::parse( + tt.clone().into(), + true, + sess, + features, + &def.attrs, + edition + ).pop().unwrap(); valid &= check_lhs_nt_follows(sess, features, &def.attrs, &tt); return tt; } @@ -257,8 +263,14 @@ pub fn compile(sess: &ParseSess, features: &Features, def: &ast::Item, edition: s.iter().map(|m| { if let MatchedNonterminal(ref nt) = *m { if let NtTT(ref tt) = **nt { - return quoted::parse(tt.clone().into(), false, sess, features, &def.attrs) - .pop().unwrap(); + return quoted::parse( + tt.clone().into(), + false, + sess, + features, + &def.attrs, + edition + ).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 77c6afa1c64a6..50bbf1e553ae9 100644 --- a/src/libsyntax/ext/tt/quoted.rs +++ b/src/libsyntax/ext/tt/quoted.rs @@ -10,11 +10,11 @@ use {ast, attr}; use ext::tt::macro_parser; -use feature_gate::{self, emit_feature_err, Features, GateIssue}; +use feature_gate::Features; use parse::{token, ParseSess}; use print::pprust; use symbol::keywords; -use syntax_pos::{BytePos, Span, DUMMY_SP}; +use syntax_pos::{BytePos, Span, DUMMY_SP, edition::Edition}; use tokenstream; use std::iter::Peekable; @@ -184,6 +184,7 @@ pub fn parse( sess: &ParseSess, features: &Features, attrs: &[ast::Attribute], + edition: Edition, ) -> Vec { // Will contain the final collection of `self::TokenTree` let mut result = Vec::new(); @@ -194,7 +195,7 @@ pub fn parse( while let Some(tree) = trees.next() { // 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); + let tree = parse_tree(tree, &mut trees, expect_matchers, sess, features, attrs, edition); match tree { TokenTree::MetaVar(start_sp, ident) if expect_matchers => { let span = match trees.next() { @@ -252,6 +253,7 @@ fn parse_tree( sess: &ParseSess, features: &Features, attrs: &[ast::Attribute], + edition: Edition, ) -> TokenTree where I: Iterator, @@ -270,9 +272,23 @@ where sess.span_diagnostic.span_err(span, &msg); } // Parse the contents of the sequence itself - let sequence = parse(delimited.tts.into(), expect_matchers, sess, features, attrs); + let sequence = parse( + delimited.tts.into(), + expect_matchers, + sess, + features, + attrs, + edition, + ); // Get the Kleene operator and optional separator - let (separator, op) = parse_sep_and_kleene_op(trees, span, sess, features, attrs); + let (separator, op) = parse_sep_and_kleene_op( + trees, + span, + sess, + features, + attrs, + edition + ); // Count the number of captured "names" (i.e. named metavars) let name_captures = macro_parser::count_names(&sequence); TokenTree::Sequence( @@ -322,19 +338,46 @@ where span, Lrc::new(Delimited { delim: delimited.delim, - tts: parse(delimited.tts.into(), expect_matchers, sess, features, attrs), + tts: parse( + delimited.tts.into(), + expect_matchers, + sess, + features, + attrs, + edition + ), }), ), } } /// Takes a token and returns `Some(KleeneOp)` if the token is `+` `*` or `?`. Otherwise, return -/// `None`. -fn kleene_op(token: &token::Token) -> Option { +/// `None`. This function takes into account what edition and feature flags are enabled. +fn kleene_op( + token: &token::Token, + span: Span, + sess: &ParseSess, + edition: Edition, + features: &Features, + attrs: &[ast::Attribute], +) -> Option { match *token { token::BinOp(token::Star) => Some(KleeneOp::ZeroOrMore), token::BinOp(token::Plus) => Some(KleeneOp::OneOrMore), - token::Question => Some(KleeneOp::ZeroOrOne), + token::Question => + if edition >= Edition::Edition2018 + || (features.macro_at_most_once_rep + && attr::contains_name(attrs, "allow_internal_unstable")) { + Some(KleeneOp::ZeroOrOne) + } else { + sess.span_diagnostic + .span_warn( + span, + "`?` as a separator is deprecated and \ + will be removed in an upcoming edition." + ); + None + }, _ => None, } } @@ -347,14 +390,20 @@ fn kleene_op(token: &token::Token) -> Option { fn parse_kleene_op( input: &mut I, span: Span, + sess: &ParseSess, + edition: Edition, + features: &Features, + attrs: &[ast::Attribute], ) -> Result, Span> where I: Iterator, { match input.next() { - Some(tokenstream::TokenTree::Token(span, tok)) => match kleene_op(&tok) { - Some(op) => Ok(Ok(op)), - None => Ok(Err((tok, span))), + Some(tokenstream::TokenTree::Token(span, tok)) => { + match kleene_op(&tok, span, sess, edition, features, attrs) { + Some(op) => Ok(Ok(op)), + None => Ok(Err((tok, span))), + } }, tree => Err(tree.as_ref() .map(tokenstream::TokenTree::span) @@ -380,51 +429,22 @@ fn parse_sep_and_kleene_op( sess: &ParseSess, features: &Features, attrs: &[ast::Attribute], + edition: Edition, ) -> (Option, KleeneOp) where I: Iterator, { // We basically look at two token trees here, denoted as #1 and #2 below - let span = match parse_kleene_op(input, span) { - // #1 is any KleeneOp (`?`) - Ok(Ok(op)) if op == KleeneOp::ZeroOrOne => { - if !features.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 (None, op); - } - - // #1 is any KleeneOp (`+`, `*`) + let span = match parse_kleene_op(input, span, sess, edition, features, attrs) { + // #1 is any KleeneOp (`+`, `*`, or `?` (on editions > 2015)) Ok(Ok(op)) => return (None, op), // #1 is a separator followed by #2, a KleeneOp - Ok(Err((tok, span))) => match parse_kleene_op(input, span) { + Ok(Err((tok, span))) => match parse_kleene_op(input, span, sess, edition, features, attrs) { // #2 is a KleeneOp :D Ok(Ok(op)) if op == KleeneOp::ZeroOrOne => { - if !features.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, - ); - } else { - sess.span_diagnostic - .span_err(span, "`?` macro repetition does not allow a separator"); - } + sess.span_diagnostic + .span_err(span, "`?` macro repetition does not allow a separator"); return (None, op); } Ok(Ok(op)) => return (Some(tok), op),