about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-09-07 23:30:13 +0200
committerGitHub <noreply@github.com>2024-09-07 23:30:13 +0200
commit7b7f2f7f74522da174910f650e737aa80cc5705e (patch)
tree207f62a4761529d2df807cdc5332e4a3081f7f6d
parent37523d2a59b4dd210ae6f938c3f05dae0ddb3571 (diff)
parent384aed834cd83bdd0e93a2ef5690d3e44bf15856 (diff)
downloadrust-7b7f2f7f74522da174910f650e737aa80cc5705e.tar.gz
rust-7b7f2f7f74522da174910f650e737aa80cc5705e.zip
Rollup merge of #129847 - compiler-errors:async-cycle, r=davidtwco
Do not call query to compute coroutine layout for synthetic body of async closure

There is code in the MIR validator that attempts to prevent query cycles when inlining a coroutine into itself, and will use the coroutine layout directly from the body when it detects that's the same coroutine as the one that's being validated. After #128506, this logic didn't take into account the fact that the coroutine def id will differ if it's the "by-move body" of an async closure. This PR implements that.

Fixes #129811
-rw-r--r--compiler/rustc_mir_transform/src/validate.rs13
-rw-r--r--tests/ui/async-await/async-closures/validate-synthetic-body.rs19
2 files changed, 31 insertions, 1 deletions
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index 69e2592e82c..e515dfc5ea5 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -1,6 +1,7 @@
 //! Validates the MIR to ensure that invariants are upheld.
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_hir as hir;
 use rustc_hir::LangItem;
 use rustc_index::bit_set::BitSet;
 use rustc_index::IndexVec;
@@ -714,7 +715,17 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                             // since we may be in the process of computing this MIR in the
                             // first place.
                             let layout = if def_id == self.caller_body.source.def_id() {
-                                // FIXME: This is not right for async closures.
+                                self.caller_body.coroutine_layout_raw()
+                            } else if let Some(hir::CoroutineKind::Desugared(
+                                _,
+                                hir::CoroutineSource::Closure,
+                            )) = self.tcx.coroutine_kind(def_id)
+                                && let ty::ClosureKind::FnOnce =
+                                    args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap()
+                                && self.caller_body.source.def_id()
+                                    == self.tcx.coroutine_by_move_body_def_id(def_id)
+                            {
+                                // Same if this is the by-move body of a coroutine-closure.
                                 self.caller_body.coroutine_layout_raw()
                             } else {
                                 self.tcx.coroutine_layout(def_id, args.as_coroutine().kind_ty())
diff --git a/tests/ui/async-await/async-closures/validate-synthetic-body.rs b/tests/ui/async-await/async-closures/validate-synthetic-body.rs
new file mode 100644
index 00000000000..67e683ac08a
--- /dev/null
+++ b/tests/ui/async-await/async-closures/validate-synthetic-body.rs
@@ -0,0 +1,19 @@
+//@ check-pass
+//@ edition: 2021
+
+#![feature(async_closure)]
+
+// Make sure that we don't hit a query cycle when validating
+// the by-move coroutine body for an async closure.
+
+use std::future::Future;
+
+async fn test<Fut: Future>(operation: impl Fn() -> Fut) {
+    operation().await;
+}
+
+pub async fn orchestrate_simple_crud() {
+    test(async || async {}.await).await;
+}
+
+fn main() {}