On 29.09.2013, at 10:45, Faisal Vali <[email protected]> wrote: > Author: faisalv > Date: Sun Sep 29 03:45:24 2013 > New Revision: 191634 > > URL: http://llvm.org/viewvc/llvm-project?rev=191634&view=rev > Log: > Implement conversion to function pointer for generic lambdas without captures.
This patch introduced windows-style newlines in many source files. Please fix. - Ben > > The general strategy is to create template versions of the conversion > function and static invoker and then during template argument deduction of > the conversion function, create the corresponding call-operator and static > invoker specializations, and when the conversion function is marked > referenced generate the body of the conversion function using the > corresponding static-invoker specialization. Similarly, Codegen does > something similar - when asked to emit the IR for a specialized static > invoker of a generic lambda, it forwards emission to the corresponding call > operator. > > This patch has been reviewed in person both by Doug and Richard. Richard > gave me the LGTM. > > A few minor changes: > - per Richard's request i added a simple check to gracefully inform that > captures (init, explicit or default) have not been added to generic lambdas > just yet (instead of the assertion violation). > - I removed a few lines of code that added the call operators instantiated > parameters to the currentinstantiationscope. Not only did it not handle > parameter packs, but it is more relevant in the patch for nested lambdas > which will follow this one, and fix that problem more comprehensively. > - Doug had commented that the original implementation strategy of using the > TypeSourceInfo of the call operator to create the static-invoker was flawed > and allowed const as a member qualifier to creep into the type of the > static-invoker. I currently kludge around it - but after my initial > discussion with Doug, with a follow up session with Richard, I have added a > FIXME so that a more elegant solution that involves the use of > TrivialTypeSourceInfo call followed by the correct wiring of the template > parameters to the functionprototypeloc is forthcoming. > > Thanks! > > > Added: > cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp > Modified: > cfe/trunk/include/clang/AST/ASTLambda.h > cfe/trunk/lib/AST/DeclCXX.cpp > cfe/trunk/lib/CodeGen/CGClass.cpp > cfe/trunk/lib/CodeGen/CodeGenFunction.h > cfe/trunk/lib/Sema/SemaDeclCXX.cpp > cfe/trunk/lib/Sema/SemaLambda.cpp > cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp > > cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp > > Modified: cfe/trunk/include/clang/AST/ASTLambda.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTLambda.h?rev=191634&r1=191633&r2=191634&view=diff > ============================================================================== > --- cfe/trunk/include/clang/AST/ASTLambda.h (original) > +++ cfe/trunk/include/clang/AST/ASTLambda.h Sun Sep 29 03:45:24 2013 > @@ -31,7 +31,13 @@ inline bool isLambdaCallOperator(const C > 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 isGenericLambdaCallOperatorS > 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 > > Modified: cfe/trunk/lib/AST/DeclCXX.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=191634&r1=191633&r2=191634&view=diff > ============================================================================== > --- cfe/trunk/lib/AST/DeclCXX.cpp (original) > +++ cfe/trunk/lib/AST/DeclCXX.cpp Sun Sep 29 03:45:24 2013 > @@ -972,9 +972,12 @@ CXXMethodDecl* CXXRecordDecl::getLambdaS > 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() cons > } > > 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, > > Modified: cfe/trunk/lib/CodeGen/CGClass.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=191634&r1=191633&r2=191634&view=diff > ============================================================================== > --- cfe/trunk/lib/CodeGen/CGClass.cpp (original) > +++ cfe/trunk/lib/CodeGen/CGClass.cpp Sun Sep 29 03:45:24 2013 > @@ -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::EmitCXXOperatorMemberCa > 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::EmitLambdaBlockInv > 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::EmitLambdaDelegati > 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) > { > > Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=191634&r1=191633&r2=191634&view=diff > ============================================================================== > --- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original) > +++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Sun Sep 29 03:45:24 2013 > @@ -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(); > > Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=191634&r1=191633&r2=191634&view=diff > ============================================================================== > --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) > +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sun Sep 29 03:45:24 2013 > @@ -10351,57 +10351,92 @@ bool Sema::isImplicitlyDeleted(FunctionD > 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); > > Modified: cfe/trunk/lib/Sema/SemaLambda.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=191634&r1=191633&r2=191634&view=diff > ============================================================================== > --- cfe/trunk/lib/Sema/SemaLambda.cpp (original) > +++ cfe/trunk/lib/Sema/SemaLambda.cpp Sun Sep 29 03:45:24 2013 > @@ -857,8 +857,6 @@ static void addFunctionPointerConversion > 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 > 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 > 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(SourceL > // 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(SourceL > } > // 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"; > > Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=191634&r1=191633&r2=191634&view=diff > ============================================================================== > --- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original) > +++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Sun Sep 29 03:45:24 2013 > @@ -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(FunctionTe > 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(FunctionTe > // 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(FunctionTe > = 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; > } > > > Modified: > cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp?rev=191634&r1=191633&r2=191634&view=diff > ============================================================================== > --- > cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp > (original) > +++ > cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp > Sun Sep 29 03:45:24 2013 > @@ -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)) { > - > - } > - > -} > > > Added: cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp?rev=191634&view=auto > ============================================================================== > --- cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp (added) > +++ cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp Sun Sep 29 03:45:24 2013 > @@ -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)) { > + } > +} > > > _______________________________________________ > cfe-commits mailing list > [email protected] > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
