`demangle`: Implement parsing for simplest constrained template arguments

C++20 introduced constraints, where concepts such as `std::integral` can be used to restrict template parameters:

```
template <std::integral T>
int foo(T t);  // Only accepts integral types.
```

Clang mangles these starting with a prefix `Tk`, followed by the concept name, which mangles as a type.
For example, compare `foo` and `bar` here: https://godbolt.org/z/Kzbrrchde

Note that this implementation doesn't cover the more complex case where the concept is templated too. See [llvm's implementation](https://github.com/llvm/llvm-project/commit/4b163e343cfa54c8d55c9da73c70d58f55ea9df2) and its tests for a thorough version.

PiperOrigin-RevId: 604976260
Change-Id: Ic116c5f6f27c3f7714638bdee8de11dce871f0be
diff --git a/absl/debugging/internal/demangle.cc b/absl/debugging/internal/demangle.cc
index 381a2b5..3ef2158 100644
--- a/absl/debugging/internal/demangle.cc
+++ b/absl/debugging/internal/demangle.cc
@@ -1461,6 +1461,9 @@
 //                 ::= <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;
@@ -1560,6 +1563,12 @@
     return true;
   }
   state->parse_state = copy;
+
+  if (ParseTwoCharToken(state, "Tk") && ParseType(state) && ParseType(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
   return false;
 }
 
diff --git a/absl/debugging/internal/demangle_test.cc b/absl/debugging/internal/demangle_test.cc
index a16ab75..c1b6125 100644
--- a/absl/debugging/internal/demangle_test.cc
+++ b/absl/debugging/internal/demangle_test.cc
@@ -31,6 +31,39 @@
 
 using ::testing::ContainsRegex;
 
+TEST(Demangle, FunctionTemplate) {
+  char tmp[100];
+
+  // template <typename T>
+  // int foo(T);
+  //
+  // foo<int>(5);
+  ASSERT_TRUE(Demangle("_Z3fooIiEiT_", tmp, sizeof(tmp)));
+  EXPECT_STREQ(tmp, "foo<>()");
+}
+
+TEST(Demangle, FunctionTemplateWithNesting) {
+  char tmp[100];
+
+  // template <typename T>
+  // int foo(T);
+  //
+  // foo<Wrapper<int>>({ .value = 5 });
+  ASSERT_TRUE(Demangle("_Z3fooI7WrapperIiEEiT_", tmp, sizeof(tmp)));
+  EXPECT_STREQ(tmp, "foo<>()");
+}
+
+TEST(Demangle, FunctionTemplateWithConstraint) {
+  char tmp[100];
+
+  // template <std::integral T>
+  // int foo(T);
+  //
+  // foo<Wrapper<int>(5);
+  ASSERT_TRUE(Demangle("_Z3fooITkSt8integraliEiT_", tmp, sizeof(tmp)));
+  EXPECT_STREQ(tmp, "foo<>()");
+}
+
 // Test corner cases of boundary conditions.
 TEST(Demangle, CornerCases) {
   char tmp[10];