Author: Aman Maurya Date: 2026-10-22T21:22:55+05:30 New Revision: 02a19785c91cd7bab502f84362f18bc53ac3caea
URL: https://github.com/llvm/llvm-project/commit/02a19785c91cd7bab502f84362f18bc53ac3caea DIFF: https://github.com/llvm/llvm-project/commit/02a19785c91cd7bab502f84362f18bc53ac3caea.diff LOG: [CIR] Support CoawaitExpr in emitLValue (#232280) 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. This patch: - Routes `Expr::CoawaitExprClass` to `emitCoawaitLValue` in `CIRGenFunction::emitLValue`. - Refactors `emitCoawaitLValue` and `emitCoyieldLValue` into a shared `emitSuspendLValue` helper. - Handles resume expressions in try/catch (where `tmpResumeLValAddr` is null) by asserting `isResumeExprInTryCatch` and returning a null pointer lvalue. - Adds FileCheck tests in `clang/test/CIR/CodeGenCoroutines/coro-await.cpp`, including test coverage with C++ exceptions enabled. Fixes #232232. Added: clang/test/CIR/CodeGenCoroutines/coro-await.cpp Modified: clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp clang/lib/CIR/CodeGen/CIRGenFunction.cpp clang/lib/CIR/CodeGen/CIRGenFunction.h Removed: ################################################################################ diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp index 3ca0a29db565c1..41c1ab1abfcc56 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)); @@ -918,7 +920,6 @@ RValue CIRGenFunction::emitCoyieldExpr(const CoyieldExpr &e, ignoreResult); } -#ifndef NDEBUG static QualType getCoroutineSuspendExprReturnType(const ASTContext &ctx, const CoroutineSuspendExpr *e) { @@ -926,31 +927,48 @@ getCoroutineSuspendExprReturnType(const ASTContext &ctx, assert(isa<CallExpr>(re) && "unexpected suspend expression type"); return cast<CallExpr>(re)->getCallReturnType(ctx); } -#endif -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(); +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, 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)); + LValue lv = emitSuspendExpression(cgf, *cgf.curCoro.data, *e, kind, + AggValueSlot::ignored(), + /*ignoreResult=*/false, currEntryBlock, + tmpResumeLValAddr, /*forLValue=*/true) + .lv; + 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) { + return emitSuspendLValue(*this, e, cir::AwaitKind::Yield); +} + mlir::LogicalResult CIRGenFunction::emitCoreturnStmt(CoreturnStmt const &s) { ++curCoro.data->coreturnCount; 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..4cd3bb9a9df454 --- /dev/null +++ b/clang/test/CIR/CodeGenCoroutines/coro-await.cpp @@ -0,0 +1,75 @@ +// 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" + +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() noexcept { 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(%{{.*}}) nothrow : (!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(%{{.*}}) nothrow : (!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: %[[RES_OGCG:.*]] = call noundef nonnull align 4 dereferenceable(4) ptr @_ZN7Awaiter12await_resumeEv(ptr {{.*}}) + // OGCG: store ptr %[[RES_OGCG]], ptr %{{.*}}, align 8 + Awaiter a; + int &r = co_await a; +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
