]> granicus.if.org Git - clang/commitdiff
Implement conversion to function pointer for generic lambdas without captures.
authorFaisal Vali <faisalv@yahoo.com>
Sun, 29 Sep 2013 08:45:24 +0000 (08:45 +0000)
committerFaisal Vali <faisalv@yahoo.com>
Sun, 29 Sep 2013 08:45:24 +0000 (08:45 +0000)
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!

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@191634 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/ASTLambda.h
lib/AST/DeclCXX.cpp
lib/CodeGen/CGClass.cpp
lib/CodeGen/CodeGenFunction.h
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaLambda.cpp
lib/Sema/SemaTemplateDeduction.cpp
test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp
test/SemaCXX/cxx1y-generic-lambdas.cpp [new file with mode: 0644]

index 814beb34e177b9812f69aa8c1ff8f5c601c3161d..9044878e35da2977b130f6b27b135b1b7e41ba28 100644 (file)
@@ -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
index 33c7ff99b0e5652949be79dccda6bb312041328f..146853586aca022269fe89fd5df25ed092693e22 100644 (file)
@@ -972,9 +972,12 @@ CXXMethodDecl* CXXRecordDecl::getLambdaStaticInvoker() const {
   DeclContext::lookup_const_result Invoker = lookup(Name);
   if (Invoker.empty()) return 0;\r
   assert(Invoker.size() == 1 && "More than one static invoker operator!");  \r
-  CXXMethodDecl *Result = cast<CXXMethodDecl>(Invoker.front());  \r
-  return Result;
-
+  NamedDecl *InvokerFun = Invoker.front();\r
+  if (FunctionTemplateDecl *InvokerTemplate =\r
+                  dyn_cast<FunctionTemplateDecl>(InvokerFun)) \r
+    return cast<CXXMethodDecl>(InvokerTemplate->getTemplatedDecl());\r
+  \r
+  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,
index c1226d5681c95b0d94c662e0acbf2ffcfd451158..4db5b09afe116816b3c1155c66bbd7f6138789ec 100644 (file)
@@ -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) {
index 5889d058606f9522f5caf13072370358a67ced57..080d0b7b6f332672c201b857c78261e91851ea77 100644 (file)
@@ -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();
index 6e1751aebd931df993730c8a5b850c7f529df7a0..4aa53e0a8e88bdd4ef64469062ccb008f58008f4 100644 (file)
@@ -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());\r
+
   Conv->markUsed(Context);
   
   SynthesizedFunctionScope Scope(*this, Conv);
index fa46a282991c0a45fdbf901eb94497ff5b2a709d..32a385caaa559fe349bd376464e371a55758d112 100644 (file)
@@ -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";
index b71aafe868addac230fbdace35a2f1804f47a903..4c73fddbb5351b3fe73f4617cddecf6ec9185030 100644 (file)
@@ -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 \r
+///  function) that contains an 'auto' in its result type, substitute it \r
+///  with the same Deduced type that the TypeToReplaceAutoWith was deduced \r
+///  with.\r
+static inline void 
+ReplaceAutoWithinFunctionReturnType(FunctionDecl *F, 
+                                    QualType TypeToReplaceAutoWith, Sema &S) {
+  if (TypeToReplaceAutoWith->getContainedAutoType())
+    TypeToReplaceAutoWith = TypeToReplaceAutoWith->
+        getContainedAutoType()->getDeducedType();
+
+  QualType AutoResultType = F->getResultType();\r
+  assert(AutoResultType->getContainedAutoType()); \r
+  QualType DeducedResultType = S.SubstAutoType(AutoResultType, \r
+                                               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;
-
+\r
+  // Create an Instantiation Scope for finalizing the operator.\r
+  LocalInstantiationScope InstScope(*this);\r
+  \r
+  CXXMethodDecl *LambdaCallOpSpec = 0;\r
+  bool GenericLambdaCallOperatorHasDeducedReturnType = false;
+  \r
+  // Having successfully deduced and matched the type of the conversion\r
+  // function against the destination type, if the destination type\r
+  // is a ptr-to-function and the source type is a generic lambda conversion\r
+  // to ptr-to-function, we know that the parameters of the destination \r
+  // ptr-to-function have matched successfully against those of our \r
+  // lambda's conversion function.  \r
+  // For instance:\r
+  //  int (*fp)(int) = [](auto a) { return a; };\r
+  //     [template<class T> operator id<auto(*)(T)>() const]\r
+  // If it is indeed the conversion operator of a generic lambda then if\r
+  // not already done, create the corresponding specializations of the call \r
+  // operator and the static-invoker; and if the return type is auto, \r
+  // deduce the return type, and then check and see if it matches the ToType.\r
+\r
+  const bool IsGenericLambdaConversionOperator = \r
+      isLambdaConversionOperator(Conv);\r
+  if (IsGenericLambdaConversionOperator) {\r
+    const Type *FromTypePtr = P.getTypePtr();\r
+    const Type *ToTypePtr = A.getTypePtr();\r
+\r
+    assert(P->isPointerType()); \r
+    FromTypePtr = P->getPointeeType().getTypePtr();\r
+    assert(A->isPointerType());\r
+    ToTypePtr = A->getPointeeType().getTypePtr();\r
+    \r
+    CXXRecordDecl *LambdaClass = Conv->getParent();\r
+    assert(LambdaClass && LambdaClass->isGenericLambda()); \r
+\r
+    const FunctionType *ToFunType = ToTypePtr->getAs<FunctionType>();\r
+\r
+    // The specialization of the Generic Lambda Call Op, instantiated\r
+    // using the deduced parameters from the conversion function\r
+    // i.e.\r
+    // auto L = [](auto a) { return f(a); };\r
+    // int (*fp)(int) = L;\r
+    //\r
+\r
+    CXXMethodDecl *CallOp = LambdaClass->getLambdaCallOperator();\r
+    QualType CallOpResultType = CallOp->getResultType(); \r
+    GenericLambdaCallOperatorHasDeducedReturnType = \r
+        CallOpResultType->getContainedAutoType();\r
+    FunctionTemplateDecl *CallOpTemplate = \r
+        CallOp->getDescribedFunctionTemplate();\r
+\r
+    TemplateDeductionInfo OpInfo(Info.getLocation()); \r
+    FunctionDecl *CallOpSpec = 0;\r
+    // Use the deduced arguments so far, to specialize our generic\r
+    // lambda's call operator.\r
+    if (TemplateDeductionResult Result\r
+                  = FinishTemplateArgumentDeduction(CallOpTemplate, Deduced, \r
+                                                    0, CallOpSpec, OpInfo))\r
+      return Result;\r
\r
+    bool HadToDeduceReturnTypeDuringCurrentCall = false;\r
+    // If we need to deduce the return type, do so (instantiates the callop).\r
+    if (GenericLambdaCallOperatorHasDeducedReturnType && \r
+        CallOpSpec->getResultType()->isUndeducedType()) {\r
+      HadToDeduceReturnTypeDuringCurrentCall = true;\r
+      DeduceReturnType(CallOpSpec, CallOpSpec->getPointOfInstantiation(),\r
+                      /*Diagnose*/ true);\r
+    }\r
+    \r
+    LambdaCallOpSpec = cast<CXXMethodDecl>(CallOpSpec);\r
+    \r
+    // Check to see if the return type of the destination ptr-to-function\r
+    // matches the return type of the call operator.\r
+    if (!Context.hasSameType(LambdaCallOpSpec->getResultType(), \r
+        ToFunType->getResultType()))\r
+      return TDK_NonDeducedMismatch;\r
+    // Since we have succeeded in matching the source and destination\r
+    // ptr-to-functions (now including return type), and have successfully \r
+    // specialized our corresponding call operator, we are ready to\r
+    // specialize the static invoker with the deduced arguments of our\r
+    // ptr-to-function.\r
+    FunctionDecl *InvokerSpecialization = 0;\r
+    FunctionTemplateDecl *InvokerTemplate = LambdaClass->\r
+                    getLambdaStaticInvoker()->getDescribedFunctionTemplate();\r
+\r
+    TemplateDeductionResult Result\r
+      = FinishTemplateArgumentDeduction(InvokerTemplate, Deduced, 0, \r
+            InvokerSpecialization, Info);\r
+    assert(Result == TDK_Success);\r
+    // Set the result type to match the corresponding call operator\r
+    // specialization's result type.\r
+    if (GenericLambdaCallOperatorHasDeducedReturnType && \r
+        InvokerSpecialization->getResultType()->isUndeducedType())\r
+      ReplaceAutoWithinFunctionReturnType(InvokerSpecialization,\r
+                                LambdaCallOpSpec->getResultType(), *this);\r
+    
+    // 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));\r
+    \r
+    // Since the original conversion operator's parameters are the same \r
+    // entities as the lambda's call operator's, we introduce a mapping\r
+    // from the generic to the specialized parameters of the call operators.\r
+    // This only needs to be done in the absence of return type deduction,\r
+    // since deducing the return type entails instantiation which adds\r
+    // the parameter mapping to the CurrentInstantiationScope. \r
+    // This is necessary when transforming nested lambdas that do not\r
+    // capture.\r
+    // FIXME: This will be fixed once nested lambdas and capturing\r
+    // is implemented since it does require handling parameter \r
+    // packs correctly which might require careful calls to\r
+    // SemaTemplateInstantiate::addInstantiatedParametersToScope.\r
+    // if (!HadToDeduceReturnTypeDuringCurrentCall) { ... }
+  }
+  \r
+  \r
   // 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;\r
+  TemplateDeductionResult Result\r
+        = FinishTemplateArgumentDeduction(ConversionTemplate, Deduced, 0, \r
+              ConversionSpec, Info);\r
+  Specialization = cast_or_null<CXXConversionDecl>(ConversionSpec);\r
+  if (Result == TDK_Success && GenericLambdaCallOperatorHasDeducedReturnType) {\r
+    // Set the return type of the conversion specialization, since even \r
+    // though we have ensured that the return types are compatible, if \r
+    // there is an auto in the return type of this conversion function, \r
+    // replace it permanently with the return type of the deduced lambda\r
+    // so we don't try and deduce against it.\r
+    assert(LambdaCallOpSpec);\r
+    if (ConversionSpec->getResultType()->isUndeducedType())\r
+      ReplaceAutoWithinFunctionReturnType(ConversionSpec, \r
+                                          LambdaCallOpSpec->getResultType(),\r
+                                         *this);\r
+  } 
   return Result;
 }
 
index 7773aedb4ee46833922ed3c36fc821bd071bf8bc..a43a98bb18f859a939a46d630561c6d238e9e9bc 100644 (file)
@@ -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 (file)
index 0000000..b66825a
--- /dev/null
@@ -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)) {
+  }
+}