aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--absl/debugging/internal/demangle.cc20
-rw-r--r--absl/debugging/internal/demangle_test.cc30
2 files changed, 48 insertions, 2 deletions
diff --git a/absl/debugging/internal/demangle.cc b/absl/debugging/internal/demangle.cc
index 1143ba9e..82420c8b 100644
--- a/absl/debugging/internal/demangle.cc
+++ b/absl/debugging/internal/demangle.cc
@@ -1434,19 +1434,35 @@ static bool ParsePointerToMemberType(State *state) {
// <template-param> ::= T_
// ::= T <parameter-2 non-negative number> _
+// ::= TL <level-1> __
+// ::= TL <level-1> _ <parameter-2 non-negative number> _
static bool ParseTemplateParam(State *state) {
ComplexityGuard guard(state);
if (guard.IsTooComplex()) return false;
if (ParseTwoCharToken(state, "T_")) {
MaybeAppend(state, "?"); // We don't support template substitutions.
- return true;
+ return true; // ::= T_
}
ParseState copy = state->parse_state;
if (ParseOneCharToken(state, 'T') && ParseNumber(state, nullptr) &&
ParseOneCharToken(state, '_')) {
MaybeAppend(state, "?"); // We don't support template substitutions.
- return true;
+ return true; // ::= T <parameter-2 non-negative number> _
+ }
+ state->parse_state = copy;
+
+ if (ParseTwoCharToken(state, "TL") && ParseNumber(state, nullptr)) {
+ if (ParseTwoCharToken(state, "__")) {
+ MaybeAppend(state, "?"); // We don't support template substitutions.
+ return true; // ::= TL <level-1> __
+ }
+
+ if (ParseOneCharToken(state, '_') && ParseNumber(state, nullptr) &&
+ ParseOneCharToken(state, '_')) {
+ MaybeAppend(state, "?"); // We don't support template substitutions.
+ return true; // ::= TL <level-1> _ <parameter-2 non-negative number> _
+ }
}
state->parse_state = copy;
return false;
diff --git a/absl/debugging/internal/demangle_test.cc b/absl/debugging/internal/demangle_test.cc
index 555e5908..2771d4d0 100644
--- a/absl/debugging/internal/demangle_test.cc
+++ b/absl/debugging/internal/demangle_test.cc
@@ -182,6 +182,36 @@ TEST(Demangle, FailsOnTwoArgTemplateBuiltinType) {
Demangle("_Z3fooIicEu17__my_builtin_typeIT_T0_Ev", tmp, sizeof(tmp)));
}
+TEST(Demangle, TemplateTemplateParamSubstitution) {
+ char tmp[100];
+
+ // template <typename T>
+ // concept True = true;
+ //
+ // template<std::integral T, T> struct Foolable {};
+ // template<template<typename T, T> typename> void foo() {}
+ //
+ // template void foo<Foolable>();
+ ASSERT_TRUE(Demangle("_Z3fooITtTyTnTL0__E8FoolableEvv", tmp, sizeof(tmp)));
+ EXPECT_STREQ(tmp, "foo<>()");
+}
+
+TEST(Demangle, TemplateParamSubstitutionWithGenericLambda) {
+ char tmp[100];
+
+ // template <typename>
+ // struct Fooer {
+ // template <typename>
+ // void foo(decltype([](auto x, auto y) {})) {}
+ // };
+ //
+ // Fooer<int> f;
+ // f.foo<int>({});
+ ASSERT_TRUE(
+ Demangle("_ZN5FooerIiE3fooIiEEvNS0_UlTL0__TL0_0_E_E", tmp, sizeof(tmp)));
+ EXPECT_STREQ(tmp, "Fooer<>::foo<>()");
+}
+
// Test corner cases of boundary conditions.
TEST(Demangle, CornerCases) {
char tmp[10];