From 4271383e1d7ccc5dcd95bd130182e722e9a8ca2a Mon Sep 17 00:00:00 2001 From: Veera Date: Sun, 5 May 2024 17:39:07 -0400 Subject: [PATCH 1/2] Update Tests --- ...ync-block-control-flow-static-semantics.rs | 4 +- ...block-control-flow-static-semantics.stderr | 8 +-- .../break-inside-coroutine-issue-124495.rs | 26 +++++++ ...break-inside-coroutine-issue-124495.stderr | 69 +++++++++++++++++++ 4 files changed, 101 insertions(+), 6 deletions(-) create mode 100644 tests/ui/coroutine/break-inside-coroutine-issue-124495.rs create mode 100644 tests/ui/coroutine/break-inside-coroutine-issue-124495.stderr diff --git a/tests/ui/async-await/async-block-control-flow-static-semantics.rs b/tests/ui/async-await/async-block-control-flow-static-semantics.rs index 0ef7cb7574a90..6e04c535cf11f 100644 --- a/tests/ui/async-await/async-block-control-flow-static-semantics.rs +++ b/tests/ui/async-await/async-block-control-flow-static-semantics.rs @@ -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 }; } } diff --git a/tests/ui/async-await/async-block-control-flow-static-semantics.stderr b/tests/ui/async-await/async-block-control-flow-static-semantics.stderr index c89671cc4811b..ce0d003f0142e 100644 --- a/tests/ui/async-await/async-block-control-flow-static-semantics.stderr +++ b/tests/ui/async-await/async-block-control-flow-static-semantics.stderr @@ -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 diff --git a/tests/ui/coroutine/break-inside-coroutine-issue-124495.rs b/tests/ui/coroutine/break-inside-coroutine-issue-124495.rs new file mode 100644 index 0000000000000..5d93db56722bf --- /dev/null +++ b/tests/ui/coroutine/break-inside-coroutine-issue-124495.rs @@ -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 +} diff --git a/tests/ui/coroutine/break-inside-coroutine-issue-124495.stderr b/tests/ui/coroutine/break-inside-coroutine-issue-124495.stderr new file mode 100644 index 0000000000000..a7f37fad35ea8 --- /dev/null +++ b/tests/ui/coroutine/break-inside-coroutine-issue-124495.stderr @@ -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`. From 21ccec0cc8a5ee253f021cdc81e05dbab43e59e1 Mon Sep 17 00:00:00 2001 From: Veera Date: Sun, 5 May 2024 18:14:23 -0400 Subject: [PATCH 2/2] Fix Error Messages for `break` Inside Coroutines 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`. --- compiler/rustc_passes/messages.ftl | 10 ++++----- compiler/rustc_passes/src/errors.rs | 10 +++++---- compiler/rustc_passes/src/loops.rs | 32 +++++++++++++++++++++-------- 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 9d58d301e2bc2..3deefcaa06c3d 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -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 diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 65cad82cc8c2b..b8586e7e974ad 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -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)] diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs index 4b5c4dfe991b7..3b20112eab7b9 100644 --- a/compiler/rustc_passes/src/loops.rs +++ b/compiler/rustc_passes/src/loops.rs @@ -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, }; @@ -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, @@ -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); @@ -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 });