[clang] [Clang][Coroutines] Properly emit EH code for initial suspend `await_resume` (PR #73073)

via cfe-commits cfe-commits at lists.llvm.org
Tue Nov 21 19:39:03 PST 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-codegen

Author: Yuxuan Chen (yuxuanchen1997)

<details>
<summary>Changes</summary>

This change aims to fix an ICE in issue https://github.com/llvm/llvm-project/issues/63803

The crash happens in `ExitCXXTryStmt` because `EmitAnyExpr()` adds additional cleanup to the `EHScopeStack`. This messes up the assumption in `ExitCXXTryStmt` that the top of the stack should be a `EHCatchScope`. 

However, since we never read a value returned from `await_resume()` of an init suspend, we can skip the part that builds this `RValue`.

---
Full diff: https://github.com/llvm/llvm-project/pull/73073.diff


2 Files Affected:

- (modified) clang/lib/CodeGen/CGCoroutine.cpp (+9-5) 
- (added) clang/test/CodeGenCoroutines/coro-init-await-nontrivial-return.cpp (+49) 


``````````diff
diff --git a/clang/lib/CodeGen/CGCoroutine.cpp b/clang/lib/CodeGen/CGCoroutine.cpp
index 7e449d5af3423cf..aaf122c0f83bc47 100644
--- a/clang/lib/CodeGen/CGCoroutine.cpp
+++ b/clang/lib/CodeGen/CGCoroutine.cpp
@@ -245,6 +245,15 @@ static LValueOrRValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Co
                                          FPOptionsOverride(), Loc, Loc);
     TryStmt = CXXTryStmt::Create(CGF.getContext(), Loc, TryBody, Catch);
     CGF.EnterCXXTryStmt(*TryStmt);
+    CGF.EmitStmt(TryBody);
+    // We don't use EmitCXXTryStmt here. We need to store to ResumeEHVar that
+    // doesn't exist in the body.
+    Builder.CreateFlagStore(false, Coro.ResumeEHVar);
+    CGF.ExitCXXTryStmt(*TryStmt);
+    LValueOrRValue Res;
+    // We are not supposed to obtain the value from init suspend await_resume().
+    Res.RV = RValue::getIgnored();
+    return Res;
   }
 
   LValueOrRValue Res;
@@ -253,11 +262,6 @@ static LValueOrRValue emitSuspendExpression(CodeGenFunction &CGF, CGCoroData &Co
   else
     Res.RV = CGF.EmitAnyExpr(S.getResumeExpr(), aggSlot, ignoreResult);
 
-  if (TryStmt) {
-    Builder.CreateFlagStore(false, Coro.ResumeEHVar);
-    CGF.ExitCXXTryStmt(*TryStmt);
-  }
-
   return Res;
 }
 
diff --git a/clang/test/CodeGenCoroutines/coro-init-await-nontrivial-return.cpp b/clang/test/CodeGenCoroutines/coro-init-await-nontrivial-return.cpp
new file mode 100644
index 000000000000000..78fc88a071d5c74
--- /dev/null
+++ b/clang/test/CodeGenCoroutines/coro-init-await-nontrivial-return.cpp
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -std=c++20 -triple=x86_64-- -emit-llvm -fcxx-exceptions \
+// RUN:            -disable-llvm-passes %s -o - | FileCheck %s
+
+#include "Inputs/coroutine.h"
+
+struct NontrivialType {
+  ~NontrivialType() {}
+};
+
+struct Task {
+    struct promise_type;
+    using handle_type = std::coroutine_handle<promise_type>;
+
+    struct initial_suspend_awaiter {
+        bool await_ready() {
+            return false;
+        }
+
+        void await_suspend(handle_type h) {}
+
+        // Nontrivial type caused crash!
+        NontrivialType await_resume() noexcept {
+          return {};
+        }
+    };
+
+    struct promise_type {
+        void return_void() {}
+        void unhandled_exception() {}
+        initial_suspend_awaiter initial_suspend() { return {}; }
+        std::suspend_never final_suspend() noexcept { return {}; }
+        Task get_return_object() {
+            return Task{handle_type::from_promise(*this)};
+        }
+    };
+
+    handle_type handler;
+};
+
+Task coro_create() {
+    co_return;
+}
+
+// CHECK-LABEL: define{{.*}} ptr @_Z11coro_createv(
+// CHECK: init.ready:
+// CHECK-NEXT: store i1 true, ptr {{.*}}
+// CHECK-NEXT: call void @_ZN4Task23initial_suspend_awaiter12await_resumeEv(
+// CHECK-NEXT: call void @_ZN14NontrivialTypeD1Ev(
+// CHECK-NEXT: store i1 false, ptr {{.*}}

``````````

</details>


https://github.com/llvm/llvm-project/pull/73073


More information about the cfe-commits mailing list