summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2012-02-17 03:02:34 +0000
committerDouglas Gregor <dgregor@apple.com>2012-02-17 03:02:34 +0000
commit355efbb2e044126adecdcadca87c8cdfb5c33a85 (patch)
tree1414f54d5ff0cc4f6b5b09b8b806178a0ae2d9e2 /clang
parentd608bac682fc88eb8ab7dc1ef65245c0f5c75712 (diff)
downloadbcm5719-llvm-355efbb2e044126adecdcadca87c8cdfb5c33a85.tar.gz
bcm5719-llvm-355efbb2e044126adecdcadca87c8cdfb5c33a85.zip
Rework the Sema/AST/IRgen dance for the lambda closure type's
conversion to function pointer. Rather than having IRgen synthesize the body of this function, we instead introduce a static member function "__invoke" with the same signature as the lambda's operator() in the AST. Sema then generates a body for the conversion to function pointer which simply returns the address of __invoke. This approach makes it easier to evaluate a call to the conversion function as a constant, makes the linkage of the __invoke function follow the normal rules for member functions, and may make life easier down the road if we ever want to constexpr'ify some of lambdas. Note that IR generation is responsible for filling in the body of __invoke (Sema just adds a dummy body), because the body can't generally be expressed in C++. Eli, please review! llvm-svn: 150783
Diffstat (limited to 'clang')
-rw-r--r--clang/include/clang/AST/DeclCXX.h9
-rw-r--r--clang/lib/AST/DeclCXX.cpp6
-rw-r--r--clang/lib/CodeGen/CGClass.cpp59
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.cpp16
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.h7
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp37
-rw-r--r--clang/lib/Sema/SemaLambda.cpp39
-rw-r--r--clang/test/CodeGenCXX/lambda-expressions.cpp18
8 files changed, 122 insertions, 69 deletions
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index 215adb9668b..c371c08560f 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -1565,6 +1565,15 @@ public:
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; }
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index b5b3f12f5e1..a4d82206258 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1455,6 +1455,12 @@ bool CXXMethodDecl::hasInlineBody() const {
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,
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index ed44679a886..7e94af391f9 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -1725,26 +1725,15 @@ void CodeGenFunction::EmitLambdaToBlockPointerBody(FunctionArgList &Args) {
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;
@@ -1760,7 +1749,7 @@ void CodeGenFunction::EmitLambdaThunkBody(llvm::Function *Fn,
}
// 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());
@@ -1769,54 +1758,24 @@ void CodeGenFunction::EmitLambdaThunkBody(llvm::Function *Fn,
// 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);
}
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index 1034de736c1..28c5935de04 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -448,13 +448,15 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
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);
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 2b9b8ab7b88..427ee08e69e 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -1377,11 +1377,8 @@ public:
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.
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 66ec800c726..82e59ddafee 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -9051,21 +9051,52 @@ bool Sema::isImplicitlyDeleted(FunctionDecl *FD) {
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);
}
}
@@ -9073,6 +9104,8 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion(
SourceLocation CurrentLocation,
CXXConversionDecl *Conv)
{
+ // Make sure that the lambda call operator is marked used.
+ markLambdaCallOperatorUsed(*this, Conv->getParent());
Conv->setUsed();
ImplicitlyDefinedFunctionScope Scope(*this, Conv);
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 4e5935701b3..2af946288f4 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -372,17 +372,18 @@ static void addFunctionPointerConversion(Sema &S,
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);
}
@@ -409,6 +410,34 @@ static void addFunctionPointerConversion(Sema &S,
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.
diff --git a/clang/test/CodeGenCXX/lambda-expressions.cpp b/clang/test/CodeGenCXX/lambda-expressions.cpp
index 237687037d7..e1aab1889c0 100644
--- a/clang/test/CodeGenCXX/lambda-expressions.cpp
+++ b/clang/test/CodeGenCXX/lambda-expressions.cpp
@@ -47,8 +47,26 @@ int e(E a, E b, bool cond) { [a,b,cond](){ return (cond ? a : b).x; }(); }
// 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"
OpenPOWER on IntegriCloud