Skip to content

Commit 8f46006

Browse files
dinordnetkex
authored andcommitted
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
1 parent ee39d7a commit 8f46006

File tree

2 files changed

+97
-7
lines changed

2 files changed

+97
-7
lines changed

absl/debugging/internal/demangle.cc

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,7 @@ static bool ParseClassEnumType(State *state);
570570
static bool ParseArrayType(State *state);
571571
static bool ParsePointerToMemberType(State *state);
572572
static bool ParseTemplateParam(State *state);
573+
static bool ParseTemplateParamDecl(State *state);
573574
static bool ParseTemplateTemplateParam(State *state);
574575
static bool ParseTemplateArgs(State *state);
575576
static bool ParseTemplateArg(State *state);
@@ -624,6 +625,9 @@ static bool ParseMangledName(State *state) {
624625
// <encoding> ::= <(function) name> <bare-function-type>
625626
// ::= <(data) name>
626627
// ::= <special-name>
628+
//
629+
// NOTE: Based on http://shortn/_Hoq9qG83rx
630+
// TODO(b/324066279): Add support for [Q <requires-clause expression>].
627631
static bool ParseEncoding(State *state) {
628632
ComplexityGuard guard(state);
629633
if (guard.IsTooComplex()) return false;
@@ -1431,6 +1435,52 @@ static bool ParseTemplateParam(State *state) {
14311435
return false;
14321436
}
14331437

1438+
// <template-param-decl>
1439+
// ::= Ty # template type parameter
1440+
// ::= Tk <concept name> [<template-args>] # constrained type parameter
1441+
// ::= Tn <type> # template non-type parameter
1442+
// ::= Tt <template-param-decl>* E # template template parameter
1443+
// ::= Tp <template-param-decl> # template parameter pack
1444+
//
1445+
// NOTE: <concept name> is just a <name>: http://shortn/_MqJVyr0fc1
1446+
// TODO(b/324066279): Implement optional suffix for `Tt`:
1447+
// [Q <requires-clause expr>]
1448+
static bool ParseTemplateParamDecl(State *state) {
1449+
ComplexityGuard guard(state);
1450+
if (guard.IsTooComplex()) return false;
1451+
ParseState copy = state->parse_state;
1452+
1453+
if (ParseTwoCharToken(state, "Ty")) {
1454+
return true;
1455+
}
1456+
state->parse_state = copy;
1457+
1458+
if (ParseTwoCharToken(state, "Tk") && ParseName(state) &&
1459+
Optional(ParseTemplateArgs(state))) {
1460+
return true;
1461+
}
1462+
state->parse_state = copy;
1463+
1464+
if (ParseTwoCharToken(state, "Tn") && ParseType(state)) {
1465+
return true;
1466+
}
1467+
state->parse_state = copy;
1468+
1469+
if (ParseTwoCharToken(state, "Tt") &&
1470+
ZeroOrMore(ParseTemplateParamDecl, state) &&
1471+
ParseOneCharToken(state, 'E')) {
1472+
return true;
1473+
}
1474+
state->parse_state = copy;
1475+
1476+
if (ParseTwoCharToken(state, "Tp") && ParseTemplateParamDecl(state)) {
1477+
return true;
1478+
}
1479+
state->parse_state = copy;
1480+
1481+
return false;
1482+
}
1483+
14341484
// <template-template-param> ::= <template-param>
14351485
// ::= <substitution>
14361486
static bool ParseTemplateTemplateParam(State *state) {
@@ -1442,6 +1492,9 @@ static bool ParseTemplateTemplateParam(State *state) {
14421492
}
14431493

14441494
// <template-args> ::= I <template-arg>+ E
1495+
//
1496+
// TODO(b/324066279): Implement optional [Q <requires-clause expr>] before E.
1497+
// See: http://shortn/_Z7yM7PonSD
14451498
static bool ParseTemplateArgs(State *state) {
14461499
ComplexityGuard guard(state);
14471500
if (guard.IsTooComplex()) return false;
@@ -1457,13 +1510,11 @@ static bool ParseTemplateArgs(State *state) {
14571510
return false;
14581511
}
14591512

1460-
// <template-arg> ::= <type>
1513+
// <template-arg> ::= <template-param-decl> <template-arg>
1514+
// ::= <type>
14611515
// ::= <expr-primary>
14621516
// ::= J <template-arg>* E # argument pack
14631517
// ::= X <expression> E
1464-
// ::= Tk <type> <type> # constraint
1465-
//
1466-
// TODO(b/323420445): Support templated constraints.
14671518
static bool ParseTemplateArg(State *state) {
14681519
ComplexityGuard guard(state);
14691520
if (guard.IsTooComplex()) return false;
@@ -1564,7 +1615,7 @@ static bool ParseTemplateArg(State *state) {
15641615
}
15651616
state->parse_state = copy;
15661617

1567-
if (ParseTwoCharToken(state, "Tk") && ParseType(state) && ParseType(state)) {
1618+
if (ParseTemplateParamDecl(state) && ParseTemplateArg(state)) {
15681619
return true;
15691620
}
15701621
state->parse_state = copy;

absl/debugging/internal/demangle_test.cc

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,56 @@ TEST(Demangle, FunctionTemplateWithNesting) {
5353
EXPECT_STREQ(tmp, "foo<>()");
5454
}
5555

56-
TEST(Demangle, FunctionTemplateWithConstraint) {
56+
TEST(Demangle, FunctionTemplateWithNonTypeParamConstraint) {
5757
char tmp[100];
5858

5959
// template <std::integral T>
6060
// int foo(T);
6161
//
62-
// foo<Wrapper<int>(5);
62+
// foo<int>(5);
6363
ASSERT_TRUE(Demangle("_Z3fooITkSt8integraliEiT_", tmp, sizeof(tmp)));
6464
EXPECT_STREQ(tmp, "foo<>()");
6565
}
6666

67+
TEST(Demangle, FunctionTemplateWithAutoParam) {
68+
char tmp[100];
69+
70+
// template <auto>
71+
// void foo();
72+
//
73+
// foo<1>();
74+
ASSERT_TRUE(Demangle("_Z3fooITnDaLi1EEvv", tmp, sizeof(tmp)));
75+
EXPECT_STREQ(tmp, "foo<>()");
76+
}
77+
78+
TEST(Demangle, FunctionTemplateWithNonTypeParamPack) {
79+
char tmp[100];
80+
81+
// template <int&..., typename T>
82+
// void foo(T);
83+
//
84+
// foo(2);
85+
ASSERT_TRUE(Demangle("_Z3fooITpTnRiJEiEvT0_", tmp, sizeof(tmp)));
86+
EXPECT_STREQ(tmp, "foo<>()");
87+
}
88+
89+
TEST(Demangle, FunctionTemplateTemplateParamWithConstrainedArg) {
90+
char tmp[100];
91+
92+
// template <typename T>
93+
// concept True = true;
94+
//
95+
// template <typename T> requires True<T>
96+
// struct Fooer {};
97+
//
98+
// template <template <typename T> typename>
99+
// void foo() {}
100+
//
101+
// foo<Fooer>();
102+
ASSERT_TRUE(Demangle("_Z3fooITtTyE5FooerEvv", tmp, sizeof(tmp)));
103+
EXPECT_STREQ(tmp, "foo<>()");
104+
}
105+
67106
// Test corner cases of boundary conditions.
68107
TEST(Demangle, CornerCases) {
69108
char tmp[10];

0 commit comments

Comments
 (0)