diff options
-rw-r--r-- | absl/debugging/internal/demangle.cc | 28 | ||||
-rw-r--r-- | absl/debugging/internal/demangle_test.cc | 36 |
2 files changed, 62 insertions, 2 deletions
diff --git a/absl/debugging/internal/demangle.cc b/absl/debugging/internal/demangle.cc index f04e4dbc..606ff4e7 100644 --- a/absl/debugging/internal/demangle.cc +++ b/absl/debugging/internal/demangle.cc @@ -585,6 +585,7 @@ static bool ParseCVQualifiers(State *state); static bool ParseBuiltinType(State *state); static bool ParseFunctionType(State *state); static bool ParseBareFunctionType(State *state); +static bool ParseOverloadAttribute(State *state); static bool ParseClassEnumType(State *state); static bool ParseArrayType(State *state); static bool ParsePointerToMemberType(State *state); @@ -1437,13 +1438,17 @@ static bool ParseFunctionType(State *state) { return true; } -// <bare-function-type> ::= <(signature) type>+ +// <bare-function-type> ::= <overload-attribute>* <(signature) type>+ +// +// The <overload-attribute>* prefix is nonstandard; see the comment on +// ParseOverloadAttribute. static bool ParseBareFunctionType(State *state) { ComplexityGuard guard(state); if (guard.IsTooComplex()) return false; ParseState copy = state->parse_state; DisableAppend(state); - if (OneOrMore(ParseType, state)) { + if (ZeroOrMore(ParseOverloadAttribute, state) && + OneOrMore(ParseType, state)) { RestoreAppend(state, copy.append); MaybeAppend(state, "()"); return true; @@ -1452,6 +1457,25 @@ static bool ParseBareFunctionType(State *state) { return false; } +// <overload-attribute> ::= Ua <name> +// +// The nonstandard <overload-attribute> production is sufficient to accept the +// current implementation of __attribute__((enable_if(condition, "message"))) +// and future attributes of a similar shape. See +// https://clang.llvm.org/docs/AttributeReference.html#enable-if and the +// definition of CXXNameMangler::mangleFunctionEncodingBareType in Clang's +// source code. +static bool ParseOverloadAttribute(State *state) { + ComplexityGuard guard(state); + if (guard.IsTooComplex()) return false; + ParseState copy = state->parse_state; + if (ParseTwoCharToken(state, "Ua") && ParseName(state)) { + return true; + } + state->parse_state = copy; + return false; +} + // <class-enum-type> ::= <name> static bool ParseClassEnumType(State *state) { ComplexityGuard guard(state); diff --git a/absl/debugging/internal/demangle_test.cc b/absl/debugging/internal/demangle_test.cc index 2c582415..998d34bb 100644 --- a/absl/debugging/internal/demangle_test.cc +++ b/absl/debugging/internal/demangle_test.cc @@ -461,6 +461,42 @@ TEST(Demangle, AbiTags) { EXPECT_STREQ("C[abi:bar][abi:foo]()", tmp); } +TEST(Demangle, EnableIfAttributeOnGlobalFunction) { + char tmp[80]; + + // int f(long l) __attribute__((enable_if(l >= 0, ""))) { return l; } + // + // f(long) [enable_if:fp >= 0] + EXPECT_TRUE(Demangle("_Z1fUa9enable_ifIXgefL0p_Li0EEEl", tmp, sizeof(tmp))); + EXPECT_STREQ("f()", tmp); +} + +TEST(Demangle, EnableIfAttributeOnNamespaceScopeFunction) { + char tmp[80]; + + // namespace ns { + // int f(long l) __attribute__((enable_if(l >= 0, ""))) { return l; } + // } // namespace ns + // + // ns::f(long) [enable_if:fp >= 0] + EXPECT_TRUE(Demangle("_ZN2ns1fEUa9enable_ifIXgefL0p_Li0EEEl", + tmp, sizeof(tmp))); + EXPECT_STREQ("ns::f()", tmp); +} + +TEST(Demangle, EnableIfAttributeOnFunctionTemplate) { + char tmp[80]; + + // template <class T> + // T f(T t) __attribute__((enable_if(t >= T{}, ""))) { return t; } + // template int f<int>(int); + // + // int f<int>(int) [enable_if:fp >= int{}] + EXPECT_TRUE(Demangle("_Z1fIiEUa9enable_ifIXgefL0p_tliEEET_S0_", + tmp, sizeof(tmp))); + EXPECT_STREQ("f<>()", tmp); +} + TEST(Demangle, ThisPointerInDependentSignature) { char tmp[80]; |