Skip to content

Commit dd5f1db

Browse files
dinordnetkex
authored andcommitted
demangle: Parse requires clauses on functions
These clauses show up in other places that end up mangled as parts of function signatures (e.g. on template struct params). We'll handle those in a follow-up. PiperOrigin-RevId: 605694497 Change-Id: I1bfe4c0cfaa739fdd24548b1547482410c92b5a7
1 parent a5eb91b commit dd5f1db

File tree

2 files changed

+53
-8
lines changed

2 files changed

+53
-8
lines changed

absl/debugging/internal/demangle.cc

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,7 @@ static bool ParseUnresolvedName(State *state);
579579
static bool ParseExpression(State *state);
580580
static bool ParseExprPrimary(State *state);
581581
static bool ParseExprCastValue(State *state);
582+
static bool ParseRequiresClauseExpression(State *state);
582583
static bool ParseLocalName(State *state);
583584
static bool ParseLocalNameSuffix(State *state);
584585
static bool ParseDiscriminator(State *state);
@@ -623,25 +624,38 @@ static bool ParseMangledName(State *state) {
623624
}
624625

625626
// <encoding> ::= <(function) name> <bare-function-type>
627+
// [`Q` <requires-clause expr>]
626628
// ::= <(data) name>
627629
// ::= <special-name>
628630
//
629631
// NOTE: Based on http://shortn/_Hoq9qG83rx
630-
// TODO(b/324066279): Add support for [Q <requires-clause expression>].
631632
static bool ParseEncoding(State *state) {
632633
ComplexityGuard guard(state);
633634
if (guard.IsTooComplex()) return false;
634-
// Implementing the first two productions together as <name>
635-
// [<bare-function-type>] avoids exponential blowup of backtracking.
635+
// Since the first two productions both start with <name>, attempt
636+
// to parse it only once to avoid exponential blowup of backtracking.
636637
//
637-
// Since Optional(...) can't fail, there's no need to copy the state for
638-
// backtracking.
639-
if (ParseName(state) && Optional(ParseBareFunctionType(state))) {
640-
return true;
638+
// We're careful about exponential blowup because <encoding> recursively
639+
// appears in other productions downstream of its first two productions,
640+
// which means that every call to `ParseName` would possibly indirectly
641+
// result in two calls to `ParseName` etc.
642+
if (ParseName(state)) {
643+
if (!ParseBareFunctionType(state)) {
644+
return true; // <(data) name>
645+
}
646+
647+
// Parsed: <(function) name> <bare-function-type>
648+
// Pending: [`Q` <requires-clause expr>]
649+
ParseState copy = state->parse_state;
650+
if (ParseOneCharToken(state, 'Q') && ParseRequiresClauseExpression(state)) {
651+
return true; // <(function) name> <bare-function-type> `Q` <requires>
652+
}
653+
state->parse_state = copy;
654+
return true; // <(function) name> <bare-function-type>
641655
}
642656

643657
if (ParseSpecialName(state)) {
644-
return true;
658+
return true; // <special-name>
645659
}
646660
return false;
647661
}
@@ -1916,6 +1930,26 @@ static bool ParseExprCastValue(State *state) {
19161930
return false;
19171931
}
19181932

1933+
// <requires-clause expr> is just an <expression>: http://shortn/_9E1Ul0rIM8
1934+
//
1935+
// Does not emit the parsed `requires` clause to simplify the implementation.
1936+
// In other words, these two functions' mangled names will demangle identically:
1937+
//
1938+
// template <typename T>
1939+
// int foo(T) requires IsIntegral<T>;
1940+
//
1941+
// vs.
1942+
//
1943+
// template <typename T>
1944+
// int foo(T);
1945+
static bool ParseRequiresClauseExpression(State *state) {
1946+
bool original_append = state->parse_state.append;
1947+
DisableAppend(state);
1948+
bool result = ParseExpression(state);
1949+
RestoreAppend(state, original_append);
1950+
return result;
1951+
}
1952+
19191953
// <local-name> ::= Z <(function) encoding> E <(entity) name> [<discriminator>]
19201954
// ::= Z <(function) encoding> E s [<discriminator>]
19211955
//

absl/debugging/internal/demangle_test.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,17 @@ TEST(Demangle, FunctionTemplateWithNonTypeParamConstraint) {
6464
EXPECT_STREQ(tmp, "foo<>()");
6565
}
6666

67+
TEST(Demangle, FunctionTemplateWithFunctionRequiresClause) {
68+
char tmp[100];
69+
70+
// template <typename T>
71+
// int foo() requires std::integral<T>;
72+
//
73+
// foo<int>();
74+
ASSERT_TRUE(Demangle("_Z3fooIiEivQsr3stdE8integralIT_E", tmp, sizeof(tmp)));
75+
EXPECT_STREQ(tmp, "foo<>()");
76+
}
77+
6778
TEST(Demangle, FunctionTemplateWithAutoParam) {
6879
char tmp[100];
6980

0 commit comments

Comments
 (0)