Skip to content

Commit 9b834d0

Browse files
authored
Rollup merge of #124777 - veera-sivarajan:bugfix-124495-identify-gen-block, r=compiler-errors
Fix Error Messages for `break` Inside Coroutines Fixes #124495 Previously, `break` inside `gen` blocks and functions were incorrectly identified to be enclosed by a closure. This PR fixes it by displaying an appropriate error message for async blocks, async closures, async functions, gen blocks, gen closures, gen functions, async gen blocks, async gen closures and async gen functions. Note: gen closure and async gen closure are not supported by the compiler yet but I have added an error message here assuming that they might be implemented in the future. ~~Also, fixes grammar in a few places by replacing `inside of a $coroutine` with `inside a $coroutine`.~~
2 parents ee9a9f8 + 21ccec0 commit 9b834d0

7 files changed

+135
-24
lines changed

compiler/rustc_passes/messages.ftl

+5-5
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,16 @@ passes_attr_only_in_functions =
5252
passes_both_ffi_const_and_pure =
5353
`#[ffi_const]` function cannot be `#[ffi_pure]`
5454
55-
passes_break_inside_async_block =
56-
`{$name}` inside of an `async` block
57-
.label = cannot `{$name}` inside of an `async` block
58-
.async_block_label = enclosing `async` block
59-
6055
passes_break_inside_closure =
6156
`{$name}` inside of a closure
6257
.label = cannot `{$name}` inside of a closure
6358
.closure_label = enclosing closure
6459
60+
passes_break_inside_coroutine =
61+
`{$name}` inside `{$kind}` {$source}
62+
.label = cannot `{$name}` inside `{$kind}` {$source}
63+
.coroutine_label = enclosing `{$kind}` {$source}
64+
6565
passes_break_non_loop =
6666
`break` with value from a `{$kind}` loop
6767
.label = can only break with a value inside `loop` or breakable block

compiler/rustc_passes/src/errors.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -1086,14 +1086,16 @@ pub struct BreakInsideClosure<'a> {
10861086
}
10871087

10881088
#[derive(Diagnostic)]
1089-
#[diag(passes_break_inside_async_block, code = E0267)]
1090-
pub struct BreakInsideAsyncBlock<'a> {
1089+
#[diag(passes_break_inside_coroutine, code = E0267)]
1090+
pub struct BreakInsideCoroutine<'a> {
10911091
#[primary_span]
10921092
#[label]
10931093
pub span: Span,
1094-
#[label(passes_async_block_label)]
1095-
pub closure_span: Span,
1094+
#[label(passes_coroutine_label)]
1095+
pub coroutine_span: Span,
10961096
pub name: &'a str,
1097+
pub kind: &'a str,
1098+
pub source: &'a str,
10971099
}
10981100

10991101
#[derive(Diagnostic)]

compiler/rustc_passes/src/loops.rs

+23-9
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc_span::hygiene::DesugaringKind;
1313
use rustc_span::{BytePos, Span};
1414

1515
use crate::errors::{
16-
BreakInsideAsyncBlock, BreakInsideClosure, BreakNonLoop, ContinueLabeledBlock, OutsideLoop,
16+
BreakInsideClosure, BreakInsideCoroutine, BreakNonLoop, ContinueLabeledBlock, OutsideLoop,
1717
OutsideLoopSuggestion, UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock,
1818
};
1919

@@ -23,7 +23,7 @@ enum Context {
2323
Fn,
2424
Loop(hir::LoopSource),
2525
Closure(Span),
26-
AsyncClosure(Span),
26+
Coroutine { coroutine_span: Span, kind: hir::CoroutineDesugaring, source: hir::CoroutineSource },
2727
UnlabeledBlock(Span),
2828
LabeledBlock,
2929
Constant,
@@ -89,12 +89,10 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
8989
hir::ExprKind::Closure(&hir::Closure {
9090
ref fn_decl, body, fn_decl_span, kind, ..
9191
}) => {
92-
// FIXME(coroutines): This doesn't handle coroutines correctly
9392
let cx = match kind {
94-
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
95-
hir::CoroutineDesugaring::Async,
96-
hir::CoroutineSource::Block,
97-
)) => AsyncClosure(fn_decl_span),
93+
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(kind, source)) => {
94+
Coroutine { coroutine_span: fn_decl_span, kind, source }
95+
}
9896
_ => Closure(fn_decl_span),
9997
};
10098
self.visit_fn_decl(fn_decl);
@@ -227,8 +225,24 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
227225
Closure(closure_span) => {
228226
self.sess.dcx().emit_err(BreakInsideClosure { span, closure_span, name });
229227
}
230-
AsyncClosure(closure_span) => {
231-
self.sess.dcx().emit_err(BreakInsideAsyncBlock { span, closure_span, name });
228+
Coroutine { coroutine_span, kind, source } => {
229+
let kind = match kind {
230+
hir::CoroutineDesugaring::Async => "async",
231+
hir::CoroutineDesugaring::Gen => "gen",
232+
hir::CoroutineDesugaring::AsyncGen => "async gen",
233+
};
234+
let source = match source {
235+
hir::CoroutineSource::Block => "block",
236+
hir::CoroutineSource::Closure => "closure",
237+
hir::CoroutineSource::Fn => "function",
238+
};
239+
self.sess.dcx().emit_err(BreakInsideCoroutine {
240+
span,
241+
coroutine_span,
242+
name,
243+
kind,
244+
source,
245+
});
232246
}
233247
UnlabeledBlock(block_span) if is_break && block_span.eq_ctxt(break_span) => {
234248
let suggestion = Some(OutsideLoopSuggestion { block_span, break_span });

tests/ui/async-await/async-block-control-flow-static-semantics.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,14 @@ async fn return_targets_async_block_not_async_fn() -> u8 {
2929

3030
fn no_break_in_async_block() {
3131
async {
32-
break 0u8; //~ ERROR `break` inside of an `async` block
32+
break 0u8; //~ ERROR `break` inside `async` block
3333
};
3434
}
3535

3636
fn no_break_in_async_block_even_with_outer_loop() {
3737
loop {
3838
async {
39-
break 0u8; //~ ERROR `break` inside of an `async` block
39+
break 0u8; //~ ERROR `break` inside `async` block
4040
};
4141
}
4242
}

tests/ui/async-await/async-block-control-flow-static-semantics.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
error[E0267]: `break` inside of an `async` block
1+
error[E0267]: `break` inside `async` block
22
--> $DIR/async-block-control-flow-static-semantics.rs:32:9
33
|
44
LL | / async {
55
LL | | break 0u8;
6-
| | ^^^^^^^^^ cannot `break` inside of an `async` block
6+
| | ^^^^^^^^^ cannot `break` inside `async` block
77
LL | | };
88
| |_____- enclosing `async` block
99

10-
error[E0267]: `break` inside of an `async` block
10+
error[E0267]: `break` inside `async` block
1111
--> $DIR/async-block-control-flow-static-semantics.rs:39:13
1212
|
1313
LL | / async {
1414
LL | | break 0u8;
15-
| | ^^^^^^^^^ cannot `break` inside of an `async` block
15+
| | ^^^^^^^^^ cannot `break` inside `async` block
1616
LL | | };
1717
| |_________- enclosing `async` block
1818

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//@ edition: 2024
2+
//@ compile-flags: -Z unstable-options
3+
4+
#![feature(gen_blocks)]
5+
#![feature(async_closure)]
6+
7+
async fn async_fn() {
8+
break; //~ ERROR `break` inside `async` function
9+
}
10+
11+
gen fn gen_fn() {
12+
break; //~ ERROR `break` inside `gen` function
13+
}
14+
15+
async gen fn async_gen_fn() {
16+
break; //~ ERROR `break` inside `async gen` function
17+
}
18+
19+
fn main() {
20+
let _ = async { break; }; //~ ERROR `break` inside `async` block
21+
let _ = async || { break; }; //~ ERROR `break` inside `async` closure
22+
23+
let _ = gen { break; }; //~ ERROR `break` inside `gen` block
24+
25+
let _ = async gen { break; }; //~ ERROR `break` inside `async gen` block
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
error[E0267]: `break` inside `async` function
2+
--> $DIR/break-inside-coroutine-issue-124495.rs:8:5
3+
|
4+
LL | async fn async_fn() {
5+
| _____________________-
6+
LL | | break;
7+
| | ^^^^^ cannot `break` inside `async` function
8+
LL | | }
9+
| |_- enclosing `async` function
10+
11+
error[E0267]: `break` inside `gen` function
12+
--> $DIR/break-inside-coroutine-issue-124495.rs:12:5
13+
|
14+
LL | gen fn gen_fn() {
15+
| _________________-
16+
LL | | break;
17+
| | ^^^^^ cannot `break` inside `gen` function
18+
LL | | }
19+
| |_- enclosing `gen` function
20+
21+
error[E0267]: `break` inside `async gen` function
22+
--> $DIR/break-inside-coroutine-issue-124495.rs:16:5
23+
|
24+
LL | async gen fn async_gen_fn() {
25+
| _____________________________-
26+
LL | | break;
27+
| | ^^^^^ cannot `break` inside `async gen` function
28+
LL | | }
29+
| |_- enclosing `async gen` function
30+
31+
error[E0267]: `break` inside `async` block
32+
--> $DIR/break-inside-coroutine-issue-124495.rs:20:21
33+
|
34+
LL | let _ = async { break; };
35+
| --------^^^^^---
36+
| | |
37+
| | cannot `break` inside `async` block
38+
| enclosing `async` block
39+
40+
error[E0267]: `break` inside `async` closure
41+
--> $DIR/break-inside-coroutine-issue-124495.rs:21:24
42+
|
43+
LL | let _ = async || { break; };
44+
| --^^^^^---
45+
| | |
46+
| | cannot `break` inside `async` closure
47+
| enclosing `async` closure
48+
49+
error[E0267]: `break` inside `gen` block
50+
--> $DIR/break-inside-coroutine-issue-124495.rs:23:19
51+
|
52+
LL | let _ = gen { break; };
53+
| ------^^^^^---
54+
| | |
55+
| | cannot `break` inside `gen` block
56+
| enclosing `gen` block
57+
58+
error[E0267]: `break` inside `async gen` block
59+
--> $DIR/break-inside-coroutine-issue-124495.rs:25:25
60+
|
61+
LL | let _ = async gen { break; };
62+
| ------------^^^^^---
63+
| | |
64+
| | cannot `break` inside `async gen` block
65+
| enclosing `async gen` block
66+
67+
error: aborting due to 7 previous errors
68+
69+
For more information about this error, try `rustc --explain E0267`.

0 commit comments

Comments
 (0)