summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Chris Mihelich <cmihelic@google.com>2024-06-07 18:27:07 -0700
committerGravatar Copybara-Service <copybara-worker@google.com>2024-06-07 18:27:59 -0700
commit696b32788ca887881547380530926314c521ea7d (patch)
tree43d71b9eba21fd1980c09fee75cc950154732b73
parentf875817b18cb6536d82b925305fb321e158f59cb (diff)
Try not to lose easy type combinators in S::operator const int*() and the like.
PiperOrigin-RevId: 641411131 Change-Id: Icba1307cccb8957e09f087a7b544f7fe8bfd8333
-rw-r--r--absl/debugging/internal/demangle.cc78
-rw-r--r--absl/debugging/internal/demangle_test.cc67
2 files changed, 139 insertions, 6 deletions
diff --git a/absl/debugging/internal/demangle.cc b/absl/debugging/internal/demangle.cc
index 7ae21dcb..d97dfad4 100644
--- a/absl/debugging/internal/demangle.cc
+++ b/absl/debugging/internal/demangle.cc
@@ -589,6 +589,7 @@ static bool ParseFloatNumber(State *state);
static bool ParseSeqId(State *state);
static bool ParseIdentifier(State *state, size_t length);
static bool ParseOperatorName(State *state, int *arity);
+static bool ParseConversionOperatorType(State *state);
static bool ParseSpecialName(State *state);
static bool ParseCallOffset(State *state);
static bool ParseNVOffset(State *state);
@@ -1056,7 +1057,7 @@ static bool ParseOperatorName(State *state, int *arity) {
// First check with "cv" (cast) case.
ParseState copy = state->parse_state;
if (ParseTwoCharToken(state, "cv") && MaybeAppend(state, "operator ") &&
- EnterNestedName(state) && ParseType(state) &&
+ EnterNestedName(state) && ParseConversionOperatorType(state) &&
LeaveNestedName(state, copy.nest_level)) {
if (arity != nullptr) {
*arity = 1;
@@ -1105,6 +1106,65 @@ static bool ParseOperatorName(State *state, int *arity) {
return false;
}
+// <operator-name> ::= cv <type> # (cast)
+//
+// The name of a conversion operator is the one place where cv-qualifiers, *, &,
+// and other simple type combinators are expected to appear in our stripped-down
+// demangling (elsewhere they appear in function signatures or template
+// arguments, which we omit from the output). We make reasonable efforts to
+// render simple cases accurately.
+static bool ParseConversionOperatorType(State *state) {
+ ComplexityGuard guard(state);
+ if (guard.IsTooComplex()) return false;
+ ParseState copy = state->parse_state;
+
+ // Scan pointers, const, and other easy mangling prefixes with postfix
+ // demanglings. Remember the range of input for later rescanning.
+ //
+ // See `ParseType` and the `switch` below for the meaning of each char.
+ const char* begin_simple_prefixes = RemainingInput(state);
+ while (ParseCharClass(state, "OPRCGrVK")) {}
+ const char* end_simple_prefixes = RemainingInput(state);
+
+ // Emit the base type first.
+ if (!ParseType(state)) {
+ state->parse_state = copy;
+ return false;
+ }
+
+ // Then rescan the easy type combinators in reverse order to emit their
+ // demanglings in the expected output order.
+ while (begin_simple_prefixes != end_simple_prefixes) {
+ switch (*--end_simple_prefixes) {
+ case 'P':
+ MaybeAppend(state, "*");
+ break;
+ case 'R':
+ MaybeAppend(state, "&");
+ break;
+ case 'O':
+ MaybeAppend(state, "&&");
+ break;
+ case 'C':
+ MaybeAppend(state, " _Complex");
+ break;
+ case 'G':
+ MaybeAppend(state, " _Imaginary");
+ break;
+ case 'r':
+ MaybeAppend(state, " restrict");
+ break;
+ case 'V':
+ MaybeAppend(state, " volatile");
+ break;
+ case 'K':
+ MaybeAppend(state, " const");
+ break;
+ }
+ }
+ return true;
+}
+
// <special-name> ::= TV <type>
// ::= TT <type>
// ::= TI <type>
@@ -1442,12 +1502,18 @@ static bool ParseExtendedQualifier(State *state) {
ComplexityGuard guard(state);
if (guard.IsTooComplex()) return false;
ParseState copy = state->parse_state;
- if (ParseOneCharToken(state, 'U') && ParseSourceName(state) &&
- Optional(ParseTemplateArgs(state))) {
- return true;
+
+ if (!ParseOneCharToken(state, 'U')) return false;
+
+ bool append = state->parse_state.append;
+ DisableAppend(state);
+ if (!ParseSourceName(state)) {
+ state->parse_state = copy;
+ return false;
}
- state->parse_state = copy;
- return false;
+ Optional(ParseTemplateArgs(state));
+ RestoreAppend(state, append);
+ return true;
}
// <builtin-type> ::= v, etc. # single-character builtin types
diff --git a/absl/debugging/internal/demangle_test.cc b/absl/debugging/internal/demangle_test.cc
index 2b58d39b..1b305f74 100644
--- a/absl/debugging/internal/demangle_test.cc
+++ b/absl/debugging/internal/demangle_test.cc
@@ -708,6 +708,73 @@ TEST(Demangle, DependentBitInt) {
EXPECT_STREQ("S::operator _BitInt(?)<>()", tmp);
}
+TEST(Demangle, ConversionToPointerType) {
+ char tmp[80];
+
+ // S::operator int*() const
+ EXPECT_TRUE(Demangle("_ZNK1ScvPiEv", tmp, sizeof(tmp)));
+ EXPECT_STREQ("S::operator int*()", tmp);
+}
+
+TEST(Demangle, ConversionToLvalueReferenceType) {
+ char tmp[80];
+
+ // S::operator int&() const
+ EXPECT_TRUE(Demangle("_ZNK1ScvRiEv", tmp, sizeof(tmp)));
+ EXPECT_STREQ("S::operator int&()", tmp);
+}
+
+TEST(Demangle, ConversionToRvalueReferenceType) {
+ char tmp[80];
+
+ // S::operator int&&() const
+ EXPECT_TRUE(Demangle("_ZNK1ScvOiEv", tmp, sizeof(tmp)));
+ EXPECT_STREQ("S::operator int&&()", tmp);
+}
+
+TEST(Demangle, ConversionToComplexFloatingPointType) {
+ char tmp[80];
+
+ // S::operator float _Complex() const
+ EXPECT_TRUE(Demangle("_ZNK1ScvCfEv", tmp, sizeof(tmp)));
+ EXPECT_STREQ("S::operator float _Complex()", tmp);
+}
+
+TEST(Demangle, ConversionToImaginaryFloatingPointType) {
+ char tmp[80];
+
+ // S::operator float _Imaginary() const
+ EXPECT_TRUE(Demangle("_ZNK1ScvGfEv", tmp, sizeof(tmp)));
+ EXPECT_STREQ("S::operator float _Imaginary()", tmp);
+}
+
+TEST(Demangle, ConversionToPointerToCvQualifiedType) {
+ char tmp[80];
+
+ // S::operator int const volatile restrict*() const
+ EXPECT_TRUE(Demangle("_ZNK1ScvPrVKiEv", tmp, sizeof(tmp)));
+ EXPECT_STREQ("S::operator int const volatile restrict*()", tmp);
+}
+
+TEST(Demangle, ConversionToLayeredPointerType) {
+ char tmp[80];
+
+ // S::operator int const* const*() const
+ EXPECT_TRUE(Demangle("_ZNK1ScvPKPKiEv", tmp, sizeof(tmp)));
+ EXPECT_STREQ("S::operator int const* const*()", tmp);
+}
+
+TEST(Demangle, ConversionToTypeWithExtendedQualifier) {
+ char tmp[80];
+
+ // S::operator int const AS128*() const
+ //
+ // Because our scan of easy type constructors stops at the extended qualifier,
+ // the demangling preserves the * but loses the const.
+ EXPECT_TRUE(Demangle("_ZNK1ScvPU5AS128KiEv", tmp, sizeof(tmp)));
+ EXPECT_STREQ("S::operator int*()", tmp);
+}
+
TEST(Demangle, GlobalInitializers) {
char tmp[80];