Skip to content

Commit c36156d

Browse files
[Clang] Fix FE crash during CGCoroutine GRO Alloca Emission (#148962)
Fixes: #148953 Currently when coroutine return object type is const qualified, we don't do direct emission. The regular emission logic assumed that the auto var emission will always result in an `AllocaInst`. However, based on my findings, NRVO var emissions don't result in `AllocaInst`s. Therefore, this [assertion](https://github.com/llvm/llvm-project/blob/1a940bfff9176fb38a71b0045d7ae25df9a4ca7d/clang/lib/CodeGen/CGCoroutine.cpp#L712) will fail. Since the NRVOed returned object don't live on the coroutine frame, we won't have the problem of it outliving the coroutine frame, therefore, we can safely omit this metadata.
1 parent b64d7ba commit c36156d

File tree

2 files changed

+37
-6
lines changed

2 files changed

+37
-6
lines changed

clang/lib/CodeGen/CGCoroutine.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -707,11 +707,15 @@ struct GetReturnObjectManager {
707707
Builder.CreateStore(Builder.getFalse(), GroActiveFlag);
708708

709709
GroEmission = CGF.EmitAutoVarAlloca(*GroVarDecl);
710-
auto *GroAlloca = dyn_cast_or_null<llvm::AllocaInst>(
711-
GroEmission.getOriginalAllocatedAddress().getPointer());
712-
assert(GroAlloca && "expected alloca to be emitted");
713-
GroAlloca->setMetadata(llvm::LLVMContext::MD_coro_outside_frame,
714-
llvm::MDNode::get(CGF.CGM.getLLVMContext(), {}));
710+
711+
if (!GroVarDecl->isNRVOVariable()) {
712+
// NRVO variables don't have allocas and won't have the same issue.
713+
auto *GroAlloca = dyn_cast_or_null<llvm::AllocaInst>(
714+
GroEmission.getOriginalAllocatedAddress().getPointer());
715+
assert(GroAlloca && "expected alloca to be emitted");
716+
GroAlloca->setMetadata(llvm::LLVMContext::MD_coro_outside_frame,
717+
llvm::MDNode::get(CGF.CGM.getLLVMContext(), {}));
718+
}
715719

716720
// Remember the top of EHStack before emitting the cleanup.
717721
auto old_top = CGF.EHStack.stable_begin();

clang/test/CodeGenCoroutines/coro-gro.cpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,31 @@ invoker g() {
106106
// CHECK: call void @_ZN7invoker15invoker_promise17get_return_objectEv({{.*}} %[[AggRes]]
107107
co_return;
108108
}
109-
// CHECK: ![[OutFrameMetadata]] = !{}
109+
110+
namespace gh148953 {
111+
112+
struct Task {
113+
struct promise_type {
114+
Task get_return_object();
115+
std::suspend_always initial_suspend() { return {}; }
116+
std::suspend_always final_suspend() noexcept { return {}; }
117+
void return_void() {}
118+
void unhandled_exception() {}
119+
};
120+
Task() {}
121+
// Different from `invoker`, this Task is copy constructible.
122+
Task(const Task&) {};
123+
};
124+
125+
// NRVO on const qualified return type should work.
126+
// CHECK: define{{.*}} void @_ZN8gh1489537exampleEv({{.*}} sret(%"struct.gh148953::Task") align 1 %[[NrvoRes:.+]])
127+
const Task example() {
128+
// CHECK: %[[ResultPtr:.+]] = alloca ptr
129+
// CHECK: store ptr %[[NrvoRes]], ptr %[[ResultPtr]]
130+
// CHECK: coro.init:
131+
// CHECK: call void @_ZN8gh1489534Task12promise_type17get_return_objectEv({{.*}} %[[NrvoRes:.+]], {{.*}})
132+
co_return;
133+
}
134+
135+
} // namespace gh148953
136+
// CHECK: ![[OutFrameMetadata]] = !{}

0 commit comments

Comments
 (0)