[clang] [CIR] Implement return for void lambda with static invoker (PR #194704)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 28 11:48:34 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Andy Kaylor (andykaylor)
<details>
<summary>Changes</summary>
We had an errorNYI call for emitting the return statement for a static invoker for a lambda with a void return. All that was needed was to emit a return operation and add a test case.
---
Full diff: https://github.com/llvm/llvm-project/pull/194704.diff
2 Files Affected:
- (modified) clang/lib/CIR/CodeGen/CIRGenClass.cpp (+1-2)
- (modified) clang/test/CIR/CodeGen/lambda-static-invoker.cpp (+109)
``````````diff
diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
index 5f9fdfba9d31b..d00a12a68535d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
@@ -922,8 +922,7 @@ void CIRGenFunction::emitForwardingCallToLambda(
"emitForwardingCallToLambda: ObjCAutoRefCount");
emitReturnOfRValue(*currSrcLoc, rv, resultType);
} else {
- cgm.errorNYI(callOperator->getSourceRange(),
- "emitForwardingCallToLambda: return slot is not null");
+ cir::ReturnOp::create(builder, *currSrcLoc);
}
}
diff --git a/clang/test/CIR/CodeGen/lambda-static-invoker.cpp b/clang/test/CIR/CodeGen/lambda-static-invoker.cpp
index e90d79b77c104..d9be0a5521c19 100644
--- a/clang/test/CIR/CodeGen/lambda-static-invoker.cpp
+++ b/clang/test/CIR/CodeGen/lambda-static-invoker.cpp
@@ -154,6 +154,98 @@ int g3() {
// The definition for _Z2g3v in OGCG is first among the functions for the g3 test, see above.
+
+void use_void_lambda() {
+ auto L = [](auto x) { (void)x; };
+ void (*p)(int) = L;
+}
+
+// lambda operator()
+// CIR: cir.func no_inline lambda internal private dso_local @_ZZ15use_void_lambdavENK3$_0clIiEEDaT_(%[[THIS_ARG:.*]]: !cir.ptr<![[REC_LAM_VOID_LAMBDA:.*]]> {{.*}}, %[[X_ARG:.*]]: !s32i {{.*}})
+// CIR: %[[THIS_ALLOCA:.*]] = cir.alloca !cir.ptr<![[REC_LAM_VOID_LAMBDA]]>, !cir.ptr<!cir.ptr<![[REC_LAM_VOID_LAMBDA]]>>, ["this", init]
+// CIR: %[[X:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init]
+// CIR: cir.store %[[THIS_ARG]], %[[THIS_ALLOCA]]
+// CIR: cir.store %[[X_ARG]], %[[X]]
+// CIR: %[[THIS:.*]] = cir.load %[[THIS_ALLOCA]]
+// CIR: cir.return
+
+// lambda invoker
+// CIR: cir.func no_inline internal private dso_local @_ZZ15use_void_lambdavEN3$_08__invokeIiEEDaT_(%[[X_ARG:.*]]: !s32i {{.*}})
+// CIR: %[[X_ALLOCA:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init]
+// CIR: %[[UNUSED_CAPTURE:.*]] = cir.alloca ![[REC_LAM_VOID_LAMBDA]], !cir.ptr<![[REC_LAM_VOID_LAMBDA]]>, ["unused.capture"]
+// CIR: cir.store %[[X_ARG]], %[[X_ALLOCA]]
+// CIR: %[[X:.*]] = cir.load{{.*}} %[[X_ALLOCA]]
+// CIR: cir.call @_ZZ15use_void_lambdavENK3$_0clIiEEDaT_(%[[UNUSED_CAPTURE]], %[[X]]) : (!cir.ptr<![[REC_LAM_VOID_LAMBDA]]> {{.*}}, !s32i {{.*}}) -> ()
+// CIR: cir.return
+
+// lambda operator void (*)(int)()
+// CIR: cir.func no_inline internal private dso_local @_ZZ15use_void_lambdavENK3$_0cvPFDaT_EIiEEv(%[[THIS_ARG:.*]]: !cir.ptr<![[REC_LAM_VOID_LAMBDA]]> {{.*}}) -> (!cir.ptr<!cir.func<(!s32i)>>{{.*}})
+// CIR: %[[THIS_ALLOCA:.*]] = cir.alloca !cir.ptr<![[REC_LAM_VOID_LAMBDA]]>, !cir.ptr<!cir.ptr<![[REC_LAM_VOID_LAMBDA]]>>, ["this", init]
+// CIR: %[[RETVAL:.*]] = cir.alloca !cir.ptr<!cir.func<(!s32i)>>, !cir.ptr<!cir.ptr<!cir.func<(!s32i)>>>, ["__retval"]
+// CIR: cir.store %[[THIS_ARG]], %[[THIS_ALLOCA]]
+// CIR: %[[THIS:.*]] = cir.load %[[THIS_ALLOCA]]
+// CIR: %[[INVOKER:.*]] = cir.get_global @_ZZ15use_void_lambdavEN3$_08__invokeIiEEDaT_ : !cir.ptr<!cir.func<(!s32i)>>
+// CIR: cir.store %[[INVOKER]], %[[RETVAL]]
+// CIR: %[[RET:.*]] = cir.load %[[RETVAL]]
+// CIR: cir.return %[[RET]]
+
+// CIR: cir.func no_inline dso_local @_Z15use_void_lambdav()
+// CIR: %[[L_ALLOCA:.*]] = cir.alloca ![[REC_LAM_VOID_LAMBDA]], !cir.ptr<![[REC_LAM_VOID_LAMBDA]]>, ["L"]
+// CIR: %[[P_ALLOCA:.*]] = cir.alloca !cir.ptr<!cir.func<(!s32i)>>, !cir.ptr<!cir.ptr<!cir.func<(!s32i)>>>, ["p", init]
+// CIR: %[[LAMBDA:.*]] = cir.call @_ZZ15use_void_lambdavENK3$_0cvPFDaT_EIiEEv(%[[L_ALLOCA]])
+// CIR: cir.store{{.*}} %[[LAMBDA]], %[[P_ALLOCA]]
+// CIR: cir.return
+
+// lambda operator()
+// LLVM: define internal void @"_ZZ15use_void_lambdavENK3$_0clIiEEDaT_"(ptr {{.*}} %[[THIS_ARG:.*]], i32 {{.*}} %[[X_ARG:.*]])
+// LLVM: %[[THIS_ALLOCA:.*]] = alloca ptr
+// LLVM: %[[X_ALLOCA:.*]] = alloca i32
+// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ALLOCA]]
+// LLVM: store i32 %[[X_ARG]], ptr %[[X_ALLOCA]]
+// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ALLOCA]]
+// LLVM: ret void
+
+// lambda invoker
+// LLVM: define internal void @"_ZZ15use_void_lambdavEN3$_08__invokeIiEEDaT_"(i32 {{.*}} %[[X_ARG:.*]])
+// LLVM: %[[X_ALLOCA:.*]] = alloca i32
+// LLVM: %[[UNUSED_CAPTURE:.*]] = alloca %[[REC_LAM_VOID_LAMBDA:.*]]
+// LLVM: store i32 %[[X_ARG]], ptr %[[X_ALLOCA]]
+// LLVM: %[[X:.*]] = load i32, ptr %[[X_ALLOCA]]
+// LLVM: call void @"_ZZ15use_void_lambdavENK3$_0clIiEEDaT_"(ptr {{.*}} %[[UNUSED_CAPTURE]], i32 {{.*}} %[[X]])
+// LLVM: ret void
+
+// lambda operator void (*)(int)()
+// LLVM: define internal noundef ptr @"_ZZ15use_void_lambdavENK3$_0cvPFDaT_EIiEEv"(ptr {{.*}} %[[THIS_ARG:.*]])
+// LLVM: %[[THIS_ALLOCA:.*]] = alloca ptr
+// LLVM: %[[RETVAL:.*]] = alloca ptr
+// LLVM: store ptr %[[THIS_ARG]], ptr %[[THIS_ALLOCA]]
+// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ALLOCA]]
+// LLVM: store ptr @"_ZZ15use_void_lambdavEN3$_08__invokeIiEEDaT_", ptr %[[RETVAL]]
+// LLVM: %[[RET:.*]] = load ptr, ptr %[[RETVAL]]
+// LLVM: ret ptr %[[RET]]
+
+// LLVM: define dso_local void @_Z15use_void_lambdav()
+// LLVM: %[[L_ALLOCA:.*]] = alloca %[[REC_LAM_VOID_LAMBDA]]
+// LLVM: %[[P_ALLOCA:.*]] = alloca ptr
+// LLVM: %[[LAMBDA:.*]] = call {{.*}} ptr @"_ZZ15use_void_lambdavENK3$_0cvPFDaT_EIiEEv"(ptr {{.*}} %[[L_ALLOCA]])
+// LLVM: store ptr %[[LAMBDA]], ptr %[[P_ALLOCA]]
+// LLVM: ret void
+
+// OGCG: define dso_local void @_Z15use_void_lambdav()
+// OGCG: %[[L_ALLOCA:.*]] = alloca %[[REC_LAM_VOID_LAMBDA:.*]]
+// OGCG: %[[P_ALLOCA:.*]] = alloca ptr
+// OGCG: %[[LAMBDA:.*]] = call {{.*}} ptr @"_ZZ15use_void_lambdavENK3$_0cvPFDaT_EIiEEv"(ptr {{.*}} %[[L_ALLOCA]])
+// OGCG: store ptr %[[LAMBDA]], ptr %[[P_ALLOCA]]
+// OGCG: ret void
+
+// lambda operator void (*)(int)()
+// OGCG: define internal noundef ptr @"_ZZ15use_void_lambdavENK3$_0cvPFDaT_EIiEEv"(ptr {{.*}} %[[THIS_ARG:.*]])
+// OGCG: %[[THIS_ALLOCA:.*]] = alloca ptr
+// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ALLOCA]]
+// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ALLOCA]]
+// OGCG: ret ptr @"_ZZ15use_void_lambdavEN3$_08__invokeIiEEDaT_"
+
+
// The functions below are emitted later in OGCG, see above for the corresponding LLVM checks.
// OGCG: define internal noundef i32 @"_ZZ2g3vEN3$_08__invokeERKi"(ptr {{.*}} %[[I_ARG:.*]])
@@ -173,3 +265,20 @@ int g3() {
// OGCG: %[[I_PTR:.*]] = load ptr, ptr %[[I_ADDR]]
// OGCG: %[[I:.*]] = load i32, ptr %[[I_PTR]]
// OGCG: ret i32 %[[I]]
+
+// lambda invoker
+// OGCG: define internal void @"_ZZ15use_void_lambdavEN3$_08__invokeIiEEDaT_"(i32 {{.*}} %[[X_ARG:.*]])
+// OGCG: %[[X_ALLOCA:.*]] = alloca i32
+// OGCG: %[[UNUSED_CAPTURE:.*]] = alloca %[[REC_LAM_VOID_LAMBDA]]
+// OGCG: store i32 %[[X_ARG]], ptr %[[X_ALLOCA]]
+// OGCG: %[[X:.*]] = load i32, ptr %[[X_ALLOCA]]
+// OGCG: call void @"_ZZ15use_void_lambdavENK3$_0clIiEEDaT_"(ptr {{.*}} %[[UNUSED_CAPTURE]], i32 {{.*}} %[[X]])
+// OGCG: ret void
+
+// OGCG: define internal void @"_ZZ15use_void_lambdavENK3$_0clIiEEDaT_"(ptr {{.*}} %[[THIS_ARG:.*]], i32 {{.*}} %[[X_ARG:.*]])
+// OGCG: %[[THIS_ALLOCA:.*]] = alloca ptr
+// OGCG: %[[X_ALLOCA:.*]] = alloca i32
+// OGCG: store ptr %[[THIS_ARG]], ptr %[[THIS_ALLOCA]]
+// OGCG: store i32 %[[X_ARG]], ptr %[[X_ALLOCA]]
+// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ALLOCA]]
+// OGCG: ret void
``````````
</details>
https://github.com/llvm/llvm-project/pull/194704
More information about the cfe-commits
mailing list