]> granicus.if.org Git - clang/commitdiff
Implement a rudimentary form of generic lambdas.
authorFaisal Vali <faisalv@yahoo.com>
Thu, 26 Sep 2013 19:54:12 +0000 (19:54 +0000)
committerFaisal Vali <faisalv@yahoo.com>
Thu, 26 Sep 2013 19:54:12 +0000 (19:54 +0000)
Specifically, the following features are not included in this commit:
  - any sort of capturing within generic lambdas
  - generic lambdas within template functions and nested
    within other generic lambdas
  - conversion operator for captureless lambdas
  - ensuring all visitors are generic lambda aware
  (Although I have gotten some useful feedback on my patches of the above and will be incorporating that as I submit those patches for commit)

As an example of what compiles through this commit:

template <class F1, class F2>
struct overload : F1, F2 {
    using F1::operator();
    using F2::operator();
    overload(F1 f1, F2 f2) : F1(f1), F2(f2) { }
  };

  auto Recursive = [](auto Self, auto h, auto ... rest) {
    return 1 + Self(Self, rest...);
  };
  auto Base = [](auto Self, auto h) {
      return 1;
  };
  overload<decltype(Base), decltype(Recursive)> O(Base, Recursive);
  int num_params =  O(O, 5, 3, "abc", 3.14, 'a');

Please see attached tests for more examples.

This patch has been reviewed by Doug and Richard.  Minor changes (non-functionality affecting) have been made since both of them formally looked at it, but the changes involve removal of supernumerary return type deduction changes (since they are now redundant, with richard having committed a recent patch to address return type deduction for C++11 lambdas using C++14 semantics).

Some implementation notes:

  - Add a new Declarator context => LambdaExprParameterContext to
    clang::Declarator to allow the use of 'auto' in declaring generic
    lambda parameters

  - Add various helpers to CXXRecordDecl to facilitate identifying
    and querying a closure class

  - LambdaScopeInfo (which maintains the current lambda's Sema state)
    was augmented to house the current depth of the template being
    parsed (id est the Parser calls Sema::RecordParsingTemplateParameterDepth)
    so that SemaType.cpp::ConvertDeclSpecToType may use it to immediately
    generate a template-parameter-type when 'auto' is parsed in a generic
    lambda parameter context.  (i.e we do NOT use AutoType deduced to
    a template parameter type - Richard seemed ok with this approach).
    We encode that this template type was generated from an auto by simply
    adding $auto to the name which can be used for better diagnostics if needed.

  - SemaLambda.h was added to hold some common lambda utility
    functions (this file is likely to grow ...)

  - Teach Sema::ActOnStartOfFunctionDef to check whether it
    is being called to instantiate a generic lambda's call
    operator, and if so, push an appropriately prepared
    LambdaScopeInfo object on the stack.

  - various tests were added - but much more will be needed.

There is obviously more work to be done, and both Richard (weakly) and Doug (strongly)
have requested that LambdaExpr be removed form the CXXRecordDecl LambdaDefinitionaData
in a future patch which is forthcoming.

A greatful thanks to all reviewers including Eli Friedman, James Dennett,
and especially the two gracious wizards (Richard Smith and Doug Gregor)
who spent hours providing feedback (in person in Chicago and on the mailing lists).
And yet I am certain that I have allowed unidentified bugs to creep in; bugs, that I will do my best to slay, once identified!

Thanks!

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

32 files changed:
include/clang/AST/ASTContext.h
include/clang/AST/ASTLambda.h [new file with mode: 0644]
include/clang/AST/DeclCXX.h
include/clang/AST/ExprCXX.h
include/clang/AST/Type.h
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/DeclSpec.h
include/clang/Sema/ScopeInfo.h
include/clang/Sema/Sema.h
lib/AST/ASTDumper.cpp
lib/AST/ASTImporter.cpp
lib/AST/DeclCXX.cpp
lib/AST/ExprCXX.cpp
lib/CodeGen/CodeGenFunction.cpp
lib/Parse/ParseDecl.cpp
lib/Parse/ParseExprCXX.cpp
lib/Sema/Sema.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaLambda.cpp
lib/Sema/SemaOverload.cpp
lib/Sema/SemaTemplateDeduction.cpp
lib/Sema/SemaType.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTReaderDecl.cpp
lib/Serialization/ASTWriter.cpp
test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-generic-lambda-1y.cpp [new file with mode: 0644]
test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp [new file with mode: 0644]
test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp [new file with mode: 0644]
test/CXX/expr/expr.prim/expr.prim.lambda/p4-1y.cpp
test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp [new file with mode: 0644]

index f1ccee2e37250683a485ed982d0330e012761e4d..b0205426750e130e992f7ba79e41c018b909aac7 100644 (file)
@@ -1130,7 +1130,7 @@ public:
 
   /// \brief C++11 deduced auto type.
   QualType getAutoType(QualType DeducedType, bool IsDecltypeAuto,
-                       bool IsDependent = false) const;
+                       bool IsDependent) const;
 
   /// \brief C++11 deduction pattern for 'auto' type.
   QualType getAutoDeductType() const;
diff --git a/include/clang/AST/ASTLambda.h b/include/clang/AST/ASTLambda.h
new file mode 100644 (file)
index 0000000..814beb3
--- /dev/null
@@ -0,0 +1,49 @@
+//===--- ASTLambda.h - Lambda Helper Functions --------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file provides some common utility functions for processing
+/// Lambda related AST Constructs.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_LAMBDA_H
+#define LLVM_CLANG_AST_LAMBDA_H
+
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
+
+namespace clang {
+inline StringRef getLambdaStaticInvokerName() {
+  return "__invoke";
+}
+// This function returns true if M is a specialization, a template,
+// or a non-generic lambda call operator.
+inline bool isLambdaCallOperator(const CXXMethodDecl *MD) {
+  const CXXRecordDecl *LambdaClass = MD->getParent();
+  if (!LambdaClass || !LambdaClass->isLambda()) return false;
+  return MD->getOverloadedOperator() == OO_Call;
+}
+
+inline bool isGenericLambdaCallOperatorSpecialization(CXXMethodDecl *MD) {
+  CXXRecordDecl *LambdaClass = MD->getParent();
+  if (LambdaClass && LambdaClass->isGenericLambda())
+    return isLambdaCallOperator(MD) && 
+                    MD->isFunctionTemplateSpecialization();
+  return false;
+}
+
+inline bool isGenericLambdaCallOperatorSpecialization(Decl *D) {
+  if (!D || !isa<CXXMethodDecl>(D)) return false;
+  return isGenericLambdaCallOperatorSpecialization(
+                                cast<CXXMethodDecl>(D));
+}
+} // clang
+
+#endif // LLVM_CLANG_AST_LAMBDA_H
index f8f2e41fe62966048075adcf442ac56a765100c8..3c970059eb556de6a798636aa789f2e21cb62c7d 100644 (file)
@@ -516,8 +516,8 @@ class CXXRecordDecl : public RecordDecl {
     
     LambdaDefinitionData(CXXRecordDecl *D, TypeSourceInfo *Info, bool Dependent) 
       : DefinitionData(D), Dependent(Dependent), NumCaptures(0), 
-        NumExplicitCaptures(0), ManglingNumber(0), ContextDecl(0), Captures(0),
-        MethodTyInfo(Info
+        NumExplicitCaptures(0), ManglingNumber(0), ContextDecl(0), 
+        Captures(0), MethodTyInfo(Info), TheLambdaExpr(0
     {
       IsLambda = true;
     }
@@ -529,7 +529,7 @@ class CXXRecordDecl : public RecordDecl {
     /// within the default argument of a function template, because the
     /// lambda will have been created with the enclosing context as its
     /// declaration context, rather than function. This is an unfortunate
-    /// artifact of having to parse the default arguments before 
+    /// artifact of having to parse the default arguments before. 
     unsigned Dependent : 1;
     
     /// \brief The number of captures in this lambda.
@@ -554,6 +554,10 @@ class CXXRecordDecl : public RecordDecl {
 
     /// \brief The type of the call method.
     TypeSourceInfo *MethodTyInfo;
+
+    /// \brief The AST node of the lambda expression.
+    LambdaExpr *TheLambdaExpr;
+       
   };
 
   struct DefinitionData &data() {
@@ -989,6 +993,36 @@ public:
   /// \brief Determine whether this class describes a lambda function object.
   bool isLambda() const { return hasDefinition() && data().IsLambda; }
 
+  /// \brief Determine whether this class describes a generic 
+  /// lambda function object (i.e. function call operator is
+  /// a template). 
+  bool isGenericLambda() const; 
+
+  /// \brief Retrieve the lambda call operator of the closure type
+  /// if this is a closure type.
+  CXXMethodDecl *getLambdaCallOperator() const; 
+
+  /// \brief Retrieve the lambda static invoker, the address of which
+  /// is returned by the conversion operator, and the body of which
+  /// is forwarded to the lambda call operator. 
+  CXXMethodDecl *getLambdaStaticInvoker() const; 
+
+  /// \brief Retrieve the generic lambda's template parameter list.
+  /// Returns null if the class does not represent a lambda or a generic 
+  /// lambda.
+  TemplateParameterList *getGenericLambdaTemplateParameterList() const;
+
+  /// \brief Assign the member call operator of the lambda. 
+  void setLambdaExpr(LambdaExpr *E) {
+    getLambdaData().TheLambdaExpr = E;
+  }
+
+  /// \brief Retrieve the parent lambda expression.
+  LambdaExpr *getLambdaExpr() const {
+    return isLambda() ? getLambdaData().TheLambdaExpr : 0;
+  }
+
+
   /// \brief For a closure type, retrieve the mapping from captured
   /// variables and \c this to the non-static data members that store the
   /// values or references of the captures.
index c39d29f80e1e88177d8d6cbc9fa4749ba1835d3f..a8949fe18b1c88f60f126022e2c05399015eec4c 100644 (file)
@@ -1606,6 +1606,13 @@ public:
   /// lambda expression. 
   CXXMethodDecl *getCallOperator() const;
 
+  /// \brief If this is a generic lambda expression, retrieve the template 
+  /// parameter list associated with it, or else return null. 
+  TemplateParameterList *getTemplateParameterList() const;
+
+  /// \brief Whether this is a generic lambda.
+  bool isGenericLambda() const { return getTemplateParameterList(); }
+
   /// \brief Retrieve the body of the lambda.
   CompoundStmt *getBody() const;
 
index 8df030c842f51c7e82ae9d212d985f408242f660..fb829e4d41039a95ef9a83b095a44bdb6050e050 100644 (file)
@@ -3630,10 +3630,13 @@ public:
 /// is no deduced type and an auto type is canonical. In the latter case, it is
 /// also a dependent type.
 class AutoType : public Type, public llvm::FoldingSetNode {
-  AutoType(QualType DeducedType, bool IsDecltypeAuto, bool IsDependent)
+  AutoType(QualType DeducedType, bool IsDecltypeAuto, 
+           bool IsDependent)
     : Type(Auto, DeducedType.isNull() ? QualType(this, 0) : DeducedType,
            /*Dependent=*/IsDependent, /*InstantiationDependent=*/IsDependent,
-           /*VariablyModified=*/false, /*ContainsParameterPack=*/false) {
+           /*VariablyModified=*/false, 
+           /*ContainsParameterPack=*/DeducedType.isNull() 
+               ? false : DeducedType->containsUnexpandedParameterPack()) {
     assert((DeducedType.isNull() || !IsDependent) &&
            "auto deduced to dependent type");
     AutoTypeBits.IsDecltypeAuto = IsDecltypeAuto;
@@ -3657,7 +3660,8 @@ public:
   }
 
   void Profile(llvm::FoldingSetNodeID &ID) {
-    Profile(ID, getDeducedType(), isDecltypeAuto(), isDependentType());
+    Profile(ID, getDeducedType(), isDecltypeAuto(), 
+                   isDependentType());
   }
 
   static void Profile(llvm::FoldingSetNodeID &ID, QualType Deduced,
index 2ac197fd520610f67b5c1cac74ab09d6ba16151b..82a36c690c669eeed55c9a42633e68459d94b8c5 100644 (file)
@@ -1470,11 +1470,12 @@ def err_illegal_decl_array_of_auto : Error<
 def err_new_array_of_auto : Error<
   "cannot allocate array of 'auto'">;
 def err_auto_not_allowed : Error<
-  "'auto' not allowed %select{in function prototype|in non-static struct member"
+  "%select{'auto'|'decltype(auto)'}0 not allowed %select{in function prototype"
+  "|in non-static struct member"
   "|in non-static union member|in non-static class member|in interface member"
   "|in exception declaration|in template parameter|in block literal"
   "|in template argument|in typedef|in type alias|in function return type"
-  "|in conversion function type|here}0">;
+  "|in conversion function type|here|in lambda parameter}1">;
 def err_auto_not_allowed_var_inst : Error<
   "'auto' variable template instantiation is not allowed">;
 def err_auto_var_requires_init : Error<
@@ -5078,6 +5079,10 @@ let CategoryName = "Lambda Issue" in {
     "cannot deduce type for lambda capture %0 from initializer list">;
 }
 
+// C++1y Generic Lambdas
+def err_glambda_not_fully_implemented : Error<
+  "unimplemented generic lambda feature: %0">;
+    
 def err_return_in_captured_stmt : Error<
   "cannot return from %0">;
 def err_capture_block_variable : Error<
index 5924a15b7e4ff793cfc9917ed1e7f0eae2fb3ae4..dfb79325f251b5b6b480a43fcb80106f5888fd28 100644 (file)
@@ -1502,6 +1502,7 @@ public:
     ObjCCatchContext,    // Objective-C catch exception-declaration
     BlockLiteralContext, // Block literal declarator.
     LambdaExprContext,   // Lambda-expression declarator.
+    LambdaExprParameterContext, // Lambda-expression parameter declarator.
     ConversionIdContext, // C++ conversion-type-id.
     TrailingReturnContext, // C++11 trailing-type-specifier.
     TemplateTypeArgContext, // Template type argument.
@@ -1577,7 +1578,6 @@ public:
   ~Declarator() {
     clear();
   }
-
   /// getDeclSpec - Return the declaration-specifier that this declarator was
   /// declared with.
   const DeclSpec &getDeclSpec() const { return DS; }
@@ -1606,7 +1606,8 @@ public:
   bool isPrototypeContext() const {
     return (Context == PrototypeContext ||
             Context == ObjCParameterContext ||
-            Context == ObjCResultContext);
+            Context == ObjCResultContext ||
+            Context == LambdaExprParameterContext);
   }
 
   /// \brief Get the source range that spans this declarator.
@@ -1670,6 +1671,7 @@ public:
     case AliasDeclContext:
     case AliasTemplateContext:
     case PrototypeContext:
+    case LambdaExprParameterContext:
     case ObjCParameterContext:
     case ObjCResultContext:
     case TemplateParamContext:
@@ -1698,6 +1700,7 @@ public:
     case ForContext:
     case ConditionContext:
     case PrototypeContext:
+    case LambdaExprParameterContext:
     case TemplateParamContext:
     case CXXCatchContext:
     case ObjCCatchContext:
@@ -1730,6 +1733,7 @@ public:
     case ForContext:
     case ConditionContext:
     case PrototypeContext:
+    case LambdaExprParameterContext:
     case TemplateParamContext:
     case CXXCatchContext:
     case ObjCCatchContext:
@@ -1782,6 +1786,7 @@ public:
     case KNRTypeListContext:
     case MemberContext:
     case PrototypeContext:
+    case LambdaExprParameterContext:
     case ObjCParameterContext:
     case ObjCResultContext:
     case TemplateParamContext:
@@ -1968,6 +1973,7 @@ public:
     case AliasDeclContext:
     case AliasTemplateContext:
     case PrototypeContext:
+    case LambdaExprParameterContext:
     case ObjCParameterContext:
     case ObjCResultContext:
     case TemplateParamContext:
index bc49dcda66d1ba8f476dd72cbc28b01e676620b4..4853f46f5f8615c4286935324f4c10b8c79ad3b6 100644 (file)
@@ -35,6 +35,8 @@ class LabelDecl;
 class ReturnStmt;
 class Scope;
 class SwitchStmt;
+class TemplateTypeParmDecl;
+class TemplateParameterList;
 class VarDecl;
 class DeclRefExpr;
 class ObjCIvarRefExpr;
@@ -615,12 +617,29 @@ public:
   /// \brief Offsets into the ArrayIndexVars array at which each capture starts
   /// its list of array index variables.
   SmallVector<unsigned, 4> ArrayIndexStarts;
-
-  LambdaScopeInfo(DiagnosticsEngine &Diag, CXXRecordDecl *Lambda,
-                  CXXMethodDecl *CallOperator)
-    : CapturingScopeInfo(Diag, ImpCap_None), Lambda(Lambda),
-      CallOperator(CallOperator), NumExplicitCaptures(0), Mutable(false),
-      ExprNeedsCleanups(false), ContainsUnexpandedParameterPack(false)
+  
+  /// \brief If this is a generic lambda, use this as the depth of 
+  /// each 'auto' parameter, during initial AST construction.
+  unsigned AutoTemplateParameterDepth;
+
+  /// \brief Store the list of the auto parameters for a generic lambda.
+  /// If this is a generic lambda, store the list of the auto 
+  /// parameters converted into TemplateTypeParmDecls into a vector
+  /// that can be used to construct the generic lambda's template
+  /// parameter list, during initial AST construction.
+  SmallVector<TemplateTypeParmDecl*, 4> AutoTemplateParams;
+
+  /// If this is a generic lambda, and the template parameter
+  /// list has been created (from the AutoTemplateParams) then
+  /// store a reference to it (cache it to avoid reconstructing it).
+  TemplateParameterList *GLTemplateParameterList;
+
+  LambdaScopeInfo(DiagnosticsEngine &Diag)
+    : CapturingScopeInfo(Diag, ImpCap_None), Lambda(0),
+      CallOperator(0), NumExplicitCaptures(0), Mutable(false),
+      ExprNeedsCleanups(false), ContainsUnexpandedParameterPack(false),
+      AutoTemplateParameterDepth(0),
+      GLTemplateParameterList(0)
   {
     Kind = SK_Lambda;
   }
index f54561528d5c6d0f7c3434ca9821f393b0e22aa7..56988b1d5704c7fa71dbdac961f5ac205501c72d 100644 (file)
@@ -965,7 +965,13 @@ public:
 
   void PushFunctionScope();
   void PushBlockScope(Scope *BlockScope, BlockDecl *Block);
-  void PushLambdaScope(CXXRecordDecl *Lambda, CXXMethodDecl *CallOperator);
+  void PushLambdaScope();
+  
+  /// \brief This is used to inform Sema what the current TemplateParameterDepth
+  /// is during Parsing.  Currently it is used to pass on the depth
+  /// when parsing generic lambda 'auto' parameters.
+  void RecordParsingTemplateParameterDepth(unsigned Depth);
+  
   void PushCapturedRegionScope(Scope *RegionScope, CapturedDecl *CD,
                                RecordDecl *RD,
                                CapturedRegionKind K);
@@ -992,9 +998,12 @@ public:
   /// \brief Retrieve the current block, if any.
   sema::BlockScopeInfo *getCurBlock();
 
-  /// \brief Retrieve the current lambda expression, if any.
+  /// \brief Retrieve the current lambda scope info, if any.
   sema::LambdaScopeInfo *getCurLambda();
 
+  /// \brief Retrieve the current generic lambda info, if any.
+  sema::LambdaScopeInfo *getCurGenericLambda();
+
   /// \brief Retrieve the current captured region, if any.
   sema::CapturedRegionScopeInfo *getCurCapturedRegion();
 
@@ -4427,14 +4436,15 @@ public:
                                        SourceLocation EndLoc,
                                        ArrayRef<ParmVarDecl *> Params);
 
-  /// \brief Introduce the scope for a lambda expression.
-  sema::LambdaScopeInfo *enterLambdaScope(CXXMethodDecl *CallOperator,
-                                          SourceRange IntroducerRange,
-                                          LambdaCaptureDefault CaptureDefault,
-                                          SourceLocation CaptureDefaultLoc,
-                                          bool ExplicitParams,
-                                          bool ExplicitResultType,
-                                          bool Mutable);
+  /// \brief Endow the lambda scope info with the relevant properties.
+  void buildLambdaScope(sema::LambdaScopeInfo *LSI, 
+                        CXXMethodDecl *CallOperator,
+                        SourceRange IntroducerRange,
+                        LambdaCaptureDefault CaptureDefault,
+                        SourceLocation CaptureDefaultLoc,
+                        bool ExplicitParams,
+                        bool ExplicitResultType,
+                        bool Mutable);
 
   /// \brief Check and build an init-capture with the specified name and
   /// initializer.
@@ -5819,6 +5829,12 @@ public:
                           sema::TemplateDeductionInfo &Info,
                           bool InOverloadResolution = false);
 
+  /// \brief Substitute Replacement for \p auto in \p TypeWithAuto
+  QualType SubstAutoType(QualType TypeWithAuto, QualType Replacement);
+  /// \brief Substitute Replacement for auto in TypeWithAuto
+  TypeSourceInfo* SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto, 
+                                          QualType Replacement);
+
   /// \brief Result type of DeduceAutoType.
   enum DeduceAutoResult {
     DAR_Succeeded,
@@ -5830,7 +5846,6 @@ public:
                                   QualType &Result);
   DeduceAutoResult DeduceAutoType(TypeLoc AutoTypeLoc, Expr *&Initializer,
                                   QualType &Result);
-  QualType SubstAutoType(QualType TypeWithAuto, QualType Replacement);
   void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init);
   bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
                         bool Diagnose = true);
index 1f9a4dce55ba278534e9655ffd0ef2146754c1f4..bdadbeddbafddbc69e631d35bf64ad4d5ccd2263 100644 (file)
@@ -286,6 +286,10 @@ namespace  {
     void VisitExprWithCleanups(const ExprWithCleanups *Node);
     void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node);
     void dumpCXXTemporary(const CXXTemporary *Temporary);
+    void VisitLambdaExpr(const LambdaExpr *Node) {
+      VisitExpr(Node);
+      dumpDecl(Node->getLambdaClass());
+    }
 
     // ObjC
     void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node);
index 922172701f0a2d42223d3ecc2649cec0b38e7ffa..c6edc7712036655d59855954b3833ac5826ec7ed 100644 (file)
@@ -1709,7 +1709,8 @@ QualType ASTNodeImporter::VisitAutoType(const AutoType *T) {
       return QualType();
   }
   
-  return Importer.getToContext().getAutoType(ToDeduced, T->isDecltypeAuto());
+  return Importer.getToContext().getAutoType(ToDeduced, T->isDecltypeAuto(), 
+                                             /*IsDependent*/false);
 }
 
 QualType ASTNodeImporter::VisitRecordType(const RecordType *T) {
index 337ca6629c9aa5814ad9f0168b56703fe69f5d71..09ab8c916abd7dedec4dccdd52a190f1bb744476 100644 (file)
@@ -10,9 +10,9 @@
 // This file implements the C++ related Decl classes.
 //
 //===----------------------------------------------------------------------===//
-
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
 #include "clang/AST/ASTMutationListener.h"
 #include "clang/AST/CXXInheritance.h"
 #include "clang/AST/DeclTemplate.h"
@@ -943,6 +943,40 @@ bool CXXRecordDecl::isCLike() const {
   return isPOD() && data().HasOnlyCMembers;
 }
 
+bool CXXRecordDecl::isGenericLambda() const { 
+  return isLambda() && 
+      getLambdaCallOperator()->getDescribedFunctionTemplate(); 
+}
+
+CXXMethodDecl* CXXRecordDecl::getLambdaCallOperator() const {
+  if (!isLambda()) return 0;
+  DeclarationName Name = \r
+    getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);\r
+  DeclContext::lookup_const_result Calls = lookup(Name);
+\r
+  assert(!Calls.empty() && "Missing lambda call operator!");\r
+  assert(Calls.size() == 1 && "More than one lambda call operator!"); \r
+   \r
+  NamedDecl *CallOp = Calls.front();\r
+  if (FunctionTemplateDecl *CallOpTmpl = \r
+                    dyn_cast<FunctionTemplateDecl>(CallOp)) \r
+    return cast<CXXMethodDecl>(CallOpTmpl->getTemplatedDecl());\r
+  
+  return cast<CXXMethodDecl>(CallOp);
+}
+
+CXXMethodDecl* CXXRecordDecl::getLambdaStaticInvoker() const {
+  if (!isLambda()) return 0;
+  DeclarationName Name = \r
+    &getASTContext().Idents.get(getLambdaStaticInvokerName());\r
+  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;
+
+}
+
 void CXXRecordDecl::getCaptureFields(
        llvm::DenseMap<const VarDecl *, FieldDecl *> &Captures,
        FieldDecl *&ThisCapture) const {
@@ -960,6 +994,14 @@ void CXXRecordDecl::getCaptureFields(
   }
 }
 
+TemplateParameterList * 
+CXXRecordDecl::getGenericLambdaTemplateParameterList() const {
+  if (!isLambda()) return 0;
+  CXXMethodDecl *CallOp = getLambdaCallOperator();     
+  if (FunctionTemplateDecl *Tmpl = CallOp->getDescribedFunctionTemplate())
+    return Tmpl->getTemplateParameters();
+  return 0;
+}
 
 static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) {
   QualType T;
@@ -1510,7 +1552,7 @@ bool CXXMethodDecl::hasInlineBody() const {
 
 bool CXXMethodDecl::isLambdaStaticInvoker() const {
   return getParent()->isLambda() && 
-         getIdentifier() && getIdentifier()->getName() == "__invoke";
+         getParent()->getLambdaStaticInvoker() == this;
 }
 
 
index 55589e6d21f92d32146ad8fa6457a1b615a68046..7478678bf0b13f685d66d2ca3831c6dcd18f7661 100644 (file)
@@ -1076,13 +1076,13 @@ CXXRecordDecl *LambdaExpr::getLambdaClass() const {
 
 CXXMethodDecl *LambdaExpr::getCallOperator() const {
   CXXRecordDecl *Record = getLambdaClass();
-  DeclarationName Name
-    = Record->getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
-  DeclContext::lookup_result Calls = Record->lookup(Name);
-  assert(!Calls.empty() && "Missing lambda call operator!");
-  assert(Calls.size() == 1 && "More than one lambda call operator!");
-  CXXMethodDecl *Result = cast<CXXMethodDecl>(Calls.front());
-  return Result;
+  return Record->getLambdaCallOperator();  
+}
+
+TemplateParameterList *LambdaExpr::getTemplateParameterList() const {
+  CXXRecordDecl *Record = getLambdaClass();
+  return Record->getGenericLambdaTemplateParameterList();
+
 }
 
 CompoundStmt *LambdaExpr::getBody() const {
index c9279a27f1170f783f5c3cf01ee99e67b7994f77..b66a849284042c4d5df2bcef7010eef7d39e0701 100644 (file)
@@ -698,7 +698,7 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
     EmitLambdaToBlockPointerBody(Args);
   } else if (isa<CXXMethodDecl>(FD) &&
              cast<CXXMethodDecl>(FD)->isLambdaStaticInvoker()) {
-    // The lambda "__invoke" function is special, because it forwards or
+    // The lambda static invoker function is special, because it forwards or
     // clones the body of the function call operator (but is actually static).
     EmitLambdaStaticInvokeFunction(cast<CXXMethodDecl>(FD));
   } else if (FD->isDefaulted() && isa<CXXMethodDecl>(FD) &&
index a1a796de4140072d6280e6f1d807a7abc13525b1..b71cced3536b30e43b704e3aaf4cb91cd4e297c7 100644 (file)
@@ -4677,6 +4677,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
     //   as part of the parameter-declaration-clause.
     if (Tok.is(tok::ellipsis) && D.getCXXScopeSpec().isEmpty() &&
         !((D.getContext() == Declarator::PrototypeContext ||
+           D.getContext() == Declarator::LambdaExprParameterContext ||
            D.getContext() == Declarator::BlockLiteralContext) &&
           NextToken().is(tok::r_paren) &&
           !D.hasGroupingParens() &&
@@ -5002,7 +5003,6 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
   TypeResult TrailingReturnType;
 
   Actions.ActOnStartFunctionDeclarator();
-
   /* LocalEndLoc is the end location for the local FunctionTypeLoc.
      EndLoc is the end location for the function declarator.
      They differ for trailing return types. */
@@ -5023,7 +5023,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
     EndLoc = RParenLoc;
   } else {
     if (Tok.isNot(tok::r_paren))
-      ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo, EllipsisLoc);
+      ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo, 
+                                      EllipsisLoc);
     else if (RequiresArg)
       Diag(Tok, diag::err_argument_required_after_attribute);
 
@@ -5254,7 +5255,6 @@ void Parser::ParseParameterDeclarationClause(
        ParsedAttributes &FirstArgAttrs,
        SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo,
        SourceLocation &EllipsisLoc) {
-
   while (1) {
     if (Tok.is(tok::ellipsis)) {
       // FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq
@@ -5284,16 +5284,21 @@ void Parser::ParseParameterDeclarationClause(
 
     ParseDeclarationSpecifiers(DS);
 
-    // Parse the declarator.  This is "PrototypeContext", because we must
-    // accept either 'declarator' or 'abstract-declarator' here.
-    Declarator ParmDecl(DS, Declarator::PrototypeContext);
-    ParseDeclarator(ParmDecl);
+
+    // Parse the declarator.  This is "PrototypeContext" or 
+    // "LambdaExprParameterContext", because we must accept either 
+    // 'declarator' or 'abstract-declarator' here.
+    Declarator ParmDeclarator(DS, 
+              D.getContext() == Declarator::LambdaExprContext ?
+                                  Declarator::LambdaExprParameterContext : 
+                                                Declarator::PrototypeContext);
+    ParseDeclarator(ParmDeclarator);
 
     // Parse GNU attributes, if present.
-    MaybeParseGNUAttributes(ParmDecl);
+    MaybeParseGNUAttributes(ParmDeclarator);
 
     // Remember this parsed parameter in ParamInfo.
-    IdentifierInfo *ParmII = ParmDecl.getIdentifier();
+    IdentifierInfo *ParmII = ParmDeclarator.getIdentifier();
 
     // DefArgToks is used when the parsing of default arguments needs
     // to be delayed.
@@ -5301,8 +5306,8 @@ void Parser::ParseParameterDeclarationClause(
 
     // If no parameter was specified, verify that *something* was specified,
     // otherwise we have a missing type and identifier.
-    if (DS.isEmpty() && ParmDecl.getIdentifier() == 0 &&
-        ParmDecl.getNumTypeObjects() == 0) {
+    if (DS.isEmpty() && ParmDeclarator.getIdentifier() == 0 &&
+        ParmDeclarator.getNumTypeObjects() == 0) {
       // Completely missing, emit error.
       Diag(DSStart, diag::err_missing_param);
     } else {
@@ -5311,8 +5316,8 @@ void Parser::ParseParameterDeclarationClause(
 
       // Inform the actions module about the parameter declarator, so it gets
       // added to the current scope.
-      Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDecl);
-
+      Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), 
+                                                       ParmDeclarator);
       // Parse the default argument, if any. We parse the default
       // arguments in all dialects; the semantic analysis in
       // ActOnParamDefaultArgument will reject the default argument in
@@ -5371,8 +5376,8 @@ void Parser::ParseParameterDeclarationClause(
       }
 
       ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
-                                          ParmDecl.getIdentifierLoc(), Param,
-                                          DefArgToks));
+                                          ParmDeclarator.getIdentifierLoc(), 
+                                          Param, DefArgToks));
     }
 
     // If the next token is a comma, consume it and keep reading arguments.
index 9ac6d435067566749fdf9194e4d32e0ba6028c29..2eace9fc74fcb2750fa9491c1c8c287405b8abfe 100644 (file)
@@ -10,7 +10,7 @@
 // This file implements the Expression parsing implementation for C++.
 //
 //===----------------------------------------------------------------------===//
-
+#include "clang/AST/DeclTemplate.h"
 #include "clang/Parse/Parser.h"
 #include "RAIIObjectsForParser.h"
 #include "clang/Basic/PrettyStackTrace.h"
@@ -21,6 +21,7 @@
 #include "clang/Sema/Scope.h"
 #include "llvm/Support/ErrorHandling.h"
 
+
 using namespace clang;
 
 static int SelectDigraphErrorMessage(tok::TokenKind Kind) {
@@ -908,12 +909,16 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
   PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), LambdaBeginLoc,
                                 "lambda expression parsing");
 
+
   // FIXME: Call into Actions to add any init-capture declarations to the
   // scope while parsing the lambda-declarator and compound-statement.
 
   // Parse lambda-declarator[opt].
   DeclSpec DS(AttrFactory);
   Declarator D(DS, Declarator::LambdaExprContext);
+  TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
+  Actions.PushLambdaScope();    
 
   if (Tok.is(tok::l_paren)) {
     ParseScope PrototypeScope(this,
@@ -931,9 +936,16 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
     SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
     SourceLocation EllipsisLoc;
 
-    if (Tok.isNot(tok::r_paren))
+    
+    if (Tok.isNot(tok::r_paren)) {
+      sema::LambdaScopeInfo *LSI = Actions.getCurLambda(); 
+      Actions.RecordParsingTemplateParameterDepth(TemplateParameterDepth);
       ParseParameterDeclarationClause(D, Attr, ParamInfo, EllipsisLoc);
-
+      // For a generic lambda, each 'auto' within the parameter declaration 
+      // clause creates a template type parameter, so increment the depth.
+      if (Actions.getCurGenericLambda()) 
+        ++CurTemplateDepthTracker;
+    }
     T.consumeClose();
     SourceLocation RParenLoc = T.getCloseLocation();
     DeclEndLoc = RParenLoc;
index 00f38bfa8c6b70f577aab193a01d7d8da6ccd903..6f2b30953260f081ef835398dd7f404de9fff05c 100644 (file)
@@ -1023,10 +1023,17 @@ void Sema::PushBlockScope(Scope *BlockScope, BlockDecl *Block) {
                                               BlockScope, Block));
 }
 
-void Sema::PushLambdaScope(CXXRecordDecl *Lambda,
-                           CXXMethodDecl *CallOperator) {
-  FunctionScopes.push_back(new LambdaScopeInfo(getDiagnostics(), Lambda,
-                                               CallOperator));
+void Sema::PushLambdaScope() {
+  FunctionScopes.push_back(new LambdaScopeInfo(getDiagnostics()));
+}
+
+void Sema::RecordParsingTemplateParameterDepth(unsigned Depth) {
+  if (LambdaScopeInfo *const LSI = getCurLambda()) {
+    LSI->AutoTemplateParameterDepth = Depth;
+    return;
+  } 
+  llvm_unreachable( 
+      "Remove assertion if intentionally called in a non-lambda context.");
 }
 
 void Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP,
@@ -1082,6 +1089,16 @@ LambdaScopeInfo *Sema::getCurLambda() {
 
   return dyn_cast<LambdaScopeInfo>(FunctionScopes.back());
 }
+// We have a generic lambda if we parsed auto parameters, or we have 
+// an associated template parameter list.
+LambdaScopeInfo *Sema::getCurGenericLambda() {
+  if (LambdaScopeInfo *LSI =  getCurLambda()) {
+    return (LSI->AutoTemplateParams.size() ||
+                    LSI->GLTemplateParameterList) ? LSI : 0;
+  }
+  return 0;
+}
+
 
 void Sema::ActOnComment(SourceRange Comment) {
   if (!LangOpts.RetainCommentsFromSystemHeaders &&
index fa51aa4c09fd5b2b599915411506145e28de38e6..5997abe029636b27e18b66ada248f10bb7bca377 100644 (file)
@@ -15,6 +15,7 @@
 #include "TypeLocBuilder.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
 #include "clang/AST/CXXInheritance.h"
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/CommentDiagnostic.h"
@@ -8975,6 +8976,7 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
   const DeclSpec &DS = D.getDeclSpec();
 
   // Verify C99 6.7.5.3p2: The only SCS allowed is 'register'.
+
   // C++03 [dcl.stc]p2 also permits 'auto'.
   VarDecl::StorageClass StorageClass = SC_None;
   if (DS.getStorageClassSpec() == DeclSpec::SCS_register) {
@@ -9334,9 +9336,37 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
     FD = FunTmpl->getTemplatedDecl();
   else
     FD = cast<FunctionDecl>(D);
-
-  // Enter a new function scope
-  PushFunctionScope();
+  // If we are instantiating a generic lambda call operator, push
+  // a LambdaScopeInfo onto the function stack.  But use the information
+  // that's already been calculated (ActOnLambdaExpr) when analyzing the
+  // template version, to prime the current LambdaScopeInfo. 
+  if (isGenericLambdaCallOperatorSpecialization(D)) {
+    CXXMethodDecl *CallOperator = cast<CXXMethodDecl>(D);
+    CXXRecordDecl *LambdaClass = CallOperator->getParent();
+    LambdaExpr    *LE = LambdaClass->getLambdaExpr();
+    assert(LE && 
+     "No LambdaExpr of closure class when instantiating a generic lambda!");
+    assert(ActiveTemplateInstantiations.size() &&
+      "There should be an active template instantiation on the stack " 
+      "when instantiating a generic lambda!");
+    PushLambdaScope();
+    LambdaScopeInfo *LSI = getCurLambda();
+    LSI->CallOperator = CallOperator;
+    LSI->Lambda = LambdaClass;
+    LSI->ReturnType = CallOperator->getResultType();
+
+    if (LE->getCaptureDefault() == LCD_None)
+      LSI->ImpCaptureStyle = CapturingScopeInfo::ImpCap_None;
+    else if (LE->getCaptureDefault() == LCD_ByCopy)
+      LSI->ImpCaptureStyle = CapturingScopeInfo::ImpCap_LambdaByval;
+    else if (LE->getCaptureDefault() == LCD_ByRef)
+      LSI->ImpCaptureStyle = CapturingScopeInfo::ImpCap_LambdaByref;
+    
+    LSI->IntroducerRange = LE->getIntroducerRange();
+  }
+  else
+    // Enter a new function scope
+    PushFunctionScope();
 
   // See if this is a redefinition.
   if (!FD->isLateTemplateParsed())
index d5c0e7a570805c082158b8a751f77ced372fbb22..6e1751aebd931df993730c8a5b850c7f529df7a0 100644 (file)
@@ -14,6 +14,7 @@
 #include "clang/Sema/SemaInternal.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
 #include "clang/AST/ASTMutationListener.h"
 #include "clang/AST/CXXInheritance.h"
 #include "clang/AST/CharUnits.h"
@@ -10364,10 +10365,10 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
        SourceLocation CurrentLocation,
        CXXConversionDecl *Conv) 
 {
-  CXXRecordDecl *Lambda = Conv->getParent();
+  CXXRecordDecl *LambdaClass = Conv->getParent();
   
   // Make sure that the lambda call operator is marked used.
-  markLambdaCallOperatorUsed(*this, Lambda);
+  markLambdaCallOperatorUsed(*this, LambdaClass);
   
   Conv->markUsed(Context);
   
@@ -10375,19 +10376,18 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
   DiagnosticErrorTrap Trap(Diags);
   
   // Return the address of the __invoke function.
-  DeclarationName InvokeName = &Context.Idents.get("__invoke");
-  CXXMethodDecl *Invoke 
-    = cast<CXXMethodDecl>(Lambda->lookup(InvokeName).front());
+  
+  CXXMethodDecl *Invoke = LambdaClass->getLambdaStaticInvoker();
   Expr *FunctionRef = BuildDeclRefExpr(Invoke, Invoke->getType(),
                                        VK_LValue, Conv->getLocation()).take();
-  assert(FunctionRef && "Can't refer to __invoke function?");
+  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 __invoke function with a dummy implementation. IR generation
-  // will fill in the actual details.
+  // 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()));
index ec69ef8ed0afa6f81bc7b45b9b8286ee1485dd81..569bfdfce22173527933f1699d950bd2d2f24729 100644 (file)
@@ -11,6 +11,7 @@
 //
 //===----------------------------------------------------------------------===//
 #include "clang/Sema/DeclSpec.h"
+#include "clang/AST/ASTLambda.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Lex/Preprocessor.h"
@@ -130,17 +131,37 @@ Sema::ExpressionEvaluationContextRecord::getMangleNumberingContext(
   return *MangleNumbering;
 }
 
+static inline TemplateParameterList *
+getGenericLambdaTemplateParameterList(LambdaScopeInfo *LSI, Sema &SemaRef) {
+  if (LSI->GLTemplateParameterList)
+    return LSI->GLTemplateParameterList;
+  else if (LSI->AutoTemplateParams.size()) {
+    SourceRange IntroRange = LSI->IntroducerRange;
+    SourceLocation LAngleLoc = IntroRange.getBegin();
+    SourceLocation RAngleLoc = IntroRange.getEnd();
+    LSI->GLTemplateParameterList = 
+          TemplateParameterList::Create(SemaRef.Context, 
+            /* Template kw loc */ SourceLocation(), 
+            LAngleLoc,
+            (NamedDecl**)LSI->AutoTemplateParams.data(), 
+            LSI->AutoTemplateParams.size(), RAngleLoc);  
+  }
+  return LSI->GLTemplateParameterList;
+}
+
+
 CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
                                            SourceRange IntroducerRange,
                                            TypeSourceInfo *MethodTypeInfo,
                                            SourceLocation EndLoc,
                                            ArrayRef<ParmVarDecl *> Params) {
   QualType MethodType = MethodTypeInfo->getType();
-
-  // If a lambda appears in a dependent context and has an 'auto' return type,
-  // deduce it to a dependent type.
-  // FIXME: Generic lambda call operators should also get this treatment.
-  if (Class->isDependentContext()) {
+  TemplateParameterList *TemplateParams = 
+            getGenericLambdaTemplateParameterList(getCurLambda(), *this);
+  // If a lambda appears in a dependent context or is a generic lambda (has
+  // template parameters) and has an 'auto' return type, deduce it to a 
+  // dependent type.
+  if (Class->isDependentContext() || TemplateParams) {
     const FunctionProtoType *FPT = MethodType->castAs<FunctionProtoType>();
     QualType Result = FPT->getResultType();
     if (Result->isUndeducedType()) {
@@ -177,6 +198,17 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
   // Temporarily set the lexical declaration context to the current
   // context, so that the Scope stack matches the lexical nesting.
   Method->setLexicalDeclContext(CurContext);  
+  // Create a function template if we have a template parameter list
+  FunctionTemplateDecl *const TemplateMethod = TemplateParams ?
+            FunctionTemplateDecl::Create(Context, Class,
+                                         Method->getLocation(), MethodName, 
+                                         TemplateParams,
+                                         Method) : 0;
+  if (TemplateMethod) {
+    TemplateMethod->setLexicalDeclContext(CurContext);
+    TemplateMethod->setAccess(AS_public);
+    Method->setDescribedFunctionTemplate(TemplateMethod);
+  }
   
   // Add parameters.
   if (!Params.empty()) {
@@ -202,15 +234,16 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
   return Method;
 }
 
-LambdaScopeInfo *Sema::enterLambdaScope(CXXMethodDecl *CallOperator,
+void Sema::buildLambdaScope(LambdaScopeInfo *LSI,
+                                        CXXMethodDecl *CallOperator,
                                         SourceRange IntroducerRange,
                                         LambdaCaptureDefault CaptureDefault,
                                         SourceLocation CaptureDefaultLoc,
                                         bool ExplicitParams,
                                         bool ExplicitResultType,
                                         bool Mutable) {
-  PushLambdaScope(CallOperator->getParent(), CallOperator);
-  LambdaScopeInfo *LSI = getCurLambda();
+  LSI->CallOperator = CallOperator;
+  LSI->Lambda = CallOperator->getParent();
   if (CaptureDefault == LCD_ByCopy)
     LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByval;
   else if (CaptureDefault == LCD_ByRef)
@@ -233,8 +266,6 @@ LambdaScopeInfo *Sema::enterLambdaScope(CXXMethodDecl *CallOperator,
   } else {
     LSI->HasImplicitReturnType = true;
   }
-
-  return LSI;
 }
 
 void Sema::finishLambdaExplicitCaptures(LambdaScopeInfo *LSI) {
@@ -384,6 +415,8 @@ static void adjustBlockReturnsToEnum(Sema &S, ArrayRef<ReturnStmt*> returns,
 
 void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
   assert(CSI.HasImplicitReturnType);
+  // If it was ever a placeholder, it had to been deduced to DependentTy.
+  assert(CSI.ReturnType.isNull() || !CSI.ReturnType->isUndeducedType()); 
 
   // C++ Core Issue #975, proposed resolution:
   //   If a lambda-expression does not include a trailing-return-type,
@@ -544,15 +577,25 @@ FieldDecl *Sema::checkInitCapture(SourceLocation Loc, bool ByRef,
 }
 
 void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
-                                        Declarator &ParamInfo,
-                                        Scope *CurScope) {
+                  Declarator &ParamInfo, Scope *CurScope) {
   // Determine if we're within a context where we know that the lambda will
   // be dependent, because there are template parameters in scope.
   bool KnownDependent = false;
-  if (Scope *TmplScope = CurScope->getTemplateParamParent())
-    if (!TmplScope->decl_empty())
+  LambdaScopeInfo *const LSI = getCurLambda();
+  assert(LSI && "LambdaScopeInfo should be on stack!");
+  TemplateParameterList *TemplateParams = 
+            getGenericLambdaTemplateParameterList(LSI, *this);
+
+  if (Scope *TmplScope = CurScope->getTemplateParamParent()) {
+    // Since we have our own TemplateParams, so check if an outer scope
+    // has template params, only then are we in a dependent scope.
+    if (TemplateParams)  {
+      TmplScope = TmplScope->getParent();
+      TmplScope = TmplScope ? TmplScope->getTemplateParamParent() : 0;
+    }
+    if (TmplScope && !TmplScope->decl_empty())
       KnownDependent = true;
-  
+  }
   // Determine the signature of the call operator.
   TypeSourceInfo *MethodTyInfo;
   bool ExplicitParams = true;
@@ -621,7 +664,6 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
 
   CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range,
                                                 MethodTyInfo, EndLoc, Params);
-  
   if (ExplicitParams)
     CheckCXXDefaultArguments(Method);
   
@@ -631,9 +673,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
   // Introduce the function call operator as the current declaration context.
   PushDeclContext(CurScope, Method);
     
-  // Introduce the lambda scope.
-  LambdaScopeInfo *LSI
-    = enterLambdaScope(Method,
+  // Build the lambda scope.
+  buildLambdaScope(LSI, Method,
                        Intro.Range,
                        Intro.Default, Intro.DefaultLoc,
                        ExplicitParams,
@@ -845,6 +886,8 @@ 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>(); 
@@ -885,10 +928,9 @@ static void addFunctionPointerConversion(Sema &S,
   Conversion->setAccess(AS_public);
   Conversion->setImplicit(true);
   Class->addDecl(Conversion);
-  
-  // Add a non-static member function "__invoke" that will be the result of
-  // the conversion.
-  Name = &S.Context.Idents.get("__invoke");
+  // 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());
   CXXMethodDecl *Invoke
     = CXXMethodDecl::Create(S.Context, Class, Loc, 
                             DeclarationNameInfo(Name, Loc), FunctionTy, 
@@ -1060,13 +1102,19 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
           LSI->ReturnType, Proto->getArgTypes(), Proto->getExtProtoInfo());
       CallOperator->setType(FunctionTy);
     }
-
     // C++ [expr.prim.lambda]p7:
     //   The lambda-expression's compound-statement yields the
     //   function-body (8.4) of the function call operator [...].
     ActOnFinishFunctionBody(CallOperator, Body, IsInstantiation);
     CallOperator->setLexicalDeclContext(Class);
-    Class->addDecl(CallOperator);
+    Decl *TemplateOrNonTemplateCallOperatorDecl = 
+        CallOperator->getDescribedFunctionTemplate()  
+        ? CallOperator->getDescribedFunctionTemplate() 
+        : cast<Decl>(CallOperator);
+
+    TemplateOrNonTemplateCallOperatorDecl->setLexicalDeclContext(Class);
+    Class->addDecl(TemplateOrNonTemplateCallOperatorDecl);
+
     PopExpressionEvaluationContext();
 
     // C++11 [expr.prim.lambda]p6:
@@ -1106,7 +1154,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
                                           CaptureInits, ArrayIndexVars, 
                                           ArrayIndexStarts, Body->getLocEnd(),
                                           ContainsUnexpandedParameterPack);
-
+  Class->setLambdaExpr(Lambda);
   // C++11 [expr.prim.lambda]p2:
   //   A lambda-expression shall not appear in an unevaluated operand
   //   (Clause 5).
@@ -1126,7 +1174,15 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
       break;
     }
   }
-  
+  // TODO: Implement capturing.
+  if (Lambda->isGenericLambda()) {
+    if (Lambda->getCaptureDefault() != LCD_None) {
+      Diag(Lambda->getIntroducerRange().getBegin(), 
+        diag::err_glambda_not_fully_implemented) 
+        << " capturing not implemented yet";
+      return ExprError();
+    }
+  }
   return MaybeBindToTemporary(Lambda);
 }
 
index 13d19b6cb98524cf3c2858355ffdcf01b543ca6e..6905ff1464c6df67c9b16838fe6e75b3f95fde7b 100644 (file)
@@ -8682,6 +8682,10 @@ void DiagnoseBadDeduction(Sema &S, Decl *Templated,
         }
       }
     }
+    // FIXME: For generic lambda parameters, check if the function is a lambda
+    // call operator, and if so, emit a prettier and more informative 
+    // diagnostic that mentions 'auto' and lambda in addition to 
+    // (or instead of?) the canonical template type parameters.
     S.Diag(Templated->getLocation(),
            diag::note_ovl_candidate_non_deduced_mismatch)
         << FirstTA << SecondTA;
index 1d52709341ec07a9157cb17230bcbaa346a5221f..5510bc2040b7f2e8a3ab04f42615596cf67f67c7 100644 (file)
@@ -3913,8 +3913,16 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result) {
   return DAR_Succeeded;
 }
 
-QualType Sema::SubstAutoType(QualType Type, QualType Deduced) {
-  return SubstituteAutoTransform(*this, Deduced).TransformType(Type);
+QualType Sema::SubstAutoType(QualType TypeWithAuto, 
+                             QualType TypeToReplaceAuto) {
+  return SubstituteAutoTransform(*this, TypeToReplaceAuto).
+               TransformType(TypeWithAuto);
+}
+
+TypeSourceInfo* Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto, 
+                             QualType TypeToReplaceAuto) {
+    return SubstituteAutoTransform(*this, TypeToReplaceAuto).
+               TransformType(TypeWithAuto);
 }
 
 void Sema::DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init) {
index 1f40eb8d1dbef031f8185c6befd83ddf5f281134..839ca7eca7c5a08c0960c1ae5cd2fb6dc3ea5449 100644 (file)
@@ -994,11 +994,54 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
 
   case DeclSpec::TST_auto:
     // TypeQuals handled by caller.
-    Result = Context.getAutoType(QualType(), /*decltype(auto)*/false);
+    // If auto is mentioned in a lambda parameter context, convert it to a 
+    // template parameter type immediately, with the appropriate depth and 
+    // index, and update sema's state (LambdaScopeInfo) for the current lambda 
+    // being analyzed (which tracks the invented type template parameter).
+    if (declarator.getContext() == Declarator::LambdaExprParameterContext) {
+      sema::LambdaScopeInfo *LSI = S.getCurLambda();
+      assert(LSI && "No LambdaScopeInfo on the stack!");
+      const unsigned TemplateParameterDepth = LSI->AutoTemplateParameterDepth;
+      const unsigned AutoParameterPosition = LSI->AutoTemplateParams.size();
+      const bool IsParameterPack = declarator.hasEllipsis();
+      
+      // Create a name for the invented template parameter type.
+      std::string InventedTemplateParamName = "$auto-";
+      llvm::raw_string_ostream ss(InventedTemplateParamName);
+      ss << TemplateParameterDepth; 
+      ss << "-" << AutoParameterPosition;
+      ss.flush();
+
+      IdentifierInfo& TemplateParamII = Context.Idents.get(
+                                        InventedTemplateParamName.c_str());
+      // Turns out we must create the TemplateTypeParmDecl here to 
+      // retrieve the corresponding template parameter type. 
+      TemplateTypeParmDecl *CorrespondingTemplateParam =
+        TemplateTypeParmDecl::Create(Context, 
+        // Temporarily add to the TranslationUnit DeclContext.  When the 
+        // associated TemplateParameterList is attached to a template
+        // declaration (such as FunctionTemplateDecl), the DeclContext 
+        // for each template parameter gets updated appropriately via
+        // a call to AdoptTemplateParameterList. 
+        Context.getTranslationUnitDecl(), 
+        /*KeyLoc*/ SourceLocation(), 
+        /*NameLoc*/ declarator.getLocStart(),  
+        TemplateParameterDepth, 
+        AutoParameterPosition,  // our template param index 
+        /* Identifier*/ &TemplateParamII, false, IsParameterPack);
+      LSI->AutoTemplateParams.push_back(CorrespondingTemplateParam);
+      // Replace the 'auto' in the function parameter with this invented 
+      // template type parameter.
+      Result = QualType(CorrespondingTemplateParam->getTypeForDecl(), 0);  
+    } else {
+      Result = Context.getAutoType(QualType(), /*decltype(auto)*/false, false);
+    }
     break;
 
   case DeclSpec::TST_decltype_auto:
-    Result = Context.getAutoType(QualType(), /*decltype(auto)*/true);
+    Result = Context.getAutoType(QualType(), 
+                                 /*decltype(auto)*/true, 
+                                 /*IsDependent*/   false);
     break;
 
   case DeclSpec::TST_unknown_anytype:
@@ -1545,7 +1588,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
         ASM = ArrayType::Normal;
       }
     } else if (!T->isDependentType() && !T->isVariablyModifiedType() &&
-               !T->isIncompleteType()) {
+               !T->isIncompleteType() && !T->isUndeducedType()) {
       // Is the array too large?
       unsigned ActiveSizeBits
         = ConstantArrayType::getNumAddressingBits(Context, T, ConstVal);
@@ -2087,6 +2130,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
   // In C++11, a function declarator using 'auto' must have a trailing return
   // type (this is checked later) and we can skip this. In other languages
   // using auto, we need to check regardless.
+  // C++14 In generic lambdas allow 'auto' in their parameters.
   if (ContainsPlaceholderType &&
       (!SemaRef.getLangOpts().CPlusPlus11 || !D.isFunctionDeclarator())) {
     int Error = -1;
@@ -2099,7 +2143,12 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
     case Declarator::ObjCParameterContext:
     case Declarator::ObjCResultContext:
     case Declarator::PrototypeContext:
-      Error = 0; // Function prototype
+      Error = 0;  
+      break;
+    case Declarator::LambdaExprParameterContext:
+      if (!(SemaRef.getLangOpts().CPlusPlus1y 
+              && D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto))
+        Error = 14;
       break;
     case Declarator::MemberContext:
       if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)
@@ -2179,8 +2228,10 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
       AutoRange = D.getName().getSourceRange();
 
     if (Error != -1) {
+      const bool IsDeclTypeAuto = 
+          D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_decltype_auto;
       SemaRef.Diag(AutoRange.getBegin(), diag::err_auto_not_allowed)
-        << Error << AutoRange;
+        << IsDeclTypeAuto << Error << AutoRange;
       T = SemaRef.Context.IntTy;
       D.setInvalidType(true);
     } else
@@ -2230,6 +2281,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
       D.setInvalidType(true);
       break;
     case Declarator::PrototypeContext:
+    case Declarator::LambdaExprParameterContext:
     case Declarator::ObjCParameterContext:
     case Declarator::ObjCResultContext:
     case Declarator::KNRTypeListContext:
@@ -2651,8 +2703,10 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
           }
         }
       }
-
-      if (const AutoType *AT = T->getContainedAutoType()) {
+      const AutoType *AT = T->getContainedAutoType();
+      // Allow arrays of auto if we are a generic lambda parameter.
+      // i.e. [](auto (&array)[5]) { return array[0]; }; OK
+      if (AT && D.getContext() != Declarator::LambdaExprParameterContext) {
         // We've already diagnosed this for decltype(auto).
         if (!AT->isDecltypeAuto())
           S.Diag(DeclType.Loc, diag::err_illegal_decl_array_of_auto)
@@ -3151,6 +3205,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
     //   is a parameter pack (14.5.3). [...]
     switch (D.getContext()) {
     case Declarator::PrototypeContext:
+    case Declarator::LambdaExprParameterContext:
       // C++0x [dcl.fct]p13:
       //   [...] When it is part of a parameter-declaration-clause, the
       //   parameter pack is a function parameter pack (14.5.3). The type T
@@ -3169,7 +3224,6 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
         T = Context.getPackExpansionType(T, None);
       }
       break;
-
     case Declarator::TemplateParamContext:
       // C++0x [temp.param]p15:
       //   If a template-parameter is a [...] is a parameter-declaration that
index 5d080f9efb780b82052e64df1287c34fae69e263..6559dede1c9415a514e7394278e8ed06246ae5e9 100644 (file)
@@ -787,7 +787,8 @@ public:
     // Note, IsDependent is always false here: we implicitly convert an 'auto'
     // which has been deduced to a dependent type into an undeduced 'auto', so
     // that we'll retry deduction after the transformation.
-    return SemaRef.Context.getAutoType(Deduced, IsDecltypeAuto);
+    return SemaRef.Context.getAutoType(Deduced, IsDecltypeAuto, 
+                                       /*IsDependent*/ false);
   }
 
   /// \brief Build a new template specialization type.
@@ -3514,7 +3515,8 @@ TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB,
         Qs.removeObjCLifetime();
         Deduced = SemaRef.Context.getQualifiedType(Deduced.getUnqualifiedType(),
                                                    Qs);
-        Result = SemaRef.Context.getAutoType(Deduced, AutoTy->isDecltypeAuto());
+        Result = SemaRef.Context.getAutoType(Deduced, AutoTy->isDecltypeAuto(), 
+                                AutoTy->isDependentType());
         TLB.TypeWasModifiedSafely(Result);
       } else {
         // Otherwise, complain about the addition of a qualifier to an
@@ -8249,6 +8251,14 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
+  // FIXME: Implement nested generic lambda transformations.
+  if (E->isGenericLambda()) {
+    getSema().Diag(E->getIntroducerRange().getBegin(), 
+      diag::err_glambda_not_fully_implemented) 
+      << " template transformation of generic lambdas not implemented yet";
+    return ExprError();
+  }
   // Transform the type of the lambda parameters and start the definition of
   // the lambda itself.
   TypeSourceInfo *MethodTy
@@ -8271,7 +8281,10 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
         E->getCallOperator()->param_size(),
         0, ParamTypes, &Params))
     return ExprError();
-
+  getSema().PushLambdaScope();
+  LambdaScopeInfo *LSI = getSema().getCurLambda();
+  // TODO: Fix for nested lambdas
+  LSI->GLTemplateParameterList = 0;
   // Build the call operator.
   CXXMethodDecl *CallOperator
     = getSema().startLambdaDefinition(Class, E->getIntroducerRange(),
@@ -8306,9 +8319,9 @@ TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E,
   // Introduce the context of the call operator.
   Sema::ContextRAII SavedContext(getSema(), CallOperator);
 
+  LambdaScopeInfo *const LSI = getSema().getCurLambda();
   // Enter the scope of the lambda.
-  sema::LambdaScopeInfo *LSI
-    = getSema().enterLambdaScope(CallOperator, E->getIntroducerRange(),
+  getSema().buildLambdaScope(LSI, CallOperator, E->getIntroducerRange(),
                                  E->getCaptureDefault(),
                                  E->getCaptureDefaultLoc(),
                                  E->hasExplicitParameters(),
index 0d8e05711eedf482152142b3bfd384a5f93534d9..eaa5c5500bedfc61708843bcfc6a85d6fa6cbcab 100644 (file)
@@ -1213,6 +1213,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
       = (Capture*)Reader.Context.Allocate(sizeof(Capture)*Lambda.NumCaptures);
     Capture *ToCapture = Lambda.Captures;
     Lambda.MethodTyInfo = GetTypeSourceInfo(Record, Idx);
+    Lambda.TheLambdaExpr = cast<LambdaExpr>(Reader.ReadExpr(F));
     for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) {
       SourceLocation Loc = ReadSourceLocation(Record, Idx);
       bool IsImplicit = Record[Idx++];
index 409c9a18a50920f3dd64c141ee78370ca051e21f..1826ad8312f49519c3a0fffe57201f0f9107e3ac 100644 (file)
@@ -5134,6 +5134,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
     Record.push_back(Lambda.ManglingNumber);
     AddDeclRef(Lambda.ContextDecl, Record);
     AddTypeSourceInfo(Lambda.MethodTyInfo, Record);
+    AddStmt(Lambda.TheLambdaExpr);
     for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) {
       LambdaExpr::Capture &Capture = Lambda.Captures[I];
       AddSourceLocation(Capture.getLocation(), Record);
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-generic-lambda-1y.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-generic-lambda-1y.cpp
new file mode 100644 (file)
index 0000000..65b085b
--- /dev/null
@@ -0,0 +1,74 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1y -DCXX1Y
+
+//FIXME: These tests were written when return type deduction had not been implemented
+// for generic lambdas, hence
+template<class T> T id(T t);
+template<class ... Ts> int vfoo(Ts&& ... ts);
+auto GL1 = [](auto a, int i) -> int { return id(a); };
+
+auto GL2 = [](auto ... As) -> int { return vfoo(As...); };
+auto GL3 = [](int i, char c, auto* ... As) -> int { return vfoo(As...); };
+
+auto GL4 = [](int i, char c, auto* ... As) -> int { return vfoo(As...); };
+
+
+void foo() {
+  auto GL1 = [](auto a, int i) -> int { return id(a); };
+
+  auto GL2 = [](auto ... As) -> int { return vfoo(As...); };
+}
+
+int main()
+{
+  auto l1 = [](auto a) -> int { return a + 5; };
+  auto l2 = [](auto *p) -> int { return p + 5; };
+  struct A { int i; char f(int) { return 'c'; } };
+  auto l3 = [](auto &&ur, 
+                auto &lr, 
+                auto v, 
+                int i, 
+                auto* p,
+                auto A::*memvar,
+                auto (A::*memfun)(int),
+                char c,
+                decltype (v)* pv
+                , auto (&array)[5] 
+              ) -> int { return v + i + c
+                          + array[0]; 
+                       };
+  int arr[5] = {0, 1, 2, 3, 4 };
+  int lval = 0;
+  double d = 3.14;
+  l3(3, lval, d, lval, &lval, &A::i, &A::f, 'c', &d, arr);
+  auto l4 = [](decltype(auto) a) -> int { return 0; }; //expected-error{{decltype(auto)}}
+  {
+    struct Local {
+      static int ifi(int i) { return i; }
+      static char cfi(int) { return 'a'; }
+      static double dfi(int i) { return i + 3.14; }
+      static Local localfi(int) { return Local{}; }
+    };
+    auto l4 = [](auto (*fp)(int)) -> int { return fp(3); }; //expected-error{{no viable conversion from 'Local' to 'int'}} 
+    l4(&Local::ifi);
+    l4(&Local::cfi);
+    l4(&Local::dfi);
+    l4(&Local::localfi); //expected-note{{in instantiation of function template specialization}}  
+  }
+  {
+    auto unnamed_parameter = [](auto, auto) -> void { };
+    unnamed_parameter(3, '4');
+  }
+  {
+    auto l = [](auto 
+                      (*)(auto)) { }; //expected-error{{'auto' not allowed}}
+    //FIXME: These diagnostics might need some work.
+    auto l2 = [](char auto::*pm) { };  //expected-error{{cannot combine with previous}}\
+                                         expected-error{{'pm' does not point into a class}}
+    auto l3 = [](char (auto::*pmf)()) { };  //expected-error{{'auto' not allowed}}\
+                                              expected-error{{'pmf' does not point into a class}}\
+                                              expected-error{{function cannot return function type 'char ()'}}
+  }
+}
+
+
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp
new file mode 100644 (file)
index 0000000..cd773b4
--- /dev/null
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++1y %s -verify -emit-llvm
+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); 
+}
+
+}
+
+namespace nested_generic_lambdas {
+void test() {
+  auto L = [](auto a) -> int {
+    auto M = [](auto b, decltype(a) b2) -> int { //expected-error{{unimplemented}}
+      return 1;
+    };
+    M(a, a);
+  };
+  L(3); //expected-note{{in instantiation of}}
+}
+template<class T> void foo(T) {
+ auto L = [](auto a) { return a; }; //expected-error{{unimplemented}}
+}
+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/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp
new file mode 100644 (file)
index 0000000..44656a3
--- /dev/null
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1y -DCXX1Y\r
+\r
+// prvalue\r
+void prvalue() {\r
+  auto&& x = [](auto a)->void { };\r
+  auto& y = [](auto *a)->void { }; // expected-error{{cannot bind to a temporary of type}}\r
+}\r
+\r
+namespace std {\r
+  class type_info;\r
+}\r
+\r
+struct P {\r
+  virtual ~P();\r
+};\r
+\r
+void unevaluated_operand(P &p, int i) {\r
+  // FIXME: this should only emit one error.\r
+  int i2 = sizeof([](auto a, auto b)->void{}(3, '4')); // expected-error{{lambda expression in an unevaluated operand}} \\r
+                                                       // expected-error{{invalid application of 'sizeof'}}\r
+  const std::type_info &ti1 = typeid([](auto &a) -> P& { static P p; return p; }(i));\r
+  const std::type_info &ti2 = typeid([](auto) -> int { return i; }(i));  // expected-error{{lambda expression in an unevaluated operand}}\r
+}\r
index 79ee76f02582675c3facd2c57c9bceb5e9f8f4da..f8461335b76896ecfee15a240cf3a8926caa8ed5 100644 (file)
@@ -7,3 +7,60 @@ int &d = [] (int &r) -> auto & { return r; } (a);
 int &e = [] (int &r) -> auto { return r; } (a); // expected-error {{cannot bind to a temporary}}
 int &f = [] (int r) -> decltype(auto) { return r; } (a); // expected-error {{cannot bind to a temporary}}
 int &g = [] (int r) -> decltype(auto) { return (r); } (a); // expected-warning {{reference to stack}}
+
+
+int test_explicit_auto_return() 
+{
+    struct X {};
+    auto L = [](auto F, auto a) { return F(a); };
+    auto M = [](auto a) -> auto { return a; }; // OK
+    auto MRef = [](auto b) -> auto& { return b; }; //expected-warning{{reference to stack}}
+    auto MPtr = [](auto c) -> auto* { return &c; }; //expected-warning{{address of stack}}
+    auto MDeclType = [](auto&& d) -> decltype(auto) { return static_cast<decltype(d)>(d); }; //OK
+    M(3);
+    
+    auto &&x = MDeclType(X{});
+    auto &&x1 = M(X{});
+    auto &&x2 = MRef(X{});//expected-note{{in instantiation of}}
+    auto &&x3 = MPtr(X{}); //expected-note{{in instantiation of}}
+    return 0;    
+}
+
+int test_implicit_auto_return() 
+{  
+  {
+    auto M = [](auto a) { return a; };
+    struct X {};
+    X x = M(X{});
+    
+  }
+}
+int test_multiple_returns()  {
+    auto M = [](auto a) { 
+      bool k;
+      if (k)
+        return a;
+      else
+        return 5; //expected-error{{deduced as 'int' here}}
+    }; 
+    M(3); // OK
+    M('a'); //expected-note{{in instantiation of}}
+  return 0;
+}
+int test_no_parameter_list()
+{
+  static int si = 0;
+    auto M = [] { return 5; }; // OK
+    auto M2 = [] -> auto&& { return si; }; // expected-error{{lambda requires '()'}}
+    M();
+}
+
+int test_conditional_in_return() {
+  auto Fac = [](auto f, auto n) { 
+    return n <= 0 ? n : f(f, n - 1) * n;
+  };
+  // FIXME: this test causes a recursive limit - need to error more gracefully.
+  //Fac(Fac, 3);
+
+}
\ No newline at end of file
index c69aa115beb5e710d8dd2b460c4feaf9e2029d0e..1016cb1d3056c8c2337d24d177606f18414368be 100644 (file)
@@ -1,5 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
-// RUN: %clang_cc1 -fsyntax-only -std=c++1y %s -verify
+// RUN: %clang_cc1 -fsyntax-only -std=c++1y %s -verify -DCPP1Y
 
 void missing_lambda_declarator() {
   [](){}();
@@ -18,7 +18,7 @@ void infer_void_return_type(int i) {
     switch (x) {
     case 0: return get<void>();
     case 1: return;
-    case 2: return { 1, 2.0 }; // expected-error{{cannot deduce lambda return type from initializer list}}
+    case 2: return { 1, 2.0 }; //expected-error{{cannot deduce}}
     }
   }(7);
 }
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp
new file mode 100644 (file)
index 0000000..c131161
--- /dev/null
@@ -0,0 +1,135 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1y -DCXX1Y -emit-llvm\r
+\r
+namespace test_factorial {\r
+\r
+auto Fact = [](auto Self, unsigned n) -> unsigned {\r
+    return !n ? 1 : Self(Self, n - 1) * n;\r
+};\r
+\r
+auto six = Fact(Fact, 3);\r
+\r
+}\r
+\r
+namespace overload_generic_lambda {\r
+  template <class F1, class F2> struct overload : F1, F2 {\r
+    using F1::operator();\r
+    using F2::operator();\r
+    overload(F1 f1, F2 f2) : F1(f1), F2(f2) { }\r
+  };\r
+\r
+  auto NumParams = [](auto Self, auto h, auto ... rest) -> unsigned {\r
+    return 1 + Self(Self, rest...);\r
+  };\r
+  auto Base = [](auto Self, auto h) -> unsigned {\r
+      return 1;\r
+  };\r
+  overload<decltype(Base), decltype(NumParams)> O(Base, NumParams);\r
+  int num_params =  O(O, 5, 3, "abc", 3.14, 'a');\r
+}\r
+\r
+\r
+namespace overload_generic_lambda_return_type_deduction {\r
+  template <class F1, class F2> struct overload : F1, F2 {\r
+    using F1::operator();\r
+    using F2::operator();\r
+    overload(F1 f1, F2 f2) : F1(f1), F2(f2) { }\r
+  };\r
+\r
+  auto NumParams = [](auto Self, auto h, auto ... rest) {\r
+    return 1 + Self(Self, rest...);\r
+  };\r
+  auto Base = [](auto Self, auto h) {\r
+      return 1;\r
+  };\r
+  overload<decltype(Base), decltype(NumParams)> O(Base, NumParams);\r
+  int num_params =  O(O, 5, 3, "abc", 3.14, 'a');\r
+}\r
+\r
+namespace test_standard_p5 {\r
+// FIXME: This test should eventually compile without an explicit trailing return type\r
+auto glambda = [](auto a, auto&& b) ->bool { return a < b; };\r
+bool b = glambda(3, 3.14); // OK\r
+\r
+}\r
+namespace test_deduction_failure {\r
+ int test() {\r
+   auto g = [](auto *a) { //expected-note{{candidate template ignored}}\r
+    return a;\r
+   };\r
+   struct X { };\r
+   X *x;\r
+   g(x);\r
+   g(3); //expected-error{{no matching function}}\r
+   return 0;\r
+ }\r
+\r
+}\r
+  \r
+namespace test_instantiation_or_sfinae_failure {\r
+int test2() {\r
+  {\r
+    auto L = [](auto *a) { \r
+                return (*a)(a); }; //expected-error{{called object type 'double' is not a function}}\r
+    //l(&l);\r
+    double d;\r
+    L(&d); //expected-note{{in instantiation of}}\r
+    auto M = [](auto b) { return b; };\r
+    L(&M); // ok\r
+  }\r
+  {\r
+    auto L = [](auto *a) ->decltype (a->foo()) { //expected-note2{{candidate template ignored:}}\r
+                return (*a)(a); }; \r
+    //l(&l);\r
+    double d;\r
+    L(&d); //expected-error{{no matching function for call}} \r
+    auto M = [](auto b) { return b; };\r
+    L(&M); //expected-error{{no matching function for call}} \r
\r
+  }\r
+  return 0;\r
+}\r
+\r
+\r
+}\r
+  \r
+namespace test_misc {\r
+auto GL = [](auto a, decltype(a) b) //expected-note{{candidate function}} \r
+                -> int { return a + b; };\r
+\r
+void test() {\r
+   struct X { };\r
+   GL(3, X{}); //expected-error{{no matching function}}\r
+}\r
+\r
+void test2() {\r
+  auto l = [](auto *a) -> int { \r
+              (*a)(a); return 0; }; //expected-error{{called object type 'double' is not a function}}\r
+  l(&l);\r
+  double d;\r
+  l(&d); //expected-note{{in instantiation of}}\r
+}\r
+\r
+}\r
+\r
+namespace nested_lambdas {\r
+  int test() {\r
+    auto L = [](auto a) {\r
+                 return [=](auto b) {  //expected-error{{unimplemented}}\r
+                           return a + b;\r
+                        };\r
+              };\r
+   // auto M = L(3.14);\r
+   // return M('4');    \r
+  }\r
+  auto get_lambda() {\r
+    return [](auto a) {\r
+      return a; \r
+    };\r
+  };\r
+  \r
+  int test2() {\r
+    auto L = get_lambda();\r
+    L(3);\r
+  }\r
+}\r
+\r