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

Reply via email to