diff options
author | Chris Mihelich <cmihelic@google.com> | 2024-06-07 18:27:07 -0700 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2024-06-07 18:27:59 -0700 |
commit | 696b32788ca887881547380530926314c521ea7d (patch) | |
tree | 43d71b9eba21fd1980c09fee75cc950154732b73 | |
parent | f875817b18cb6536d82b925305fb321e158f59cb (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.cc | 78 | ||||
-rw-r--r-- | absl/debugging/internal/demangle_test.cc | 67 |
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]; |