diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2024-03-05 06:40:30 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-03-05 06:40:30 +0100 |
| commit | 94bb2d2a974ece985dfea0da0622d4f987505dd3 (patch) | |
| tree | 74bf2532698d90d3089cbca56caf93184690cc45 | |
| parent | 72651306b3e6d7308bb35897501940cd9b97baff (diff) | |
| parent | e0a726ca4bc08d1009803a6c819f701173810761 (diff) | |
| download | rust-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.rs | 52 | ||||
| -rw-r--r-- | tests/ui/async-await/async-outside-of-await-issue-121096.rs | 9 | ||||
| -rw-r--r-- | tests/ui/async-await/async-outside-of-await-issue-121096.stderr | 12 |
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`. |
