Skip to content

Commit 8574085

Browse files
committed
recover from for-else and while-else
1 parent 07c993e commit 8574085

11 files changed

+120
-0
lines changed

compiler/rustc_parse/locales/en-US.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@ parse_missing_in_in_for_loop = missing `in` in `for` loop
151151
parse_missing_expression_in_for_loop = missing expression to iterate on in `for` loop
152152
.suggestion = try adding an expression to the `for` loop
153153
154+
parse_loop_else = `{$loop_kind}...else` loops are not supported
155+
.note = consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run
156+
154157
parse_missing_comma_after_match_arm = expected `,` following `match` arm
155158
.suggestion = missing a comma here to end this `match` arm
156159

compiler/rustc_parse/src/errors.rs

+9
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,15 @@ pub(crate) struct MissingExpressionInForLoop {
451451
pub span: Span,
452452
}
453453

454+
#[derive(Diagnostic)]
455+
#[diag(parse_loop_else)]
456+
#[note]
457+
pub(crate) struct LoopElseNotSupported {
458+
#[primary_span]
459+
pub span: Span,
460+
pub loop_kind: &'static str,
461+
}
462+
454463
#[derive(Diagnostic)]
455464
#[diag(parse_missing_comma_after_match_arm)]
456465
pub(crate) struct MissingCommaAfterMatchArm {

compiler/rustc_parse/src/parser/expr.rs

+20
Original file line numberDiff line numberDiff line change
@@ -2491,9 +2491,26 @@ impl<'a> Parser<'a> {
24912491
let (attrs, loop_block) = self.parse_inner_attrs_and_block()?;
24922492

24932493
let kind = ExprKind::ForLoop(pat, expr, loop_block, opt_label);
2494+
2495+
self.recover_loop_else("for")?;
2496+
24942497
Ok(self.mk_expr_with_attrs(lo.to(self.prev_token.span), kind, attrs))
24952498
}
24962499

2500+
/// Recovers from an `else` clause after a loop (`for...else`, `while...else`)
2501+
fn recover_loop_else(&mut self, loop_kind: &'static str) -> PResult<'a, ()> {
2502+
if self.token.is_keyword(kw::Else) && self.may_recover() {
2503+
let else_span = self.token.span;
2504+
self.bump();
2505+
let else_clause = self.parse_else_expr()?;
2506+
self.sess.emit_err(errors::LoopElseNotSupported {
2507+
span: else_span.to(else_clause.span),
2508+
loop_kind,
2509+
});
2510+
}
2511+
Ok(())
2512+
}
2513+
24972514
fn error_missing_in_for_loop(&mut self) {
24982515
let (span, sub): (_, fn(_) -> _) = if self.token.is_ident_named(sym::of) {
24992516
// Possibly using JS syntax (#75311).
@@ -2518,6 +2535,9 @@ impl<'a> Parser<'a> {
25182535
err.span_label(cond.span, "this `while` condition successfully parsed");
25192536
err
25202537
})?;
2538+
2539+
self.recover_loop_else("while")?;
2540+
25212541
Ok(self.mk_expr_with_attrs(
25222542
lo.to(self.prev_token.span),
25232543
ExprKind::While(cond, body, opt_label),

tests/ui/for/for-else-err.rs

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
fn main() {
2+
for _ in 0..1 {
3+
4+
} else {
5+
//~^ ERROR `for...else` loops are not supported
6+
//~| NOTE consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run
7+
}
8+
}

tests/ui/for/for-else-err.stderr

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: `for...else` loops are not supported
2+
--> $DIR/for-else-err.rs:4:7
3+
|
4+
LL | } else {
5+
| _______^
6+
LL | |
7+
LL | |
8+
LL | | }
9+
| |_____^
10+
|
11+
= note: consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run
12+
13+
error: aborting due to previous error
14+

tests/ui/for/for-else-let-else-err.rs

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
fn main() {
2+
let _ = for _ in 0..1 {
3+
4+
} else {
5+
//~^ ERROR `for...else` loops are not supported
6+
//~| NOTE consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run
7+
};
8+
}
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: `for...else` loops are not supported
2+
--> $DIR/for-else-let-else-err.rs:4:7
3+
|
4+
LL | } else {
5+
| _______^
6+
LL | |
7+
LL | |
8+
LL | | };
9+
| |_____^
10+
|
11+
= note: consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run
12+
13+
error: aborting due to previous error
14+

tests/ui/while/while-else-err.rs

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
fn main() {
2+
while false {
3+
4+
} else {
5+
//~^ ERROR `while...else` loops are not supported
6+
//~| NOTE consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run
7+
};
8+
}

tests/ui/while/while-else-err.stderr

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: `while...else` loops are not supported
2+
--> $DIR/while-else-err.rs:4:7
3+
|
4+
LL | } else {
5+
| _______^
6+
LL | |
7+
LL | |
8+
LL | | };
9+
| |_____^
10+
|
11+
= note: consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run
12+
13+
error: aborting due to previous error
14+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
fn main() {
2+
let _ = while false {
3+
4+
} else {
5+
//~^ ERROR `while...else` loops are not supported
6+
//~| NOTE consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run
7+
};
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: `while...else` loops are not supported
2+
--> $DIR/while-else-let-else-err.rs:4:7
3+
|
4+
LL | } else {
5+
| _______^
6+
LL | |
7+
LL | |
8+
LL | | };
9+
| |_____^
10+
|
11+
= note: consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run
12+
13+
error: aborting due to previous error
14+

0 commit comments

Comments
 (0)