diff --git a/include/clang/AST/ASTLambda.h b/include/clang/AST/ASTLambda.h index 814beb34e177b9812f69aa8c1ff8f5c601c3161d..9044878e35da2977b130f6b27b135b1b7e41ba28 100644 --- a/include/clang/AST/ASTLambda.h +++ b/include/clang/AST/ASTLambda.h @@ -31,7 +31,13 @@ inline bool isLambdaCallOperator(const CXXMethodDecl *MD) { return MD->getOverloadedOperator() == OO_Call; } +inline bool isLambdaCallOperator(const DeclContext *DC) { + if (!DC || !isa<CXXMethodDecl>(DC)) return false; + return isLambdaCallOperator(cast<CXXMethodDecl>(DC)); +} + inline bool isGenericLambdaCallOperatorSpecialization(CXXMethodDecl *MD) { + if (!MD) return false; CXXRecordDecl *LambdaClass = MD->getParent(); if (LambdaClass && LambdaClass->isGenericLambda()) return isLambdaCallOperator(MD) && @@ -44,6 +50,27 @@ inline bool isGenericLambdaCallOperatorSpecialization(Decl *D) { return isGenericLambdaCallOperatorSpecialization( cast<CXXMethodDecl>(D)); } + +inline bool isLambdaConversionOperator(CXXConversionDecl *C) { + return C ? C->getParent()->isLambda() : false; +} + +inline bool isLambdaConversionOperator(Decl *D) { + if (!D) return false; + if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(D)) + return isLambdaConversionOperator(Conv); + if (FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(D)) + if (CXXConversionDecl *Conv = + dyn_cast_or_null<CXXConversionDecl>(F->getTemplatedDecl())) + return isLambdaConversionOperator(Conv); + return false; +} + +inline bool isGenericLambdaCallOperatorSpecialization(DeclContext *DC) { + return isGenericLambdaCallOperatorSpecialization( + dyn_cast<CXXMethodDecl>(DC)); +} + } // clang #endif // LLVM_CLANG_AST_LAMBDA_H diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 33c7ff99b0e5652949be79dccda6bb312041328f..146853586aca022269fe89fd5df25ed092693e22 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -972,9 +972,12 @@ CXXMethodDecl* CXXRecordDecl::getLambdaStaticInvoker() const { DeclContext::lookup_const_result Invoker = lookup(Name); if (Invoker.empty()) return 0; assert(Invoker.size() == 1 && "More than one static invoker operator!"); - CXXMethodDecl *Result = cast<CXXMethodDecl>(Invoker.front()); - return Result; - + NamedDecl *InvokerFun = Invoker.front(); + if (FunctionTemplateDecl *InvokerTemplate = + dyn_cast<FunctionTemplateDecl>(InvokerFun)) + return cast<CXXMethodDecl>(InvokerTemplate->getTemplatedDecl()); + + return cast<CXXMethodDecl>(InvokerFun); } void CXXRecordDecl::getCaptureFields( @@ -1552,11 +1555,17 @@ bool CXXMethodDecl::hasInlineBody() const { } bool CXXMethodDecl::isLambdaStaticInvoker() const { - return getParent()->isLambda() && - getParent()->getLambdaStaticInvoker() == this; + const CXXRecordDecl *P = getParent(); + if (P->isLambda()) { + if (const CXXMethodDecl *StaticInvoker = P->getLambdaStaticInvoker()) { + if (StaticInvoker == this) return true; + if (P->isGenericLambda() && this->isFunctionTemplateSpecialization()) + return StaticInvoker == this->getPrimaryTemplate()->getTemplatedDecl(); + } + } + return false; } - CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context, TypeSourceInfo *TInfo, bool IsVirtual, SourceLocation L, Expr *Init, diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index c1226d5681c95b0d94c662e0acbf2ffcfd451158..4db5b09afe116816b3c1155c66bbd7f6138789ec 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -17,6 +17,7 @@ #include "CodeGenFunction.h" #include "CGCXXABI.h" #include "clang/AST/CXXInheritance.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtCXX.h" @@ -2104,14 +2105,9 @@ CodeGenFunction::EmitCXXOperatorMemberCallee(const CXXOperatorCallExpr *E, return CGM.GetAddrOfFunction(MD, fnType); } -void CodeGenFunction::EmitForwardingCallToLambda(const CXXRecordDecl *lambda, - CallArgList &callArgs) { - // Lookup the call operator - DeclarationName operatorName - = getContext().DeclarationNames.getCXXOperatorName(OO_Call); - CXXMethodDecl *callOperator = - cast<CXXMethodDecl>(lambda->lookup(operatorName).front()); - +void CodeGenFunction::EmitForwardingCallToLambda( + const CXXMethodDecl *callOperator, + CallArgList &callArgs) { // Get the address of the call operator. const CGFunctionInfo &calleeFnInfo = CGM.getTypes().arrangeCXXMethodDeclaration(callOperator); @@ -2162,8 +2158,9 @@ void CodeGenFunction::EmitLambdaBlockInvokeBody() { ParmVarDecl *param = *I; EmitDelegateCallArg(CallArgs, param); } - - EmitForwardingCallToLambda(Lambda, CallArgs); + assert(!Lambda->isGenericLambda() && + "generic lambda interconversion to block not implemented"); + EmitForwardingCallToLambda(Lambda->getLambdaCallOperator(), CallArgs); } void CodeGenFunction::EmitLambdaToBlockPointerBody(FunctionArgList &Args) { @@ -2193,8 +2190,20 @@ void CodeGenFunction::EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD) { ParmVarDecl *param = *I; EmitDelegateCallArg(CallArgs, param); } - - EmitForwardingCallToLambda(Lambda, CallArgs); + const CXXMethodDecl *CallOp = Lambda->getLambdaCallOperator(); + // For a generic lambda, find the corresponding call operator specialization + // to which the call to the static-invoker shall be forwarded. + if (Lambda->isGenericLambda()) { + assert(MD->isFunctionTemplateSpecialization()); + const TemplateArgumentList *TAL = MD->getTemplateSpecializationArgs(); + FunctionTemplateDecl *CallOpTemplate = CallOp->getDescribedFunctionTemplate(); + void *InsertPos = 0; + FunctionDecl *CorrespondingCallOpSpecialization = + CallOpTemplate->findSpecialization(TAL->data(), TAL->size(), InsertPos); + assert(CorrespondingCallOpSpecialization); + CallOp = cast<CXXMethodDecl>(CorrespondingCallOpSpecialization); + } + EmitForwardingCallToLambda(CallOp, CallArgs); } void CodeGenFunction::EmitLambdaStaticInvokeFunction(const CXXMethodDecl *MD) { diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 5889d058606f9522f5caf13072370358a67ced57..080d0b7b6f332672c201b857c78261e91851ea77 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1138,7 +1138,7 @@ public: void emitImplicitAssignmentOperatorBody(FunctionArgList &Args); void EmitFunctionBody(FunctionArgList &Args); - void EmitForwardingCallToLambda(const CXXRecordDecl *Lambda, + void EmitForwardingCallToLambda(const CXXMethodDecl *LambdaCallOperator, CallArgList &CallArgs); void EmitLambdaToBlockPointerBody(FunctionArgList &Args); void EmitLambdaBlockInvokeBody(); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 6e1751aebd931df993730c8a5b850c7f529df7a0..4aa53e0a8e88bdd4ef64469062ccb008f58008f4 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -10351,57 +10351,92 @@ bool Sema::isImplicitlyDeleted(FunctionDecl *FD) { return FD->isDeleted() && FD->isDefaulted() && 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)).front()); - CallOperator->setReferenced(); - CallOperator->markUsed(S.Context); -} - void Sema::DefineImplicitLambdaToFunctionPointerConversion( - SourceLocation CurrentLocation, - CXXConversionDecl *Conv) -{ - CXXRecordDecl *LambdaClass = Conv->getParent(); - - // Make sure that the lambda call operator is marked used. - markLambdaCallOperatorUsed(*this, LambdaClass); - - Conv->markUsed(Context); + SourceLocation CurrentLocation, + CXXConversionDecl *Conv) { + CXXRecordDecl *Lambda = Conv->getParent(); + CXXMethodDecl *CallOp = Lambda->getLambdaCallOperator(); + // If we are defining a specialization of a conversion to function-ptr + // cache the deduced template arguments for this specialization + // so that we can use them to retrieve the corresponding call-operator + // and static-invoker. + const TemplateArgumentList *DeducedTemplateArgs = 0; + + // Retrieve the corresponding call-operator specialization. + if (Lambda->isGenericLambda()) { + assert(Conv->isFunctionTemplateSpecialization()); + FunctionTemplateDecl *CallOpTemplate = + CallOp->getDescribedFunctionTemplate(); + DeducedTemplateArgs = Conv->getTemplateSpecializationArgs(); + void *InsertPos = 0; + FunctionDecl *CallOpSpec = CallOpTemplate->findSpecialization( + DeducedTemplateArgs->data(), + DeducedTemplateArgs->size(), + InsertPos); + assert(CallOpSpec && + "Conversion operator must have a corresponding call operator"); + CallOp = cast<CXXMethodDecl>(CallOpSpec); + } + // Mark the call operator referenced (and add to pending instantiations + // if necessary). + // For both the conversion and static-invoker template specializations + // we construct their body's in this function, so no need to add them + // to the PendingInstantiations. + MarkFunctionReferenced(CurrentLocation, CallOp); + SynthesizedFunctionScope Scope(*this, Conv); DiagnosticErrorTrap Trap(Diags); + + // Retreive the static invoker... + CXXMethodDecl *Invoker = Lambda->getLambdaStaticInvoker(); + // ... and get the corresponding specialization for a generic lambda. + if (Lambda->isGenericLambda()) { + assert(DeducedTemplateArgs && + "Must have deduced template arguments from Conversion Operator"); + FunctionTemplateDecl *InvokeTemplate = + Invoker->getDescribedFunctionTemplate(); + void *InsertPos = 0; + FunctionDecl *InvokeSpec = InvokeTemplate->findSpecialization( + DeducedTemplateArgs->data(), + DeducedTemplateArgs->size(), + InsertPos); + assert(InvokeSpec && + "Must have a corresponding static invoker specialization"); + Invoker = cast<CXXMethodDecl>(InvokeSpec); + } + // Construct the body of the conversion function { return __invoke; }. + Expr *FunctionRef = BuildDeclRefExpr(Invoker, Invoker->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, + Conv->getLocation(), + Conv->getLocation())); + + Conv->markUsed(Context); + Conv->setReferenced(); - // Return the address of the __invoke function. - - CXXMethodDecl *Invoke = LambdaClass->getLambdaStaticInvoker(); - Expr *FunctionRef = BuildDeclRefExpr(Invoke, Invoke->getType(), - VK_LValue, Conv->getLocation()).take(); - assert(FunctionRef && "Can't refer to lambda static invoker function?"); - Stmt *Return = ActOnReturnStmt(Conv->getLocation(), FunctionRef).take(); - Conv->setBody(new (Context) CompoundStmt(Context, Return, - Conv->getLocation(), - Conv->getLocation())); - - // Fill in the static invoker function with a dummy implementation. - // IR generation will fill in the actual details. - Invoke->markUsed(Context); - Invoke->setReferenced(); - Invoke->setBody(new (Context) CompoundStmt(Conv->getLocation())); - + // Fill in the __invoke function with a dummy implementation. IR generation + // will fill in the actual details. + Invoker->markUsed(Context); + Invoker->setReferenced(); + Invoker->setBody(new (Context) CompoundStmt(Conv->getLocation())); + if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Conv); - L->CompletedImplicitDefinition(Invoke); - } + L->CompletedImplicitDefinition(Invoker); + } } + + void Sema::DefineImplicitLambdaToBlockPointerConversion( SourceLocation CurrentLocation, CXXConversionDecl *Conv) { + assert(!Conv->getParent()->isGenericLambda()); + Conv->markUsed(Context); SynthesizedFunctionScope Scope(*this, Conv); diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index fa46a282991c0a45fdbf901eb94497ff5b2a709d..32a385caaa559fe349bd376464e371a55758d112 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -857,8 +857,6 @@ static void addFunctionPointerConversion(Sema &S, SourceRange IntroducerRange, CXXRecordDecl *Class, CXXMethodDecl *CallOperator) { - // FIXME: The conversion operator needs to be fixed for generic lambdas. - if (Class->isGenericLambda()) return; // Add the conversion to function pointer. const FunctionProtoType *Proto = CallOperator->getType()->getAs<FunctionProtoType>(); @@ -898,10 +896,34 @@ static void addFunctionPointerConversion(Sema &S, CallOperator->getBody()->getLocEnd()); Conversion->setAccess(AS_public); Conversion->setImplicit(true); - Class->addDecl(Conversion); + + if (Class->isGenericLambda()) { + // Create a template version of the conversion operator, using the template + // parameter list of the function call operator. + FunctionTemplateDecl *TemplateCallOperator = + CallOperator->getDescribedFunctionTemplate(); + FunctionTemplateDecl *ConversionTemplate = + FunctionTemplateDecl::Create(S.Context, Class, + Loc, Name, + TemplateCallOperator->getTemplateParameters(), + Conversion); + ConversionTemplate->setAccess(AS_public); + ConversionTemplate->setImplicit(true); + Conversion->setDescribedFunctionTemplate(ConversionTemplate); + Class->addDecl(ConversionTemplate); + } else + Class->addDecl(Conversion); // Add a non-static member function that will be the result of // the conversion with a certain unique ID. Name = &S.Context.Idents.get(getLambdaStaticInvokerName()); + // FIXME: Instead of passing in the CallOperator->getTypeSourceInfo() + // we should get a prebuilt TrivialTypeSourceInfo from Context + // using FunctionTy & Loc and get its TypeLoc as a FunctionProtoTypeLoc + // then rewire the parameters accordingly, by hoisting up the InvokeParams + // loop below and then use its Params to set Invoke->setParams(...) below. + // This would avoid the 'const' qualifier of the calloperator from + // contaminating the type of the invoker, which is currently adjusted + // in SemaTemplateDeduction.cpp:DeduceTemplateArguments. CXXMethodDecl *Invoke = CXXMethodDecl::Create(S.Context, Class, Loc, DeclarationNameInfo(Name, Loc), FunctionTy, @@ -924,7 +946,19 @@ static void addFunctionPointerConversion(Sema &S, Invoke->setParams(InvokeParams); Invoke->setAccess(AS_private); Invoke->setImplicit(true); - Class->addDecl(Invoke); + if (Class->isGenericLambda()) { + FunctionTemplateDecl *TemplateCallOperator = + CallOperator->getDescribedFunctionTemplate(); + FunctionTemplateDecl *StaticInvokerTemplate = FunctionTemplateDecl::Create( + S.Context, Class, Loc, Name, + TemplateCallOperator->getTemplateParameters(), + Invoke); + StaticInvokerTemplate->setAccess(AS_private); + StaticInvokerTemplate->setImplicit(true); + Invoke->setDescribedFunctionTemplate(StaticInvokerTemplate); + Class->addDecl(StaticInvokerTemplate); + } else + Class->addDecl(Invoke); } /// \brief Add a lambda's conversion to block pointer. @@ -1096,7 +1130,9 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, // non-explicit const conversion function to a block pointer having the // same parameter and return types as the closure type's function call // operator. - if (getLangOpts().Blocks && getLangOpts().ObjC1) + // FIXME: Fix generic lambda to block conversions. + if (getLangOpts().Blocks && getLangOpts().ObjC1 && + !Class->isGenericLambda()) addBlockPointerConversion(*this, IntroducerRange, Class, CallOperator); // Finalize the lambda class. @@ -1141,7 +1177,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, } // TODO: Implement capturing. if (Lambda->isGenericLambda()) { - if (Lambda->getCaptureDefault() != LCD_None) { + if (!Captures.empty() || Lambda->getCaptureDefault() != LCD_None) { Diag(Lambda->getIntroducerRange().getBegin(), diag::err_glambda_not_fully_implemented) << " capturing not implemented yet"; diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index b71aafe868addac230fbdace35a2f1804f47a903..4c73fddbb5351b3fe73f4617cddecf6ec9185030 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -13,6 +13,7 @@ #include "clang/Sema/TemplateDeduction.h" #include "TreeTransform.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTLambda.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" @@ -26,7 +27,6 @@ namespace clang { using namespace sema; - /// \brief Various flags that control template argument deduction. /// /// These flags can be bitwise-OR'd together. @@ -3607,19 +3607,37 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, return TDK_Success; } +/// \brief Given a function declaration (e.g. a generic lambda conversion +/// function) that contains an 'auto' in its result type, substitute it +/// with the same Deduced type that the TypeToReplaceAutoWith was deduced +/// with. +static inline void +ReplaceAutoWithinFunctionReturnType(FunctionDecl *F, + QualType TypeToReplaceAutoWith, Sema &S) { + if (TypeToReplaceAutoWith->getContainedAutoType()) + TypeToReplaceAutoWith = TypeToReplaceAutoWith-> + getContainedAutoType()->getDeducedType(); + + QualType AutoResultType = F->getResultType(); + assert(AutoResultType->getContainedAutoType()); + QualType DeducedResultType = S.SubstAutoType(AutoResultType, + TypeToReplaceAutoWith); + S.Context.adjustDeducedFunctionResultType(F, DeducedResultType); +} /// \brief Deduce template arguments for a templated conversion /// function (C++ [temp.deduct.conv]) and, if successful, produce a /// conversion function template specialization. Sema::TemplateDeductionResult -Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, +Sema::DeduceTemplateArguments(FunctionTemplateDecl *ConversionTemplate, QualType ToType, CXXConversionDecl *&Specialization, TemplateDeductionInfo &Info) { - if (FunctionTemplate->isInvalidDecl()) + if (ConversionTemplate->isInvalidDecl()) return TDK_Invalid; CXXConversionDecl *Conv - = cast<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl()); + = cast<CXXConversionDecl>(ConversionTemplate->getTemplatedDecl()); + QualType FromType = Conv->getConversionType(); // Canonicalize the types for deduction. @@ -3675,7 +3693,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // type that is required as the result of the conversion (call it // A) as described in 14.8.2.4. TemplateParameterList *TemplateParams - = FunctionTemplate->getTemplateParameters(); + = ConversionTemplate->getTemplateParameters(); SmallVector<DeducedTemplateArgument, 4> Deduced; Deduced.resize(TemplateParams->size()); @@ -3703,14 +3721,147 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, = DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams, P, A, Info, Deduced, TDF)) return Result; - + + // Create an Instantiation Scope for finalizing the operator. + LocalInstantiationScope InstScope(*this); + + CXXMethodDecl *LambdaCallOpSpec = 0; + bool GenericLambdaCallOperatorHasDeducedReturnType = false; + + // Having successfully deduced and matched the type of the conversion + // function against the destination type, if the destination type + // is a ptr-to-function and the source type is a generic lambda conversion + // to ptr-to-function, we know that the parameters of the destination + // ptr-to-function have matched successfully against those of our + // lambda's conversion function. + // For instance: + // int (*fp)(int) = [](auto a) { return a; }; + // [template<class T> operator id<auto(*)(T)>() const] + // If it is indeed the conversion operator of a generic lambda then if + // not already done, create the corresponding specializations of the call + // operator and the static-invoker; and if the return type is auto, + // deduce the return type, and then check and see if it matches the ToType. + + const bool IsGenericLambdaConversionOperator = + isLambdaConversionOperator(Conv); + if (IsGenericLambdaConversionOperator) { + const Type *FromTypePtr = P.getTypePtr(); + const Type *ToTypePtr = A.getTypePtr(); + + assert(P->isPointerType()); + FromTypePtr = P->getPointeeType().getTypePtr(); + assert(A->isPointerType()); + ToTypePtr = A->getPointeeType().getTypePtr(); + + CXXRecordDecl *LambdaClass = Conv->getParent(); + assert(LambdaClass && LambdaClass->isGenericLambda()); + + const FunctionType *ToFunType = ToTypePtr->getAs<FunctionType>(); + + // The specialization of the Generic Lambda Call Op, instantiated + // using the deduced parameters from the conversion function + // i.e. + // auto L = [](auto a) { return f(a); }; + // int (*fp)(int) = L; + // + + CXXMethodDecl *CallOp = LambdaClass->getLambdaCallOperator(); + QualType CallOpResultType = CallOp->getResultType(); + GenericLambdaCallOperatorHasDeducedReturnType = + CallOpResultType->getContainedAutoType(); + FunctionTemplateDecl *CallOpTemplate = + CallOp->getDescribedFunctionTemplate(); + + TemplateDeductionInfo OpInfo(Info.getLocation()); + FunctionDecl *CallOpSpec = 0; + // Use the deduced arguments so far, to specialize our generic + // lambda's call operator. + if (TemplateDeductionResult Result + = FinishTemplateArgumentDeduction(CallOpTemplate, Deduced, + 0, CallOpSpec, OpInfo)) + return Result; + + bool HadToDeduceReturnTypeDuringCurrentCall = false; + // If we need to deduce the return type, do so (instantiates the callop). + if (GenericLambdaCallOperatorHasDeducedReturnType && + CallOpSpec->getResultType()->isUndeducedType()) { + HadToDeduceReturnTypeDuringCurrentCall = true; + DeduceReturnType(CallOpSpec, CallOpSpec->getPointOfInstantiation(), + /*Diagnose*/ true); + } + + LambdaCallOpSpec = cast<CXXMethodDecl>(CallOpSpec); + + // Check to see if the return type of the destination ptr-to-function + // matches the return type of the call operator. + if (!Context.hasSameType(LambdaCallOpSpec->getResultType(), + ToFunType->getResultType())) + return TDK_NonDeducedMismatch; + // Since we have succeeded in matching the source and destination + // ptr-to-functions (now including return type), and have successfully + // specialized our corresponding call operator, we are ready to + // specialize the static invoker with the deduced arguments of our + // ptr-to-function. + FunctionDecl *InvokerSpecialization = 0; + FunctionTemplateDecl *InvokerTemplate = LambdaClass-> + getLambdaStaticInvoker()->getDescribedFunctionTemplate(); + + TemplateDeductionResult Result + = FinishTemplateArgumentDeduction(InvokerTemplate, Deduced, 0, + InvokerSpecialization, Info); + assert(Result == TDK_Success); + // Set the result type to match the corresponding call operator + // specialization's result type. + if (GenericLambdaCallOperatorHasDeducedReturnType && + InvokerSpecialization->getResultType()->isUndeducedType()) + ReplaceAutoWithinFunctionReturnType(InvokerSpecialization, + LambdaCallOpSpec->getResultType(), *this); + + // Ensure that static invoker doesn't have a const qualifier. + // FIXME: When creating the InvokerTemplate in SemaLambda.cpp + // do not use the CallOperator's TypeSourceInfo which allows + // the const qualifier to leak through. + const FunctionProtoType *InvokerFPT = InvokerSpecialization-> + getType().getTypePtr()->castAs<FunctionProtoType>(); + FunctionProtoType::ExtProtoInfo EPI = InvokerFPT->getExtProtoInfo(); + EPI.TypeQuals = 0; + InvokerSpecialization->setType(Context.getFunctionType( + InvokerFPT->getResultType(), InvokerFPT->getArgTypes(),EPI)); + + // Since the original conversion operator's parameters are the same + // entities as the lambda's call operator's, we introduce a mapping + // from the generic to the specialized parameters of the call operators. + // This only needs to be done in the absence of return type deduction, + // since deducing the return type entails instantiation which adds + // the parameter mapping to the CurrentInstantiationScope. + // This is necessary when transforming nested lambdas that do not + // capture. + // FIXME: This will be fixed once nested lambdas and capturing + // is implemented since it does require handling parameter + // packs correctly which might require careful calls to + // SemaTemplateInstantiate::addInstantiatedParametersToScope. + // if (!HadToDeduceReturnTypeDuringCurrentCall) { ... } + } + + // Finish template argument deduction. - LocalInstantiationScope InstScope(*this); - FunctionDecl *Spec = 0; - TemplateDeductionResult Result - = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, 0, Spec, - Info); - Specialization = cast_or_null<CXXConversionDecl>(Spec); + FunctionDecl *ConversionSpec = 0; + TemplateDeductionResult Result + = FinishTemplateArgumentDeduction(ConversionTemplate, Deduced, 0, + ConversionSpec, Info); + Specialization = cast_or_null<CXXConversionDecl>(ConversionSpec); + if (Result == TDK_Success && GenericLambdaCallOperatorHasDeducedReturnType) { + // Set the return type of the conversion specialization, since even + // though we have ensured that the return types are compatible, if + // there is an auto in the return type of this conversion function, + // replace it permanently with the return type of the deduced lambda + // so we don't try and deduce against it. + assert(LambdaCallOpSpec); + if (ConversionSpec->getResultType()->isUndeducedType()) + ReplaceAutoWithinFunctionReturnType(ConversionSpec, + LambdaCallOpSpec->getResultType(), + *this); + } return Result; } diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp index 7773aedb4ee46833922ed3c36fc821bd071bf8bc..a43a98bb18f859a939a46d630561c6d238e9e9bc 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp @@ -1,20 +1,30 @@ // RUN: %clang_cc1 -fsyntax-only -std=c++1y %s -verify -namespace return_type_deduction_ok { - auto l = [](auto a) ->auto { return a; }(2); - auto l2 = [](auto a) ->decltype(auto) { return a; }(2); - auto l3 = [](auto a) { return a; }(2); - -} namespace lambda_capturing { // FIXME: Once return type deduction is implemented for generic lambdas // this will need to be updated. void test() { int i = 10; - auto L = [=](auto a) -> int { //expected-error{{unimplemented}} - return i + a; - }; - L(3); + { + auto L = [=](auto a) -> int { //expected-error{{unimplemented}} + return i + a; + }; + L(3); + } + { + auto L = [i](auto a) -> int { //expected-error{{unimplemented}} + return i + a; + }; + L(3); + } + { + auto L = [i = i](auto a) -> int { //expected-error{{unimplemented}} + return i + a; + }; + L(3); + } + + } } @@ -35,17 +45,4 @@ template<class T> void foo(T) { template void foo(int); //expected-note{{in instantiation of}} } -namespace conversion_operator { -void test() { - auto L = [](auto a) -> int { return a; }; - int (*fp)(int) = L; //expected-error{{no viable conversion}} - } -} - -namespace generic_lambda_as_default_argument_ok { - void test(int i = [](auto a)->int { return a; }(3)) { - - } - -} diff --git a/test/SemaCXX/cxx1y-generic-lambdas.cpp b/test/SemaCXX/cxx1y-generic-lambdas.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b66825a536dc3939b7df65135325df5f42847984 --- /dev/null +++ b/test/SemaCXX/cxx1y-generic-lambdas.cpp @@ -0,0 +1,116 @@ +// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks %s +// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING +// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fms-extensions %s -DMS_EXTENSIONS +// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING + +namespace explicit_call { +int test() { + auto L = [](auto a) { return a; }; + L.operator()(3); + L.operator()<char>(3.14); //expected-warning{{implicit conversion}} + return 0; +} +} //end ns + +namespace test_conversion_to_fptr { + +void f1(int (*)(int)) { } +void f2(char (*)(int)) { } // expected-note{{candidate}} +void g(int (*)(int)) { } // #1 expected-note{{candidate}} +void g(char (*)(char)) { } // #2 expected-note{{candidate}} +void h(int (*)(int)) { } // #3 +void h(char (*)(int)) { } // #4 + +int test() { +{ + auto glambda = [](auto a) { return a; }; + glambda(1); + f1(glambda); // OK + f2(glambda); // expected-error{{no matching function}} + g(glambda); // expected-error{{call to 'g' is ambiguous}} + h(glambda); // OK: calls #3 since it is convertible from ID + + int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK + +} +{ + + auto L = [](auto a) { return a; }; + int (*fp)(int) = L; + fp(5); + L(3); + char (*fc)(char) = L; + fc('b'); + L('c'); + double (*fd)(double) = L; + fd(3.14); + fd(6.26); + L(4.25); +} +{ + auto L = [](auto a) ->int { return a; }; //expected-note 2{{candidate template ignored}} + int (*fp)(int) = L; + char (*fc)(char) = L; //expected-error{{no viable conversion}} + double (*fd)(double) = L; //expected-error{{no viable conversion}} +} + +} + +namespace more_converion_to_ptr_to_function_tests { + + +int test() { + { + int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK + int (*fp2)(int) = [](auto b) -> int { return b; }; + int (*fp3)(char) = [](auto c) -> int { return c; }; + char (*fp4)(int) = [](auto d) { return d; }; //expected-error{{no viable conversion}}\ + //expected-note{{candidate template ignored}} + char (*fp5)(char) = [](auto e) -> int { return e; }; //expected-error{{no viable conversion}}\ + //expected-note{{candidate template ignored}} + + fp2(3); + fp3('\n'); + fp3('a'); + return 0; + } +} // end test() + +template<class ... Ts> void vfun(Ts ... ) { } + +int variadic_test() { + + int (*fp)(int, char, double) = [](auto ... a) -> int { vfun(a...); return 4; }; + fp(3, '4', 3.14); + + int (*fp2)(int, char, double) = [](auto ... a) { vfun(a...); return 4; }; + fp(3, '4', 3.14); + return 2; +} + +} // end ns + +namespace conversion_operator { +void test() { + auto L = [](auto a) -> int { return a; }; + int (*fp)(int) = L; + int (&fp2)(int) = [](auto a) { return a; }; // expected-error{{non-const lvalue}} + int (&&fp3)(int) = [](auto a) { return a; }; // expected-error{{no viable conversion}}\ + //expected-note{{candidate}} + } +} + +} + + +namespace return_type_deduction_ok { + auto l = [](auto a) ->auto { return a; }(2); + auto l2 = [](auto a) ->decltype(auto) { return a; }(2); + auto l3 = [](auto a) { return a; }(2); + +} + +namespace generic_lambda_as_default_argument_ok { + void test(int i = [](auto a)->int { return a; }(3)) { + } +}