From 1455a419c9b02b9ffd7bb9a6633fee7058cf218f Mon Sep 17 00:00:00 2001 From: Yuxuan Chen Date: Tue, 15 Jul 2025 13:24:39 -0700 Subject: [PATCH] [clang] fix FE crash during CGCoroutine Gro: NRVO var emission didn't result in an AllocaInst --- clang/lib/CodeGen/CGCoroutine.cpp | 14 +++++++---- clang/test/CodeGenCoroutines/coro-gro.cpp | 29 ++++++++++++++++++++++- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/clang/lib/CodeGen/CGCoroutine.cpp b/clang/lib/CodeGen/CGCoroutine.cpp index 0fc488e98aaf0..117ef3d16e21b 100644 --- a/clang/lib/CodeGen/CGCoroutine.cpp +++ b/clang/lib/CodeGen/CGCoroutine.cpp @@ -707,11 +707,15 @@ struct GetReturnObjectManager { Builder.CreateStore(Builder.getFalse(), GroActiveFlag); GroEmission = CGF.EmitAutoVarAlloca(*GroVarDecl); - auto *GroAlloca = dyn_cast_or_null( - GroEmission.getOriginalAllocatedAddress().getPointer()); - assert(GroAlloca && "expected alloca to be emitted"); - GroAlloca->setMetadata(llvm::LLVMContext::MD_coro_outside_frame, - llvm::MDNode::get(CGF.CGM.getLLVMContext(), {})); + + if (!GroVarDecl->isNRVOVariable()) { + // NRVO variables don't have allocas and won't have the same issue. + auto *GroAlloca = dyn_cast_or_null( + GroEmission.getOriginalAllocatedAddress().getPointer()); + assert(GroAlloca && "expected alloca to be emitted"); + GroAlloca->setMetadata(llvm::LLVMContext::MD_coro_outside_frame, + llvm::MDNode::get(CGF.CGM.getLLVMContext(), {})); + } // Remember the top of EHStack before emitting the cleanup. auto old_top = CGF.EHStack.stable_begin(); diff --git a/clang/test/CodeGenCoroutines/coro-gro.cpp b/clang/test/CodeGenCoroutines/coro-gro.cpp index b62134317cef2..037fd03349e76 100644 --- a/clang/test/CodeGenCoroutines/coro-gro.cpp +++ b/clang/test/CodeGenCoroutines/coro-gro.cpp @@ -106,4 +106,31 @@ invoker g() { // CHECK: call void @_ZN7invoker15invoker_promise17get_return_objectEv({{.*}} %[[AggRes]] co_return; } -// CHECK: ![[OutFrameMetadata]] = !{} \ No newline at end of file + +namespace gh148953 { + +struct Task { + struct promise_type { + Task get_return_object(); + std::suspend_always initial_suspend() { return {}; } + std::suspend_always final_suspend() noexcept { return {}; } + void return_void() {} + void unhandled_exception() {} + }; + Task() {} + // Different from `invoker`, this Task is copy constructible. + Task(const Task&) {}; +}; + +// NRVO on const qualified return type should work. +// CHECK: define{{.*}} void @_ZN8gh1489537exampleEv({{.*}} sret(%"struct.gh148953::Task") align 1 %[[NrvoRes:.+]]) +const Task example() { + // CHECK: %[[ResultPtr:.+]] = alloca ptr + // CHECK: store ptr %[[NrvoRes]], ptr %[[ResultPtr]] + // CHECK: coro.init: + // CHECK: call void @_ZN8gh1489534Task12promise_type17get_return_objectEv({{.*}} %[[NrvoRes:.+]], {{.*}}) + co_return; +} + +} // namespace gh148953 +// CHECK: ![[OutFrameMetadata]] = !{}