bool hasInlineBody() const;
+ /// \brief Determine whether this is a lambda closure type's static member
+ /// function that is used for the result of the lambda's conversion to
+ /// function pointer (for a lambda with no captures).
+ ///
+ /// The function itself, if used, will have a placeholder body that will be
+ /// supplied by IR generation to either forward to the function call operator
+ /// or clone the function call operator.
+ bool isLambdaStaticInvoker() const;
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const CXXMethodDecl *D) { return true; }
return CheckFn->hasBody(fn) && !fn->isOutOfLine();
}
+bool CXXMethodDecl::isLambdaStaticInvoker() const {
+ return getParent()->isLambda() &&
+ getIdentifier() && getIdentifier()->getName() == "__invoke";
+}
+
+
CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
TypeSourceInfo *TInfo, bool IsVirtual,
SourceLocation L, Expr *Init,
CGM.ErrorUnsupported(CurFuncDecl, "lambda conversion to block");
}
-void CodeGenFunction::EmitLambdaThunkBody(llvm::Function *Fn,
- const CGFunctionInfo &FnInfo,
- const CXXRecordDecl *Lambda) {
+void CodeGenFunction::EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD) {
+ const CXXRecordDecl *Lambda = MD->getParent();
DeclarationName Name
= getContext().DeclarationNames.getCXXOperatorName(OO_Call);
DeclContext::lookup_const_result Calls = Lambda->lookup(Name);
- CXXMethodDecl *MD = cast<CXXMethodDecl>(*Calls.first++);
+ CXXMethodDecl *CallOperator = cast<CXXMethodDecl>(*Calls.first++);
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
QualType ResultType = FPT->getResultType();
- // Begin function
- FunctionArgList FunctionArgs;
- for (FunctionDecl::param_const_iterator I = MD->param_begin(),
- E = MD->param_end(); I != E; ++I) {
- ParmVarDecl *Param = *I;
- FunctionArgs.push_back(Param);
- }
- StartFunction(GlobalDecl(), ResultType, Fn, FnInfo, FunctionArgs,
- SourceLocation());
-
// Start building arguments for forwarding call
CallArgList CallArgs;
}
// Get the address of the call operator.
- GlobalDecl GD(MD);
+ GlobalDecl GD(CallOperator);
const CGFunctionInfo &CalleeFnInfo = CGM.getTypes().getFunctionInfo(GD);
llvm::Type *Ty =
CGM.getTypes().GetFunctionType(CalleeFnInfo, FPT->isVariadic());
// Determine whether we have a return value slot to use.
ReturnValueSlot Slot;
if (!ResultType->isVoidType() &&
- FnInfo.getReturnInfo().getKind() == ABIArgInfo::Indirect &&
+ CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect &&
hasAggregateLLVMType(CurFnInfo->getReturnType()))
Slot = ReturnValueSlot(ReturnValue, ResultType.isVolatileQualified());
// Now emit our call.
- RValue RV = EmitCall(CalleeFnInfo, Callee, Slot, CallArgs, MD);
+ RValue RV = EmitCall(CalleeFnInfo, Callee, Slot, CallArgs, CallOperator);
// Forward the returned value
if (!ResultType->isVoidType() && Slot.isNull())
EmitReturnOfRValue(RV, ResultType);
-
- // End the function.
- FinishFunction();
}
-llvm::Constant *
-CodeGenFunction::EmitLambdaConvertedFnPtr(const CXXMethodDecl *MD) {
- QualType FnTy = MD->getResultType()->getPointeeType();
- CanQual<FunctionProtoType> CanFnTy =
- CGM.getContext().getCanonicalType(FnTy)->getAs<FunctionProtoType>();
- llvm::FunctionType *FnLLVMTy = cast<llvm::FunctionType>(CGM.getTypes().ConvertType(FnTy));
- const CXXRecordDecl *Lambda = MD->getParent();
- const CGFunctionInfo &FnInfo = CGM.getTypes().getFunctionInfo(CanFnTy);
-
- if (CanFnTy->isVariadic()) {
+void CodeGenFunction::EmitLambdaStaticInvokeFunction(const CXXMethodDecl *MD) {
+ if (MD->isVariadic()) {
// FIXME: Making this work correctly is nasty because it requires either
// cloning the body of the call operator or making the call operator forward.
CGM.ErrorUnsupported(MD, "lambda conversion to variadic function");
- return llvm::UndefValue::get(FnLLVMTy->getPointerTo());
}
- // Build a declaration for the function which this function will
- // return a pointer to.
- // FIXME: Should the "thunk" actually be part of the AST? That would allow
- // the conversion to function pointer to be constexpr...
- std::string MangledName =
- (llvm::Twine(CurFn->getName()) + "_lambdacallthunk").str();
- llvm::Function *Fn =
- llvm::Function::Create(FnLLVMTy, llvm::Function::InternalLinkage,
- MangledName, &CGM.getModule());
-
- // Emit the definition of the new function.
- CodeGenFunction(CGM).EmitLambdaThunkBody(Fn, FnInfo, Lambda);
- return Fn;
-}
-
-void CodeGenFunction::EmitLambdaToFunctionPointerBody(FunctionArgList &Args) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(CurFuncDecl);
- EmitReturnOfRValue(RValue::get(EmitLambdaConvertedFnPtr(MD)),
- MD->getResultType());
+ EmitLambdaDelegatingInvokeBody(MD);
}
FD->hasAttr<CUDAGlobalAttr>())
CGM.getCUDARuntime().EmitDeviceStubBody(*this, Args);
else if (isa<CXXConversionDecl>(FD) &&
- cast<CXXConversionDecl>(FD)->getParent()->isLambda()) {
- // The lambda conversion operators are special; the semantics can't be
- // expressed in the AST, so IRGen needs to special-case them.
- if (cast<CXXConversionDecl>(FD)->isLambdaToBlockPointerConversion())
- EmitLambdaToBlockPointerBody(Args);
- else
- EmitLambdaToFunctionPointerBody(Args);
+ cast<CXXConversionDecl>(FD)->isLambdaToBlockPointerConversion()) {
+ // The lambda conversion to block pointer is special; the semantics can't be
+ // expressed in the AST, so IRGen needs to special-case it.
+ EmitLambdaToBlockPointerBody(Args);
+ } else if (isa<CXXMethodDecl>(FD) &&
+ cast<CXXMethodDecl>(FD)->isLambdaStaticInvoker()) {
+ // The lambda "__invoke" function is special, because it forwards or
+ // clones the body of the function call operator (but is actually static).
+ EmitLambdaStaticInvokeFunction(cast<CXXMethodDecl>(FD));
}
else
EmitFunctionBody(Args);
void EmitFunctionBody(FunctionArgList &Args);
void EmitLambdaToBlockPointerBody(FunctionArgList &Args);
- void EmitLambdaToFunctionPointerBody(FunctionArgList &Args);
- llvm::Constant *EmitLambdaConvertedFnPtr(const CXXMethodDecl *MD);
- void EmitLambdaThunkBody(llvm::Function *Fn,
- const CGFunctionInfo &FnInfo,
- const CXXRecordDecl *Lambda);
+ void EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD);
+ void EmitLambdaStaticInvokeFunction(const CXXMethodDecl *MD);
/// EmitReturnBlock - Emit the unified return block, trying to avoid its
/// emission when possible.
isa<CXXMethodDecl>(FD);
}
+/// \brief Mark the call operator of the given lambda closure type as "used".
+static void markLambdaCallOperatorUsed(Sema &S, CXXRecordDecl *Lambda) {
+ CXXMethodDecl *CallOperator
+ = cast<CXXMethodDecl>(
+ *Lambda->lookup(
+ S.Context.DeclarationNames.getCXXOperatorName(OO_Call)).first);
+ CallOperator->setReferenced();
+ CallOperator->setUsed();
+}
+
void Sema::DefineImplicitLambdaToFunctionPointerConversion(
SourceLocation CurrentLocation,
CXXConversionDecl *Conv)
{
+ CXXRecordDecl *Lambda = Conv->getParent();
+
+ // Make sure that the lambda call operator is marked used.
+ markLambdaCallOperatorUsed(*this, Lambda);
+
Conv->setUsed();
ImplicitlyDefinedFunctionScope Scope(*this, Conv);
DiagnosticErrorTrap Trap(Diags);
- // Introduce a bogus body, which IR generation will override anyway.
- Conv->setBody(new (Context) CompoundStmt(Context, 0, 0, Conv->getLocation(),
+ // Return the address of the __invoke function.
+ DeclarationName InvokeName = &Context.Idents.get("__invoke");
+ CXXMethodDecl *Invoke
+ = cast<CXXMethodDecl>(*Lambda->lookup(InvokeName).first);
+ Expr *FunctionRef = BuildDeclRefExpr(Invoke, Invoke->getType(),
+ VK_LValue, Conv->getLocation()).take();
+ assert(FunctionRef && "Can't refer to __invoke function?");
+ Stmt *Return = ActOnReturnStmt(Conv->getLocation(), FunctionRef).take();
+ Conv->setBody(new (Context) CompoundStmt(Context, &Return, 1,
+ Conv->getLocation(),
Conv->getLocation()));
+
+ // Fill in the __invoke function with a dummy implementation. IR generation
+ // will fill in the actual details.
+ Invoke->setUsed();
+ Invoke->setReferenced();
+ Invoke->setBody(new (Context) CompoundStmt(Context, 0, 0, Conv->getLocation(),
+ Conv->getLocation()));
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Conv);
+ L->CompletedImplicitDefinition(Invoke);
}
}
SourceLocation CurrentLocation,
CXXConversionDecl *Conv)
{
+ // Make sure that the lambda call operator is marked used.
+ markLambdaCallOperatorUsed(*this, Conv->getParent());
Conv->setUsed();
ImplicitlyDefinedFunctionScope Scope(*this, Conv);
SourceRange IntroducerRange,
CXXRecordDecl *Class,
CXXMethodDecl *CallOperator) {
+ // Add the conversion to function pointer.
const FunctionProtoType *Proto
= CallOperator->getType()->getAs<FunctionProtoType>();
QualType FunctionPtrTy;
+ QualType FunctionTy;
{
FunctionProtoType::ExtProtoInfo ExtInfo = Proto->getExtProtoInfo();
ExtInfo.TypeQuals = 0;
- QualType FunctionTy
- = S.Context.getFunctionType(Proto->getResultType(),
- Proto->arg_type_begin(),
- Proto->getNumArgs(),
- ExtInfo);
+ FunctionTy = S.Context.getFunctionType(Proto->getResultType(),
+ Proto->arg_type_begin(),
+ Proto->getNumArgs(),
+ ExtInfo);
FunctionPtrTy = S.Context.getPointerType(FunctionTy);
}
Conversion->setAccess(AS_public);
Conversion->setImplicit(true);
Class->addDecl(Conversion);
+
+ // Add a non-static member function "__invoke" that will be the result of
+ // the conversion.
+ Name = &S.Context.Idents.get("__invoke");
+ CXXMethodDecl *Invoke
+ = CXXMethodDecl::Create(S.Context, Class, Loc,
+ DeclarationNameInfo(Name, Loc), FunctionTy,
+ CallOperator->getTypeSourceInfo(),
+ /*IsStatic=*/true, SC_Static, /*IsInline=*/true,
+ /*IsConstexpr=*/false,
+ CallOperator->getBody()->getLocEnd());
+ SmallVector<ParmVarDecl *, 4> InvokeParams;
+ for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I) {
+ ParmVarDecl *From = CallOperator->getParamDecl(I);
+ InvokeParams.push_back(ParmVarDecl::Create(S.Context, Invoke,
+ From->getLocStart(),
+ From->getLocation(),
+ From->getIdentifier(),
+ From->getType(),
+ From->getTypeSourceInfo(),
+ From->getStorageClass(),
+ From->getStorageClassAsWritten(),
+ /*DefaultArg=*/0));
+ }
+ Invoke->setParams(InvokeParams);
+ Invoke->setAccess(AS_private);
+ Invoke->setImplicit(true);
+ Class->addDecl(Invoke);
}
/// \brief Add a lambda's conversion to block pointer.
// CHECK: invoke i32 @"_ZZ1e1ES_bENK3$_4clEv"
// CHECK: call void @"_ZZ1e1ES_bEN3$_4D1Ev"
// CHECK: call void @"_ZZ1e1ES_bEN3$_4D1Ev"
+
// CHECK: define internal i32 @"_ZZ1e1ES_bENK3$_4clEv"
// CHECK: trunc i8
// CHECK: load i32*
// CHECK: ret i32
+
+void f() {
+ // CHECK: define void @_Z1fv()
+ // CHECK: {{call.*_5cvPFiiiEEv}}
+ // CHECK-NEXT: store i32 (i32, i32)*
+ // CHECK-NEXT: ret void
+ int (*fp)(int, int) = [](int x, int y){ return x + y; };
+}
+
+// CHECK: define internal i32 @"_ZZ1fvEN3$_58__invokeEii"
+// CHECK: store i32
+// CHECK-NEXT: store i32
+// CHECK-NEXT: load i32*
+// CHECK-NEXT: load i32*
+// CHECK-NEXT: call i32 @"_ZZ1fvENK3$_5clEii"
+// CHECK-NEXT: ret i32
+
// CHECK: define internal void @"_ZZ1e1ES_bEN3$_4D2Ev"