[clang] cd18342 - [clang][Interp] Fix handling of generic lambdas
Timm Bäder via cfe-commits
cfe-commits at lists.llvm.org
Thu Feb 8 07:04:03 PST 2024
Author: Timm Bäder
Date: 2024-02-08T16:03:42+01:00
New Revision: cd183428a9af6d7dda2018a88aeb495f268716b5
URL: https://github.com/llvm/llvm-project/commit/cd183428a9af6d7dda2018a88aeb495f268716b5
DIFF: https://github.com/llvm/llvm-project/commit/cd183428a9af6d7dda2018a88aeb495f268716b5.diff
LOG: [clang][Interp] Fix handling of generic lambdas
When compiling their static invoker, we need to get the
right specialization.
Added:
Modified:
clang/lib/AST/Interp/ByteCodeEmitter.cpp
clang/test/AST/Interp/lambda.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/ByteCodeEmitter.cpp b/clang/lib/AST/Interp/ByteCodeEmitter.cpp
index 8bbfa928bd645..e697e24fb341d 100644
--- a/clang/lib/AST/Interp/ByteCodeEmitter.cpp
+++ b/clang/lib/AST/Interp/ByteCodeEmitter.cpp
@@ -23,6 +23,34 @@ using namespace clang;
using namespace clang::interp;
Function *ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) {
+ bool IsLambdaStaticInvoker = false;
+ if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl);
+ MD && MD->isLambdaStaticInvoker()) {
+ // For a lambda static invoker, we might have to pick a specialized
+ // version if the lambda is generic. In that case, the picked function
+ // will *NOT* be a static invoker anymore. However, it will still
+ // be a non-static member function, this (usually) requiring an
+ // instance pointer. We suppress that later in this function.
+ IsLambdaStaticInvoker = true;
+
+ const CXXRecordDecl *ClosureClass = MD->getParent();
+ assert(ClosureClass->captures_begin() == ClosureClass->captures_end());
+ if (ClosureClass->isGenericLambda()) {
+ const CXXMethodDecl *LambdaCallOp = ClosureClass->getLambdaCallOperator();
+ assert(MD->isFunctionTemplateSpecialization() &&
+ "A generic lambda's static-invoker function must be a "
+ "template specialization");
+ const TemplateArgumentList *TAL = MD->getTemplateSpecializationArgs();
+ FunctionTemplateDecl *CallOpTemplate =
+ LambdaCallOp->getDescribedFunctionTemplate();
+ void *InsertPos = nullptr;
+ const FunctionDecl *CorrespondingCallOpSpecialization =
+ CallOpTemplate->findSpecialization(TAL->asArray(), InsertPos);
+ assert(CorrespondingCallOpSpecialization);
+ FuncDecl = cast<CXXMethodDecl>(CorrespondingCallOpSpecialization);
+ }
+ }
+
// Set up argument indices.
unsigned ParamOffset = 0;
SmallVector<PrimType, 8> ParamTypes;
@@ -46,7 +74,7 @@ Function *ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) {
// InterpStack when calling the function.
bool HasThisPointer = false;
if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl)) {
- if (MD->isImplicitObjectMemberFunction()) {
+ if (MD->isImplicitObjectMemberFunction() && !IsLambdaStaticInvoker) {
HasThisPointer = true;
ParamTypes.push_back(PT_Ptr);
ParamOffsets.push_back(ParamOffset);
diff --git a/clang/test/AST/Interp/lambda.cpp b/clang/test/AST/Interp/lambda.cpp
index f8400898acc0c..a433e5666e4f4 100644
--- a/clang/test/AST/Interp/lambda.cpp
+++ b/clang/test/AST/Interp/lambda.cpp
@@ -155,6 +155,19 @@ namespace StaticInvoker {
return fp(i).a;
}
static_assert(sv6(12) == 12);
+
+
+ /// A generic lambda.
+ auto GL = [](auto a) { return a; };
+ constexpr char (*fp2)(char) = GL;
+ static_assert(fp2('3') == '3', "");
+
+ struct GLS {
+ int a;
+ };
+ auto GL2 = [](auto a) { return GLS{a}; };
+ constexpr GLS (*fp3)(char) = GL2;
+ static_assert(fp3('3').a == '3', "");
}
namespace LambdasAsParams {
More information about the cfe-commits
mailing list