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

Changed a documentation comment to use \brief instead of stating the function 
name.
Only enter the template parameter scope if needed.
Changed the phrasing of the diagnostic when an empty template parameter list is 
encountered.

Since submitting this patch for review, a test 
<https://github.com/llvm-mirror/clang/blob/e017f9615d3a4ff53f47984e8293ef68361cf3cf/test/CXX/temp/temp.decls/temp.variadic/p4.cpp#L284>
 has been added which fails with this patch. The test has a FIXME comment about 
moving the test somewhere when template lambda syntax is supported, but I'm not 
sure what needs to be done. Any ideas?


https://reviews.llvm.org/D36527

Files:
  include/clang/Basic/DiagnosticParseKinds.td
  include/clang/Sema/ScopeInfo.h
  include/clang/Sema/Sema.h
  lib/Parse/ParseExprCXX.cpp
  lib/Sema/Sema.cpp
  lib/Sema/SemaLambda.cpp
  lib/Sema/SemaType.cpp
  test/Parser/cxx2a-template-lambdas.cpp
  test/SemaCXX/cxx2a-template-lambdas.cpp
  www/cxx_status.html

Index: www/cxx_status.html
===================================================================
--- www/cxx_status.html
+++ www/cxx_status.html
@@ -822,7 +822,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: 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: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp
+++ lib/Sema/SemaType.cpp
@@ -2789,8 +2789,8 @@
         // template parameter type.
         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 TemplateParameterDepth = LSI->TemplateParameterDepth;
+        const unsigned AutoParameterPosition = LSI->TemplateParams.size();
         const bool IsParameterPack = D.hasEllipsis();
 
         // Create the TemplateTypeParmDecl here to retrieve the corresponding
@@ -2802,7 +2802,7 @@
                 /*KeyLoc*/SourceLocation(), /*NameLoc*/D.getLocStart(),
                 TemplateParameterDepth, AutoParameterPosition,
                 /*Identifier*/nullptr, false, IsParameterPack);
-        LSI->AutoTemplateParams.push_back(CorrespondingTemplateParam);
+        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
@@ -229,15 +229,17 @@
   if (LSI->GLTemplateParameterList)
     return LSI->GLTemplateParameterList;
 
-  if (!LSI->AutoTemplateParams.empty()) {
-    SourceRange IntroRange = LSI->IntroducerRange;
-    SourceLocation LAngleLoc = IntroRange.getBegin();
-    SourceLocation RAngleLoc = IntroRange.getEnd();
+  if (!LSI->TemplateParams.empty()) {
+    SourceRange ListRange = LSI->ExplicitTemplateParamsRange.isValid()
+                              ? LSI->ExplicitTemplateParamsRange
+                              : LSI->IntroducerRange;
+    SourceLocation LAngleLoc = ListRange.getBegin();
+    SourceLocation RAngleLoc = ListRange.getEnd();
     LSI->GLTemplateParameterList = TemplateParameterList::Create(
         SemaRef.Context,
         /*Template kw loc*/ SourceLocation(), LAngleLoc,
-        llvm::makeArrayRef((NamedDecl *const *)LSI->AutoTemplateParams.data(),
-                           LSI->AutoTemplateParams.size()),
+        llvm::makeArrayRef((NamedDecl *const *)LSI->TemplateParams.data(),
+                           LSI->TemplateParams.size()),
         RAngleLoc, nullptr);
   }
   return LSI->GLTemplateParameterList;
@@ -479,6 +481,44 @@
   LSI->finishedExplicitCaptures();
 }
 
+TemplateParameterList *
+Sema::ActOnLambdaTemplateParameterList(unsigned Depth,
+                                       SourceLocation LAngleLoc,
+                                       ArrayRef<Decl *> 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 ones");
+
+  TemplateParameterList *ret = ActOnTemplateParameterList(
+      Depth,
+      /*ExportLoc=*/SourceLocation(), /*TemplateLoc=*/SourceLocation(),
+      LAngleLoc, TParams, RAngleLoc,
+      /*RequiresClause=*/nullptr);
+
+  LSI->TemplateParams.append(TParams.begin(), TParams.end());
+  LSI->NumExplicitTemplateParams = TParams.size();
+  LSI->ExplicitTemplateParamsRange = {LAngleLoc, RAngleLoc};
+
+  return ret;
+}
+
+void Sema::addLambdaExplicitTemplateParameters(ArrayRef<Decl*> TParams,
+                                               Scope *CurScope) {
+  for (Decl *T : TParams) {
+    NamedDecl *NT = dyn_cast<NamedDecl>(T);
+    assert(NT && "Template parameter should be convertable to NamedDecl");
+
+    // If this has an identifier, add it to the scope stack.
+    if (CurScope && NT->getIdentifier())
+      PushOnScopeChains(NT, CurScope);
+  }
+}
+
 void Sema::addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope) {  
   // Introduce our parameters into the function scope
   for (unsigned p = 0, NumParams = CallOperator->getNumParams(); 
@@ -1121,6 +1161,10 @@
 
   LSI->ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack;
 
+  // Add explicit template parameters into scope.
+  addLambdaExplicitTemplateParameters(LSI->getExplicitTemplateParams(),
+                                      CurScope);
+
   // Add lambda parameters into scope.
   addLambdaParameters(Method, CurScope);
 
Index: lib/Sema/Sema.cpp
===================================================================
--- lib/Sema/Sema.cpp
+++ lib/Sema/Sema.cpp
@@ -1292,7 +1292,7 @@
 
 void Sema::RecordParsingTemplateParameterDepth(unsigned Depth) {
   if (LambdaScopeInfo *const LSI = getCurLambda()) {
-    LSI->AutoTemplateParameterDepth = Depth;
+    LSI->TemplateParameterDepth = Depth;
     return;
   } 
   llvm_unreachable( 
@@ -1376,7 +1376,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] ']'
@@ -1082,9 +1084,11 @@
   // Parse lambda-declarator[opt].
   DeclSpec DS(AttrFactory);
   Declarator D(DS, Declarator::LambdaExprContext);
-  TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
   Actions.PushLambdaScope();
 
+  TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
+  Actions.RecordParsingTemplateParameterDepth(TemplateParameterDepth);
+
   ParsedAttributes Attr(AttrFactory);
   SourceLocation DeclLoc = Tok.getLocation();
   if (getLangOpts().CUDA) {
@@ -1105,6 +1109,30 @@
               << A->getName()->getName();
   };
 
+  // FIXME: Consider allowing this as an extension for GCC compatibiblity.
+  bool HasExplicitTemplateParams = getLangOpts().CPlusPlus2a
+                                   && Tok.is(tok::less);
+  ParseScope TemplateParamScope(this, Scope::TemplateParamScope,
+                                /*EnteredScope=*/HasExplicitTemplateParams);
+  if (HasExplicitTemplateParams) {
+    SmallVector<Decl*, 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.ActOnLambdaTemplateParameterList(
+          CurTemplateDepthTracker.getDepth(),
+          LAngleLoc, TemplateParams, RAngleLoc);
+    }
+  }
+
   TypeResult TrailingReturnType;
   if (Tok.is(tok::l_paren)) {
     ParseScope PrototypeScope(this,
@@ -1120,14 +1148,9 @@
     SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
     SourceLocation EllipsisLoc;
     
-    if (Tok.isNot(tok::r_paren)) {
-      Actions.RecordParsingTemplateParameterDepth(TemplateParameterDepth);
+    if (Tok.isNot(tok::r_paren))
       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();
     SourceLocation DeclEndLoc = RParenLoc;
@@ -1279,6 +1302,13 @@
                   Attr, DeclEndLoc);
   }
 
+  TemplateParamScope.Exit();
+
+  // getCurGenericLambda is used to see if we've added any template parameters.
+  // If so, the template depth needs to be increased.
+  if (Actions.getCurGenericLambda()) 
+    ++CurTemplateDepthTracker;
+
   // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using
   // it.
   unsigned ScopeFlags = Scope::BlockScope | Scope::FnScope | Scope::DeclScope |
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -5466,6 +5466,18 @@
   /// given lambda.
   void finishLambdaExplicitCaptures(sema::LambdaScopeInfo *LSI);
 
+  /// \brief This is called after parsing the explicit template parameter list
+  /// (if it exists) in C++2a.
+  TemplateParameterList *
+  ActOnLambdaTemplateParameterList(unsigned Depth,
+                                   SourceLocation LAngleLoc,
+                                   ArrayRef<Decl *> TParams,
+                                   SourceLocation RAngleLoc);
+
+  /// \brief Introduce the explicit lambda template parameters into scope.
+  void addLambdaExplicitTemplateParameters(ArrayRef<Decl*> TParams,
+                                           Scope *CurScope);
+
   /// \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
@@ -767,18 +767,27 @@
   bool ContainsUnexpandedParameterPack;
 
   /// \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
+  /// each template parameter, during initial AST construction.
+  unsigned TemplateParameterDepth;
+  
+  /// \brief The number of parameters in the template parameter list that were
+  /// explicitely 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<Decl*, 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;
   
@@ -819,8 +828,8 @@
     : CapturingScopeInfo(Diag, ImpCap_None), Lambda(nullptr),
       CallOperator(nullptr), NumExplicitCaptures(0), Mutable(false),
       ExplicitParams(false), Cleanup{},
-      ContainsUnexpandedParameterPack(false), AutoTemplateParameterDepth(0),
-      GLTemplateParameterList(nullptr) {
+      ContainsUnexpandedParameterPack(false), TemplateParameterDepth(0),
+      NumExplicitTemplateParams(0), GLTemplateParameterList(nullptr) {
     Kind = SK_Lambda;
   }
 
@@ -834,9 +843,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;
   }
 
   ///
@@ -938,6 +947,12 @@
                                   PotentialThisCaptureLocation.isValid(); 
   }
 
+  llvm::ArrayRef<Decl*> getExplicitTemplateParams() const {
+    // Explicit template parameters should always be first in the list.
+    return llvm::makeArrayRef(TemplateParams)
+               .slice(0, NumExplicitTemplateParams);
+  }
+
   // When passed the index, returns the VarDecl and Expr associated
   // with the index.
   void getPotentialVariableCapture(unsigned Idx, VarDecl *&VD, Expr *&E) const;
Index: include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -822,6 +822,10 @@
 def ext_constexpr_on_lambda_cxx17 : ExtWarn<
   "'constexpr' on lambda expressions is a C++17 extension">, InGroup<CXX17>;
 
+ // C++2a template lambdas
+ 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]]'">;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to