diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -26,8 +26,10 @@ #include "clang/Basic/CodeGenOptions.h" #include "clang/Basic/TargetBuiltins.h" #include "clang/CodeGen/CGFunctionInfo.h" +#include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/Metadata.h" +#include "llvm/Transforms/Utils/Cloning.h" #include "llvm/Transforms/Utils/SanitizerStats.h" using namespace clang; @@ -3044,3 +3046,22 @@ EmitLambdaDelegatingInvokeBody(MD); } + +void CodeGenFunction::EmitClonedLambdaStaticInvoke(const CXXMethodDecl *MD) { + llvm::Function *Fn = + cast(CGM.GetAddrOfFunction(GlobalDecl(MD))); + + const CXXMethodDecl *CallOp = MD->getParent()->getLambdaCallOperator(); + llvm::Function *CallOpFn = + cast(CGM.GetAddrOfFunction(GlobalDecl(CallOp))); + + // Clone from call operator, which we've made sure is already emitted. + llvm::ValueToValueMapTy VMap; + + // Don't copy the %this argument, which is the first argument. + llvm::Argument &A = *CallOpFn->arg_begin(); + VMap[&A] = llvm::Constant::getNullValue(A.getType()); + + CreateClonedFunction(Fn, CallOpFn, VMap); + CurFn->setCallingConv(Fn->getCallingConv()); +} diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp --- a/clang/lib/CodeGen/CGVTables.cpp +++ b/clang/lib/CodeGen/CGVTables.cpp @@ -139,6 +139,21 @@ } } +void CodeGenFunction::CreateClonedFunction( + llvm::Function *Fn, llvm::Function *BaseFn, llvm::ValueToValueMapTy &VMap) { + // We are cloning a function while some Metadata nodes are still unresolved. + // Ensure that the value mapper does not encounter any of them. + resolveTopLevelMetadata(BaseFn, VMap); + llvm::Function *NewFn = llvm::CloneFunction(BaseFn, VMap); + Fn->replaceAllUsesWith(NewFn); + NewFn->takeName(Fn); + Fn->eraseFromParent(); + Fn = NewFn; + + // "Initialize" CGF (minimally). + CurFn = Fn; +} + // This function does roughly the same thing as GenerateThunk, but in a // very different way, so that va_start and va_end work correctly. // FIXME: This function assumes "this" is the first non-sret LLVM argument of @@ -181,17 +196,7 @@ // Clone to thunk. llvm::ValueToValueMapTy VMap; - // We are cloning a function while some Metadata nodes are still unresolved. - // Ensure that the value mapper does not encounter any of them. - resolveTopLevelMetadata(BaseFn, VMap); - llvm::Function *NewFn = llvm::CloneFunction(BaseFn, VMap); - Fn->replaceAllUsesWith(NewFn); - NewFn->takeName(Fn); - Fn->eraseFromParent(); - Fn = NewFn; - - // "Initialize" CGF (minimally). - CurFn = Fn; + CreateClonedFunction(Fn, BaseFn, VMap); // Get the "this" value llvm::Function::arg_iterator AI = Fn->arg_begin(); diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -2223,6 +2223,8 @@ void EmitLambdaBlockInvokeBody(); void EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD); void EmitLambdaStaticInvokeBody(const CXXMethodDecl *MD); + void EmitClonedLambdaStaticInvoke(const CXXMethodDecl *MD); + void EmitLambdaVLACapture(const VariableArrayType *VAT, LValue LV) { EmitStoreThroughLValue(RValue::get(VLASizeMap[VAT->getSizeExpr()]), LV); } @@ -2255,6 +2257,8 @@ GlobalDecl GD, const ThunkInfo &Thunk, bool IsUnprototyped); + void CreateClonedFunction(llvm::Function *Fn, llvm::Function *BaseFn, + llvm::ValueToValueMapTy &VMap); llvm::Function *GenerateVarArgsThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo, GlobalDecl GD, const ThunkInfo &Thunk); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -3554,6 +3554,18 @@ EmitGlobalFunctionDefinition(GD, GV); } +static bool isInAllocaArg(CGCXXABI &ABI, QualType T) { + const CXXRecordDecl *RD = T->getAsCXXRecordDecl(); + return RD && ABI.getRecordArgABI(RD) == CGCXXABI::RAA_DirectInMemory; +} + +static bool hasInAllocaArg(const TargetInfo &TI, CGCXXABI &CGABI, const CXXMethodDecl *MD) { + return TI.getCXXABI().isMicrosoft() && + llvm::any_of(MD->parameters(), [&](ParmVarDecl *P) { + return isInAllocaArg(CGABI, P->getType()); + }); +} + void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD, llvm::GlobalValue *GV) { const auto *D = cast(GD.getDecl()); @@ -3580,6 +3592,14 @@ // This is necessary for the generation of certain thunks. if (isa(Method) || isa(Method)) ABI->emitCXXStructor(GD); + // Special path for emitting lambda static invokers with inalloca parameters. + else if (Method->isLambdaStaticInvoker() && + hasInAllocaArg(getTarget(), getCXXABI(), Method)) { + // Emit the call operator definition before emitting a static invoker. + const CXXMethodDecl *CallOp = Method->getParent()->getLambdaCallOperator(); + EmitGlobalFunctionDefinition(GlobalDecl(CallOp), nullptr); + CodeGenFunction(*this).EmitClonedLambdaStaticInvoke(Method); + } else if (FD->isMultiVersion()) EmitMultiVersionFunctionDefinition(GD, GV); else diff --git a/clang/test/CodeGenCXX/inalloca-lambda.cpp b/clang/test/CodeGenCXX/inalloca-lambda.cpp --- a/clang/test/CodeGenCXX/inalloca-lambda.cpp +++ b/clang/test/CodeGenCXX/inalloca-lambda.cpp @@ -1,7 +1,4 @@ -// RUN: not %clang_cc1 -triple i686-windows-msvc -emit-llvm -o /dev/null %s 2>&1 | FileCheck %s - -// PR28299 -// CHECK: error: cannot compile this forwarded non-trivially copyable parameter yet +// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -o - %s 2>&1 | FileCheck %s class A { A(const A &); @@ -9,3 +6,7 @@ typedef void (*fptr_t)(A); fptr_t fn1() { return [](A) {}; } +// CHECK: define internal void @"?__invoke@@?0??fn1@@YAP6AXVA@@@ZXZ@CA?A?@@0@Z" +// CHECK-SAME: (ptr inalloca(<{ %class.A, [3 x i8] }>) %0) +// CHECK: %1 = getelementptr inbounds <{ %class.A, [3 x i8] }>, ptr %0, i32 0, i32 0 +// CHECK: ret void