about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-05-09 06:04:38 +0200
committerGitHub <noreply@github.com>2024-05-09 06:04:38 +0200
commit9b834d01e5face5a0869626f429bd68229c09afe (patch)
tree3a25b41184307a8807963efdbfa203018099763f
parentee9a9f84c599492eb9613292394d6d05d9f9e6ba (diff)
parent21ccec0cc8a5ee253f021cdc81e05dbab43e59e1 (diff)
downloadrust-9b834d01e5face5a0869626f429bd68229c09afe.tar.gz
rust-9b834d01e5face5a0869626f429bd68229c09afe.zip
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`.~~
-rw-r--r--compiler/rustc_passes/messages.ftl10
-rw-r--r--compiler/rustc_passes/src/errors.rs10
-rw-r--r--compiler/rustc_passes/src/loops.rs32
-rw-r--r--tests/ui/async-await/async-block-control-flow-static-semantics.rs4
-rw-r--r--tests/ui/async-await/async-block-control-flow-static-semantics.stderr8
-rw-r--r--tests/ui/coroutine/break-inside-coroutine-issue-124495.rs26
-rw-r--r--tests/ui/coroutine/break-inside-coroutine-issue-124495.stderr69
7 files changed, 135 insertions, 24 deletions
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`.