summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--absl/debugging/internal/demangle.cc28
-rw-r--r--absl/debugging/internal/demangle_test.cc36
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];