diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/DeclCXX.cpp | 6 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGClass.cpp | 59 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.cpp | 16 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.h | 7 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 37 | ||||
-rw-r--r-- | clang/lib/Sema/SemaLambda.cpp | 39 |
6 files changed, 95 insertions, 69 deletions
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. |