mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 00:34:06 +00:00
Implement edition-based macro pat feature
This commit is contained in:
parent
2987785df3
commit
40bf3c0f09
@ -15,7 +15,7 @@ use rustc_span::hygiene::ExpnKind;
|
|||||||
use rustc_span::source_map::SourceMap;
|
use rustc_span::source_map::SourceMap;
|
||||||
use rustc_span::symbol::{kw, sym};
|
use rustc_span::symbol::{kw, sym};
|
||||||
use rustc_span::symbol::{Ident, Symbol};
|
use rustc_span::symbol::{Ident, Symbol};
|
||||||
use rustc_span::{self, FileName, RealFileName, Span, DUMMY_SP};
|
use rustc_span::{self, edition::Edition, FileName, RealFileName, Span, DUMMY_SP};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::{fmt, mem};
|
use std::{fmt, mem};
|
||||||
|
|
||||||
@ -690,7 +690,16 @@ pub enum NonterminalKind {
|
|||||||
Item,
|
Item,
|
||||||
Block,
|
Block,
|
||||||
Stmt,
|
Stmt,
|
||||||
Pat,
|
Pat2018 {
|
||||||
|
/// Keep track of whether the user used `:pat2018` or `:pat` and we inferred it from the
|
||||||
|
/// edition of the span. This is used for diagnostics.
|
||||||
|
inferred: bool,
|
||||||
|
},
|
||||||
|
Pat2021 {
|
||||||
|
/// Keep track of whether the user used `:pat2018` or `:pat` and we inferred it from the
|
||||||
|
/// edition of the span. This is used for diagnostics.
|
||||||
|
inferred: bool,
|
||||||
|
},
|
||||||
Expr,
|
Expr,
|
||||||
Ty,
|
Ty,
|
||||||
Ident,
|
Ident,
|
||||||
@ -703,12 +712,25 @@ pub enum NonterminalKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl NonterminalKind {
|
impl NonterminalKind {
|
||||||
pub fn from_symbol(symbol: Symbol) -> Option<NonterminalKind> {
|
/// The `edition` closure is used to get the edition for the given symbol. Doing
|
||||||
|
/// `span.edition()` is expensive, so we do it lazily.
|
||||||
|
pub fn from_symbol(
|
||||||
|
symbol: Symbol,
|
||||||
|
edition: impl FnOnce() -> Edition,
|
||||||
|
) -> Option<NonterminalKind> {
|
||||||
Some(match symbol {
|
Some(match symbol {
|
||||||
sym::item => NonterminalKind::Item,
|
sym::item => NonterminalKind::Item,
|
||||||
sym::block => NonterminalKind::Block,
|
sym::block => NonterminalKind::Block,
|
||||||
sym::stmt => NonterminalKind::Stmt,
|
sym::stmt => NonterminalKind::Stmt,
|
||||||
sym::pat => NonterminalKind::Pat,
|
sym::pat => match edition() {
|
||||||
|
Edition::Edition2015 | Edition::Edition2018 => {
|
||||||
|
NonterminalKind::Pat2018 { inferred: true }
|
||||||
|
}
|
||||||
|
// FIXME(mark-i-m): uncomment when 2021 machinery is available.
|
||||||
|
//Edition::Edition2021 => NonterminalKind::Pat2021{inferred:true},
|
||||||
|
},
|
||||||
|
sym::pat2018 => NonterminalKind::Pat2018 { inferred: false },
|
||||||
|
sym::pat2021 => NonterminalKind::Pat2021 { inferred: false },
|
||||||
sym::expr => NonterminalKind::Expr,
|
sym::expr => NonterminalKind::Expr,
|
||||||
sym::ty => NonterminalKind::Ty,
|
sym::ty => NonterminalKind::Ty,
|
||||||
sym::ident => NonterminalKind::Ident,
|
sym::ident => NonterminalKind::Ident,
|
||||||
@ -726,7 +748,10 @@ impl NonterminalKind {
|
|||||||
NonterminalKind::Item => sym::item,
|
NonterminalKind::Item => sym::item,
|
||||||
NonterminalKind::Block => sym::block,
|
NonterminalKind::Block => sym::block,
|
||||||
NonterminalKind::Stmt => sym::stmt,
|
NonterminalKind::Stmt => sym::stmt,
|
||||||
NonterminalKind::Pat => sym::pat,
|
NonterminalKind::Pat2018 { inferred: false } => sym::pat2018,
|
||||||
|
NonterminalKind::Pat2021 { inferred: false } => sym::pat2021,
|
||||||
|
NonterminalKind::Pat2018 { inferred: true }
|
||||||
|
| NonterminalKind::Pat2021 { inferred: true } => sym::pat,
|
||||||
NonterminalKind::Expr => sym::expr,
|
NonterminalKind::Expr => sym::expr,
|
||||||
NonterminalKind::Ty => sym::ty,
|
NonterminalKind::Ty => sym::ty,
|
||||||
NonterminalKind::Ident => sym::ident,
|
NonterminalKind::Ident => sym::ident,
|
||||||
|
@ -77,9 +77,9 @@ use TokenTreeOrTokenTreeSlice::*;
|
|||||||
use crate::mbe::{self, TokenTree};
|
use crate::mbe::{self, TokenTree};
|
||||||
|
|
||||||
use rustc_ast::token::{self, DocComment, Nonterminal, Token};
|
use rustc_ast::token::{self, DocComment, Nonterminal, Token};
|
||||||
use rustc_parse::parser::{OrPatNonterminalMode, Parser};
|
use rustc_parse::parser::Parser;
|
||||||
use rustc_session::parse::ParseSess;
|
use rustc_session::parse::ParseSess;
|
||||||
use rustc_span::{edition::Edition, symbol::MacroRulesNormalizedIdent};
|
use rustc_span::symbol::MacroRulesNormalizedIdent;
|
||||||
|
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
|
|
||||||
@ -419,18 +419,6 @@ fn token_name_eq(t1: &Token, t2: &Token) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// In edition 2015/18, `:pat` can only match `pat<no_top_alt>` because otherwise, we have
|
|
||||||
/// breakage. As of edition 2021, `:pat` matches `top_pat`.
|
|
||||||
///
|
|
||||||
/// See <https://github.com/rust-lang/rust/issues/54883> for more info.
|
|
||||||
fn or_pat_mode(edition: Edition) -> OrPatNonterminalMode {
|
|
||||||
match edition {
|
|
||||||
Edition::Edition2015 | Edition::Edition2018 => OrPatNonterminalMode::NoTopAlt,
|
|
||||||
// FIXME(mark-i-m): uncomment this when edition 2021 machinery is added.
|
|
||||||
// Edition::Edition2021 => OrPatNonterminalMode::TopPat,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Process the matcher positions of `cur_items` until it is empty. In the process, this will
|
/// Process the matcher positions of `cur_items` until it is empty. In the process, this will
|
||||||
/// produce more items in `next_items`, `eof_items`, and `bb_items`.
|
/// produce more items in `next_items`, `eof_items`, and `bb_items`.
|
||||||
///
|
///
|
||||||
@ -578,14 +566,13 @@ fn inner_parse_loop<'root, 'tt>(
|
|||||||
|
|
||||||
// We need to match a metavar with a valid ident... call out to the black-box
|
// We need to match a metavar with a valid ident... call out to the black-box
|
||||||
// parser by adding an item to `bb_items`.
|
// parser by adding an item to `bb_items`.
|
||||||
TokenTree::MetaVarDecl(span, _, Some(kind)) => {
|
TokenTree::MetaVarDecl(_, _, Some(kind)) => {
|
||||||
// Built-in nonterminals never start with these tokens, so we can eliminate
|
// Built-in nonterminals never start with these tokens, so we can eliminate
|
||||||
// them from consideration.
|
// them from consideration.
|
||||||
//
|
//
|
||||||
// We use the span of the metavariable declaration to determine any
|
// We use the span of the metavariable declaration to determine any
|
||||||
// edition-specific matching behavior for non-terminals.
|
// edition-specific matching behavior for non-terminals.
|
||||||
if Parser::nonterminal_may_begin_with(kind, token, or_pat_mode(span.edition()))
|
if Parser::nonterminal_may_begin_with(kind, token) {
|
||||||
{
|
|
||||||
bb_items.push(item);
|
bb_items.push(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -749,8 +736,7 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na
|
|||||||
let match_cur = item.match_cur;
|
let match_cur = item.match_cur;
|
||||||
// We use the span of the metavariable declaration to determine any
|
// We use the span of the metavariable declaration to determine any
|
||||||
// edition-specific matching behavior for non-terminals.
|
// edition-specific matching behavior for non-terminals.
|
||||||
let nt = match parser.to_mut().parse_nonterminal(kind, or_pat_mode(span.edition()))
|
let nt = match parser.to_mut().parse_nonterminal(kind) {
|
||||||
{
|
|
||||||
Err(mut err) => {
|
Err(mut err) => {
|
||||||
err.span_label(
|
err.span_label(
|
||||||
span,
|
span,
|
||||||
|
@ -476,10 +476,15 @@ pub fn compile_declarative_macro(
|
|||||||
.map(|m| {
|
.map(|m| {
|
||||||
if let MatchedNonterminal(ref nt) = *m {
|
if let MatchedNonterminal(ref nt) = *m {
|
||||||
if let NtTT(ref tt) = **nt {
|
if let NtTT(ref tt) = **nt {
|
||||||
let tt =
|
let tt = mbe::quoted::parse(
|
||||||
mbe::quoted::parse(tt.clone().into(), true, &sess.parse_sess, def.id)
|
tt.clone().into(),
|
||||||
.pop()
|
true,
|
||||||
.unwrap();
|
&sess.parse_sess,
|
||||||
|
def.id,
|
||||||
|
features,
|
||||||
|
)
|
||||||
|
.pop()
|
||||||
|
.unwrap();
|
||||||
valid &= check_lhs_nt_follows(&sess.parse_sess, features, &def.attrs, &tt);
|
valid &= check_lhs_nt_follows(&sess.parse_sess, features, &def.attrs, &tt);
|
||||||
return tt;
|
return tt;
|
||||||
}
|
}
|
||||||
@ -501,6 +506,7 @@ pub fn compile_declarative_macro(
|
|||||||
false,
|
false,
|
||||||
&sess.parse_sess,
|
&sess.parse_sess,
|
||||||
def.id,
|
def.id,
|
||||||
|
features,
|
||||||
)
|
)
|
||||||
.pop()
|
.pop()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -1090,7 +1096,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
|
|||||||
_ => IsInFollow::No(TOKENS),
|
_ => IsInFollow::No(TOKENS),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NonterminalKind::Pat => {
|
NonterminalKind::Pat2018 { .. } | NonterminalKind::Pat2021 { .. } => {
|
||||||
const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`in`"];
|
const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`in`"];
|
||||||
match tok {
|
match tok {
|
||||||
TokenTree::Token(token) => match token.kind {
|
TokenTree::Token(token) => match token.kind {
|
||||||
|
@ -5,8 +5,9 @@ use rustc_ast::token::{self, Token};
|
|||||||
use rustc_ast::tokenstream;
|
use rustc_ast::tokenstream;
|
||||||
use rustc_ast::{NodeId, DUMMY_NODE_ID};
|
use rustc_ast::{NodeId, DUMMY_NODE_ID};
|
||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
use rustc_session::parse::ParseSess;
|
use rustc_feature::Features;
|
||||||
use rustc_span::symbol::{kw, Ident};
|
use rustc_session::parse::{feature_err, ParseSess};
|
||||||
|
use rustc_span::symbol::{kw, sym, Ident};
|
||||||
|
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
||||||
@ -29,10 +30,8 @@ const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \
|
|||||||
/// `ident` are "matchers". They are not present in the body of a macro rule -- just in the
|
/// `ident` are "matchers". They are not present in the body of a macro rule -- just in the
|
||||||
/// pattern, so we pass a parameter to indicate whether to expect them or not.
|
/// pattern, so we pass a parameter to indicate whether to expect them or not.
|
||||||
/// - `sess`: the parsing session. Any errors will be emitted to this session.
|
/// - `sess`: the parsing session. Any errors will be emitted to this session.
|
||||||
/// - `features`, `attrs`: language feature flags and attributes so that we know whether to use
|
/// - `node_id`: the NodeId of the macro we are parsing.
|
||||||
/// unstable features or not.
|
/// - `features`: language features so we can do feature gating.
|
||||||
/// - `edition`: which edition are we in.
|
|
||||||
/// - `macro_node_id`: the NodeId of the macro we are parsing.
|
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
///
|
///
|
||||||
@ -42,6 +41,7 @@ pub(super) fn parse(
|
|||||||
expect_matchers: bool,
|
expect_matchers: bool,
|
||||||
sess: &ParseSess,
|
sess: &ParseSess,
|
||||||
node_id: NodeId,
|
node_id: NodeId,
|
||||||
|
features: &Features,
|
||||||
) -> Vec<TokenTree> {
|
) -> Vec<TokenTree> {
|
||||||
// Will contain the final collection of `self::TokenTree`
|
// Will contain the final collection of `self::TokenTree`
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
@ -52,7 +52,7 @@ pub(super) fn parse(
|
|||||||
while let Some(tree) = trees.next() {
|
while let Some(tree) = trees.next() {
|
||||||
// Given the parsed tree, if there is a metavar and we are expecting matchers, actually
|
// 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`).
|
// 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, node_id);
|
let tree = parse_tree(tree, &mut trees, expect_matchers, sess, node_id, features);
|
||||||
match tree {
|
match tree {
|
||||||
TokenTree::MetaVar(start_sp, ident) if expect_matchers => {
|
TokenTree::MetaVar(start_sp, ident) if expect_matchers => {
|
||||||
let span = match trees.next() {
|
let span = match trees.next() {
|
||||||
@ -61,18 +61,39 @@ pub(super) fn parse(
|
|||||||
Some(tokenstream::TokenTree::Token(token)) => match token.ident() {
|
Some(tokenstream::TokenTree::Token(token)) => match token.ident() {
|
||||||
Some((frag, _)) => {
|
Some((frag, _)) => {
|
||||||
let span = token.span.with_lo(start_sp.lo());
|
let span = token.span.with_lo(start_sp.lo());
|
||||||
let kind = token::NonterminalKind::from_symbol(frag.name)
|
|
||||||
.unwrap_or_else(|| {
|
match frag.name {
|
||||||
let msg = format!(
|
sym::pat2018 | sym::pat2021 => {
|
||||||
"invalid fragment specifier `{}`",
|
if !features.edition_macro_pats {
|
||||||
frag.name
|
feature_err(
|
||||||
);
|
sess,
|
||||||
sess.span_diagnostic
|
sym::edition_macro_pats,
|
||||||
.struct_span_err(span, &msg)
|
frag.span,
|
||||||
.help(VALID_FRAGMENT_NAMES_MSG)
|
"`pat2018` and `pat2021` are unstable.",
|
||||||
|
)
|
||||||
.emit();
|
.emit();
|
||||||
token::NonterminalKind::Ident
|
}
|
||||||
});
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
let kind =
|
||||||
|
token::NonterminalKind::from_symbol(frag.name, || {
|
||||||
|
span.edition()
|
||||||
|
})
|
||||||
|
.unwrap_or_else(
|
||||||
|
|| {
|
||||||
|
let msg = format!(
|
||||||
|
"invalid fragment specifier `{}`",
|
||||||
|
frag.name
|
||||||
|
);
|
||||||
|
sess.span_diagnostic
|
||||||
|
.struct_span_err(span, &msg)
|
||||||
|
.help(VALID_FRAGMENT_NAMES_MSG)
|
||||||
|
.emit();
|
||||||
|
token::NonterminalKind::Ident
|
||||||
|
},
|
||||||
|
);
|
||||||
result.push(TokenTree::MetaVarDecl(span, ident, Some(kind)));
|
result.push(TokenTree::MetaVarDecl(span, ident, Some(kind)));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -110,14 +131,14 @@ pub(super) fn parse(
|
|||||||
/// converting `tree`
|
/// converting `tree`
|
||||||
/// - `expect_matchers`: same as for `parse` (see above).
|
/// - `expect_matchers`: same as for `parse` (see above).
|
||||||
/// - `sess`: the parsing session. Any errors will be emitted to this session.
|
/// - `sess`: the parsing session. Any errors will be emitted to this session.
|
||||||
/// - `features`, `attrs`: language feature flags and attributes so that we know whether to use
|
/// - `features`: language features so we can do feature gating.
|
||||||
/// unstable features or not.
|
|
||||||
fn parse_tree(
|
fn parse_tree(
|
||||||
tree: tokenstream::TokenTree,
|
tree: tokenstream::TokenTree,
|
||||||
outer_trees: &mut impl Iterator<Item = tokenstream::TokenTree>,
|
outer_trees: &mut impl Iterator<Item = tokenstream::TokenTree>,
|
||||||
expect_matchers: bool,
|
expect_matchers: bool,
|
||||||
sess: &ParseSess,
|
sess: &ParseSess,
|
||||||
node_id: NodeId,
|
node_id: NodeId,
|
||||||
|
features: &Features,
|
||||||
) -> TokenTree {
|
) -> TokenTree {
|
||||||
// Depending on what `tree` is, we could be parsing different parts of a macro
|
// Depending on what `tree` is, we could be parsing different parts of a macro
|
||||||
match tree {
|
match tree {
|
||||||
@ -145,7 +166,7 @@ fn parse_tree(
|
|||||||
sess.span_diagnostic.span_err(span.entire(), &msg);
|
sess.span_diagnostic.span_err(span.entire(), &msg);
|
||||||
}
|
}
|
||||||
// Parse the contents of the sequence itself
|
// Parse the contents of the sequence itself
|
||||||
let sequence = parse(tts, expect_matchers, sess, node_id);
|
let sequence = parse(tts, expect_matchers, sess, node_id, features);
|
||||||
// Get the Kleene operator and optional separator
|
// Get the Kleene operator and optional separator
|
||||||
let (separator, kleene) =
|
let (separator, kleene) =
|
||||||
parse_sep_and_kleene_op(&mut trees, span.entire(), sess);
|
parse_sep_and_kleene_op(&mut trees, span.entire(), sess);
|
||||||
@ -196,7 +217,10 @@ fn parse_tree(
|
|||||||
// descend into the delimited set and further parse it.
|
// descend into the delimited set and further parse it.
|
||||||
tokenstream::TokenTree::Delimited(span, delim, tts) => TokenTree::Delimited(
|
tokenstream::TokenTree::Delimited(span, delim, tts) => TokenTree::Delimited(
|
||||||
span,
|
span,
|
||||||
Lrc::new(Delimited { delim, tts: parse(tts, expect_matchers, sess, node_id) }),
|
Lrc::new(Delimited {
|
||||||
|
delim,
|
||||||
|
tts: parse(tts, expect_matchers, sess, node_id, features),
|
||||||
|
}),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -620,6 +620,9 @@ declare_features! (
|
|||||||
/// Allows arbitrary expressions in key-value attributes at parse time.
|
/// Allows arbitrary expressions in key-value attributes at parse time.
|
||||||
(active, extended_key_value_attributes, "1.50.0", Some(78835), None),
|
(active, extended_key_value_attributes, "1.50.0", Some(78835), None),
|
||||||
|
|
||||||
|
/// `:pat2018` and `:pat2021` macro matchers.
|
||||||
|
(active, edition_macro_pats, "1.51.0", Some(54883), None),
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// feature-group-end: actual feature gates
|
// feature-group-end: actual feature gates
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
@ -12,7 +12,6 @@ mod ty;
|
|||||||
use crate::lexer::UnmatchedBrace;
|
use crate::lexer::UnmatchedBrace;
|
||||||
pub use diagnostics::AttemptLocalParseRecovery;
|
pub use diagnostics::AttemptLocalParseRecovery;
|
||||||
use diagnostics::Error;
|
use diagnostics::Error;
|
||||||
pub use pat::OrPatNonterminalMode;
|
|
||||||
pub use path::PathStyle;
|
pub use path::PathStyle;
|
||||||
|
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::ptr::P;
|
||||||
|
@ -4,7 +4,7 @@ use rustc_ast_pretty::pprust;
|
|||||||
use rustc_errors::PResult;
|
use rustc_errors::PResult;
|
||||||
use rustc_span::symbol::{kw, Ident};
|
use rustc_span::symbol::{kw, Ident};
|
||||||
|
|
||||||
use crate::parser::pat::{GateOr, OrPatNonterminalMode, RecoverComma};
|
use crate::parser::pat::{GateOr, RecoverComma};
|
||||||
use crate::parser::{FollowedByType, Parser, PathStyle};
|
use crate::parser::{FollowedByType, Parser, PathStyle};
|
||||||
|
|
||||||
impl<'a> Parser<'a> {
|
impl<'a> Parser<'a> {
|
||||||
@ -12,11 +12,7 @@ impl<'a> Parser<'a> {
|
|||||||
///
|
///
|
||||||
/// Returning `false` is a *stability guarantee* that such a matcher will *never* begin with that
|
/// Returning `false` is a *stability guarantee* that such a matcher will *never* begin with that
|
||||||
/// token. Be conservative (return true) if not sure.
|
/// token. Be conservative (return true) if not sure.
|
||||||
pub fn nonterminal_may_begin_with(
|
pub fn nonterminal_may_begin_with(kind: NonterminalKind, token: &Token) -> bool {
|
||||||
kind: NonterminalKind,
|
|
||||||
token: &Token,
|
|
||||||
or_pat_mode: OrPatNonterminalMode,
|
|
||||||
) -> bool {
|
|
||||||
/// Checks whether the non-terminal may contain a single (non-keyword) identifier.
|
/// Checks whether the non-terminal may contain a single (non-keyword) identifier.
|
||||||
fn may_be_ident(nt: &token::Nonterminal) -> bool {
|
fn may_be_ident(nt: &token::Nonterminal) -> bool {
|
||||||
match *nt {
|
match *nt {
|
||||||
@ -62,7 +58,7 @@ impl<'a> Parser<'a> {
|
|||||||
},
|
},
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
NonterminalKind::Pat => match token.kind {
|
NonterminalKind::Pat2018 { .. } | NonterminalKind::Pat2021 { .. } => match token.kind {
|
||||||
token::Ident(..) | // box, ref, mut, and other identifiers (can stricten)
|
token::Ident(..) | // box, ref, mut, and other identifiers (can stricten)
|
||||||
token::OpenDelim(token::Paren) | // tuple pattern
|
token::OpenDelim(token::Paren) | // tuple pattern
|
||||||
token::OpenDelim(token::Bracket) | // slice pattern
|
token::OpenDelim(token::Bracket) | // slice pattern
|
||||||
@ -76,7 +72,7 @@ impl<'a> Parser<'a> {
|
|||||||
token::Lt | // path (UFCS constant)
|
token::Lt | // path (UFCS constant)
|
||||||
token::BinOp(token::Shl) => true, // path (double UFCS)
|
token::BinOp(token::Shl) => true, // path (double UFCS)
|
||||||
// leading vert `|` or-pattern
|
// leading vert `|` or-pattern
|
||||||
token::BinOp(token::Or) => matches!(or_pat_mode, OrPatNonterminalMode::TopPat),
|
token::BinOp(token::Or) => matches!(kind, NonterminalKind::Pat2021 {..}),
|
||||||
token::Interpolated(ref nt) => may_be_ident(nt),
|
token::Interpolated(ref nt) => may_be_ident(nt),
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
@ -94,11 +90,7 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a non-terminal (e.g. MBE `:pat` or `:ident`).
|
/// Parse a non-terminal (e.g. MBE `:pat` or `:ident`).
|
||||||
pub fn parse_nonterminal(
|
pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, Nonterminal> {
|
||||||
&mut self,
|
|
||||||
kind: NonterminalKind,
|
|
||||||
or_pat_mode: OrPatNonterminalMode,
|
|
||||||
) -> PResult<'a, Nonterminal> {
|
|
||||||
// Any `Nonterminal` which stores its tokens (currently `NtItem` and `NtExpr`)
|
// Any `Nonterminal` which stores its tokens (currently `NtItem` and `NtExpr`)
|
||||||
// needs to have them force-captured here.
|
// needs to have them force-captured here.
|
||||||
// A `macro_rules!` invocation may pass a captured item/expr to a proc-macro,
|
// A `macro_rules!` invocation may pass a captured item/expr to a proc-macro,
|
||||||
@ -141,12 +133,13 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NonterminalKind::Pat => {
|
NonterminalKind::Pat2018 { .. } | NonterminalKind::Pat2021 { .. } => {
|
||||||
let (mut pat, tokens) = self.collect_tokens(|this| match or_pat_mode {
|
let (mut pat, tokens) = self.collect_tokens(|this| match kind {
|
||||||
OrPatNonterminalMode::TopPat => {
|
NonterminalKind::Pat2018 { .. } => this.parse_pat(None),
|
||||||
|
NonterminalKind::Pat2021 { .. } => {
|
||||||
this.parse_top_pat(GateOr::Yes, RecoverComma::No)
|
this.parse_top_pat(GateOr::Yes, RecoverComma::No)
|
||||||
}
|
}
|
||||||
OrPatNonterminalMode::NoTopAlt => this.parse_pat(None),
|
_ => unreachable!(),
|
||||||
})?;
|
})?;
|
||||||
// We have have eaten an NtPat, which could already have tokens
|
// We have have eaten an NtPat, which could already have tokens
|
||||||
if pat.tokens.is_none() {
|
if pat.tokens.is_none() {
|
||||||
|
@ -31,13 +31,6 @@ pub(super) enum RecoverComma {
|
|||||||
No,
|
No,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used when parsing a non-terminal (see `parse_nonterminal`) to determine if `:pat` should match
|
|
||||||
/// `top_pat` or `pat<no_top_alt>`. See issue <https://github.com/rust-lang/rust/pull/78935>.
|
|
||||||
pub enum OrPatNonterminalMode {
|
|
||||||
TopPat,
|
|
||||||
NoTopAlt,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Parser<'a> {
|
impl<'a> Parser<'a> {
|
||||||
/// Parses a pattern.
|
/// Parses a pattern.
|
||||||
///
|
///
|
||||||
|
@ -470,6 +470,7 @@ symbols! {
|
|||||||
dropck_parametricity,
|
dropck_parametricity,
|
||||||
dylib,
|
dylib,
|
||||||
dyn_trait,
|
dyn_trait,
|
||||||
|
edition_macro_pats,
|
||||||
eh_catch_typeinfo,
|
eh_catch_typeinfo,
|
||||||
eh_personality,
|
eh_personality,
|
||||||
emit_enum,
|
emit_enum,
|
||||||
@ -808,6 +809,8 @@ symbols! {
|
|||||||
partial_ord,
|
partial_ord,
|
||||||
passes,
|
passes,
|
||||||
pat,
|
pat,
|
||||||
|
pat2018,
|
||||||
|
pat2021,
|
||||||
path,
|
path,
|
||||||
pattern_parentheses,
|
pattern_parentheses,
|
||||||
phantom_data,
|
phantom_data,
|
||||||
|
8
src/test/ui/feature-gate-edition_macro_pats.rs
Normal file
8
src/test/ui/feature-gate-edition_macro_pats.rs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// Feature gate test for `edition_macro_pats` feature.
|
||||||
|
|
||||||
|
macro_rules! foo {
|
||||||
|
($x:pat2018) => {}; //~ERROR `pat2018` and `pat2021` are unstable
|
||||||
|
($x:pat2021) => {}; //~ERROR `pat2018` and `pat2021` are unstable
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
21
src/test/ui/feature-gate-edition_macro_pats.stderr
Normal file
21
src/test/ui/feature-gate-edition_macro_pats.stderr
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
error[E0658]: `pat2018` and `pat2021` are unstable.
|
||||||
|
--> $DIR/feature-gate-edition_macro_pats.rs:4:9
|
||||||
|
|
|
||||||
|
LL | ($x:pat2018) => {};
|
||||||
|
| ^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #54883 <https://github.com/rust-lang/rust/issues/54883> for more information
|
||||||
|
= help: add `#![feature(edition_macro_pats)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error[E0658]: `pat2018` and `pat2021` are unstable.
|
||||||
|
--> $DIR/feature-gate-edition_macro_pats.rs:5:9
|
||||||
|
|
|
||||||
|
LL | ($x:pat2021) => {};
|
||||||
|
| ^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #54883 <https://github.com/rust-lang/rust/issues/54883> for more information
|
||||||
|
= help: add `#![feature(edition_macro_pats)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
14
src/test/ui/macros/edition-macro-pats.rs
Normal file
14
src/test/ui/macros/edition-macro-pats.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// run-pass
|
||||||
|
|
||||||
|
#![feature(or_patterns)]
|
||||||
|
#![feature(edition_macro_pats)]
|
||||||
|
|
||||||
|
macro_rules! foo {
|
||||||
|
(a $x:pat2018) => {};
|
||||||
|
(b $x:pat2021) => {};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
foo!(a None);
|
||||||
|
foo!(b 1 | 2);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user