`demangle`: Parse C++20-compatible template param declarations, except those with `requires` expressions

Support for `requires` expressions will be added in a follow-up.

PiperOrigin-RevId: 605418370
Change-Id: I2c84cdf0c4599e36683b3c94dcbb173ab4fc3ee8
diff --git a/absl/debugging/internal/demangle.cc b/absl/debugging/internal/demangle.cc
index 3ef2158..fd3aef7 100644
--- a/absl/debugging/internal/demangle.cc
+++ b/absl/debugging/internal/demangle.cc
@@ -570,6 +570,7 @@
 static bool ParseArrayType(State *state);
 static bool ParsePointerToMemberType(State *state);
 static bool ParseTemplateParam(State *state);
+static bool ParseTemplateParamDecl(State *state);
 static bool ParseTemplateTemplateParam(State *state);
 static bool ParseTemplateArgs(State *state);
 static bool ParseTemplateArg(State *state);
@@ -624,6 +625,9 @@
 // <encoding> ::= <(function) name> <bare-function-type>
 //            ::= <(data) name>
 //            ::= <special-name>
+//
+// NOTE: Based on http://shortn/_Hoq9qG83rx
+// TODO(b/324066279): Add support for [Q <requires-clause expression>].
 static bool ParseEncoding(State *state) {
   ComplexityGuard guard(state);
   if (guard.IsTooComplex()) return false;
@@ -1431,6 +1435,52 @@
   return false;
 }
 
+// <template-param-decl>
+//   ::= Ty                                  # template type parameter
+//   ::= Tk <concept name> [<template-args>] # constrained type parameter
+//   ::= Tn <type>                           # template non-type parameter
+//   ::= Tt <template-param-decl>* E         # template template parameter
+//   ::= Tp <template-param-decl>            # template parameter pack
+//
+// NOTE: <concept name> is just a <name>: http://shortn/_MqJVyr0fc1
+// TODO(b/324066279): Implement optional suffix for `Tt`:
+// [Q <requires-clause expr>]
+static bool ParseTemplateParamDecl(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+
+  if (ParseTwoCharToken(state, "Ty")) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseTwoCharToken(state, "Tk") && ParseName(state) &&
+      Optional(ParseTemplateArgs(state))) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseTwoCharToken(state, "Tn") && ParseType(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseTwoCharToken(state, "Tt") &&
+      ZeroOrMore(ParseTemplateParamDecl, state) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseTwoCharToken(state, "Tp") && ParseTemplateParamDecl(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  return false;
+}
+
 // <template-template-param> ::= <template-param>
 //                           ::= <substitution>
 static bool ParseTemplateTemplateParam(State *state) {
@@ -1442,6 +1492,9 @@
 }
 
 // <template-args> ::= I <template-arg>+ E
+//
+// TODO(b/324066279): Implement optional [Q <requires-clause expr>] before E.
+// See: http://shortn/_Z7yM7PonSD
 static bool ParseTemplateArgs(State *state) {
   ComplexityGuard guard(state);
   if (guard.IsTooComplex()) return false;
@@ -1457,13 +1510,11 @@
   return false;
 }
 
-// <template-arg>  ::= <type>
+// <template-arg>  ::= <template-param-decl> <template-arg>
+//                 ::= <type>
 //                 ::= <expr-primary>
 //                 ::= J <template-arg>* E        # argument pack
 //                 ::= X <expression> E
-//                 ::= Tk <type> <type>           # constraint
-//
-// TODO(b/323420445): Support templated constraints.
 static bool ParseTemplateArg(State *state) {
   ComplexityGuard guard(state);
   if (guard.IsTooComplex()) return false;
@@ -1564,7 +1615,7 @@
   }
   state->parse_state = copy;
 
-  if (ParseTwoCharToken(state, "Tk") && ParseType(state) && ParseType(state)) {
+  if (ParseTemplateParamDecl(state) && ParseTemplateArg(state)) {
     return true;
   }
   state->parse_state = copy;
diff --git a/absl/debugging/internal/demangle_test.cc b/absl/debugging/internal/demangle_test.cc
index c1b6125..4e04210 100644
--- a/absl/debugging/internal/demangle_test.cc
+++ b/absl/debugging/internal/demangle_test.cc
@@ -53,17 +53,56 @@
   EXPECT_STREQ(tmp, "foo<>()");
 }
 
-TEST(Demangle, FunctionTemplateWithConstraint) {
+TEST(Demangle, FunctionTemplateWithNonTypeParamConstraint) {
   char tmp[100];
 
   // template <std::integral T>
   // int foo(T);
   //
-  // foo<Wrapper<int>(5);
+  // foo<int>(5);
   ASSERT_TRUE(Demangle("_Z3fooITkSt8integraliEiT_", tmp, sizeof(tmp)));
   EXPECT_STREQ(tmp, "foo<>()");
 }
 
+TEST(Demangle, FunctionTemplateWithAutoParam) {
+  char tmp[100];
+
+  // template <auto>
+  // void foo();
+  //
+  // foo<1>();
+  ASSERT_TRUE(Demangle("_Z3fooITnDaLi1EEvv", tmp, sizeof(tmp)));
+  EXPECT_STREQ(tmp, "foo<>()");
+}
+
+TEST(Demangle, FunctionTemplateWithNonTypeParamPack) {
+  char tmp[100];
+
+  // template <int&..., typename T>
+  // void foo(T);
+  //
+  // foo(2);
+  ASSERT_TRUE(Demangle("_Z3fooITpTnRiJEiEvT0_", tmp, sizeof(tmp)));
+  EXPECT_STREQ(tmp, "foo<>()");
+}
+
+TEST(Demangle, FunctionTemplateTemplateParamWithConstrainedArg) {
+  char tmp[100];
+
+  // template <typename T>
+  // concept True = true;
+  //
+  // template <typename T> requires True<T>
+  // struct Fooer {};
+  //
+  // template <template <typename T> typename>
+  // void foo() {}
+  //
+  // foo<Fooer>();
+  ASSERT_TRUE(Demangle("_Z3fooITtTyE5FooerEvv", tmp, sizeof(tmp)));
+  EXPECT_STREQ(tmp, "foo<>()");
+}
+
 // Test corner cases of boundary conditions.
 TEST(Demangle, CornerCases) {
   char tmp[10];