Skip to content

Commit

Permalink
Rollup merge of #124777 - veera-sivarajan:bugfix-124495-identify-gen-…
Browse files Browse the repository at this point in the history
…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`.~~
  • Loading branch information
matthiaskrgr authored May 9, 2024
2 parents ee9a9f8 + 21ccec0 commit 9b834d0
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 24 deletions.
10 changes: 5 additions & 5 deletions compiler/rustc_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,16 @@ passes_attr_only_in_functions =
passes_both_ffi_const_and_pure =
`#[ffi_const]` function cannot be `#[ffi_pure]`
passes_break_inside_async_block =
`{$name}` inside of an `async` block
.label = cannot `{$name}` inside of an `async` block
.async_block_label = enclosing `async` block
passes_break_inside_closure =
`{$name}` inside of a closure
.label = cannot `{$name}` inside of a closure
.closure_label = enclosing closure
passes_break_inside_coroutine =
`{$name}` inside `{$kind}` {$source}
.label = cannot `{$name}` inside `{$kind}` {$source}
.coroutine_label = enclosing `{$kind}` {$source}
passes_break_non_loop =
`break` with value from a `{$kind}` loop
.label = can only break with a value inside `loop` or breakable block
Expand Down
10 changes: 6 additions & 4 deletions compiler/rustc_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1086,14 +1086,16 @@ pub struct BreakInsideClosure<'a> {
}

#[derive(Diagnostic)]
#[diag(passes_break_inside_async_block, code = E0267)]
pub struct BreakInsideAsyncBlock<'a> {
#[diag(passes_break_inside_coroutine, code = E0267)]
pub struct BreakInsideCoroutine<'a> {
#[primary_span]
#[label]
pub span: Span,
#[label(passes_async_block_label)]
pub closure_span: Span,
#[label(passes_coroutine_label)]
pub coroutine_span: Span,
pub name: &'a str,
pub kind: &'a str,
pub source: &'a str,
}

#[derive(Diagnostic)]
Expand Down
32 changes: 23 additions & 9 deletions compiler/rustc_passes/src/loops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use rustc_span::hygiene::DesugaringKind;
use rustc_span::{BytePos, Span};

use crate::errors::{
BreakInsideAsyncBlock, BreakInsideClosure, BreakNonLoop, ContinueLabeledBlock, OutsideLoop,
BreakInsideClosure, BreakInsideCoroutine, BreakNonLoop, ContinueLabeledBlock, OutsideLoop,
OutsideLoopSuggestion, UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock,
};

Expand All @@ -23,7 +23,7 @@ enum Context {
Fn,
Loop(hir::LoopSource),
Closure(Span),
AsyncClosure(Span),
Coroutine { coroutine_span: Span, kind: hir::CoroutineDesugaring, source: hir::CoroutineSource },
UnlabeledBlock(Span),
LabeledBlock,
Constant,
Expand Down Expand Up @@ -89,12 +89,10 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
hir::ExprKind::Closure(&hir::Closure {
ref fn_decl, body, fn_decl_span, kind, ..
}) => {
// FIXME(coroutines): This doesn't handle coroutines correctly
let cx = match kind {
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
hir::CoroutineDesugaring::Async,
hir::CoroutineSource::Block,
)) => AsyncClosure(fn_decl_span),
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(kind, source)) => {
Coroutine { coroutine_span: fn_decl_span, kind, source }
}
_ => Closure(fn_decl_span),
};
self.visit_fn_decl(fn_decl);
Expand Down Expand Up @@ -227,8 +225,24 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
Closure(closure_span) => {
self.sess.dcx().emit_err(BreakInsideClosure { span, closure_span, name });
}
AsyncClosure(closure_span) => {
self.sess.dcx().emit_err(BreakInsideAsyncBlock { span, closure_span, name });
Coroutine { coroutine_span, kind, source } => {
let kind = match kind {
hir::CoroutineDesugaring::Async => "async",
hir::CoroutineDesugaring::Gen => "gen",
hir::CoroutineDesugaring::AsyncGen => "async gen",
};
let source = match source {
hir::CoroutineSource::Block => "block",
hir::CoroutineSource::Closure => "closure",
hir::CoroutineSource::Fn => "function",
};
self.sess.dcx().emit_err(BreakInsideCoroutine {
span,
coroutine_span,
name,
kind,
source,
});
}
UnlabeledBlock(block_span) if is_break && block_span.eq_ctxt(break_span) => {
let suggestion = Some(OutsideLoopSuggestion { block_span, break_span });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ async fn return_targets_async_block_not_async_fn() -> u8 {

fn no_break_in_async_block() {
async {
break 0u8; //~ ERROR `break` inside of an `async` block
break 0u8; //~ ERROR `break` inside `async` block
};
}

fn no_break_in_async_block_even_with_outer_loop() {
loop {
async {
break 0u8; //~ ERROR `break` inside of an `async` block
break 0u8; //~ ERROR `break` inside `async` block
};
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
error[E0267]: `break` inside of an `async` block
error[E0267]: `break` inside `async` block
--> $DIR/async-block-control-flow-static-semantics.rs:32:9
|
LL | / async {
LL | | break 0u8;
| | ^^^^^^^^^ cannot `break` inside of an `async` block
| | ^^^^^^^^^ cannot `break` inside `async` block
LL | | };
| |_____- enclosing `async` block

error[E0267]: `break` inside of an `async` block
error[E0267]: `break` inside `async` block
--> $DIR/async-block-control-flow-static-semantics.rs:39:13
|
LL | / async {
LL | | break 0u8;
| | ^^^^^^^^^ cannot `break` inside of an `async` block
| | ^^^^^^^^^ cannot `break` inside `async` block
LL | | };
| |_________- enclosing `async` block

Expand Down
26 changes: 26 additions & 0 deletions tests/ui/coroutine/break-inside-coroutine-issue-124495.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//@ edition: 2024
//@ compile-flags: -Z unstable-options

#![feature(gen_blocks)]
#![feature(async_closure)]

async fn async_fn() {
break; //~ ERROR `break` inside `async` function
}

gen fn gen_fn() {
break; //~ ERROR `break` inside `gen` function
}

async gen fn async_gen_fn() {
break; //~ ERROR `break` inside `async gen` function
}

fn main() {
let _ = async { break; }; //~ ERROR `break` inside `async` block
let _ = async || { break; }; //~ ERROR `break` inside `async` closure

let _ = gen { break; }; //~ ERROR `break` inside `gen` block

let _ = async gen { break; }; //~ ERROR `break` inside `async gen` block
}
69 changes: 69 additions & 0 deletions tests/ui/coroutine/break-inside-coroutine-issue-124495.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
error[E0267]: `break` inside `async` function
--> $DIR/break-inside-coroutine-issue-124495.rs:8:5
|
LL | async fn async_fn() {
| _____________________-
LL | | break;
| | ^^^^^ cannot `break` inside `async` function
LL | | }
| |_- enclosing `async` function

error[E0267]: `break` inside `gen` function
--> $DIR/break-inside-coroutine-issue-124495.rs:12:5
|
LL | gen fn gen_fn() {
| _________________-
LL | | break;
| | ^^^^^ cannot `break` inside `gen` function
LL | | }
| |_- enclosing `gen` function

error[E0267]: `break` inside `async gen` function
--> $DIR/break-inside-coroutine-issue-124495.rs:16:5
|
LL | async gen fn async_gen_fn() {
| _____________________________-
LL | | break;
| | ^^^^^ cannot `break` inside `async gen` function
LL | | }
| |_- enclosing `async gen` function

error[E0267]: `break` inside `async` block
--> $DIR/break-inside-coroutine-issue-124495.rs:20:21
|
LL | let _ = async { break; };
| --------^^^^^---
| | |
| | cannot `break` inside `async` block
| enclosing `async` block

error[E0267]: `break` inside `async` closure
--> $DIR/break-inside-coroutine-issue-124495.rs:21:24
|
LL | let _ = async || { break; };
| --^^^^^---
| | |
| | cannot `break` inside `async` closure
| enclosing `async` closure

error[E0267]: `break` inside `gen` block
--> $DIR/break-inside-coroutine-issue-124495.rs:23:19
|
LL | let _ = gen { break; };
| ------^^^^^---
| | |
| | cannot `break` inside `gen` block
| enclosing `gen` block

error[E0267]: `break` inside `async gen` block
--> $DIR/break-inside-coroutine-issue-124495.rs:25:25
|
LL | let _ = async gen { break; };
| ------------^^^^^---
| | |
| | cannot `break` inside `async gen` block
| enclosing `async gen` block

error: aborting due to 7 previous errors

For more information about this error, try `rustc --explain E0267`.

0 comments on commit 9b834d0

Please sign in to comment.