diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 9d58d301e2b..3deefcaa06c 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 65cad82cc8c..b8586e7e974 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 4b5c4dfe991..3b20112eab7 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 }); 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 0ef7cb7574a..6e04c535cf1 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 c89671cc481..ce0d003f014 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 00000000000..5d93db56722 --- /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 00000000000..a7f37fad35e --- /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`.