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 { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits