hamzasood updated this revision to Diff 123015.
hamzasood added a comment.

Resolved merge conflicts from the last month of changes 
(`unittests/AST/StmtPrinterTest.cpp` and `lib/AST/DeclCXX.cpp`)


https://reviews.llvm.org/D36527

Files:
  include/clang/AST/DeclCXX.h
  include/clang/AST/DeclTemplate.h
  include/clang/AST/ExprCXX.h
  include/clang/AST/RecursiveASTVisitor.h
  include/clang/Basic/DiagnosticParseKinds.td
  include/clang/Parse/Parser.h
  include/clang/Sema/ScopeInfo.h
  include/clang/Sema/Sema.h
  lib/AST/DeclCXX.cpp
  lib/AST/DeclPrinter.cpp
  lib/AST/ExprCXX.cpp
  lib/AST/ItaniumMangle.cpp
  lib/AST/StmtPrinter.cpp
  lib/AST/TypePrinter.cpp
  lib/Parse/ParseExprCXX.cpp
  lib/Sema/Sema.cpp
  lib/Sema/SemaLambda.cpp
  lib/Sema/SemaType.cpp
  test/CXX/temp/temp.decls/temp.variadic/p4.cpp
  test/CodeGenCXX/mangle-lambda-explicit-template-params.cpp
  test/PCH/cxx11-lambdas.mm
  test/PCH/cxx1y-lambdas.mm
  test/PCH/cxx2a-template-lambdas.cpp
  test/Parser/cxx2a-template-lambdas.cpp
  test/SemaCXX/cxx2a-template-lambdas.cpp
  unittests/AST/StmtPrinterTest.cpp
  unittests/Tooling/RecursiveASTVisitorTest.cpp
  unittests/Tooling/TestVisitor.h
  www/cxx_status.html

Index: www/cxx_status.html
===================================================================
--- www/cxx_status.html
+++ www/cxx_status.html
@@ -823,7 +823,7 @@
     <tr>
       <td><i>template-parameter-list</i> for generic lambdas</td>
       <td><a href="http://wg21.link/p0428r2";>P0428R2</a></td>
-      <td class="none" align="center">No</td>
+      <td class="svn" align="center">SVN</td>
     </tr>
     <tr>
       <td>Initializer list constructors in class template argument deduction</td>
Index: unittests/Tooling/TestVisitor.h
===================================================================
--- unittests/Tooling/TestVisitor.h
+++ unittests/Tooling/TestVisitor.h
@@ -44,6 +44,8 @@
     Lang_CXX98,
     Lang_CXX11,
     Lang_CXX14,
+    Lang_CXX17,
+    Lang_CXX2a,
     Lang_OBJC,
     Lang_OBJCXX11,
     Lang_CXX = Lang_CXX98
@@ -60,6 +62,8 @@
       case Lang_CXX98: Args.push_back("-std=c++98"); break;
       case Lang_CXX11: Args.push_back("-std=c++11"); break;
       case Lang_CXX14: Args.push_back("-std=c++14"); break;
+      case Lang_CXX17: Args.push_back("-std=c++17"); break;
+      case Lang_CXX2a: Args.push_back("-std=c++2a"); break;
       case Lang_OBJC:
         Args.push_back("-ObjC");
         Args.push_back("-fobjc-runtime=macosx-10.12.0");
Index: unittests/Tooling/RecursiveASTVisitorTest.cpp
===================================================================
--- unittests/Tooling/RecursiveASTVisitorTest.cpp
+++ unittests/Tooling/RecursiveASTVisitorTest.cpp
@@ -79,6 +79,41 @@
                               LambdaDefaultCaptureVisitor::Lang_CXX11));
 }
 
+// Matches (optional) explicit template parameters.
+class LambdaTemplateParametersVisitor
+  : public ExpectedLocationVisitor<LambdaTemplateParametersVisitor> {
+public:
+  bool shouldVisitImplicitCode() const { return false; }
+
+  bool VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
+    EXPECT_FALSE(D->isImplicit());
+    Match(D->getName(), D->getLocStart());
+    return true;
+  }
+  bool VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
+    EXPECT_FALSE(D->isImplicit());
+    Match(D->getName(), D->getLocStart());
+    return true;
+  }
+  bool VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
+    EXPECT_FALSE(D->isImplicit());
+    Match(D->getName(), D->getLocStart());
+    return true;
+  }
+};
+
+TEST(RecursiveASTVisitor, VisitsLambdaExplicitTemplateParameters) {
+  LambdaTemplateParametersVisitor Visitor;
+  Visitor.ExpectMatch("T",  2, 15);
+  Visitor.ExpectMatch("I",  2, 24);
+  Visitor.ExpectMatch("TT", 2, 31);
+  EXPECT_TRUE(Visitor.runOver(
+      "void f() { \n"
+      "  auto l = []<class T, int I, template<class> class TT>(auto p) { }; \n"
+      "}",
+      LambdaTemplateParametersVisitor::Lang_CXX2a));
+}
+
 // Checks for lambda classes that are not marked as implicitly-generated.
 // (There should be none.)
 class ClassVisitor : public ExpectedLocationVisitor<ClassVisitor> {
Index: unittests/AST/StmtPrinterTest.cpp
===================================================================
--- unittests/AST/StmtPrinterTest.cpp
+++ unittests/AST/StmtPrinterTest.cpp
@@ -106,78 +106,73 @@
   return ::testing::AssertionSuccess();
 }
 
-::testing::AssertionResult
-PrintedStmtCXX98Matches(StringRef Code, const StatementMatcher &NodeMatch,
-                        StringRef ExpectedPrinted) {
-  std::vector<std::string> Args;
-  Args.push_back("-std=c++98");
-  Args.push_back("-Wno-unused-value");
-  return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted);
-}
-
-::testing::AssertionResult PrintedStmtCXX98Matches(
-                                              StringRef Code,
-                                              StringRef ContainingFunction,
-                                              StringRef ExpectedPrinted) {
-  std::vector<std::string> Args;
-  Args.push_back("-std=c++98");
-  Args.push_back("-Wno-unused-value");
-  return PrintedStmtMatches(Code,
-                            Args,
-                            functionDecl(hasName(ContainingFunction),
-                                         has(compoundStmt(has(stmt().bind("id"))))),
-                            ExpectedPrinted);
+enum class StdVer { CXX98, CXX11, CXX14, CXX17, CXX2a };
+
+DeclarationMatcher FunctionBodyMatcher(StringRef ContainingFunction) {
+  return functionDecl(hasName(ContainingFunction),
+                      has(compoundStmt(has(stmt().bind("id")))));
 }
 
+template <typename T>
 ::testing::AssertionResult
-PrintedStmtCXX11Matches(StringRef Code, const StatementMatcher &NodeMatch,
-                        StringRef ExpectedPrinted,
-                        PolicyAdjusterType PolicyAdjuster = None) {
-  std::vector<std::string> Args;
-  Args.push_back("-std=c++11");
-  Args.push_back("-Wno-unused-value");
+PrintedStmtCXXMatches(StdVer Standard, StringRef Code, const T &NodeMatch,
+                      StringRef ExpectedPrinted,
+                      PolicyAdjusterType PolicyAdjuster = None) {
+  const char *StdOpt;
+  switch (Standard) {
+  case StdVer::CXX98: StdOpt = "-std=c++98"; break;
+  case StdVer::CXX11: StdOpt = "-std=c++11"; break;
+  case StdVer::CXX14: StdOpt = "-std=c++14"; break;
+  case StdVer::CXX17: StdOpt = "-std=c++17"; break;
+  case StdVer::CXX2a: StdOpt = "-std=c++2a"; break;
+  }
+
+  std::vector<std::string> Args = {
+    StdOpt,
+    "-Wno-unused-value",
+  };
   return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted,
                             PolicyAdjuster);
 }
 
-::testing::AssertionResult PrintedStmtMSMatches(
-                                              StringRef Code,
-                                              StringRef ContainingFunction,
-                                              StringRef ExpectedPrinted) {
-  std::vector<std::string> Args;
-  Args.push_back("-target");
-  Args.push_back("i686-pc-win32");
-  Args.push_back("-std=c++98");
-  Args.push_back("-fms-extensions");
-  Args.push_back("-Wno-unused-value");
-  return PrintedStmtMatches(Code,
-                            Args,
-                            functionDecl(hasName(ContainingFunction),
-                                         has(compoundStmt(has(stmt().bind("id"))))),
-                            ExpectedPrinted);
+template <typename T>
+::testing::AssertionResult
+PrintedStmtMSMatches(StringRef Code, const T &NodeMatch,
+                     StringRef ExpectedPrinted,
+                     PolicyAdjusterType PolicyAdjuster = None) {
+  std::vector<std::string> Args = {
+    "-std=c++98",
+    "-target", "i686-pc-win32",
+    "-fms-extensions",
+    "-Wno-unused-value",
+  };
+  return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted,
+                            PolicyAdjuster);
 }
 
+template <typename T>
 ::testing::AssertionResult
-PrintedStmtObjCMatches(StringRef Code, const StatementMatcher &NodeMatch,
+PrintedStmtObjCMatches(StringRef Code, const T &NodeMatch,
                        StringRef ExpectedPrinted,
                        PolicyAdjusterType PolicyAdjuster = None) {
-  std::vector<std::string> Args;
-  Args.push_back("-ObjC");
-  Args.push_back("-fobjc-runtime=macosx-10.12.0");
+  std::vector<std::string> Args = {
+    "-ObjC",
+    "-fobjc-runtime=macosx-10.12.0",
+  };
   return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted,
                             PolicyAdjuster);
 }
 
 } // unnamed namespace
 
 TEST(StmtPrinter, TestIntegerLiteral) {
-  ASSERT_TRUE(PrintedStmtCXX98Matches(
+  ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX98,
     "void A() {"
     "  1, -1, 1U, 1u,"
     "  1L, 1l, -1L, 1UL, 1ul,"
     "  1LL, -1LL, 1ULL;"
     "}",
-    "A",
+    FunctionBodyMatcher("A"),
     "1 , -1 , 1U , 1U , "
     "1L , 1L , -1L , 1UL , 1UL , "
     "1LL , -1LL , 1ULL"));
@@ -192,24 +187,24 @@
     "  1i32, -1i32, 1ui32, "
     "  1i64, -1i64, 1ui64;"
     "}",
-    "A",
+    FunctionBodyMatcher("A"),
     "1i8 , -1i8 , 1Ui8 , "
     "1i16 , -1i16 , 1Ui16 , "
     "1 , -1 , 1U , "
     "1LL , -1LL , 1ULL"));
     // Should be: with semicolon
 }
 
 TEST(StmtPrinter, TestFloatingPointLiteral) {
-  ASSERT_TRUE(PrintedStmtCXX98Matches(
+  ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX98,
     "void A() { 1.0f, -1.0f, 1.0, -1.0, 1.0l, -1.0l; }",
-    "A",
+    FunctionBodyMatcher("A"),
     "1.F , -1.F , 1. , -1. , 1.L , -1.L"));
     // Should be: with semicolon
 }
 
 TEST(StmtPrinter, TestCXXConversionDeclImplicit) {
-  ASSERT_TRUE(PrintedStmtCXX98Matches(
+  ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX98,
     "struct A {"
       "operator void *();"
       "A operator&(A);"
@@ -223,7 +218,7 @@
 }
 
 TEST(StmtPrinter, TestCXXConversionDeclExplicit) {
-  ASSERT_TRUE(PrintedStmtCXX11Matches(
+  ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11,
     "struct A {"
       "operator void *();"
       "A operator&(A);"
@@ -237,20 +232,57 @@
     // WRONG; Should be: (a & b).operator void *()
 }
 
+TEST(StmtPrinter, TestCXXLamda) {
+  ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11,
+    "void A() {"
+    "  auto l = [] { };"
+    "}",
+    lambdaExpr(anything()).bind("id"),
+    "[] {\n"
+    "}"));
+
+  ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11,
+    "void A() {"
+    "  int a = 0, b = 1;"
+    "  auto l = [a,b](int c, float d) { };"
+    "}",
+    lambdaExpr(anything()).bind("id"),
+    "[a, b](int c, float d) {\n"
+    "}"));
+
+  ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX14,
+    "void A() {"
+    "  auto l = [](auto a, int b, auto c, int, auto) { };"
+    "}",
+    lambdaExpr(anything()).bind("id"),
+    "[](auto a, int b, auto c, int, auto) {\n"
+    "}"));
+
+  ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX2a,
+    "void A() {"
+    "  auto l = []<typename T1, class T2, int I,"
+    "              template<class, typename> class T3>"
+    "           (int a, auto, int, auto d) { };"
+    "}",
+    lambdaExpr(anything()).bind("id"),
+    "[]<typename T1, class T2, int I, template <class, typename> class T3>(int a, auto, int, auto d) {\n"
+    "}"));
+}
+
 TEST(StmtPrinter, TestNoImplicitBases) {
   const char *CPPSource = R"(
 class A {
   int field;
   int member() { return field; }
 };
 )";
   // No implicit 'this'.
-  ASSERT_TRUE(PrintedStmtCXX11Matches(
+  ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11,
       CPPSource, memberExpr(anything()).bind("id"), "field",
       PolicyAdjusterType(
           [](PrintingPolicy &PP) { PP.SuppressImplicitBase = true; })));
   // Print implicit 'this'.
-  ASSERT_TRUE(PrintedStmtCXX11Matches(
+  ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11,
       CPPSource, memberExpr(anything()).bind("id"), "this->field"));
 
   const char *ObjCSource = R"(
Index: test/SemaCXX/cxx2a-template-lambdas.cpp
===================================================================
--- test/SemaCXX/cxx2a-template-lambdas.cpp
+++ test/SemaCXX/cxx2a-template-lambdas.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -std=c++2a -verify %s
+
+template<typename, typename>
+constexpr bool is_same = false;
+
+template<typename T>
+constexpr bool is_same<T, T> = true;
+
+template<typename T>
+struct DummyTemplate { };
+
+void func() {
+  auto L0 = []<typename T>(T arg) {
+    static_assert(is_same<T, int>);
+  };
+  L0(0);
+
+  auto L1 = []<int I> {
+    static_assert(I == 5);
+  };
+  L1.operator()<5>();
+
+  auto L2 = []<template<typename> class T, class U>(T<U> &&arg) {
+    static_assert(is_same<T<U>, DummyTemplate<float>>);
+  };
+  L2(DummyTemplate<float>());
+}
+
+template<typename T> // expected-note {{declared here}}
+struct ShadowMe {
+  void member_func() {
+    auto L = []<typename T> { }; // expected-error {{'T' shadows template parameter}}
+  }
+};
Index: test/Parser/cxx2a-template-lambdas.cpp
===================================================================
--- test/Parser/cxx2a-template-lambdas.cpp
+++ test/Parser/cxx2a-template-lambdas.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -std=c++2a %s -verify
+
+auto L0 = []<> { }; //expected-error {{cannot be empty}}
+
+auto L1 = []<typename T1, typename T2> { };
+auto L2 = []<typename T1, typename T2>(T1 arg1, T2 arg2) -> T1 { };
+auto L3 = []<typename T>(auto arg) { T t; };
+auto L4 = []<int I>() { };
Index: test/PCH/cxx2a-template-lambdas.cpp
===================================================================
--- test/PCH/cxx2a-template-lambdas.cpp
+++ test/PCH/cxx2a-template-lambdas.cpp
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -std=c++2a -emit-pch %s -o %t
+// RUN: %clang_cc1 -std=c++2a -include-pch %t -verify %s
+
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+auto l1 = []<int I>() constexpr -> int {
+    return I;
+};
+
+auto l2 = []<auto I>() constexpr -> decltype(I) {
+    return I;
+};
+
+auto l3 = []<class T>(auto i) constexpr -> T {
+  return T(i);
+};
+
+auto l4 = []<template<class> class T, class U>(T<U>, auto i) constexpr -> U {
+  return U(i);
+};
+
+#else /*included pch*/
+
+static_assert(l1.operator()<5>() == 5);
+static_assert(l1.operator()<6>() == 6);
+
+static_assert(l2.operator()<7>() == 7);
+static_assert(l2.operator()<nullptr>() == nullptr);
+
+static_assert(l3.operator()<int>(8.4) == 8);
+static_assert(l3.operator()<int>(9.9) == 9);
+
+template<typename T>
+struct DummyTemplate { };
+
+static_assert(l4(DummyTemplate<float>(), 12) == 12.0);
+static_assert(l4(DummyTemplate<int>(), 19.8) == 19);
+
+#endif // HEADER
Index: test/PCH/cxx1y-lambdas.mm
===================================================================
--- test/PCH/cxx1y-lambdas.mm
+++ test/PCH/cxx1y-lambdas.mm
@@ -50,7 +50,7 @@
 }
 
 // CHECK-PRINT: inline int add_int_slowly_twice 
-// CHECK-PRINT: lambda = [] (type-parameter-0-0 z
+// CHECK-PRINT: lambda = [](auto z
 
 // CHECK-PRINT: init_capture
 // CHECK-PRINT: [&, x(t)]
Index: test/PCH/cxx11-lambdas.mm
===================================================================
--- test/PCH/cxx11-lambdas.mm
+++ test/PCH/cxx11-lambdas.mm
@@ -54,7 +54,7 @@
 }
 
 // CHECK-PRINT: inline int add_int_slowly_twice 
-// CHECK-PRINT: lambda = [&] (int z)
+// CHECK-PRINT: lambda = [&](int z)
 
 // CHECK-PRINT: init_capture
 // CHECK-PRINT: [&, x(t)]
Index: test/CodeGenCXX/mangle-lambda-explicit-template-params.cpp
===================================================================
--- test/CodeGenCXX/mangle-lambda-explicit-template-params.cpp
+++ test/CodeGenCXX/mangle-lambda-explicit-template-params.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -std=c++2a -triple %itanium_abi_triple -emit-llvm -o - %s -w | FileCheck %s
+
+template<class, int, class>
+struct DummyType { };
+
+inline void inline_func() {
+  // CHECK: UlvE
+  []{}();
+
+  // CHECK: UlTyvE
+  []<class>{}.operator()<int>();
+
+  // CHECK: UlTyT_E
+  []<class T>(T){}(1);
+
+  // CHECK: UlTyTyT_T0_E
+  []<class T1, class T2>(T1, T2){}(1, 2);
+
+  // CHECK: UlTyTyT0_T_E
+  []<class T1, class T2>(T2, T1){}(2, 1);
+
+  // CHECK: UlTniTyTnjT0_E
+  []<int I, class T, unsigned U>(T){}.operator()<1, int, 2>(3);
+
+  // CHECK: UlTyTtTyTniTyETniTyvE
+  []<class,
+     template<class, int, class> class,
+     int,
+     class>{}.operator()<unsigned, DummyType, 5, int>();
+}
+
+void call_inline_func() {
+  inline_func();
+}
Index: test/CXX/temp/temp.decls/temp.variadic/p4.cpp
===================================================================
--- test/CXX/temp/temp.decls/temp.variadic/p4.cpp
+++ test/CXX/temp/temp.decls/temp.variadic/p4.cpp
@@ -213,8 +213,10 @@
       };
 #endif
 
+#if __cplusplus > 201703L
       //    - in a template parameter pack that is a pack expansion
-      // FIXME: We do not support any way to reach this case yet.
+      swallow([]<T *...v, template<T *> typename ...W>(W<v> ...wv) { });
+#endif
 
       //    - in an initializer-list
       int arr[] = {T().x...};
@@ -279,11 +281,6 @@
   struct T { int x; using U = int; };
   void g() { f<T>(1, 2, 3); }
 
-  template<typename ...T, typename ...U> void pack_in_lambda(U ...u) { // expected-note {{here}}
-    // FIXME: Move this test into 'f' above once we support this syntax.
-    []<T *...v, template<T *> typename ...U>(U<v> ...uv) {}; // expected-error {{expected body of lambda}} expected-error {{does not refer to a value}}
-  }
-
   template<typename ...T> void pack_expand_attr() {
     // FIXME: Move this test into 'f' above once we support this.
     [[gnu::aligned(alignof(T))...]] int x; // expected-error {{cannot be used as an attribute pack}} expected-error {{unexpanded}}
Index: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp
+++ lib/Sema/SemaType.cpp
@@ -2791,7 +2791,7 @@
         sema::LambdaScopeInfo *LSI = SemaRef.getCurLambda();
         assert(LSI && "No LambdaScopeInfo on the stack!");
         const unsigned TemplateParameterDepth = LSI->AutoTemplateParameterDepth;
-        const unsigned AutoParameterPosition = LSI->AutoTemplateParams.size();
+        const unsigned AutoParameterPosition = LSI->TemplateParams.size();
         const bool IsParameterPack = D.hasEllipsis();
 
         // Create the TemplateTypeParmDecl here to retrieve the corresponding
@@ -2803,7 +2803,8 @@
                 /*KeyLoc*/SourceLocation(), /*NameLoc*/D.getLocStart(),
                 TemplateParameterDepth, AutoParameterPosition,
                 /*Identifier*/nullptr, false, IsParameterPack);
-        LSI->AutoTemplateParams.push_back(CorrespondingTemplateParam);
+        CorrespondingTemplateParam->setImplicit();
+        LSI->TemplateParams.push_back(CorrespondingTemplateParam);
         // Replace the 'auto' in the function parameter with this invented 
         // template type parameter.
         // FIXME: Retain some type sugar to indicate that this was written
Index: lib/Sema/SemaLambda.cpp
===================================================================
--- lib/Sema/SemaLambda.cpp
+++ lib/Sema/SemaLambda.cpp
@@ -21,6 +21,7 @@
 #include "clang/Sema/ScopeInfo.h"
 #include "clang/Sema/SemaInternal.h"
 #include "clang/Sema/SemaLambda.h"
+#include "llvm/ADT/STLExtras.h"
 using namespace clang;
 using namespace sema;
 
@@ -226,19 +227,14 @@
 
 static inline TemplateParameterList *
 getGenericLambdaTemplateParameterList(LambdaScopeInfo *LSI, Sema &SemaRef) {
-  if (LSI->GLTemplateParameterList)
-    return LSI->GLTemplateParameterList;
-
-  if (!LSI->AutoTemplateParams.empty()) {
-    SourceRange IntroRange = LSI->IntroducerRange;
-    SourceLocation LAngleLoc = IntroRange.getBegin();
-    SourceLocation RAngleLoc = IntroRange.getEnd();
+  if (!LSI->GLTemplateParameterList && !LSI->TemplateParams.empty()) {
     LSI->GLTemplateParameterList = TemplateParameterList::Create(
         SemaRef.Context,
-        /*Template kw loc*/ SourceLocation(), LAngleLoc,
-        llvm::makeArrayRef((NamedDecl *const *)LSI->AutoTemplateParams.data(),
-                           LSI->AutoTemplateParams.size()),
-        RAngleLoc, nullptr);
+        /*Template kw loc*/ SourceLocation(),
+        /*L angle loc*/ LSI->ExplicitTemplateParamsRange.getBegin(),
+        LSI->TemplateParams,
+        /*R angle loc*/LSI->ExplicitTemplateParamsRange.getEnd(),
+        nullptr);
   }
   return LSI->GLTemplateParameterList;
 }
@@ -493,6 +489,25 @@
   LSI->finishedExplicitCaptures();
 }
 
+void Sema::ActOnLambdaExplicitTemplateParameterList(SourceLocation LAngleLoc,
+                                                    ArrayRef<NamedDecl *> TParams,
+                                                    SourceLocation RAngleLoc) {
+  LambdaScopeInfo *LSI = getCurLambda();
+  assert(LSI && "Expected a lambda scope");
+
+  assert(LSI->NumExplicitTemplateParams == 0 &&
+         "Already acted on explicit template parameters");
+  assert(LSI->TemplateParams.size() == 0 &&
+         "Explicit template parameters should come "
+         "before invented (auto) ones");
+  assert(TParams.size() > 0 &&
+         "No template parameters to act on");
+
+  LSI->TemplateParams.append(TParams.begin(), TParams.end());
+  LSI->NumExplicitTemplateParams = TParams.size();
+  LSI->ExplicitTemplateParamsRange = {LAngleLoc, RAngleLoc};
+}
+
 void Sema::addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope) {  
   // Introduce our parameters into the function scope
   for (unsigned p = 0, NumParams = CallOperator->getNumParams(); 
@@ -825,17 +840,23 @@
 void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
                                         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;
   LambdaScopeInfo *const LSI = getCurLambda();
   assert(LSI && "LambdaScopeInfo should be on stack!");
 
-  // The lambda-expression's closure type might be dependent even if its
-  // semantic context isn't, if it appears within a default argument of a
-  // function template.
-  if (CurScope->getTemplateParamParent())
-    KnownDependent = true;
+  // 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;
+  if (LSI->NumExplicitTemplateParams > 0) {
+    auto *TemplateParamScope = CurScope->getTemplateParamParent();
+    assert(TemplateParamScope &&
+           "Lambda with explicit template param list should establish a "
+           "template param scope");
+    assert(TemplateParamScope->getParent());
+    KnownDependent = TemplateParamScope->getParent()
+                                       ->getTemplateParamParent() != nullptr;
+  } else {
+    KnownDependent = CurScope->getTemplateParamParent() != nullptr;
+  }
 
   // Determine the signature of the call operator.
   TypeSourceInfo *MethodTyInfo;
Index: lib/Sema/Sema.cpp
===================================================================
--- lib/Sema/Sema.cpp
+++ lib/Sema/Sema.cpp
@@ -1451,7 +1451,7 @@
 // an associated template parameter list.
 LambdaScopeInfo *Sema::getCurGenericLambda() {
   if (LambdaScopeInfo *LSI =  getCurLambda()) {
-    return (LSI->AutoTemplateParams.size() ||
+    return (LSI->TemplateParams.size() ||
                     LSI->GLTemplateParameterList) ? LSI : nullptr;
   }
   return nullptr;
Index: lib/Parse/ParseExprCXX.cpp
===================================================================
--- lib/Parse/ParseExprCXX.cpp
+++ lib/Parse/ParseExprCXX.cpp
@@ -635,6 +635,8 @@
 ///
 ///       lambda-expression:
 ///         lambda-introducer lambda-declarator[opt] compound-statement
+///         lambda-introducer '<' template-parameter-list '>'
+///             lambda-declarator[opt] compound-statement
 ///
 ///       lambda-introducer:
 ///         '[' lambda-capture[opt] ']'
@@ -1114,6 +1116,32 @@
               << A->getName()->getName();
   };
 
+  // FIXME: Consider allowing this as an extension for GCC compatibiblity.
+  const bool HasExplicitTemplateParams = Tok.is(tok::less);
+  ParseScope TemplateParamScope(this, Scope::TemplateParamScope,
+                                /*EnteredScope=*/HasExplicitTemplateParams);
+  if (HasExplicitTemplateParams) {
+    Diag(Tok, getLangOpts().CPlusPlus2a
+                  ? diag::warn_cxx17_compat_lambda_template_parameter_list
+                  : diag::ext_lambda_template_parameter_list);
+
+    SmallVector<NamedDecl*, 4> TemplateParams;
+    SourceLocation LAngleLoc, RAngleLoc;
+    if (ParseTemplateParameters(CurTemplateDepthTracker.getDepth(),
+                                TemplateParams, LAngleLoc, RAngleLoc)) {
+      return ExprError();
+    }
+
+    if (TemplateParams.empty()) {
+      Diag(RAngleLoc,
+           diag::err_lambda_template_parameter_list_empty);
+    } else {
+      Actions.ActOnLambdaExplicitTemplateParameterList(
+          LAngleLoc, TemplateParams, RAngleLoc);
+      ++CurTemplateDepthTracker;
+    }
+  }
+
   TypeResult TrailingReturnType;
   if (Tok.is(tok::l_paren)) {
     ParseScope PrototypeScope(this,
@@ -1128,15 +1156,25 @@
     // Parse parameter-declaration-clause.
     SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
     SourceLocation EllipsisLoc;
-    
+
     if (Tok.isNot(tok::r_paren)) {
-      Actions.RecordParsingTemplateParameterDepth(TemplateParameterDepth);
+      // Record the template parameter depth for auto parameters.
+      // We want the auto parameter depth to be the same as the explicit
+      // template params (if they exist).
+      Actions.RecordParsingTemplateParameterDepth(
+          CurTemplateDepthTracker.getOriginalDepth());
+
       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;
+      // Note that if there are any explicit template params, then the depth
+      // will have already been increased. So we make sure to not increment
+      // past 1 added depth level.
+      if (Actions.getCurGenericLambda())
+        CurTemplateDepthTracker.setAddedDepth(1);
     }
+
     T.consumeClose();
     SourceLocation RParenLoc = T.getCloseLocation();
     SourceLocation DeclEndLoc = RParenLoc;
@@ -1154,7 +1192,7 @@
     SourceLocation ConstexprLoc;
     tryConsumeMutableOrConstexprToken(*this, MutableLoc, ConstexprLoc,
                                       DeclEndLoc);
-    
+
     addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS);
 
     // Parse exception-specification[opt].
@@ -1305,6 +1343,7 @@
 
   StmtResult Stmt(ParseCompoundStatementBody());
   BodyScope.Exit();
+  TemplateParamScope.Exit();
 
   if (!Stmt.isInvalid() && !TrailingReturnType.isInvalid())
     return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.get(), getCurScope());
Index: lib/AST/TypePrinter.cpp
===================================================================
--- lib/AST/TypePrinter.cpp
+++ lib/AST/TypePrinter.cpp
@@ -1090,8 +1090,18 @@
                                               raw_ostream &OS) { 
   if (IdentifierInfo *Id = T->getIdentifier())
     OS << Id->getName();
-  else
-    OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex();
+  else {
+    bool IsLambdaAutoParam = false;
+    if (auto D = T->getDecl()) {
+      if (auto M = dyn_cast_or_null<CXXMethodDecl>(D->getDeclContext()))
+        IsLambdaAutoParam = D->isImplicit() && M->getParent()->isLambda();
+    }
+
+    if (IsLambdaAutoParam)
+      OS << "auto";
+    else
+      OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex();
+  }
   spaceBeforePlaceHolder(OS);
 }
 void TypePrinter::printTemplateTypeParmAfter(const TemplateTypeParmType *T, 
Index: lib/AST/StmtPrinter.cpp
===================================================================
--- lib/AST/StmtPrinter.cpp
+++ lib/AST/StmtPrinter.cpp
@@ -2264,8 +2264,14 @@
   }
   OS << ']';
 
+  if (Node->getExplicitTemplateParameterCount() > 0) {
+    Node->getTemplateParameterList()->print(
+        OS, Node->getLambdaClass()->getASTContext(),
+        /*OmitTemplateKW*/true);
+  }
+
   if (Node->hasExplicitParameters()) {
-    OS << " (";
+    OS << '(';
     CXXMethodDecl *Method = Node->getCallOperator();
     NeedComma = false;
     for (auto P : Method->parameters()) {
@@ -2301,9 +2307,8 @@
   }
 
   // Print the body.
-  CompoundStmt *Body = Node->getBody();
   OS << ' ';
-  PrintStmt(Body);
+  PrintRawCompoundStmt(Node->getBody());
 }
 
 void StmtPrinter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *Node) {
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp
+++ lib/AST/ItaniumMangle.cpp
@@ -503,6 +503,7 @@
                        const AbiTagList *AdditionalAbiTags);
   void mangleBlockForPrefix(const BlockDecl *Block);
   void mangleUnqualifiedBlock(const BlockDecl *Block);
+  void mangleTemplateParamDecl(const NamedDecl *Decl);
   void mangleLambda(const CXXRecordDecl *Lambda);
   void mangleNestedName(const NamedDecl *ND, const DeclContext *DC,
                         const AbiTagList *AdditionalAbiTags,
@@ -1378,7 +1379,8 @@
     // <unnamed-type-name> ::= <closure-type-name>
     // 
     // <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
-    // <lambda-sig> ::= <parameter-type>+   # Parameter types or 'v' for 'void'.
+    // <lambda-sig> ::= <template-param-decl>* <parameter-type>+
+    //     # Parameter types or 'v' for 'void'.
     if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(TD)) {
       if (Record->isLambda() && Record->getLambdaManglingNumber()) {
         assert(!AdditionalAbiTags &&
@@ -1685,6 +1687,26 @@
   Out << '_';
 }
 
+// <template-param-decl>
+//   ::= Ty                              # template type parameter
+//   ::= Tn <type>                       # template non-type parameter
+//   ::= Tt <template-param-decl>* E     # template template parameter
+void CXXNameMangler::mangleTemplateParamDecl(const NamedDecl *Decl) {
+  if (isa<TemplateTypeParmDecl>(Decl)) {
+    Out << "Ty";
+  }
+  else if (auto *Tn = dyn_cast<NonTypeTemplateParmDecl>(Decl)) {
+    Out << "Tn";
+    mangleType(Tn->getType());
+  }
+  else if (auto *Tt = dyn_cast<TemplateTemplateParmDecl>(Decl)) {
+    Out << "Tt";
+    for (auto *Param : *Tt->getTemplateParameters())
+      mangleTemplateParamDecl(Param);
+    Out << "E";
+  }
+}
+
 void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
   // If the context of a closure type is an initializer for a class member 
   // (static or nonstatic), it is encoded in a qualified name with a final 
@@ -1712,6 +1734,16 @@
   }
 
   Out << "Ul";
+  if (unsigned ExplcitTemplateParamCount
+          = Lambda->getLambdaExplicitTemplateParameterCount()) {
+    const auto *List = Lambda->getGenericLambdaTemplateParameterList();
+    assert(List && "Lambda says it has explicit template parameters, "
+                   "but it doesn't have a template parameter list");
+    for (auto It = List->begin(), End = It + ExplcitTemplateParamCount;
+         It != End;
+         ++It)
+      mangleTemplateParamDecl(*It);
+  }
   const FunctionProtoType *Proto = Lambda->getLambdaTypeInfo()->getType()->
                                    getAs<FunctionProtoType>();
   mangleBareFunctionType(Proto, /*MangleReturnType=*/false,
Index: lib/AST/ExprCXX.cpp
===================================================================
--- lib/AST/ExprCXX.cpp
+++ lib/AST/ExprCXX.cpp
@@ -991,6 +991,13 @@
   return capture_range(implicit_capture_begin(), implicit_capture_end());
 }
 
+SourceRange LambdaExpr::getExplicitTemplateParameterListRange() const {
+  TemplateParameterList *List = getTemplateParameterList();
+  if (!List)
+    return SourceRange();
+  return {List->getLAngleLoc(), List->getRAngleLoc()};
+}
+
 CXXRecordDecl *LambdaExpr::getLambdaClass() const {
   return getType()->getAsCXXRecordDecl();
 }
@@ -1003,7 +1010,11 @@
 TemplateParameterList *LambdaExpr::getTemplateParameterList() const {
   CXXRecordDecl *Record = getLambdaClass();
   return Record->getGenericLambdaTemplateParameterList();
+}
 
+unsigned LambdaExpr::getExplicitTemplateParameterCount() const {
+  const CXXRecordDecl *Record = getLambdaClass();
+  return Record->getLambdaExplicitTemplateParameterCount();
 }
 
 CompoundStmt *LambdaExpr::getBody() const {
Index: lib/AST/DeclPrinter.cpp
===================================================================
--- lib/AST/DeclPrinter.cpp
+++ lib/AST/DeclPrinter.cpp
@@ -16,6 +16,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
 #include "clang/AST/DeclVisitor.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
@@ -101,7 +102,8 @@
     void VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D);
     void VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D);
 
-    void printTemplateParameters(const TemplateParameterList *Params);
+    void printTemplateParameters(const TemplateParameterList *Params,
+                                 bool OmitTemplateKW = false);
     void printTemplateArguments(const TemplateArgumentList &Args,
                                 const TemplateParameterList *Params = nullptr);
     void prettyPrintAttributes(Decl *D);
@@ -122,6 +124,18 @@
   Printer.Visit(const_cast<Decl*>(this));
 }
 
+void TemplateParameterList::print(raw_ostream &Out, const ASTContext &Context,
+                                  bool OmitTemplateKW) const {
+  print(Out, Context, Context.getPrintingPolicy(), OmitTemplateKW);
+}
+
+void TemplateParameterList::print(raw_ostream &Out, const ASTContext &Context,
+                                  const PrintingPolicy &Policy,
+                                  bool OmitTemplateKW) const {
+  DeclPrinter Printer(Out, Policy, Context);
+  Printer.printTemplateParameters(this, OmitTemplateKW);
+}
+
 static QualType GetBaseType(QualType T) {
   // FIXME: This should be on the Type class!
   QualType BaseType = T;
@@ -963,25 +977,35 @@
     Visit(*D->decls_begin());
 }
 
-void DeclPrinter::printTemplateParameters(const TemplateParameterList *Params) {
+void DeclPrinter::printTemplateParameters(const TemplateParameterList *Params,
+                                          bool OmitTemplateKW) {
   assert(Params);
 
-  Out << "template <";
+  if (!OmitTemplateKW)
+    Out << "template ";
+  Out << '<';
+
+  bool NeedComma = false;
+  for (const Decl *Param : *Params) {
+    if (Param->isImplicit())
+      continue;
 
-  for (unsigned i = 0, e = Params->size(); i != e; ++i) {
-    if (i != 0)
+    if (NeedComma)
       Out << ", ";
+    else
+      NeedComma = true;
 
-    const Decl *Param = Params->getParam(i);
     if (auto TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
 
       if (TTP->wasDeclaredWithTypename())
-        Out << "typename ";
+        Out << "typename";
       else
-        Out << "class ";
+        Out << "class";
 
       if (TTP->isParameterPack())
-        Out << "...";
+        Out << " ...";
+      else if (!TTP->getName().empty())
+        Out << ' ';
 
       Out << *TTP;
 
@@ -1006,7 +1030,9 @@
     }
   }
 
-  Out << "> ";
+  Out << '>';
+  if (!OmitTemplateKW)
+    Out << ' ';
 }
 
 void DeclPrinter::printTemplateArguments(const TemplateArgumentList &Args,
Index: lib/AST/DeclCXX.cpp
===================================================================
--- lib/AST/DeclCXX.cpp
+++ lib/AST/DeclCXX.cpp
@@ -1170,13 +1170,26 @@
 
 TemplateParameterList * 
 CXXRecordDecl::getGenericLambdaTemplateParameterList() const {
-  if (!isLambda()) return nullptr;
+  if (!isGenericLambda()) return nullptr;
   CXXMethodDecl *CallOp = getLambdaCallOperator();     
   if (FunctionTemplateDecl *Tmpl = CallOp->getDescribedFunctionTemplate())
     return Tmpl->getTemplateParameters();
   return nullptr;
 }
 
+unsigned CXXRecordDecl::getLambdaExplicitTemplateParameterCount() const {
+  TemplateParameterList *List = getGenericLambdaTemplateParameterList();
+  if (!List)
+    return 0;
+
+  assert(std::is_partitioned(List->begin(), List->end(),
+                             [](const NamedDecl *D) { return !D->isImplicit(); })
+         && "Explicit template params should be ordered before implicit ones");
+
+  return std::count_if(List->begin(), List->end(),
+                       [](const NamedDecl *D) { return !D->isImplicit(); });
+}
+
 Decl *CXXRecordDecl::getLambdaContextDecl() const {
   assert(isLambda() && "Not a lambda closure type!");
   ExternalASTSource *Source = getParentASTContext().getExternalSource();
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -5512,6 +5512,12 @@
   /// given lambda.
   void finishLambdaExplicitCaptures(sema::LambdaScopeInfo *LSI);
 
+  /// \brief This is called after parsing the explicit template parameter list
+  /// (if it exists) in C++2a.
+  void ActOnLambdaExplicitTemplateParameterList(SourceLocation LAngleLoc,
+                                                ArrayRef<NamedDecl *> TParams,
+                                                SourceLocation RAngleLoc);
+
   /// \brief Introduce the lambda parameters into scope.
   void addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope);
 
Index: include/clang/Sema/ScopeInfo.h
===================================================================
--- include/clang/Sema/ScopeInfo.h
+++ include/clang/Sema/ScopeInfo.h
@@ -769,19 +769,28 @@
   /// \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
+  
+  /// \brief The number of parameters in the template parameter list that were
+  /// explicitly specified by the user, as opposed to being invented by use
+  /// of an auto parameter.
+  unsigned NumExplicitTemplateParams;
+ 
+  /// \brief Source range covering the explicit template parameter list
+  /// (if it exists).
+  SourceRange ExplicitTemplateParamsRange;
+
+  /// \brief Store the list of the template parameters for a generic lambda.
+  /// If this is a generic lambda, this holds the explicit template parameters
+  /// followed by the auto parameters converted into TemplateTypeParmDecls.
+  /// It can be used to construct the generic lambda's template
   /// parameter list, during initial AST construction.
-  SmallVector<TemplateTypeParmDecl*, 4> AutoTemplateParams;
+  SmallVector<NamedDecl*, 4> TemplateParams;
 
   /// If this is a generic lambda, and the template parameter
-  /// list has been created (from the AutoTemplateParams) then
+  /// list has been created (from the TemplateParams) then
   /// store a reference to it (cache it to avoid reconstructing it).
   TemplateParameterList *GLTemplateParameterList;
-  
+
   /// \brief Contains all variable-referring-expressions (i.e. DeclRefExprs
   ///  or MemberExprs) that refer to local variables in a generic lambda
   ///  or a lambda in a potentially-evaluated-if-used context.
@@ -795,7 +804,6 @@
   ///  will truly be odr-used (i.e. need to be captured) by that nested lambda,
   ///  until its instantiation. But we still need to capture it in the 
   ///  enclosing lambda if all intervening lambdas can capture the variable.
-
   llvm::SmallVector<Expr*, 4> PotentiallyCapturingExprs;
 
   /// \brief Contains all variable-referring-expressions that refer
@@ -820,7 +828,7 @@
       CallOperator(nullptr), NumExplicitCaptures(0), Mutable(false),
       ExplicitParams(false), Cleanup{},
       ContainsUnexpandedParameterPack(false), AutoTemplateParameterDepth(0),
-      GLTemplateParameterList(nullptr) {
+      NumExplicitTemplateParams(0), GLTemplateParameterList(nullptr) {
     Kind = SK_Lambda;
   }
 
@@ -834,9 +842,9 @@
   }
 
   /// Is this scope known to be for a generic lambda? (This will be false until
-  /// we parse the first 'auto'-typed parameter.
+  /// we parse a template parameter list or the first 'auto'-typed parameter).
   bool isGenericLambda() const {
-    return !AutoTemplateParams.empty() || GLTemplateParameterList;
+    return !TemplateParams.empty() || GLTemplateParameterList;
   }
 
   ///
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -231,7 +231,13 @@
       Depth += D;
       AddedLevels += D;
     }
+    void setAddedDepth(unsigned D) {
+      Depth = Depth - AddedLevels + D;
+      AddedLevels = D;
+    }
+  
     unsigned getDepth() const { return Depth; }
+    unsigned getOriginalDepth() const { return Depth - AddedLevels; }
   };
 
   /// Factory object for creating AttributeList objects.
Index: include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -829,6 +829,16 @@
 def ext_constexpr_on_lambda_cxx17 : ExtWarn<
   "'constexpr' on lambda expressions is a C++17 extension">, InGroup<CXX17>;
 
+ // C++2a template lambdas
+ def ext_lambda_template_parameter_list: ExtWarn<
+  "explicit template parameter list for lambdas is a C++2a extension">,
+  InGroup<CXX2a>;
+def warn_cxx17_compat_lambda_template_parameter_list: Warning<
+  "explicit template parameter list for lambdas is incompatible with "
+  "C++ standards before C++2a">, InGroup<CXXPre2aCompat>, DefaultIgnore;
+ def err_lambda_template_parameter_list_empty : Error<
+   "lambda template parameter list cannot be empty">;
+
 // Availability attribute
 def err_expected_version : Error<
   "expected a version of the form 'major[.minor[.subminor]]'">;
Index: include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- include/clang/AST/RecursiveASTVisitor.h
+++ include/clang/AST/RecursiveASTVisitor.h
@@ -2379,6 +2379,13 @@
     }
   }
 
+  if (TemplateParameterList *TPL = S->getTemplateParameterList()) {
+    for (Decl *D : *TPL) {
+      if (!D->isImplicit() || getDerived().shouldVisitImplicitCode())
+        TRY_TO(TraverseDecl(D));
+    }
+  }
+
   TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
   FunctionProtoTypeLoc Proto = TL.getAsAdjusted<FunctionProtoTypeLoc>();
 
Index: include/clang/AST/ExprCXX.h
===================================================================
--- include/clang/AST/ExprCXX.h
+++ include/clang/AST/ExprCXX.h
@@ -1684,6 +1684,10 @@
   /// brackets ([...]).
   SourceRange getIntroducerRange() const { return IntroducerRange; }
 
+  /// \brief Retrieve the source range covering the explicit template parameter
+  /// list, including the surrounding angle brackets (<...>).
+  SourceRange getExplicitTemplateParameterListRange() const;
+
   /// \brief Retrieve the class that corresponds to the lambda.
   /// 
   /// This is the "closure type" (C++1y [expr.prim.lambda]), and stores the
@@ -1699,6 +1703,10 @@
   /// parameter list associated with it, or else return null. 
   TemplateParameterList *getTemplateParameterList() const;
 
+  /// \brief How many of the template parameters were explicitly specified
+  /// (as opposed to being invented by use of an auto parameter).
+  unsigned getExplicitTemplateParameterCount() const;
+
   /// \brief Whether this is a generic lambda.
   bool isGenericLambda() const { return getTemplateParameterList(); }
 
Index: include/clang/AST/DeclTemplate.h
===================================================================
--- include/clang/AST/DeclTemplate.h
+++ include/clang/AST/DeclTemplate.h
@@ -157,6 +157,11 @@
     return SourceRange(TemplateLoc, RAngleLoc);
   }
 
+  void print(raw_ostream &Out, const ASTContext &Context,
+             bool OmitTemplateKW = false) const;
+  void print(raw_ostream &Out, const ASTContext &Context,
+             const PrintingPolicy &Policy, bool OmitTemplateKW = false) const;
+
   friend TrailingObjects;
 
   template <size_t N, bool HasRequiresClause>
Index: include/clang/AST/DeclCXX.h
===================================================================
--- include/clang/AST/DeclCXX.h
+++ include/clang/AST/DeclCXX.h
@@ -1174,6 +1174,10 @@
   /// lambda.
   TemplateParameterList *getGenericLambdaTemplateParameterList() const;
 
+  /// \brief Retrieve the number of lambda template parameter's that were
+  /// specified explicitly in code.
+  unsigned getLambdaExplicitTemplateParameterCount() const;
+
   LambdaCaptureDefault getLambdaCaptureDefault() const {
     assert(isLambda());
     return static_cast<LambdaCaptureDefault>(getLambdaData().CaptureDefault);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to