Commit 1ac7f340 by Dino Radakovic Committed by Copybara-Service

`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
parent 760b2153
...@@ -579,6 +579,7 @@ static bool ParseUnresolvedName(State *state); ...@@ -579,6 +579,7 @@ static bool ParseUnresolvedName(State *state);
static bool ParseExpression(State *state); static bool ParseExpression(State *state);
static bool ParseExprPrimary(State *state); static bool ParseExprPrimary(State *state);
static bool ParseExprCastValue(State *state); static bool ParseExprCastValue(State *state);
static bool ParseRequiresClauseExpression(State *state);
static bool ParseLocalName(State *state); static bool ParseLocalName(State *state);
static bool ParseLocalNameSuffix(State *state); static bool ParseLocalNameSuffix(State *state);
static bool ParseDiscriminator(State *state); static bool ParseDiscriminator(State *state);
...@@ -623,25 +624,38 @@ static bool ParseMangledName(State *state) { ...@@ -623,25 +624,38 @@ static bool ParseMangledName(State *state) {
} }
// <encoding> ::= <(function) name> <bare-function-type> // <encoding> ::= <(function) name> <bare-function-type>
// [`Q` <requires-clause expr>]
// ::= <(data) name> // ::= <(data) name>
// ::= <special-name> // ::= <special-name>
// //
// NOTE: Based on http://shortn/_Hoq9qG83rx // NOTE: Based on http://shortn/_Hoq9qG83rx
// TODO(b/324066279): Add support for [Q <requires-clause expression>].
static bool ParseEncoding(State *state) { static bool ParseEncoding(State *state) {
ComplexityGuard guard(state); ComplexityGuard guard(state);
if (guard.IsTooComplex()) return false; if (guard.IsTooComplex()) return false;
// Implementing the first two productions together as <name> // Since the first two productions both start with <name>, attempt
// [<bare-function-type>] avoids exponential blowup of backtracking. // to parse it only once to avoid exponential blowup of backtracking.
// //
// Since Optional(...) can't fail, there's no need to copy the state for // We're careful about exponential blowup because <encoding> recursively
// backtracking. // appears in other productions downstream of its first two productions,
if (ParseName(state) && Optional(ParseBareFunctionType(state))) { // which means that every call to `ParseName` would possibly indirectly
return true; // result in two calls to `ParseName` etc.
if (ParseName(state)) {
if (!ParseBareFunctionType(state)) {
return true; // <(data) name>
}
// Parsed: <(function) name> <bare-function-type>
// Pending: [`Q` <requires-clause expr>]
ParseState copy = state->parse_state;
if (ParseOneCharToken(state, 'Q') && ParseRequiresClauseExpression(state)) {
return true; // <(function) name> <bare-function-type> `Q` <requires>
}
state->parse_state = copy;
return true; // <(function) name> <bare-function-type>
} }
if (ParseSpecialName(state)) { if (ParseSpecialName(state)) {
return true; return true; // <special-name>
} }
return false; return false;
} }
...@@ -1916,6 +1930,26 @@ static bool ParseExprCastValue(State *state) { ...@@ -1916,6 +1930,26 @@ static bool ParseExprCastValue(State *state) {
return false; return false;
} }
// <requires-clause expr> is just an <expression>: http://shortn/_9E1Ul0rIM8
//
// Does not emit the parsed `requires` clause to simplify the implementation.
// In other words, these two functions' mangled names will demangle identically:
//
// template <typename T>
// int foo(T) requires IsIntegral<T>;
//
// vs.
//
// template <typename T>
// int foo(T);
static bool ParseRequiresClauseExpression(State *state) {
bool original_append = state->parse_state.append;
DisableAppend(state);
bool result = ParseExpression(state);
RestoreAppend(state, original_append);
return result;
}
// <local-name> ::= Z <(function) encoding> E <(entity) name> [<discriminator>] // <local-name> ::= Z <(function) encoding> E <(entity) name> [<discriminator>]
// ::= Z <(function) encoding> E s [<discriminator>] // ::= Z <(function) encoding> E s [<discriminator>]
// //
......
...@@ -64,6 +64,17 @@ TEST(Demangle, FunctionTemplateWithNonTypeParamConstraint) { ...@@ -64,6 +64,17 @@ TEST(Demangle, FunctionTemplateWithNonTypeParamConstraint) {
EXPECT_STREQ(tmp, "foo<>()"); EXPECT_STREQ(tmp, "foo<>()");
} }
TEST(Demangle, FunctionTemplateWithFunctionRequiresClause) {
char tmp[100];
// template <typename T>
// int foo() requires std::integral<T>;
//
// foo<int>();
ASSERT_TRUE(Demangle("_Z3fooIiEivQsr3stdE8integralIT_E", tmp, sizeof(tmp)));
EXPECT_STREQ(tmp, "foo<>()");
}
TEST(Demangle, FunctionTemplateWithAutoParam) { TEST(Demangle, FunctionTemplateWithAutoParam) {
char tmp[100]; char tmp[100];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment