about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-03-05 06:40:30 +0100
committerGitHub <noreply@github.com>2024-03-05 06:40:30 +0100
commit94bb2d2a974ece985dfea0da0622d4f987505dd3 (patch)
tree74bf2532698d90d3089cbca56caf93184690cc45
parent72651306b3e6d7308bb35897501940cd9b97baff (diff)
parente0a726ca4bc08d1009803a6c819f701173810761 (diff)
downloadrust-94bb2d2a974ece985dfea0da0622d4f987505dd3.tar.gz
rust-94bb2d2a974ece985dfea0da0622d4f987505dd3.zip
Rollup merge of #121664 - compiler-errors:adjust-error-yield-lowering, r=spastorino
Adjust error `yield`/`await` lowering

Adjust the lowering of `yield`/`await` outside of their correct scopes so that we no longer make orpan HIR exprs.

Previously, `yield EXPR` would be lowered directly to `hir::TyKind::Error` (which I'll call `<error>`) which means that `EXPR` was not present in the HIR, but now we lower it to `{ EXPR; <error> }` so that `EXPR` is not orphaned.

Fixes #121096
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs52
-rw-r--r--tests/ui/async-await/async-outside-of-await-issue-121096.rs9
-rw-r--r--tests/ui/async-await/async-outside-of-await-issue-121096.stderr12
3 files changed, 64 insertions, 9 deletions
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 0b1cb124080..85b599902b9 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -760,10 +760,28 @@ impl<'hir> LoweringContext<'_, 'hir> {
             Some(hir::CoroutineKind::Coroutine(_))
             | Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _))
             | None => {
-                return hir::ExprKind::Err(self.dcx().emit_err(AwaitOnlyInAsyncFnAndBlocks {
-                    await_kw_span,
-                    item_span: self.current_item,
-                }));
+                // Lower to a block `{ EXPR; <error> }` so that the awaited expr
+                // is not accidentally orphaned.
+                let stmt_id = self.next_id();
+                let expr_err = self.expr(
+                    expr.span,
+                    hir::ExprKind::Err(self.dcx().emit_err(AwaitOnlyInAsyncFnAndBlocks {
+                        await_kw_span,
+                        item_span: self.current_item,
+                    })),
+                );
+                return hir::ExprKind::Block(
+                    self.block_all(
+                        expr.span,
+                        arena_vec![self; hir::Stmt {
+                            hir_id: stmt_id,
+                            kind: hir::StmtKind::Semi(expr),
+                            span: expr.span,
+                        }],
+                        Some(self.arena.alloc(expr_err)),
+                    ),
+                    None,
+                );
             }
         };
 
@@ -1496,12 +1514,31 @@ impl<'hir> LoweringContext<'_, 'hir> {
     }
 
     fn lower_expr_yield(&mut self, span: Span, opt_expr: Option<&Expr>) -> hir::ExprKind<'hir> {
+        let yielded =
+            opt_expr.as_ref().map(|x| self.lower_expr(x)).unwrap_or_else(|| self.expr_unit(span));
+
         let is_async_gen = match self.coroutine_kind {
             Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) => false,
             Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => true,
             Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => {
-                return hir::ExprKind::Err(
-                    self.dcx().emit_err(AsyncCoroutinesNotSupported { span }),
+                // Lower to a block `{ EXPR; <error> }` so that the awaited expr
+                // is not accidentally orphaned.
+                let stmt_id = self.next_id();
+                let expr_err = self.expr(
+                    yielded.span,
+                    hir::ExprKind::Err(self.dcx().emit_err(AsyncCoroutinesNotSupported { span })),
+                );
+                return hir::ExprKind::Block(
+                    self.block_all(
+                        yielded.span,
+                        arena_vec![self; hir::Stmt {
+                            hir_id: stmt_id,
+                            kind: hir::StmtKind::Semi(yielded),
+                            span: yielded.span,
+                        }],
+                        Some(self.arena.alloc(expr_err)),
+                    ),
+                    None,
                 );
             }
             Some(hir::CoroutineKind::Coroutine(_)) => {
@@ -1531,9 +1568,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
             }
         };
 
-        let yielded =
-            opt_expr.as_ref().map(|x| self.lower_expr(x)).unwrap_or_else(|| self.expr_unit(span));
-
         if is_async_gen {
             // `yield $expr` is transformed into `task_context = yield async_gen_ready($expr)`.
             // This ensures that we store our resumed `ResumeContext` correctly, and also that
diff --git a/tests/ui/async-await/async-outside-of-await-issue-121096.rs b/tests/ui/async-await/async-outside-of-await-issue-121096.rs
new file mode 100644
index 00000000000..e3999035ef9
--- /dev/null
+++ b/tests/ui/async-await/async-outside-of-await-issue-121096.rs
@@ -0,0 +1,9 @@
+//@ edition:2021
+
+fn main() {
+    async {
+        use std::ops::Add;
+        let _ = 1.add(3);
+    }.await
+    //~^ ERROR `await` is only allowed inside `async` functions and blocks
+}
diff --git a/tests/ui/async-await/async-outside-of-await-issue-121096.stderr b/tests/ui/async-await/async-outside-of-await-issue-121096.stderr
new file mode 100644
index 00000000000..b0677a83864
--- /dev/null
+++ b/tests/ui/async-await/async-outside-of-await-issue-121096.stderr
@@ -0,0 +1,12 @@
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+  --> $DIR/async-outside-of-await-issue-121096.rs:7:7
+   |
+LL | fn main() {
+   |    ---- this is not `async`
+...
+LL |     }.await
+   |       ^^^^^ only allowed inside `async` functions and blocks
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0728`.