From f999a90b7b7118a73bf7aacb18e918edf1849441 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 19 Aug 2025 13:22:13 +0000 Subject: [PATCH] Reject async closures in AST lowering --- compiler/rustc_ast_lowering/messages.ftl | 2 +- compiler/rustc_ast_lowering/src/errors.rs | 3 ++- compiler/rustc_ast_lowering/src/expr.rs | 15 ++++++++++++++- tests/ui/unpretty/exhaustive.expanded.stdout | 6 ++++-- tests/ui/unpretty/exhaustive.hir.stderr | 14 +++++++++++++- tests/ui/unpretty/exhaustive.hir.stdout | 12 ++++++++++-- tests/ui/unpretty/exhaustive.rs | 4 ++-- 7 files changed, 46 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index 370b15d2871a9..473ea39655723 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -48,7 +48,7 @@ ast_lowering_bad_return_type_notation_position = return type notation not allowe ast_lowering_clobber_abi_not_supported = `clobber_abi` is not supported on this target -ast_lowering_closure_cannot_be_static = closures cannot be static +ast_lowering_closure_cannot_be_static = {$modifier}closures cannot be static ast_lowering_coroutine_too_many_parameters = too many parameters for a coroutine (expected 0 or 1 parameters) diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 83f3a976e83f7..e966e909eb623 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -126,9 +126,10 @@ pub(crate) struct CoroutineTooManyParameters { #[derive(Diagnostic)] #[diag(ast_lowering_closure_cannot_be_static, code = E0697)] -pub(crate) struct ClosureCannotBeStatic { +pub(crate) struct ClosureCannotBeStatic<'a> { #[primary_span] pub fn_decl_span: Span, + pub modifier: &'a str, } #[derive(Diagnostic)] diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index cbd17d66b7548..cf4f6252ddd69 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -225,6 +225,7 @@ impl<'hir> LoweringContext<'_, 'hir> { e.id, expr_hir_id, *coroutine_kind, + *movability, fn_decl, body, *fn_decl_span, @@ -1125,7 +1126,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } None => { if movability == Movability::Static { - self.dcx().emit_err(ClosureCannotBeStatic { fn_decl_span }); + self.dcx().emit_err(ClosureCannotBeStatic { modifier: "", fn_decl_span }); } hir::ClosureKind::Closure } @@ -1154,6 +1155,7 @@ impl<'hir> LoweringContext<'_, 'hir> { closure_id: NodeId, closure_hir_id: HirId, coroutine_kind: CoroutineKind, + movability: Movability, decl: &FnDecl, body: &Expr, fn_decl_span: Span, @@ -1170,6 +1172,17 @@ impl<'hir> LoweringContext<'_, 'hir> { } }; + // Movability doesn't make sense on an async/gen closure, so reject outright. + match movability { + Movability::Static => { + self.dcx().emit_err(ClosureCannotBeStatic { + modifier: &format!("{coroutine_desugaring:#}"), + fn_decl_span, + }); + } + Movability::Movable => {} + } + let body = self.with_new_scopes(fn_decl_span, |this| { let inner_decl = FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) }; diff --git a/tests/ui/unpretty/exhaustive.expanded.stdout b/tests/ui/unpretty/exhaustive.expanded.stdout index 0327ad5f92bb3..40b6bba9cc6a9 100644 --- a/tests/ui/unpretty/exhaustive.expanded.stdout +++ b/tests/ui/unpretty/exhaustive.expanded.stdout @@ -185,8 +185,10 @@ mod expressions { async move || value; static || value; static move || value; - (static async || value); - (static async move || value); + (static async || + value); + (static async move || + value); || -> u8 { value }; 1 + || {}; } diff --git a/tests/ui/unpretty/exhaustive.hir.stderr b/tests/ui/unpretty/exhaustive.hir.stderr index aa411ce81eb4c..b31ea833f118b 100644 --- a/tests/ui/unpretty/exhaustive.hir.stderr +++ b/tests/ui/unpretty/exhaustive.hir.stderr @@ -10,6 +10,18 @@ error[E0697]: closures cannot be static LL | static move || value; | ^^^^^^^^^^^^^^ +error[E0697]: `async` closures cannot be static + --> $DIR/exhaustive.rs:211:10 + | +LL | (static async || value); + | ^^^^^^^^^^^^^^^ + +error[E0697]: `async` closures cannot be static + --> $DIR/exhaustive.rs:212:10 + | +LL | (static async move || value); + | ^^^^^^^^^^^^^^^^^^^^ + error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/exhaustive.rs:239:13 | @@ -166,7 +178,7 @@ LL | let _: impl for<'a> Send; = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 20 previous errors +error: aborting due to 22 previous errors Some errors have detailed explanations: E0214, E0562, E0697, E0703, E0728. For more information about an error, try `rustc --explain E0214`. diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout index 68356a33c9e60..2ab2a6118f38d 100644 --- a/tests/ui/unpretty/exhaustive.hir.stdout +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -215,8 +215,16 @@ mod expressions { move || |mut _task_context: ResumeTy| { { let _t = value; _t } }; || value; move || value; - || |mut _task_context: ResumeTy| { { let _t = value; _t } }; - move || |mut _task_context: ResumeTy| { { let _t = value; _t } }; + || + |mut _task_context: ResumeTy| + { + { let _t = value; _t } + }; + move || + |mut _task_context: ResumeTy| + { + { let _t = value; _t } + }; || -> u8 { value }; 1 + (|| { }); } diff --git a/tests/ui/unpretty/exhaustive.rs b/tests/ui/unpretty/exhaustive.rs index b19d4f9fe2c0c..a593c42f3850c 100644 --- a/tests/ui/unpretty/exhaustive.rs +++ b/tests/ui/unpretty/exhaustive.rs @@ -208,8 +208,8 @@ mod expressions { async move || value; static || value; //[hir]~ ERROR closures cannot be static static move || value; //[hir]~ ERROR closures cannot be static - (static async || value); - (static async move || value); + (static async || value); //[hir]~ ERROR `async` closures cannot be static + (static async move || value); //[hir]~ ERROR `async` closures cannot be static || -> u8 { value }; 1 + || {}; }