https://github.com/amanmaurya92 updated 
https://github.com/llvm/llvm-project/pull/232280

>From 29ca56a4f16688f7e4840bef2609dc142d0f7cb6 Mon Sep 17 00:00:00 2001
From: amanmaurya92 <[email protected]>
Date: Wed, 21 Oct 2026 02:08:00 +0530
Subject: [PATCH 1/2] [CIR] Support CoawaitExpr in emitLValue (#232232)

In CIRGenFunction::emitLValue, Expr::CoawaitExprClass previously called 
errorNYI. When a coroutine awaits an expression whose await_resume() returns an 
lvalue reference (for example, int &x = co_await awaiter; or (co_await awaiter) 
= 42;), Clang evaluates the CoawaitExpr as an lvalue. The resume pointer is 
spilled and reloaded across cir.await to maintain MLIR SSA dominance in the 
parent scope.

Fixes #232232.
---
 clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp     | 27 ++++++-
 clang/lib/CIR/CodeGen/CIRGenFunction.cpp      |  3 +-
 clang/lib/CIR/CodeGen/CIRGenFunction.h        |  1 +
 .../test/CIR/CodeGenCoroutines/coro-await.cpp | 72 +++++++++++++++++++
 4 files changed, 100 insertions(+), 3 deletions(-)
 create mode 100644 clang/test/CIR/CodeGenCoroutines/coro-await.cpp

diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
index 3ca0a29db565c1..77fc82cce6a700 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
@@ -822,7 +822,9 @@ emitSuspendExpression(CIRGenFunction &cgf, CGCoroData &coro,
           assert(awaitRes.lv.isSimple() &&
                  "expected simple lvalue for coroutine resume");
           mlir::Value ptr = awaitRes.lv.getPointer();
-          llvm::StringRef tmpName = "__coyield_resume_lval";
+          llvm::StringRef tmpName = kind == cir::AwaitKind::Yield
+                                        ? "__coyield_resume_lval"
+                                        : "__coawait_resume_lval";
           tmpResumeRValAddr = cgf.emitAlloca(
               tmpName, ptr.getType(), loc, cgf.getPointerAlign(),
               builder.getBestAllocaInsertPoint(scopeParentBlock));
@@ -928,6 +930,29 @@ getCoroutineSuspendExprReturnType(const ASTContext &ctx,
 }
 #endif
 
+LValue CIRGenFunction::emitCoawaitLValue(const CoawaitExpr *e) {
+  assert(
+      getCoroutineSuspendExprReturnType(getContext(), e)->isReferenceType() &&
+      "Can't have a scalar return unless the return type is a "
+      "reference type!");
+  mlir::Location scopeLoc = getLoc(e->getSourceRange());
+  mlir::Block *currEntryBlock = curLexScope->getEntryBlock();
+  mlir::Value tmpResumeLValAddr;
+  LValue lv = emitSuspendExpression(*this, *curCoro.data, *e,
+                                    curCoro.data->currentAwaitKind,
+                                    AggValueSlot::ignored(),
+                                    /*ignoreResult=*/false, currEntryBlock,
+                                    tmpResumeLValAddr, /*forLValue=*/true)
+                  .lv;
+  if (tmpResumeLValAddr) {
+    Address addr = lv.getAddress();
+    mlir::Value loadedPtr = cir::LoadOp::create(
+        getBuilder(), scopeLoc, addr.getPointer().getType(), 
tmpResumeLValAddr);
+    lv.setAddress(addr.withPointer(loadedPtr));
+  }
+  return lv;
+}
+
 LValue CIRGenFunction::emitCoyieldLValue(const CoyieldExpr *e) {
   assert(
       getCoroutineSuspendExprReturnType(getContext(), e)->isReferenceType() &&
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp 
b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index e5f20f7dec01d1..409a94b9acff8f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -1373,8 +1373,7 @@ LValue CIRGenFunction::emitLValue(const Expr *e) {
   case Expr::MaterializeTemporaryExprClass:
     return emitMaterializeTemporaryExpr(cast<MaterializeTemporaryExpr>(e));
   case Expr::CoawaitExprClass:
-    getCIRGenModule().errorNYI(e->getSourceRange(), "emitLValue: CoawaitExpr");
-    return LValue();
+    return emitCoawaitLValue(cast<CoawaitExpr>(e));
   case Expr::CoyieldExprClass:
     return emitCoyieldLValue(cast<CoyieldExpr>(e));
   case Expr::PackIndexingExprClass:
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index a143483d49391e..b97b0fe1f700c1 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -2316,6 +2316,7 @@ class CIRGenFunction : public CIRGenTypeCache {
   RValue emitCoawaitExpr(const CoawaitExpr &e,
                          AggValueSlot aggSlot = AggValueSlot::ignored(),
                          bool ignoreResult = false);
+  LValue emitCoawaitLValue(const CoawaitExpr *e);
 
   RValue emitCoyieldExpr(const CoyieldExpr &e,
                          AggValueSlot aggSlot = AggValueSlot::ignored(),
diff --git a/clang/test/CIR/CodeGenCoroutines/coro-await.cpp 
b/clang/test/CIR/CodeGenCoroutines/coro-await.cpp
new file mode 100644
index 00000000000000..a592dd1db10d28
--- /dev/null
+++ b/clang/test/CIR/CodeGenCoroutines/coro-await.cpp
@@ -0,0 +1,72 @@
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir 
-Wno-coroutine-missing-unhandled-exception -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-llvm 
-disable-llvm-passes -Wno-coroutine-missing-unhandled-exception %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+
+#include "Inputs/coroutine.h"
+
+struct Task {
+  struct promise_type {
+    Task get_return_object() { return {}; }
+    std::suspend_never initial_suspend() noexcept { return {}; }
+    std::suspend_never final_suspend() noexcept { return {}; }
+    void return_void() {}
+    void unhandled_exception() {}
+  };
+};
+
+struct Awaiter {
+  bool await_ready() { return false; }
+  void await_suspend(std::coroutine_handle<>) {}
+  int &await_resume() { return value; }
+  int value;
+};
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z17test_await_assignv
+// OGCG-LABEL: define dso_local void @_Z17test_await_assignv
+Task test_await_assign() {
+  // CIR: %[[VAL:.*]] = cir.const #cir.int<42> : !s32i
+  // CIR: cir.await(user, ready : {
+  // CIR:   %[[READY:.*]] = cir.call @_ZN7Awaiter11await_readyEv(%{{.*}}) : 
(!cir.ptr<!rec_Awaiter>{{.*}}) -> (!cir.bool{{.*}})
+  // CIR:   cir.condition(%[[READY]])
+  // CIR: }, suspend : {
+  // CIR:   cir.call 
@_ZN7Awaiter13await_suspendESt16coroutine_handleIvE(%{{.*}})
+  // CIR:   cir.coro.suspend_point
+  // CIR: }, resume : {
+  // CIR:   %[[RES:.*]] = cir.call @_ZN7Awaiter12await_resumeEv(%{{.*}}) : 
(!cir.ptr<!rec_Awaiter>{{.*}}) -> (!cir.ptr<!s32i>{{.*}})
+  // CIR:   cir.store %[[RES]], %[[TMP_ADDR:.*]] : !cir.ptr<!s32i>, 
!cir.ptr<!cir.ptr<!s32i>>
+  // CIR:   cir.yield
+  // CIR: },)
+  // CIR: %[[LOADED_PTR:.*]] = cir.load %[[TMP_ADDR]] : 
!cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+  // CIR: cir.store align(4) %[[VAL]], %[[LOADED_PTR]] : !s32i, !cir.ptr<!s32i>
+
+  // OGCG: %[[RES_OGCG:.*]] = call noundef nonnull align 4 dereferenceable(4) 
ptr @_ZN7Awaiter12await_resumeEv(ptr {{.*}})
+  // OGCG: store i32 42, ptr %[[RES_OGCG]], align 4
+  Awaiter a;
+  (co_await a) = 42;
+}
+
+// CIR-LABEL: cir.func coroutine {{.*}} @_Z14test_await_refv
+// OGCG-LABEL: define dso_local void @_Z14test_await_refv
+Task test_await_ref() {
+  // CIR: %[[R_ADDR:.*]] = cir.alloca "r" align(8) init const : 
!cir.ptr<!cir.ptr<!s32i>>
+  // CIR: cir.await(user, ready : {
+  // CIR:   %[[READY:.*]] = cir.call @_ZN7Awaiter11await_readyEv(%{{.*}}) : 
(!cir.ptr<!rec_Awaiter>{{.*}}) -> (!cir.bool{{.*}})
+  // CIR:   cir.condition(%[[READY]])
+  // CIR: }, suspend : {
+  // CIR:   cir.call 
@_ZN7Awaiter13await_suspendESt16coroutine_handleIvE(%{{.*}})
+  // CIR:   cir.coro.suspend_point
+  // CIR: }, resume : {
+  // CIR:   %[[RES:.*]] = cir.call @_ZN7Awaiter12await_resumeEv(%{{.*}}) : 
(!cir.ptr<!rec_Awaiter>{{.*}}) -> (!cir.ptr<!s32i>{{.*}})
+  // CIR:   cir.store %[[RES]], %[[TMP_ADDR:.*]] : !cir.ptr<!s32i>, 
!cir.ptr<!cir.ptr<!s32i>>
+  // CIR:   cir.yield
+  // CIR: },)
+  // CIR: %[[LOADED_PTR:.*]] = cir.load %[[TMP_ADDR]] : 
!cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+  // CIR: cir.store align(8) %[[LOADED_PTR]], %[[R_ADDR]] : !cir.ptr<!s32i>, 
!cir.ptr<!cir.ptr<!s32i>>
+
+  // OGCG: %[[R_ADDR_OGCG:.*]] = alloca ptr, align 8
+  // OGCG: %[[RES_OGCG:.*]] = call noundef nonnull align 4 dereferenceable(4) 
ptr @_ZN7Awaiter12await_resumeEv(ptr {{.*}})
+  // OGCG: store ptr %[[RES_OGCG]], ptr %[[R_ADDR_OGCG]], align 8
+  Awaiter a;
+  int &r = co_await a;
+}

>From 0d9ad5face04131189bc0a5bc27dc06cd14d7b7a Mon Sep 17 00:00:00 2001
From: amanmaurya92 <[email protected]>
Date: Wed, 21 Oct 2026 10:13:52 +0530
Subject: [PATCH 2/2] [CIR] Address review comments for CoawaitExpr emitLValue

- Merge emitCoawaitLValue and emitCoyieldLValue into emitSuspendLValue helper.
- Add assertion and return null pointer lvalue when tmpResumeLValAddr is null.
- Add exception-enabled RUN lines to coro-await.cpp test.
---
 clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp     | 65 +++++++++----------
 .../test/CIR/CodeGenCoroutines/coro-await.cpp |  4 ++
 2 files changed, 33 insertions(+), 36 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
index 77fc82cce6a700..41c1ab1abfcc56 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
@@ -920,7 +920,6 @@ RValue CIRGenFunction::emitCoyieldExpr(const CoyieldExpr &e,
                          ignoreResult);
 }
 
-#ifndef NDEBUG
 static QualType
 getCoroutineSuspendExprReturnType(const ASTContext &ctx,
                                   const CoroutineSuspendExpr *e) {
@@ -928,52 +927,46 @@ getCoroutineSuspendExprReturnType(const ASTContext &ctx,
   assert(isa<CallExpr>(re) && "unexpected suspend expression type");
   return cast<CallExpr>(re)->getCallReturnType(ctx);
 }
-#endif
 
-LValue CIRGenFunction::emitCoawaitLValue(const CoawaitExpr *e) {
-  assert(
-      getCoroutineSuspendExprReturnType(getContext(), e)->isReferenceType() &&
-      "Can't have a scalar return unless the return type is a "
-      "reference type!");
-  mlir::Location scopeLoc = getLoc(e->getSourceRange());
-  mlir::Block *currEntryBlock = curLexScope->getEntryBlock();
+static LValue emitSuspendLValue(CIRGenFunction &cgf,
+                                const CoroutineSuspendExpr *e,
+                                cir::AwaitKind kind) {
+  QualType retTy = getCoroutineSuspendExprReturnType(cgf.getContext(), e);
+  assert(retTy->isReferenceType() &&
+         "Can't have a scalar return unless the return type is a "
+         "reference type!");
+  mlir::Location scopeLoc = cgf.getLoc(e->getSourceRange());
+  mlir::Block *currEntryBlock = cgf.curLexScope->getEntryBlock();
   mlir::Value tmpResumeLValAddr;
-  LValue lv = emitSuspendExpression(*this, *curCoro.data, *e,
-                                    curCoro.data->currentAwaitKind,
+  LValue lv = emitSuspendExpression(cgf, *cgf.curCoro.data, *e, kind,
                                     AggValueSlot::ignored(),
                                     /*ignoreResult=*/false, currEntryBlock,
                                     tmpResumeLValAddr, /*forLValue=*/true)
                   .lv;
-  if (tmpResumeLValAddr) {
-    Address addr = lv.getAddress();
-    mlir::Value loadedPtr = cir::LoadOp::create(
-        getBuilder(), scopeLoc, addr.getPointer().getType(), 
tmpResumeLValAddr);
-    lv.setAddress(addr.withPointer(loadedPtr));
+  if (!tmpResumeLValAddr) {
+    assert(isResumeExprInTryCatch(*cgf.curCoro.data, kind, *e) &&
+           "expected resume in try/catch");
+    QualType pointeeTy = retTy->getPointeeType();
+    mlir::Type elemTy = cgf.convertType(pointeeTy);
+    mlir::Value nullPtr = cgf.getBuilder().getNullPtr(
+        cgf.getBuilder().getPointerTo(elemTy), scopeLoc);
+    return cgf.makeNaturalAlignAddrLValue(nullPtr, pointeeTy);
   }
+
+  Address addr = lv.getAddress();
+  mlir::Value loadedPtr =
+      cir::LoadOp::create(cgf.getBuilder(), scopeLoc,
+                          addr.getPointer().getType(), tmpResumeLValAddr);
+  lv.setAddress(addr.withPointer(loadedPtr));
   return lv;
 }
 
+LValue CIRGenFunction::emitCoawaitLValue(const CoawaitExpr *e) {
+  return emitSuspendLValue(*this, e, curCoro.data->currentAwaitKind);
+}
+
 LValue CIRGenFunction::emitCoyieldLValue(const CoyieldExpr *e) {
-  assert(
-      getCoroutineSuspendExprReturnType(getContext(), e)->isReferenceType() &&
-      "Can't have a scalar return unless the return type is a "
-      "reference type!");
-  mlir::Location scopeLoc = getLoc(e->getSourceRange());
-  mlir::Block *currEntryBlock = curLexScope->getEntryBlock();
-  mlir::Value tmpResumeLValAddr;
-  LValue lv =
-      emitSuspendExpression(*this, *curCoro.data, *e, cir::AwaitKind::Yield,
-                            AggValueSlot::ignored(),
-                            /*ignoreResult=*/false, currEntryBlock,
-                            tmpResumeLValAddr, /*forLValue=*/true)
-          .lv;
-  if (tmpResumeLValAddr) {
-    Address addr = lv.getAddress();
-    mlir::Value loadedPtr = cir::LoadOp::create(
-        getBuilder(), scopeLoc, addr.getPointer().getType(), 
tmpResumeLValAddr);
-    lv.setAddress(addr.withPointer(loadedPtr));
-  }
-  return lv;
+  return emitSuspendLValue(*this, e, cir::AwaitKind::Yield);
 }
 
 mlir::LogicalResult CIRGenFunction::emitCoreturnStmt(CoreturnStmt const &s) {
diff --git a/clang/test/CIR/CodeGenCoroutines/coro-await.cpp 
b/clang/test/CIR/CodeGenCoroutines/coro-await.cpp
index a592dd1db10d28..dedde25f11b8b8 100644
--- a/clang/test/CIR/CodeGenCoroutines/coro-await.cpp
+++ b/clang/test/CIR/CodeGenCoroutines/coro-await.cpp
@@ -1,7 +1,11 @@
 // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir 
-Wno-coroutine-missing-unhandled-exception -emit-cir %s -o %t.cir
 // RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir 
-fcxx-exceptions -fexceptions -Wno-coroutine-missing-unhandled-exception 
-emit-cir %s -o %t.eh.cir
+// RUN: FileCheck --input-file=%t.eh.cir %s -check-prefix=CIR
 // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-llvm 
-disable-llvm-passes -Wno-coroutine-missing-unhandled-exception %s -o %t.ll
 // RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu 
-fcxx-exceptions -fexceptions -emit-llvm -disable-llvm-passes 
-Wno-coroutine-missing-unhandled-exception %s -o %t.eh.ll
+// RUN: FileCheck --input-file=%t.eh.ll %s -check-prefix=OGCG
 
 #include "Inputs/coroutine.h"
 

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to