Skip to content

Commit c8a538a

Browse files
authored
Unrolled build for rust-lang#120221
Rollup merge of rust-lang#120221 - compiler-errors:statements-are-not-patterns, r=nnethercote Don't make statement nonterminals match pattern nonterminals Right now, the heuristic we use to check if a token may begin a pattern nonterminal falls back to `may_be_ident`: https://github.com/rust-lang/rust/blob/ef71f1047e04438181d7cb925a833e2ada6ab390/compiler/rustc_parse/src/parser/nonterminal.rs#L21-L37 This has the unfortunate side effect that a `stmt` nonterminal eagerly matches against a `pat` nonterminal, leading to a parse error: ```rust macro_rules! m { ($pat:pat) => {}; ($stmt:stmt) => {}; } macro_rules! m2 { ($stmt:stmt) => { m! { $stmt } }; } m2! { let x = 1 } ``` This PR fixes it by more accurately reflecting the set of nonterminals that may begin a pattern nonterminal. As a side-effect, I modified `Token::can_begin_pattern` to work correctly and used that in `Parser::nonterminal_may_begin_with`.
2 parents fa72f07 + c61f85b commit c8a538a

File tree

5 files changed

+65
-42
lines changed

5 files changed

+65
-42
lines changed

compiler/rustc_ast/src/token.rs

+36-21
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,9 @@ impl Token {
486486
}
487487

488488
/// Returns `true` if the token can appear at the start of an expression.
489+
///
490+
/// **NB**: Take care when modifying this function, since it will change
491+
/// the stable set of tokens that are allowed to match an expr nonterminal.
489492
pub fn can_begin_expr(&self) -> bool {
490493
match self.uninterpolate().kind {
491494
Ident(name, is_raw) =>
@@ -504,34 +507,46 @@ impl Token {
504507
PathSep | // global path
505508
Lifetime(..) | // labeled loop
506509
Pound => true, // expression attributes
507-
Interpolated(ref nt) => matches!(&**nt, NtLiteral(..) |
508-
NtExpr(..) |
509-
NtBlock(..) |
510-
NtPath(..)),
510+
Interpolated(ref nt) =>
511+
matches!(&**nt,
512+
NtBlock(..) |
513+
NtExpr(..) |
514+
NtLiteral(..) |
515+
NtPath(..)
516+
),
511517
_ => false,
512518
}
513519
}
514520

515521
/// Returns `true` if the token can appear at the start of a pattern.
516522
///
517523
/// Shamelessly borrowed from `can_begin_expr`, only used for diagnostics right now.
518-
pub fn can_begin_pattern(&self) -> bool {
519-
match self.uninterpolate().kind {
520-
Ident(name, is_raw) =>
521-
ident_can_begin_expr(name, self.span, is_raw), // value name or keyword
522-
| OpenDelim(Delimiter::Bracket | Delimiter::Parenthesis) // tuple or array
523-
| Literal(..) // literal
524-
| BinOp(Minus) // unary minus
525-
| BinOp(And) // reference
526-
| AndAnd // double reference
527-
// DotDotDot is no longer supported
528-
| DotDot | DotDotDot | DotDotEq // ranges
529-
| Lt | BinOp(Shl) // associated path
530-
| PathSep => true, // global path
531-
Interpolated(ref nt) => matches!(&**nt, NtLiteral(..) |
532-
NtPat(..) |
533-
NtBlock(..) |
534-
NtPath(..)),
524+
pub fn can_begin_pattern(&self, pat_kind: NtPatKind) -> bool {
525+
match &self.uninterpolate().kind {
526+
// box, ref, mut, and other identifiers (can stricten)
527+
Ident(..) | NtIdent(..) |
528+
OpenDelim(Delimiter::Parenthesis) | // tuple pattern
529+
OpenDelim(Delimiter::Bracket) | // slice pattern
530+
BinOp(And) | // reference
531+
BinOp(Minus) | // negative literal
532+
AndAnd | // double reference
533+
Literal(_) | // literal
534+
DotDot | // range pattern (future compat)
535+
DotDotDot | // range pattern (future compat)
536+
PathSep | // path
537+
Lt | // path (UFCS constant)
538+
BinOp(Shl) => true, // path (double UFCS)
539+
// leading vert `|` or-pattern
540+
BinOp(Or) => matches!(pat_kind, PatWithOr),
541+
Interpolated(nt) =>
542+
matches!(&**nt,
543+
| NtExpr(..)
544+
| NtLiteral(..)
545+
| NtMeta(..)
546+
| NtPat(..)
547+
| NtPath(..)
548+
| NtTy(..)
549+
),
535550
_ => false,
536551
}
537552
}

compiler/rustc_parse/src/parser/nonterminal.rs

+1-19
Original file line numberDiff line numberDiff line change
@@ -86,25 +86,7 @@ impl<'a> Parser<'a> {
8686
token::Interpolated(nt) => may_be_ident(nt),
8787
_ => false,
8888
},
89-
NonterminalKind::Pat(pat_kind) => match &token.kind {
90-
// box, ref, mut, and other identifiers (can stricten)
91-
token::Ident(..) | token::NtIdent(..) |
92-
token::OpenDelim(Delimiter::Parenthesis) | // tuple pattern
93-
token::OpenDelim(Delimiter::Bracket) | // slice pattern
94-
token::BinOp(token::And) | // reference
95-
token::BinOp(token::Minus) | // negative literal
96-
token::AndAnd | // double reference
97-
token::Literal(_) | // literal
98-
token::DotDot | // range pattern (future compat)
99-
token::DotDotDot | // range pattern (future compat)
100-
token::PathSep | // path
101-
token::Lt | // path (UFCS constant)
102-
token::BinOp(token::Shl) => true, // path (double UFCS)
103-
// leading vert `|` or-pattern
104-
token::BinOp(token::Or) => matches!(pat_kind, PatWithOr),
105-
token::Interpolated(nt) => may_be_ident(nt),
106-
_ => false,
107-
},
89+
NonterminalKind::Pat(pat_kind) => token.can_begin_pattern(pat_kind),
10890
NonterminalKind::Lifetime => match &token.kind {
10991
token::Lifetime(_) | token::NtLifetime(..) => true,
11092
_ => false,

compiler/rustc_parse/src/parser/pat.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,11 @@ impl<'a> Parser<'a> {
444444

445445
let mut lo = self.token.span;
446446

447-
if self.token.is_keyword(kw::Let) && self.look_ahead(1, |tok| tok.can_begin_pattern()) {
447+
if self.token.is_keyword(kw::Let)
448+
&& self.look_ahead(1, |tok| {
449+
tok.can_begin_pattern(token::NtPatKind::PatParam { inferred: false })
450+
})
451+
{
448452
self.bump();
449453
self.dcx().emit_err(RemoveLet { span: lo });
450454
lo = self.token.span;

compiler/rustc_parse/src/parser/path.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,10 @@ impl<'a> Parser<'a> {
378378
if self.may_recover()
379379
&& prev_token_before_parsing == token::PathSep
380380
&& (style == PathStyle::Expr && self.token.can_begin_expr()
381-
|| style == PathStyle::Pat && self.token.can_begin_pattern())
381+
|| style == PathStyle::Pat
382+
&& self.token.can_begin_pattern(token::NtPatKind::PatParam {
383+
inferred: false,
384+
}))
382385
{
383386
snapshot = Some(self.create_snapshot_for_diagnostic());
384387
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//@ check-pass
2+
3+
// Make sure that a `stmt` nonterminal does not eagerly match against
4+
// a `pat`, since this will always cause a parse error...
5+
6+
macro_rules! m {
7+
($pat:pat) => {};
8+
($stmt:stmt) => {};
9+
}
10+
11+
macro_rules! m2 {
12+
($stmt:stmt) => {
13+
m! { $stmt }
14+
};
15+
}
16+
17+
m2! { let x = 1 }
18+
19+
fn main() {}

0 commit comments

Comments
 (0)