[Clang] Correctly handle generic lambda used as default template argument.
authorCorentin Jabot <corentinjabot@gmail.com>
Wed, 24 May 2023 16:11:40 +0000 (18:11 +0200)
committerCorentin Jabot <corentinjabot@gmail.com>
Fri, 26 May 2023 14:04:10 +0000 (16:04 +0200)
Adjust the template pparameter depth when parsing default
template arguments as they may introduce generic lambda whose parameters
are not substituted at the same depth.

Fixes #62611

Reviewed By: erichkeane, #clang-language-wg

Differential Revision: https://reviews.llvm.org/D151342

clang/docs/ReleaseNotes.rst
clang/lib/Parse/ParseTemplate.cpp
clang/test/SemaCXX/cxx2a-template-lambdas.cpp

index f1cc205..4387f9b 100644 (file)
@@ -507,6 +507,8 @@ Bug Fixes to C++ Support
   (`#114 <https://github.com/llvm/llvm-project/issues/114>`_)
 - Fix parsing of `auto(x)`, when it is surrounded by parentheses.
   (`#62494 <https://github.com/llvm/llvm-project/issues/62494>`_)
+- Fix handling of generic lambda used as template arguments.
+  (`#62611 <https://github.com/llvm/llvm-project/issues/62611>`_)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
index 964d985..79f4ab6 100644 (file)
@@ -841,10 +841,17 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
   // we introduce the type parameter into the local scope.
   SourceLocation EqualLoc;
   ParsedType DefaultArg;
-  if (TryConsumeToken(tok::equal, EqualLoc))
+  if (TryConsumeToken(tok::equal, EqualLoc)) {
+    // The default argument may declare template parameters, notably
+    // if it contains a generic lambda, so we need to increase
+    // the template depth as these parameters would not be instantiated
+    // at the current level.
+    TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
+    ++CurTemplateDepthTracker;
     DefaultArg =
         ParseTypeName(/*Range=*/nullptr, DeclaratorContext::TemplateTypeArg)
             .get();
+  }
 
   NamedDecl *NewDecl = Actions.ActOnTypeParameter(getCurScope(),
                                                   TypenameKeyword, EllipsisLoc,
@@ -1030,6 +1037,14 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
       //   end of the template-parameter-list rather than a greater-than
       //   operator.
       GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
+
+      // The default argument may declare template parameters, notably
+      // if it contains a generic lambda, so we need to increase
+      // the template depth as these parameters would not be instantiated
+      // at the current level.
+      TemplateParameterDepthRAII CurTemplateDepthTracker(
+          TemplateParameterDepth);
+      ++CurTemplateDepthTracker;
       EnterExpressionEvaluationContext ConstantEvaluated(
           Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
       DefaultArg =
index 65baf29..cc50292 100644 (file)
@@ -43,3 +43,30 @@ constexpr T outer() {
 }
 static_assert(outer<int>() == 123);
 template int *outer<int *>(); // expected-note {{in instantiation}}
+
+
+namespace GH62611 {
+template <auto A = [](auto x){}>
+struct C {
+  static constexpr auto B = A;
+};
+
+int test() {
+  C<>::B(42);
+}
+
+namespace AutoParam
+{
+template <auto A = [](auto x) { return x;}>
+auto B = A;
+static_assert(B<>(42) == 42);
+}
+
+namespace TypeParam
+{
+template <typename T = decltype([](auto x) {return x;})>
+auto B = T{};
+static_assert(B<>(42) == 42);
+}
+
+}