diff options
-rw-r--r-- | llvm/lib/Demangle/MicrosoftDemangle.cpp | 544 | ||||
-rw-r--r-- | llvm/test/Demangle/ms-operators.test | 223 | ||||
-rw-r--r-- | llvm/test/Demangle/ms-string-literals.test | 8 |
3 files changed, 553 insertions, 222 deletions
diff --git a/llvm/lib/Demangle/MicrosoftDemangle.cpp b/llvm/lib/Demangle/MicrosoftDemangle.cpp index 4793ca8ad23..4364ff8e55a 100644 --- a/llvm/lib/Demangle/MicrosoftDemangle.cpp +++ b/llvm/lib/Demangle/MicrosoftDemangle.cpp @@ -135,7 +135,7 @@ enum class StorageClass : uint8_t { ProtectedStatic, PublicStatic, Global, - FunctionLocalStatic + FunctionLocalStatic, }; enum class QualifierMangleMode { Drop, Mangle, Result }; @@ -191,7 +191,175 @@ enum class PrimTy : uint8_t { Float, Double, Ldouble, - Nullptr + Nullptr, + Vftable, + Vbtable, + LocalStaticGuard +}; + +enum class OperatorTy : uint8_t { + Ctor, // ?0 # Foo::Foo() + Dtor, // ?1 # Foo::~Foo() + New, // ?2 # operator new + Delete, // ?3 # operator delete + Assign, // ?4 # operator= + RightShift, // ?5 # operator>> + LeftShift, // ?6 # operator<< + LogicalNot, // ?7 # operator! + Equals, // ?8 # operator== + NotEquals, // ?9 # operator!= + ArraySubscript, // ?A # operator[] + Conversion, // ?B # Foo::operator <type>() + Pointer, // ?C # operator-> + Dereference, // ?D # operator* + Increment, // ?E # operator++ + Decrement, // ?F # operator-- + Minus, // ?G # operator- + Plus, // ?H # operator+ + BitwiseAnd, // ?I # operator& + MemberPointer, // ?J # operator->* + Divide, // ?K # operator/ + Modulus, // ?L # operator% + LessThan, // ?M operator< + LessThanEqual, // ?N operator<= + GreaterThan, // ?O operator> + GreaterThanEqual, // ?P operator>= + Comma, // ?Q operator, + Parens, // ?R operator() + BitwiseNot, // ?S operator~ + BitwiseXor, // ?T operator^ + BitwiseOr, // ?U operator| + LogicalAnd, // ?V operator&& + LogicalOr, // ?W operator|| + TimesEqual, // ?X operator*= + PlusEqual, // ?Y operator+= + MinusEqual, // ?Z operator-= + DivEqual, // ?_0 operator/= + ModEqual, // ?_1 operator%= + RshEqual, // ?_2 operator>>= + LshEqual, // ?_3 operator<<= + BitwiseAndEqual, // ?_4 operator&= + BitwiseOrEqual, // ?_5 operator|= + BitwiseXorEqual, // ?_6 operator^= + Vftable, // ?_7 # vftable + Vbtable, // ?_8 # vbtable + Vcall, // ?_9 # vcall + Typeof, // ?_A # typeof + LocalStaticGuard, // ?_B # local static guard + StringLiteral, // ?_C # string literal + VbaseDtor, // ?_D # vbase destructor + VecDelDtor, // ?_E # vector deleting destructor + DefaultCtorClosure, // ?_F # default constructor closure + ScalarDelDtor, // ?_G # scalar deleting destructor + VecCtorIter, // ?_H # vector constructor iterator + VecDtorIter, // ?_I # vector destructor iterator + VecVbaseCtorIter, // ?_J # vector vbase constructor iterator + VdispMap, // ?_K # virtual displacement map + EHVecCtorIter, // ?_L # eh vector constructor iterator + EHVecDtorIter, // ?_M # eh vector destructor iterator + EHVecVbaseCtorIter, // ?_N # eh vector vbase constructor iterator + CopyCtorClosure, // ?_O # copy constructor closure + UdtReturning, // ?_P<name> # udt returning <name> + Unknown, // ?_Q # <unknown> + RttiTypeDescriptor, // ?_R0 # RTTI Type Descriptor + RttiBaseClassDescriptor, // ?_R1 # RTTI Base Class Descriptor at (a,b,c,d) + RttiBaseClassArray, // ?_R2 # RTTI Base Class Array + RttiClassHierarchyDescriptor, // ?_R3 # RTTI Class Hierarchy Descriptor + RttiCompleteObjLocator, // ?_R4 # RTTI Complete Object Locator + LocalVftable, // ?_S # local vftable + LocalVftableCtorClosure, // ?_T # local vftable constructor closure + ArrayNew, // ?_U operator new[] + ArrayDelete, // ?_V operator delete[] + LiteralOperator, // ?__K operator ""_name + CoAwait, // ?__L co_await + Spaceship, // operator<=> +}; + +// A map to translate from operator prefix to operator type. +struct OperatorMapEntry { + StringView Prefix; + StringView Name; + OperatorTy Operator; +}; + +OperatorMapEntry OperatorMap[] = { + {"0", " <ctor>", OperatorTy::Ctor}, + {"1", " <dtor>", OperatorTy::Dtor}, + {"2", "operator new", OperatorTy::New}, + {"3", "operator delete", OperatorTy::Delete}, + {"4", "operator=", OperatorTy::Assign}, + {"5", "operator>>", OperatorTy::RightShift}, + {"6", "operator<<", OperatorTy::LeftShift}, + {"7", "operator!", OperatorTy::LogicalNot}, + {"8", "operator==", OperatorTy::Equals}, + {"9", "operator!=", OperatorTy::NotEquals}, + {"A", "operator[]", OperatorTy::ArraySubscript}, + {"B", "operator <conversion>", OperatorTy::Conversion}, + {"C", "operator->", OperatorTy::Pointer}, + {"D", "operator*", OperatorTy::Dereference}, + {"E", "operator++", OperatorTy::Increment}, + {"F", "operator--", OperatorTy::Decrement}, + {"G", "operator-", OperatorTy::Minus}, + {"H", "operator+", OperatorTy::Plus}, + {"I", "operator&", OperatorTy::BitwiseAnd}, + {"J", "operator->*", OperatorTy::MemberPointer}, + {"K", "operator/", OperatorTy::Divide}, + {"L", "operator%", OperatorTy::Modulus}, + {"M", "operator<", OperatorTy::LessThan}, + {"N", "operator<=", OperatorTy::LessThanEqual}, + {"O", "operator>", OperatorTy::GreaterThan}, + {"P", "operator>=", OperatorTy::GreaterThanEqual}, + {"Q", "operator,", OperatorTy::Comma}, + {"R", "operator()", OperatorTy::Parens}, + {"S", "operator~", OperatorTy::BitwiseNot}, + {"T", "operator^", OperatorTy::BitwiseXor}, + {"U", "operator|", OperatorTy::BitwiseOr}, + {"V", "operator&&", OperatorTy::LogicalAnd}, + {"W", "operator||", OperatorTy::LogicalOr}, + {"X", "operator*=", OperatorTy::TimesEqual}, + {"Y", "operator+=", OperatorTy::PlusEqual}, + {"Z", "operator-=", OperatorTy::MinusEqual}, + {"_0", "operator/=", OperatorTy::DivEqual}, + {"_1", "operator%=", OperatorTy::ModEqual}, + {"_2", "operator>>=", OperatorTy::RshEqual}, + {"_3", "operator<<=", OperatorTy::LshEqual}, + {"_4", "operator&=", OperatorTy::BitwiseAndEqual}, + {"_5", "operator|=", OperatorTy::BitwiseOrEqual}, + {"_6", "operator^=", OperatorTy::BitwiseXorEqual}, + {"_7", "`vftable'", OperatorTy::Vftable}, + {"_8", "`vbtable'", OperatorTy::Vbtable}, + {"_9", "`vcall'", OperatorTy::Vcall}, + {"_A", "`typeof'", OperatorTy::Typeof}, + {"_B", "`local static guard'", OperatorTy::LocalStaticGuard}, + {"_C", "`string'", OperatorTy::StringLiteral}, + {"_D", "`vbase dtor'", OperatorTy::VbaseDtor}, + {"_E", "`vector deleting dtor'", OperatorTy::VecDelDtor}, + {"_F", "`default ctor closure'", OperatorTy::DefaultCtorClosure}, + {"_G", "`scalar deleting dtor'", OperatorTy::ScalarDelDtor}, + {"_H", "`vector ctor iterator'", OperatorTy::VecCtorIter}, + {"_I", "`vector dtor iterator'", OperatorTy::VecDtorIter}, + {"_J", "`vector vbase ctor iterator'", OperatorTy::VecVbaseCtorIter}, + {"_K", "`virtual displacement map'", OperatorTy::VdispMap}, + {"_L", "`eh vector ctor iterator'", OperatorTy::EHVecCtorIter}, + {"_M", "`eh vector dtor iterator'", OperatorTy::EHVecDtorIter}, + {"_N", "`eh vector vbase ctor iterator'", OperatorTy::EHVecVbaseCtorIter}, + {"_O", "`copy ctor closure'", OperatorTy::CopyCtorClosure}, + {"_P", "`udt returning'", OperatorTy::UdtReturning}, + {"_Q", "`unknown'", OperatorTy::Unknown}, + {"_R0", "`RTTI Type Descriptor'", OperatorTy::RttiTypeDescriptor}, + {"_R1", "`RTTI Base Class Descriptor'", + OperatorTy::RttiBaseClassDescriptor}, + {"_R2", "`RTTI Base Class Array'", OperatorTy::RttiBaseClassArray}, + {"_R3", "`RTTI Class Hierarchy Descriptor'", + OperatorTy::RttiClassHierarchyDescriptor}, + {"_R4", "`RTTI Complete Object Locator'", + OperatorTy::RttiCompleteObjLocator}, + {"_S", "`local vftable'", OperatorTy::LocalVftable}, + {"_T", "`local vftable ctor closure'", OperatorTy::LocalVftableCtorClosure}, + {"_U", "operator new[]", OperatorTy::ArrayNew}, + {"_V", "operator delete[]", OperatorTy::ArrayDelete}, + {"__K", "operator \"\"", OperatorTy::LiteralOperator}, + {"__L", "co_await", OperatorTy::CoAwait}, }; // Function classes @@ -213,7 +381,7 @@ enum NameBackrefBehavior : uint8_t { NBB_Simple = 1 << 1, // save simple names. }; -enum class SymbolCategory { Unknown, Function, Variable, StringLiteral }; +enum class SymbolCategory { Unknown, Function, Variable }; namespace { @@ -287,26 +455,33 @@ struct Type { // Represents an identifier which may be a template. struct Name { + virtual ~Name() = default; + bool IsTemplateInstantiation = false; bool IsOperator = false; bool IsBackReference = false; - bool IsConversionOperator = false; - bool IsStringLiteral = false; - bool IsLongStringLiteral = false; - // If IsStringLiteral is true, this is the character type. - PrimTy StringLiteralType = PrimTy::None; + bool isStringLiteralOperatorInfo() const; // Name read from an MangledName string. StringView Str; - // Template parameters. Only valid if Flags contains NF_TemplateInstantiation. + // Template parameters. Only valid if IsTemplateInstantiation is true. TemplateParams *TParams = nullptr; // Nested BackReferences (e.g. "A::B::C") are represented as a linked list. Name *Next = nullptr; }; +struct OperatorInfo : public Name { + const OperatorMapEntry *Info = nullptr; +}; + +struct StringLiteral : public OperatorInfo { + PrimTy CharType; + bool IsTruncated = false; +}; + struct PointerType : public Type { Type *clone(ArenaAllocator &Arena) const override; void outputPre(OutputStream &OS, NameResolver &Resolver) override; @@ -526,9 +701,8 @@ static void outputParameterList(OutputStream &OS, const FunctionParams &Params, } } -static void outputStringLiteral(OutputStream &OS, const Name &TheString) { - assert(TheString.IsStringLiteral); - switch (TheString.StringLiteralType) { +static void outputStringLiteral(OutputStream &OS, const StringLiteral &Str) { + switch (Str.CharType) { case PrimTy::Wchar: OS << "const wchar_t * {L\""; break; @@ -544,8 +718,8 @@ static void outputStringLiteral(OutputStream &OS, const Name &TheString) { default: LLVM_BUILTIN_UNREACHABLE; } - OS << TheString.Str << "\""; - if (TheString.IsLongStringLiteral) + OS << Str.Str << "\""; + if (Str.IsTruncated) OS << "..."; OS << "}"; } @@ -593,20 +767,20 @@ static void outputParameterList(OutputStream &OS, const TemplateParams &Params, OS << ">"; } -static void outputNameComponent(OutputStream &OS, const Name &N, +static void outputNameComponent(OutputStream &OS, bool IsBackReference, + const TemplateParams *TParams, StringView Str, NameResolver &Resolver) { - if (N.IsConversionOperator) { - OS << " conv"; - } else { - StringView S = N.Str; + if (IsBackReference) + Str = Resolver.resolve(Str); + OS << Str; - if (N.IsBackReference) - S = Resolver.resolve(N.Str); - OS << S; - } + if (TParams) + outputParameterList(OS, *TParams, Resolver); +} - if (N.IsTemplateInstantiation && N.TParams) - outputParameterList(OS, *N.TParams, Resolver); +static void outputNameComponent(OutputStream &OS, const Name &N, + NameResolver &Resolver) { + outputNameComponent(OS, N.IsBackReference, N.TParams, N.Str, Resolver); } static void outputName(OutputStream &OS, const Name *TheName, const Type *Ty, @@ -630,16 +804,17 @@ static void outputName(OutputStream &OS, const Name *TheName, const Type *Ty, return; } + const OperatorInfo &Operator = static_cast<const OperatorInfo &>(*TheName); + // Print out ctor or dtor. - if (TheName->Str == "dtor") + switch (Operator.Info->Operator) { + case OperatorTy::Dtor: OS << "~"; - - if (TheName->Str == "ctor" || TheName->Str == "dtor") { + LLVM_FALLTHROUGH; + case OperatorTy::Ctor: outputNameComponent(OS, *Previous, Resolver); - return; - } - - if (TheName->IsConversionOperator) { + break; + case OperatorTy::Conversion: OS << "operator"; if (TheName->IsTemplateInstantiation && TheName->TParams) outputParameterList(OS, *TheName->TParams, Resolver); @@ -651,15 +826,33 @@ static void outputName(OutputStream &OS, const Name *TheName, const Type *Ty, } else { OS << "<conversion>"; } - } else { - // Print out an overloaded operator. - OS << "operator"; + break; + case OperatorTy::StringLiteral: { + const StringLiteral &SL = static_cast<const StringLiteral &>(Operator); + outputStringLiteral(OS, SL); + break; + } + case OperatorTy::LiteralOperator: + OS << Operator.Info->Name; outputNameComponent(OS, *TheName, Resolver); + break; + default: + OS << Operator.Info->Name; + if (Operator.IsTemplateInstantiation) + outputParameterList(OS, *Operator.TParams, Resolver); + break; } } namespace { +bool Name::isStringLiteralOperatorInfo() const { + if (!IsOperator) + return false; + const OperatorInfo &O = static_cast<const OperatorInfo &>(*this); + return O.Info->Operator == OperatorTy::StringLiteral; +} + Type *Type::clone(ArenaAllocator &Arena) const { return Arena.alloc<Type>(*this); } @@ -767,6 +960,9 @@ void Type::outputPre(OutputStream &OS, NameResolver &Resolver) { case PrimTy::Nullptr: OS << "std::nullptr_t"; break; + case PrimTy::Vbtable: + case PrimTy::Vftable: + break; default: assert(false && "Invalid primitive type!"); } @@ -862,9 +1058,11 @@ void FunctionType::outputPre(OutputStream &OS, NameResolver &Resolver) { if (FunctionClass & Static) OS << "static "; } - if (FunctionClass & ExternC) { + if (FunctionClass & ExternC) OS << "extern \"C\" "; - } + + if (FunctionClass & Virtual) + OS << "virtual "; if (ReturnType) { Type::outputPre(OS, *ReturnType, Resolver); @@ -997,6 +1195,7 @@ public: private: Type *demangleVariableEncoding(StringView &MangledName); Type *demangleFunctionEncoding(StringView &MangledName); + Type *demangleVtableEncoding(StringView &MangledName); Qualifiers demanglePointerExtQualifiers(StringView &MangledName); @@ -1034,11 +1233,11 @@ private: Name *demangleBackRefName(StringView &MangledName); Name *demangleTemplateInstantiationName(StringView &MangledName, NameBackrefBehavior NBB); - Name *demangleOperatorName(StringView &MangledName); + OperatorInfo *demangleOperatorName(StringView &MangledName); Name *demangleSimpleName(StringView &MangledName, bool Memorize); Name *demangleAnonymousNamespaceName(StringView &MangledName); Name *demangleLocallyScopedNamePiece(StringView &MangledName); - Name *demangleStringLiteral(StringView &MangledName); + StringLiteral *demangleStringLiteral(StringView &MangledName); StringView demangleSimpleString(StringView &MangledName, bool Memorize); @@ -1102,26 +1301,31 @@ Symbol *Demangler::parse(StringView &MangledName) { return S; } - if (MangledName.consumeFront("?_C@_")) { - // This is a string literal. Just demangle it and return. - S->Category = SymbolCategory::StringLiteral; - S->SymbolName = demangleStringLiteral(MangledName); - S->SymbolType = nullptr; - return S; - } - // What follows is a main symbol name. This may include // namespaces or class BackReferences. S->SymbolName = demangleFullyQualifiedSymbolName(MangledName); if (Error) return nullptr; + + if (S->SymbolName->isStringLiteralOperatorInfo()) + return S; + // Read a variable. - if (startsWithDigit(MangledName) && !MangledName.startsWith('9')) { - // 9 is a special marker for an extern "C" function with - // no prototype. + switch (MangledName.front()) { + case '0': + case '1': + case '2': + case '3': + case '4': S->Category = SymbolCategory::Variable; S->SymbolType = demangleVariableEncoding(MangledName); - } else { + break; + case '6': + case '7': + S->Category = SymbolCategory::Variable; + S->SymbolType = demangleVtableEncoding(MangledName); + break; + default: S->Category = SymbolCategory::Function; S->SymbolType = demangleFunctionEncoding(MangledName); } @@ -1132,6 +1336,23 @@ Symbol *Demangler::parse(StringView &MangledName) { return S; } +Type *Demangler::demangleVtableEncoding(StringView &MangledName) { + Type *Ty = Arena.alloc<Type>(); + switch (MangledName.popFront()) { + case '6': + Ty->Prim = PrimTy::Vftable; + break; + case '7': + Ty->Prim = PrimTy::Vbtable; + break; + } + bool IsMember = false; + std::tie(Ty->Quals, IsMember) = demangleQualifiers(MangledName); + Ty->Storage = StorageClass::None; + MangledName.consumeFront('@'); + return Ty; +} + // <type-encoding> ::= <storage-class> <variable-type> // <storage-class> ::= 0 # private static member // ::= 1 # protected static member @@ -1271,166 +1492,41 @@ Name *Demangler::demangleTemplateInstantiationName(StringView &MangledName, return Node; } -Name *Demangler::demangleOperatorName(StringView &MangledName) { +OperatorInfo *Demangler::demangleOperatorName(StringView &MangledName) { assert(MangledName.startsWith('?')); MangledName.consumeFront('?'); - auto NameString = [this, &MangledName]() -> StringView { - switch (MangledName.popFront()) { - case '0': - return "ctor"; - case '1': - return "dtor"; - case '2': - return " new"; - case '3': - return " delete"; - case '4': - return "="; - case '5': - return ">>"; - case '6': - return "<<"; - case '7': - return "!"; - case '8': - return "=="; - case '9': - return "!="; - case 'A': - return "[]"; - case 'C': - return "->"; - case 'D': - return "*"; - case 'E': - return "++"; - case 'F': - return "--"; - case 'G': - return "-"; - case 'H': - return "+"; - case 'I': - return "&"; - case 'J': - return "->*"; - case 'K': - return "/"; - case 'L': - return "%"; - case 'M': - return "<"; - case 'N': - return "<="; - case 'O': - return ">"; - case 'P': - return ">="; - case 'Q': - return ","; - case 'R': - return "()"; - case 'S': - return "~"; - case 'T': - return "^"; - case 'U': - return "|"; - case 'V': - return "&&"; - case 'W': - return "||"; - case 'X': - return "*="; - case 'Y': - return "+="; - case 'Z': - return "-="; - case '_': { - if (MangledName.empty()) - break; - - switch (MangledName.popFront()) { - case '0': - return "/="; - case '1': - return "%="; - case '2': - return ">>="; - case '3': - return "<<="; - case '4': - return "&="; - case '5': - return "|="; - case '6': - return "^="; - // case '7': # vftable - // case '8': # vbtable - // case '9': # vcall - // case 'A': # typeof - // case 'B': # local static guard - // case 'D': # vbase destructor - // case 'E': # vector deleting destructor - // case 'F': # default constructor closure - // case 'G': # scalar deleting destructor - // case 'H': # vector constructor iterator - // case 'I': # vector destructor iterator - // case 'J': # vector vbase constructor iterator - // case 'K': # virtual displacement map - // case 'L': # eh vector constructor iterator - // case 'M': # eh vector destructor iterator - // case 'N': # eh vector vbase constructor iterator - // case 'O': # copy constructor closure - // case 'P<name>': # udt returning <name> - // case 'Q': # <unknown> - // case 'R0': # RTTI Type Descriptor - // case 'R1': # RTTI Base Class Descriptor at (a,b,c,d) - // case 'R2': # RTTI Base Class Array - // case 'R3': # RTTI Class Hierarchy Descriptor - // case 'R4': # RTTI Complete Object Locator - // case 'S': # local vftable - // case 'T': # local vftable constructor closure - case 'U': - return " new[]"; - case 'V': - return " delete[]"; - case '_': - if (MangledName.consumeFront("L")) - return " co_await"; - if (MangledName.consumeFront("K")) { - size_t EndPos = MangledName.find('@'); - if (EndPos == StringView::npos) - break; - StringView OpName = demangleSimpleString(MangledName, false); - size_t FullSize = OpName.size() + 3; // <space>""OpName - char *Buffer = Arena.allocUnalignedBuffer(FullSize); - Buffer[0] = ' '; - Buffer[1] = '"'; - Buffer[2] = '"'; - std::memcpy(Buffer + 3, OpName.begin(), OpName.size()); - return {Buffer, FullSize}; - } - } - } - } + const OperatorMapEntry *Entry = nullptr; + for (const auto &MapEntry : OperatorMap) { + if (!MangledName.consumeFront(MapEntry.Prefix)) + continue; + Entry = &MapEntry; + break; + } + if (!Entry) { Error = true; - return ""; - }; + return nullptr; + } - Name *Node = Arena.alloc<Name>(); - if (MangledName.consumeFront('B')) { - // Handle conversion operator specially. - Node->IsConversionOperator = true; - } else { - Node->Str = NameString(); + OperatorInfo *Oper = nullptr; + switch (Entry->Operator) { + case OperatorTy::StringLiteral: + Oper = demangleStringLiteral(MangledName); + break; + case OperatorTy::LiteralOperator: + Oper = Arena.alloc<OperatorInfo>(); + Oper->Str = demangleSimpleString(MangledName, false); + break; + default: + Oper = Arena.alloc<OperatorInfo>(); } + + Oper->Info = Entry; + Oper->IsOperator = true; if (Error) return nullptr; - Node->IsOperator = true; - return Node; + return Oper; } Name *Demangler::demangleSimpleName(StringView &MangledName, bool Memorize) { @@ -1601,11 +1697,13 @@ static void outputEscapedChar(OutputStream &OS, unsigned C) { unsigned countTrailingNullBytes(const uint8_t *StringBytes, int Length) { const uint8_t *End = StringBytes + Length - 1; + unsigned Count = 0; while (Length > 0 && *End == 0) { --Length; --End; + ++Count; } - return End - StringBytes + 1; + return Count; } unsigned countEmbeddedNulls(const uint8_t *StringBytes, unsigned Length) { @@ -1664,7 +1762,7 @@ static unsigned decodeMultiByteChar(const uint8_t *StringBytes, return Result; } -Name *Demangler::demangleStringLiteral(StringView &MangledName) { +StringLiteral *Demangler::demangleStringLiteral(StringView &MangledName) { // This function uses goto, so declare all variables up front. OutputStream OS; StringView CRC; @@ -1674,10 +1772,11 @@ Name *Demangler::demangleStringLiteral(StringView &MangledName) { size_t CrcEndPos = 0; char *ResultBuffer = nullptr; - Name *Result = Arena.alloc<Name>(); - Result->IsStringLiteral = true; + StringLiteral *Result = Arena.alloc<StringLiteral>(); // Prefix indicating the beginning of a string literal + if (!MangledName.consumeFront("@_")) + goto StringLiteralError; if (MangledName.empty()) goto StringLiteralError; @@ -1708,14 +1807,14 @@ Name *Demangler::demangleStringLiteral(StringView &MangledName) { OS = OutputStream::create(nullptr, nullptr, 1024); if (IsWcharT) { - Result->StringLiteralType = PrimTy::Wchar; + Result->CharType = PrimTy::Wchar; if (StringByteSize > 64) - Result->IsLongStringLiteral = true; + Result->IsTruncated = true; while (!MangledName.consumeFront('@')) { assert(StringByteSize >= 2); wchar_t W = demangleWcharLiteral(MangledName); - if (StringByteSize != 2 || Result->IsLongStringLiteral) + if (StringByteSize != 2 || Result->IsTruncated) outputEscapedChar(OS, W); StringByteSize -= 2; if (Error) @@ -1723,7 +1822,7 @@ Name *Demangler::demangleStringLiteral(StringView &MangledName) { } } else { if (StringByteSize > 32) - Result->IsLongStringLiteral = true; + Result->IsTruncated = true; constexpr unsigned MaxStringByteLength = 32; uint8_t StringBytes[MaxStringByteLength]; @@ -1739,13 +1838,13 @@ Name *Demangler::demangleStringLiteral(StringView &MangledName) { assert(StringByteSize % CharBytes == 0); switch (CharBytes) { case 1: - Result->StringLiteralType = PrimTy::Char; + Result->CharType = PrimTy::Char; break; case 2: - Result->StringLiteralType = PrimTy::Char16; + Result->CharType = PrimTy::Char16; break; case 4: - Result->StringLiteralType = PrimTy::Char32; + Result->CharType = PrimTy::Char32; break; default: LLVM_BUILTIN_UNREACHABLE; @@ -1754,7 +1853,7 @@ Name *Demangler::demangleStringLiteral(StringView &MangledName) { for (unsigned CharIndex = 0; CharIndex < NumChars; ++CharIndex) { unsigned NextChar = decodeMultiByteChar(StringBytes, CharIndex, CharBytes); - if (CharIndex + 1 < NumChars || Result->IsLongStringLiteral) + if (CharIndex + 1 < NumChars || Result->IsTruncated) outputEscapedChar(OS, NextChar); } } @@ -1856,7 +1955,11 @@ Name *Demangler::demangleFullyQualifiedSymbolName(StringView &MangledName) { Name *SymbolName = demangleUnqualifiedSymbolName(MangledName, NBB_Simple); if (Error) return nullptr; + + // This is a special case that isn't followed by a scope. assert(SymbolName); + if (SymbolName->isStringLiteralOperatorInfo()) + return SymbolName; Name *QualName = demangleNameScopeChain(MangledName, SymbolName); if (Error) @@ -2590,10 +2693,6 @@ void Demangler::output(const Symbol *S, OutputStream &OS) { outputName(OS, S->SymbolName, S->SymbolType, *this); return; } - if (S->Category == SymbolCategory::StringLiteral) { - outputStringLiteral(OS, *S->SymbolName); - return; - } // Converts an AST to a string. // @@ -2612,9 +2711,12 @@ void Demangler::output(const Symbol *S, OutputStream &OS) { // the "first half" of type declaration, and outputPost() writes the // "second half". For example, outputPre() writes a return type for a // function and outputPost() writes an parameter list. - Type::outputPre(OS, *S->SymbolType, *this); - outputName(OS, S->SymbolName, S->SymbolType, *this); - Type::outputPost(OS, *S->SymbolType, *this); + if (S->SymbolType) { + Type::outputPre(OS, *S->SymbolType, *this); + outputName(OS, S->SymbolName, S->SymbolType, *this); + Type::outputPost(OS, *S->SymbolType, *this); + } else + outputName(OS, S->SymbolName, nullptr, *this); } void Demangler::dumpBackReferences() { diff --git a/llvm/test/Demangle/ms-operators.test b/llvm/test/Demangle/ms-operators.test new file mode 100644 index 00000000000..388f3ea9d54 --- /dev/null +++ b/llvm/test/Demangle/ms-operators.test @@ -0,0 +1,223 @@ +; RUN: llvm-undname < %s | FileCheck %s + +; CHECK-NOT: Invalid mangled name + +??0Base@@QEAA@XZ +; CHECK: __cdecl Base::Base(void) + +??1Base@@UEAA@XZ +; CHECK: virtual __cdecl Base::~Base(void) + +??2@YAPEAX_K@Z +; CHECK: void * __cdecl operator new(unsigned __int64) + +??3@YAXPEAX_K@Z +; CHECK: void __cdecl operator delete(void *, unsigned __int64) + +??4Base@@QEAAHH@Z +; CHECK: int __cdecl Base::operator=(int) + +??6Base@@QEAAHH@Z +; CHECK: int __cdecl Base::operator<<(int) + +??5Base@@QEAAHH@Z +; CHECK: int __cdecl Base::operator>>(int) + +??7Base@@QEAAHXZ +; CHECK: int __cdecl Base::operator!(void) + +??8Base@@QEAAHH@Z +; CHECK: int __cdecl Base::operator==(int) + +??9Base@@QEAAHH@Z +; CHECK: int __cdecl Base::operator!=(int) + +??ABase@@QEAAHH@Z +; CHECK: int __cdecl Base::operator[](int) + +??BBase@@QEAAHXZ +; CHECK: __cdecl Base::operator int(void) + +??CBase@@QEAAHXZ +; CHECK: int __cdecl Base::operator->(void) + +??DBase@@QEAAHXZ +; CHECK: int __cdecl Base::operator*(void) + +??EBase@@QEAAHXZ +; CHECK: int __cdecl Base::operator++(void) + +??EBase@@QEAAHH@Z +; CHECK: int __cdecl Base::operator++(int) + +??FBase@@QEAAHXZ +; CHECK: int __cdecl Base::operator--(void) + +??FBase@@QEAAHH@Z +; CHECK: int __cdecl Base::operator--(int) + +??GBase@@QEAAHH@Z +; CHECK: int __cdecl Base::operator-(int) + +??HBase@@QEAAHH@Z +; CHECK: int __cdecl Base::operator+(int) + +??IBase@@QEAAHH@Z +; CHECK: int __cdecl Base::operator&(int) + +??JBase@@QEAAHH@Z +; CHECK: int __cdecl Base::operator->*(int) + +??KBase@@QEAAHH@Z +; CHECK: int __cdecl Base::operator/(int) + +??LBase@@QEAAHH@Z +; CHECK: int __cdecl Base::operator%(int) + +??MBase@@QEAAHH@Z +; CHECK: int __cdecl Base::operator<(int) + +??NBase@@QEAAHH@Z +; CHECK: int __cdecl Base::operator<=(int) + +??OBase@@QEAAHH@Z +; CHECK: int __cdecl Base::operator>(int) + +??PBase@@QEAAHH@Z +; CHECK: int __cdecl Base::operator>=(int) + +??QBase@@QEAAHH@Z +; CHECK: int __cdecl Base::operator,(int) + +??RBase@@QEAAHXZ +; CHECK: int __cdecl Base::operator()(void) + +??SBase@@QEAAHXZ +; CHECK: int __cdecl Base::operator~(void) + +??TBase@@QEAAHH@Z +; CHECK: int __cdecl Base::operator^(int) + +??UBase@@QEAAHH@Z +; CHECK: int __cdecl Base::operator|(int) + +??VBase@@QEAAHH@Z +; CHECK: int __cdecl Base::operator&&(int) + +??WBase@@QEAAHH@Z +; CHECK: int __cdecl Base::operator||(int) + +??XBase@@QEAAHH@Z +; CHECK: int __cdecl Base::operator*=(int) + +??YBase@@QEAAHH@Z +; CHECK: int __cdecl Base::operator+=(int) + +??ZBase@@QEAAHH@Z +; CHECK: int __cdecl Base::operator-=(int) + +??_0Base@@QEAAHH@Z +; CHECK: int __cdecl Base::operator/=(int) + +??_1Base@@QEAAHH@Z +; CHECK: int __cdecl Base::operator%=(int) + +??_2Base@@QEAAHH@Z +; CHECK: int __cdecl Base::operator>>=(int) + +??_3Base@@QEAAHH@Z +; CHECK: int __cdecl Base::operator<<=(int) + +??_4Base@@QEAAHH@Z +; CHECK: int __cdecl Base::operator&=(int) + +??_5Base@@QEAAHH@Z +; CHECK: int __cdecl Base::operator|=(int) + +??_6Base@@QEAAHH@Z +; CHECK: int __cdecl Base::operator^=(int) + +??_7Base@@6B@ +; CHECK: const Base::`vftable' + +??_8Middle2@@7B@ +; CHECK: const Middle2::`vbtable' + +; ??_9Base@@$B7AA +; FIXME: [thunk]: __cdecl Base::`vcall'{8, {flat}}' }' + +; ??_B?1??getS@@YAAAUS@@XZ@51 +; FIXME: `struct S & __cdecl getS(void)'::`2'::`local static guard'{2}' + +??_C@_02PCEFGMJL@hi?$AA@ +; CHECK: const char * {"hi"} + +??_DDiamond@@QEAAXXZ +; CHECK: void __cdecl Diamond::`vbase dtor'(void) + +??_EBase@@UEAAPEAXI@Z +; CHECK: virtual void * __cdecl Base::`vector deleting dtor'(unsigned int) + +; ??_EDerived@@$4PPPPPPPM@A@EAAPEAXI@Z +; FIXME: [thunk]:virtual void * __cdecl Derived::`vector deleting dtor'`vtordisp{4294967292, 0}' (unsigned int) + +??_F?$SomeTemplate@H@@QAEXXZ +; CHECK: void __thiscall SomeTemplate<int>::`default ctor closure'(void) + +??_GBase@@UEAAPEAXI@Z +; CHECK: virtual void * __cdecl Base::`scalar deleting dtor'(unsigned int) + +??_H@YAXPEAX_K1P6APEAX0@Z@Z +; CHECK: void __cdecl `vector ctor iterator'(void *, unsigned __int64, unsigned __int64, void * (__cdecl *)(void *)) + +??_I@YAXPEAX_K1P6AX0@Z@Z +; CHECK: void __cdecl `vector dtor iterator'(void *, unsigned __int64, unsigned __int64, void (__cdecl *)(void *)) + +??_JBase@@UEAAPEAXI@Z +; CHECK: virtual void * __cdecl Base::`vector vbase ctor iterator'(unsigned int) + +??_KBase@@UEAAPEAXI@Z +; CHECK: virtual void * __cdecl Base::`virtual displacement map'(unsigned int) + +??_LBase@@UEAAPEAXI@Z +; CHECK: virtual void * __cdecl Base::`eh vector ctor iterator'(unsigned int) + +??_MBase@@UEAAPEAXI@Z +; CHECK: virtual void * __cdecl Base::`eh vector dtor iterator'(unsigned int) + +??_NBase@@UEAAPEAXI@Z +; CHECK: virtual void * __cdecl Base::`eh vector vbase ctor iterator'(unsigned int) + +??_O?$SomeTemplate@H@@QAEXXZ +; CHECK: void __thiscall SomeTemplate<int>::`copy ctor closure'(void) + +??_SBase@@6B@ +; CHECK: const Base::`local vftable' + +??_TDerived@@QEAAXXZ +; CHECK: void __cdecl Derived::`local vftable ctor closure'(void) + +??_U@YAPEAX_KAEAVklass@@@Z +; CHECK: void * __cdecl operator new[](unsigned __int64, class klass &) + +??_V@YAXPEAXAEAVklass@@@Z +; CHECK: void __cdecl operator delete[](void *, class klass &) + +; ??_R0?AUBase@@@8 +; FIXME: struct Base `RTTI Type Descriptor' + +; ??_R1A@?0A@EA@Base@@8 +; FIXME: Base::`RTTI Base Class Descriptor at (0, -1, 0, 64)' + +; ??_R2Base@@8 +; FIXME: Base::`RTTI Base Class Array' + +; ??_R3Base@@8 +; FIXME: Base::`RTTI Class Hierarchy Descriptor' + +??_R4Base@@6B@ +; CHECK: const Base::`RTTI Complete Object Locator' + +??__K_deg@@YAHO@Z +; CHECK: int __cdecl operator ""_deg(long double) + diff --git a/llvm/test/Demangle/ms-string-literals.test b/llvm/test/Demangle/ms-string-literals.test index 5575df51c13..77a1882b49d 100644 --- a/llvm/test/Demangle/ms-string-literals.test +++ b/llvm/test/Demangle/ms-string-literals.test @@ -514,7 +514,13 @@ ; CHECK: const char * {"\x03"} ; CHECK: const char * {"\x02"} ; CHECK: const char * {"\x01"} -; CHECK: const char * {"\x00"} + +; The mangling doesn't distinguish between char and char16 types, so even though +; this was originally written as a char * with one embedded null, it mangles +; identically to a char16_t * that is empty. So when demangling, we choose the +; "smartest" one, which happened to be wrong, but it's still a "better" +; demangling. +; CHECK: const char16_t * {u""} ??_C@_13KDLDGPGJ@?$AA?7?$AA?$AA@ |