diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index f63064002c559..96caf0b8fd706 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -2929,12 +2929,26 @@ impl<'a> Parser<'a> {
// parentheses in what should have been a tuple pattern; return a
// suggestion-enhanced error here rather than choking on the comma later.
let comma_span = self.token.span;
+ // `EitherTupleOrPipe` is only ever used for the pattern of a `match` arm, which has to be
+ // followed by either a `=>` or an `if` guard. Take a snapshot so that we can rewind to the
+ // comma if neither of those follows the comma-separated list.
+ let snapshot = (rt == CommaRecoveryMode::EitherTupleOrPipe)
+ .then(|| self.create_snapshot_for_diagnostic());
self.bump();
if let Err(err) = self.skip_pat_list() {
// We didn't expect this to work anyway; we just wanted to advance to the
// end of the comma-sequence so we know the span to suggest parenthesizing.
err.cancel();
}
+ if let Some(snapshot) = snapshot
+ && self.token != token::FatArrow
+ && !self.token.is_keyword(kw::If)
+ {
+ // Neither parenthesising the patterns nor joining them with `|` would give the arm a
+ // body, so the comma is far more likely to stand in for a missing `=>
`.
+ self.restore_snapshot(snapshot);
+ return Ok(());
+ }
let seq_span = lo.to(self.prev_token.span);
let mut err = self.dcx().struct_span_err(comma_span, "unexpected `,` in pattern");
err.multipart_suggestion(
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 026fe8acb35cd..08e37c9d4c36b 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -73,6 +73,8 @@ pub enum RecoverColon {
#[derive(PartialEq, Copy, Clone)]
pub enum CommaRecoveryMode {
LikelyTuple,
+ /// Only used for the pattern of a `match` arm, which the recovery relies on: it gives up when
+ /// the comma-separated list is not followed by the `=>` or the guard of an arm.
EitherTupleOrPipe,
}
diff --git a/tests/ui/feature-gates/feature-gate-never_patterns.rs b/tests/ui/feature-gates/feature-gate-never_patterns.rs
index 2cb0b5a6679d5..cb7155a8ad8af 100644
--- a/tests/ui/feature-gates/feature-gate-never_patterns.rs
+++ b/tests/ui/feature-gates/feature-gate-never_patterns.rs
@@ -31,7 +31,7 @@ fn main() {
match Some(0) {
None => {}
Some(_),
- //~^ ERROR unexpected `,` in pattern
+ //~^ ERROR `match` arm with no body
}
match Some(0) {
None => {}
@@ -59,6 +59,7 @@ fn main() {
// Check that the gate operates even behind `cfg`.
match Some(0) {
+ //~^ ERROR non-exhaustive patterns: `Some(_)` not covered
None => {}
#[cfg(false)]
Some(_)
diff --git a/tests/ui/feature-gates/feature-gate-never_patterns.stderr b/tests/ui/feature-gates/feature-gate-never_patterns.stderr
index e655209924a08..ad0057e86e695 100644
--- a/tests/ui/feature-gates/feature-gate-never_patterns.stderr
+++ b/tests/ui/feature-gates/feature-gate-never_patterns.stderr
@@ -1,19 +1,3 @@
-error: unexpected `,` in pattern
- --> $DIR/feature-gate-never_patterns.rs:33:16
- |
-LL | Some(_),
- | ^
- |
-help: try adding parentheses to match on a tuple...
- |
-LL | (Some(_),)
- | + +
-help: ...or a vertical bar to match on alternatives
- |
-LL - Some(_),
-LL + Some(_) |
- |
-
error[E0658]: `!` patterns are experimental
--> $DIR/feature-gate-never_patterns.rs:8:24
|
@@ -54,6 +38,17 @@ LL | ! => {}
= help: add `#![feature(never_patterns)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+error: `match` arm with no body
+ --> $DIR/feature-gate-never_patterns.rs:33:9
+ |
+LL | Some(_),
+ | ^^^^^^^
+ |
+help: add a body after the pattern
+ |
+LL | Some(_) => { todo!() },
+ | ++++++++++++++
+
error: `match` arm with no body
--> $DIR/feature-gate-never_patterns.rs:38:9
|
@@ -108,7 +103,7 @@ LL | Err(!) if false,
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: `match` arm with no body
- --> $DIR/feature-gate-never_patterns.rs:64:9
+ --> $DIR/feature-gate-never_patterns.rs:65:9
|
LL | Some(_)
| ^^^^^^^
@@ -119,7 +114,7 @@ LL | Some(_) => { todo!() }
| ++++++++++++++
error: `match` arm with no body
- --> $DIR/feature-gate-never_patterns.rs:70:9
+ --> $DIR/feature-gate-never_patterns.rs:71:9
|
LL | Some(_) if false
| ^^^^^^^^^^^^^^^^
@@ -135,6 +130,25 @@ error: a guard on a never pattern will never be run
LL | Err(!) if false,
| ^^^^^ help: remove this guard
-error: aborting due to 13 previous errors
+error[E0004]: non-exhaustive patterns: `Some(_)` not covered
+ --> $DIR/feature-gate-never_patterns.rs:61:11
+ |
+LL | match Some(0) {
+ | ^^^^^^^ pattern `Some(_)` not covered
+ |
+note: `Option` defined here
+ --> $SRC_DIR/core/src/option.rs:LL:COL
+ ::: $SRC_DIR/core/src/option.rs:LL:COL
+ |
+ = note: not covered
+ = note: the matched value is of type `Option`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ None => {},
+LL + Some(_) => todo!()
+ |
+
+error: aborting due to 14 previous errors
-For more information about this error, try `rustc --explain E0658`.
+Some errors have detailed explanations: E0004, E0658.
+For more information about an error, try `rustc --explain E0004`.
diff --git a/tests/ui/parser/match-arm-without-body.rs b/tests/ui/parser/match-arm-without-body.rs
index 7fe5b6d253980..7711f7314496f 100644
--- a/tests/ui/parser/match-arm-without-body.rs
+++ b/tests/ui/parser/match-arm-without-body.rs
@@ -13,18 +13,26 @@ fn main() {
_ => {}
//~^ ERROR expected one of
}
+ match Some(false) {
+ Some(_),
+ //~^ ERROR `match` arm with no body
+ //~| HELP add a body after the pattern
+ }
+ // The comma is only taken for a missing body when parenthesising the patterns (or joining
+ // them with `|`) wouldn't give the arm a body either.
match Some(false) {
Some(_),
//~^ ERROR unexpected `,` in pattern
//~| HELP try adding parentheses to match on a tuple
//~| HELP or a vertical bar to match on alternative
+ _ => {}
}
match Some(false) {
Some(_),
//~^ ERROR unexpected `,` in pattern
//~| HELP try adding parentheses to match on a tuple
//~| HELP or a vertical bar to match on alternative
- _ => {}
+ None if true => {}
}
match Some(false) {
Some(_) if true
diff --git a/tests/ui/parser/match-arm-without-body.stderr b/tests/ui/parser/match-arm-without-body.stderr
index 59a323f2cc1cf..297875912047f 100644
--- a/tests/ui/parser/match-arm-without-body.stderr
+++ b/tests/ui/parser/match-arm-without-body.stderr
@@ -7,15 +7,19 @@ LL | _ => {}
| ^ unexpected token
error: unexpected `,` in pattern
- --> $DIR/match-arm-without-body.rs:17:16
+ --> $DIR/match-arm-without-body.rs:24:16
|
LL | Some(_),
| ^
|
help: try adding parentheses to match on a tuple...
|
-LL | (Some(_),)
- | + +
+LL ~ (Some(_),
+LL |
+LL |
+LL |
+LL ~ _) => {}
+ |
help: ...or a vertical bar to match on alternatives
|
LL - Some(_),
@@ -23,7 +27,7 @@ LL + Some(_) |
|
error: unexpected `,` in pattern
- --> $DIR/match-arm-without-body.rs:23:16
+ --> $DIR/match-arm-without-body.rs:31:16
|
LL | Some(_),
| ^
@@ -34,7 +38,7 @@ LL ~ (Some(_),
LL |
LL |
LL |
-LL ~ _) => {}
+LL ~ None) if true => {}
|
help: ...or a vertical bar to match on alternatives
|
@@ -43,7 +47,7 @@ LL + Some(_) |
|
error: expected one of `.`, `=>`, `?`, or an operator, found reserved identifier `_`
- --> $DIR/match-arm-without-body.rs:36:9
+ --> $DIR/match-arm-without-body.rs:44:9
|
LL | Some(_) if true
| - expected one of `.`, `=>`, `?`, or an operator
@@ -51,7 +55,7 @@ LL | _ => {}
| ^ unexpected token
error: expected `,` following `match` arm
- --> $DIR/match-arm-without-body.rs:66:15
+ --> $DIR/match-arm-without-body.rs:74:15
|
LL | pat!()
| ^
@@ -73,7 +77,18 @@ LL | Some(_) => { todo!() }
| ++++++++++++++
error: `match` arm with no body
- --> $DIR/match-arm-without-body.rs:30:9
+ --> $DIR/match-arm-without-body.rs:17:9
+ |
+LL | Some(_),
+ | ^^^^^^^
+ |
+help: add a body after the pattern
+ |
+LL | Some(_) => { todo!() },
+ | ++++++++++++++
+
+error: `match` arm with no body
+ --> $DIR/match-arm-without-body.rs:38:9
|
LL | Some(_) if true
| ^^^^^^^^^^^^^^^
@@ -84,7 +99,7 @@ LL | Some(_) if true => { todo!() }
| ++++++++++++++
error: `match` arm with no body
- --> $DIR/match-arm-without-body.rs:40:9
+ --> $DIR/match-arm-without-body.rs:48:9
|
LL | Some(_) if true,
| ^^^^^^^^^^^^^^^
@@ -95,7 +110,7 @@ LL | Some(_) if true => { todo!() },
| ++++++++++++++
error: `match` arm with no body
- --> $DIR/match-arm-without-body.rs:45:9
+ --> $DIR/match-arm-without-body.rs:53:9
|
LL | Some(_) if true,
| ^^^^^^^^^^^^^^^
@@ -106,7 +121,7 @@ LL | Some(_) if true => { todo!() },
| ++++++++++++++
error: `match` arm with no body
- --> $DIR/match-arm-without-body.rs:51:9
+ --> $DIR/match-arm-without-body.rs:59:9
|
LL | pat!()
| ^^^^^^
@@ -117,7 +132,7 @@ LL | pat!() => { todo!() }
| ++++++++++++++
error: `match` arm with no body
- --> $DIR/match-arm-without-body.rs:56:9
+ --> $DIR/match-arm-without-body.rs:64:9
|
LL | pat!(),
| ^^^^^^
@@ -128,7 +143,7 @@ LL | pat!() => { todo!() },
| ++++++++++++++
error: `match` arm with no body
- --> $DIR/match-arm-without-body.rs:61:9
+ --> $DIR/match-arm-without-body.rs:69:9
|
LL | pat!() if true,
| ^^^^^^^^^^^^^^
@@ -139,7 +154,7 @@ LL | pat!() if true => { todo!() },
| ++++++++++++++
error: `match` arm with no body
- --> $DIR/match-arm-without-body.rs:72:9
+ --> $DIR/match-arm-without-body.rs:80:9
|
LL | pat!(),
| ^^^^^^
@@ -149,5 +164,5 @@ help: add a body after the pattern
LL | pat!() => { todo!() },
| ++++++++++++++
-error: aborting due to 13 previous errors
+error: aborting due to 14 previous errors