<div dir="ltr">Builds were broken by this... I tried to fix the most obvious cause (broke my build) in r340721....</div><br><div class="gmail_quote"><div dir="ltr">On Sun, Aug 26, 2018 at 8:48 PM Zachary Turner via llvm-commits <<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: zturner<br>
Date: Sun Aug 26 20:48:03 2018<br>
New Revision: 340710<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=340710&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=340710&view=rev</a><br>
Log:<br>
[MS Demangler] Re-write the Microsoft demangler.<br>
<br>
This is a pretty large refactor / re-write of the Microsoft<br>
demangler. The previous one was a little hackish because it<br>
evolved as I was learning about all the various edge cases,<br>
exceptions, etc. It didn't have a proper AST and so there was<br>
lots of custom handling of things that should have been much<br>
more clean.<br>
<br>
Taking what was learned from that experience, it's now<br>
re-written with a completely redesigned and much more sensible<br>
AST. It's probably still not perfect, but at least it's<br>
comprehensible now to someone else who wants to come along<br>
and make some modifications or read the code.<br>
<br>
Incidentally, this fixed a couple of bugs, so I've enabled<br>
the tests which now pass.<br>
<br>
Added:<br>
llvm/trunk/lib/Demangle/MicrosoftDemangleNodes.cpp<br>
llvm/trunk/lib/Demangle/MicrosoftDemangleNodes.h<br>
Modified:<br>
llvm/trunk/lib/Demangle/CMakeLists.txt<br>
llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp<br>
llvm/trunk/test/Demangle/ms-basic.test<br>
llvm/trunk/test/Demangle/ms-operators.test<br>
llvm/trunk/test/Demangle/ms-templates-memptrs-2.test<br>
llvm/trunk/test/Demangle/ms-templates-memptrs.test<br>
<br>
Modified: llvm/trunk/lib/Demangle/CMakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Demangle/CMakeLists.txt?rev=340710&r1=340709&r2=340710&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Demangle/CMakeLists.txt?rev=340710&r1=340709&r2=340710&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Demangle/CMakeLists.txt (original)<br>
+++ llvm/trunk/lib/Demangle/CMakeLists.txt Sun Aug 26 20:48:03 2018<br>
@@ -1,6 +1,7 @@<br>
add_llvm_library(LLVMDemangle<br>
ItaniumDemangle.cpp<br>
MicrosoftDemangle.cpp<br>
+ MicrosoftDemangleNodes.cpp<br>
<br>
ADDITIONAL_HEADER_DIRS<br>
"${LLVM_MAIN_INCLUDE_DIR}/llvm/Demangle"<br>
<br>
Modified: llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp?rev=340710&r1=340709&r2=340710&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp?rev=340710&r1=340709&r2=340710&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp (original)<br>
+++ llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp Sun Aug 26 20:48:03 2018<br>
@@ -14,6 +14,7 @@<br>
//<br>
//===----------------------------------------------------------------------===//<br>
<br>
+#include "MicrosoftDemangleNodes.h"<br>
#include "llvm/Demangle/Demangle.h"<br>
<br>
#include "llvm/Demangle/Compiler.h"<br>
@@ -25,386 +26,21 @@<br>
#include <cstdio><br>
#include <tuple><br>
<br>
-// This memory allocator is extremely fast, but it doesn't call dtors<br>
-// for allocated objects. That means you can't use STL containers<br>
-// (such as std::vector) with this allocator. But it pays off --<br>
-// the demangler is 3x faster with this allocator compared to one with<br>
-// STL containers.<br>
-namespace {<br>
- constexpr size_t AllocUnit = 4096;<br>
-<br>
-class ArenaAllocator {<br>
- struct AllocatorNode {<br>
- uint8_t *Buf = nullptr;<br>
- size_t Used = 0;<br>
- size_t Capacity = 0;<br>
- AllocatorNode *Next = nullptr;<br>
- };<br>
-<br>
- void addNode(size_t Capacity) {<br>
- AllocatorNode *NewHead = new AllocatorNode;<br>
- NewHead->Buf = new uint8_t[Capacity];<br>
- NewHead->Next = Head;<br>
- NewHead->Capacity = Capacity;<br>
- Head = NewHead;<br>
- NewHead->Used = 0;<br>
- }<br>
-<br>
-public:<br>
- ArenaAllocator() { addNode(AllocUnit); }<br>
-<br>
- ~ArenaAllocator() {<br>
- while (Head) {<br>
- assert(Head->Buf);<br>
- delete[] Head->Buf;<br>
- AllocatorNode *Next = Head->Next;<br>
- delete Head;<br>
- Head = Next;<br>
- }<br>
- }<br>
-<br>
- char *allocUnalignedBuffer(size_t Length) {<br>
- uint8_t *Buf = Head->Buf + Head->Used;<br>
-<br>
- Head->Used += Length;<br>
- if (Head->Used > Head->Capacity) {<br>
- // It's possible we need a buffer which is larger than our default unit<br>
- // size, so we need to be careful to add a node with capacity that is at<br>
- // least as large as what we need.<br>
- addNode(std::max(AllocUnit, Length));<br>
- Head->Used = Length;<br>
- Buf = Head->Buf;<br>
- }<br>
-<br>
- return reinterpret_cast<char *>(Buf);<br>
- }<br>
-<br>
- template <typename T, typename... Args> T *alloc(Args &&... ConstructorArgs) {<br>
-<br>
- size_t Size = sizeof(T);<br>
- assert(Head && Head->Buf);<br>
-<br>
- size_t P = (size_t)Head->Buf + Head->Used;<br>
- uintptr_t AlignedP =<br>
- (((size_t)P + alignof(T) - 1) & ~(size_t)(alignof(T) - 1));<br>
- uint8_t *PP = (uint8_t *)AlignedP;<br>
- size_t Adjustment = AlignedP - P;<br>
-<br>
- Head->Used += Size + Adjustment;<br>
- if (Head->Used < Head->Capacity)<br>
- return new (PP) T(std::forward<Args>(ConstructorArgs)...);<br>
-<br>
- addNode(AllocUnit);<br>
- Head->Used = Size;<br>
- return new (Head->Buf) T(std::forward<Args>(ConstructorArgs)...);<br>
- }<br>
-<br>
-private:<br>
- AllocatorNode *Head = nullptr;<br>
-};<br>
-} // namespace<br>
+using namespace llvm;<br>
+using namespace ms_demangle;<br>
<br>
static bool startsWithDigit(StringView S) {<br>
return !S.empty() && std::isdigit(S.front());<br>
}<br>
<br>
-// Writes a space if the last token does not end with a punctuation.<br>
-static void outputSpaceIfNecessary(OutputStream &OS) {<br>
- if (OS.empty())<br>
- return;<br>
-<br>
- char C = OS.back();<br>
- if (isalnum(C) || C == '>')<br>
- OS << " ";<br>
-}<br>
-<br>
-// Storage classes<br>
-enum Qualifiers : uint8_t {<br>
- Q_None = 0,<br>
- Q_Const = 1 << 0,<br>
- Q_Volatile = 1 << 1,<br>
- Q_Far = 1 << 2,<br>
- Q_Huge = 1 << 3,<br>
- Q_Unaligned = 1 << 4,<br>
- Q_Restrict = 1 << 5,<br>
- Q_Pointer64 = 1 << 6<br>
-};<br>
-<br>
-enum class StorageClass : uint8_t {<br>
- None,<br>
- PrivateStatic,<br>
- ProtectedStatic,<br>
- PublicStatic,<br>
- Global,<br>
- FunctionLocalStatic,<br>
-};<br>
-<br>
enum class QualifierMangleMode { Drop, Mangle, Result };<br>
<br>
-enum class PointerAffinity { Pointer, Reference, RValueReference };<br>
-<br>
-// Calling conventions<br>
-enum class CallingConv : uint8_t {<br>
- None,<br>
- Cdecl,<br>
- Pascal,<br>
- Thiscall,<br>
- Stdcall,<br>
- Fastcall,<br>
- Clrcall,<br>
- Eabi,<br>
- Vectorcall,<br>
- Regcall,<br>
-};<br>
-<br>
-enum class ReferenceKind : uint8_t { None, LValueRef, RValueRef };<br>
-<br>
-// Types<br>
-enum class PrimTy : uint8_t {<br>
- Unknown,<br>
- None,<br>
- Function,<br>
- Ptr,<br>
- MemberPtr,<br>
- Array,<br>
-<br>
- Struct,<br>
- Union,<br>
- Class,<br>
- Enum,<br>
-<br>
- Void,<br>
- Bool,<br>
- Char,<br>
- Schar,<br>
- Uchar,<br>
- Char16,<br>
- Char32,<br>
- Short,<br>
- Ushort,<br>
- Int,<br>
- Uint,<br>
- Long,<br>
- Ulong,<br>
- Int64,<br>
- Uint64,<br>
- Wchar,<br>
- Float,<br>
- Double,<br>
- Ldouble,<br>
- Nullptr,<br>
- Custom,<br>
- Vftable,<br>
- Vbtable,<br>
- LocalStaticGuard<br>
+struct NodeList {<br>
+ Node *N = nullptr;<br>
+ NodeList *Next = nullptr;<br>
};<br>
<br>
-enum class OperatorTy : uint8_t {<br>
- Ctor, // ?0 # Foo::Foo()<br>
- Dtor, // ?1 # Foo::~Foo()<br>
- New, // ?2 # operator new<br>
- Delete, // ?3 # operator delete<br>
- Assign, // ?4 # operator=<br>
- RightShift, // ?5 # operator>><br>
- LeftShift, // ?6 # operator<<<br>
- LogicalNot, // ?7 # operator!<br>
- Equals, // ?8 # operator==<br>
- NotEquals, // ?9 # operator!=<br>
- ArraySubscript, // ?A # operator[]<br>
- Conversion, // ?B # Foo::operator <type>()<br>
- Pointer, // ?C # operator-><br>
- Dereference, // ?D # operator*<br>
- Increment, // ?E # operator++<br>
- Decrement, // ?F # operator--<br>
- Minus, // ?G # operator-<br>
- Plus, // ?H # operator+<br>
- BitwiseAnd, // ?I # operator&<br>
- MemberPointer, // ?J # operator->*<br>
- Divide, // ?K # operator/<br>
- Modulus, // ?L # operator%<br>
- LessThan, // ?M operator<<br>
- LessThanEqual, // ?N operator<=<br>
- GreaterThan, // ?O operator><br>
- GreaterThanEqual, // ?P operator>=<br>
- Comma, // ?Q operator,<br>
- Parens, // ?R operator()<br>
- BitwiseNot, // ?S operator~<br>
- BitwiseXor, // ?T operator^<br>
- BitwiseOr, // ?U operator|<br>
- LogicalAnd, // ?V operator&&<br>
- LogicalOr, // ?W operator||<br>
- TimesEqual, // ?X operator*=<br>
- PlusEqual, // ?Y operator+=<br>
- MinusEqual, // ?Z operator-=<br>
- DivEqual, // ?_0 operator/=<br>
- ModEqual, // ?_1 operator%=<br>
- RshEqual, // ?_2 operator>>=<br>
- LshEqual, // ?_3 operator<<=<br>
- BitwiseAndEqual, // ?_4 operator&=<br>
- BitwiseOrEqual, // ?_5 operator|=<br>
- BitwiseXorEqual, // ?_6 operator^=<br>
- Vftable, // ?_7 # vftable<br>
- Vbtable, // ?_8 # vbtable<br>
- Vcall, // ?_9 # vcall<br>
- Typeof, // ?_A # typeof<br>
- LocalStaticGuard, // ?_B # local static guard<br>
- StringLiteral, // ?_C # string literal<br>
- VbaseDtor, // ?_D # vbase destructor<br>
- VecDelDtor, // ?_E # vector deleting destructor<br>
- DefaultCtorClosure, // ?_F # default constructor closure<br>
- ScalarDelDtor, // ?_G # scalar deleting destructor<br>
- VecCtorIter, // ?_H # vector constructor iterator<br>
- VecDtorIter, // ?_I # vector destructor iterator<br>
- VecVbaseCtorIter, // ?_J # vector vbase constructor iterator<br>
- VdispMap, // ?_K # virtual displacement map<br>
- EHVecCtorIter, // ?_L # eh vector constructor iterator<br>
- EHVecDtorIter, // ?_M # eh vector destructor iterator<br>
- EHVecVbaseCtorIter, // ?_N # eh vector vbase constructor iterator<br>
- CopyCtorClosure, // ?_O # copy constructor closure<br>
- UdtReturning, // ?_P<name> # udt returning <name><br>
- Unknown, // ?_Q # <unknown><br>
- RttiTypeDescriptor, // ?_R0 # RTTI Type Descriptor<br>
- RttiBaseClassDescriptor, // ?_R1 # RTTI Base Class Descriptor at (a,b,c,d)<br>
- RttiBaseClassArray, // ?_R2 # RTTI Base Class Array<br>
- RttiClassHierarchyDescriptor, // ?_R3 # RTTI Class Hierarchy Descriptor<br>
- RttiCompleteObjLocator, // ?_R4 # RTTI Complete Object Locator<br>
- LocalVftable, // ?_S # local vftable<br>
- LocalVftableCtorClosure, // ?_T # local vftable constructor closure<br>
- ArrayNew, // ?_U operator new[]<br>
- ArrayDelete, // ?_V operator delete[]<br>
- ManVectorCtorIter, // ?__A managed vector ctor iterator<br>
- ManVectorDtorIter, // ?__B managed vector dtor iterator<br>
- EHVectorCopyCtorIter, // ?__C EH vector copy ctor iterator<br>
- EHVectorVbaseCopyCtorIter, // ?__D EH vector vbase copy ctor iterator<br>
- DynamicInitializer, // ?__E dynamic initializer for `T'<br>
- DynamicAtexitDestructor, // ?__F dynamic atexit destructor for `T'<br>
- VectorCopyCtorIter, // ?__G vector copy constructor iterator<br>
- VectorVbaseCopyCtorIter, // ?__H vector vbase copy constructor iterator<br>
- ManVectorVbaseCopyCtorIter, // ?__I managed vector vbase copy constructor<br>
- // iterator<br>
- LocalStaticThreadGuard, // ?__J local static thread guard<br>
- LiteralOperator, // ?__K operator ""_name<br>
- CoAwait, // ?__L co_await<br>
- Spaceship, // operator<=><br>
-};<br>
-<br>
-// A map to translate from operator prefix to operator type.<br>
-struct OperatorMapEntry {<br>
- StringView Prefix;<br>
- StringView Name;<br>
- OperatorTy Operator;<br>
-};<br>
-<br>
-// The entries here must be in the same order as the enumeration so that it can<br>
-// be indexed by enum value.<br>
-OperatorMapEntry OperatorMap[] = {<br>
- {"0", " <ctor>", OperatorTy::Ctor},<br>
- {"1", " <dtor>", OperatorTy::Dtor},<br>
- {"2", "operator new", OperatorTy::New},<br>
- {"3", "operator delete", OperatorTy::Delete},<br>
- {"4", "operator=", OperatorTy::Assign},<br>
- {"5", "operator>>", OperatorTy::RightShift},<br>
- {"6", "operator<<", OperatorTy::LeftShift},<br>
- {"7", "operator!", OperatorTy::LogicalNot},<br>
- {"8", "operator==", OperatorTy::Equals},<br>
- {"9", "operator!=", OperatorTy::NotEquals},<br>
- {"A", "operator[]", OperatorTy::ArraySubscript},<br>
- {"B", "operator <conversion>", OperatorTy::Conversion},<br>
- {"C", "operator->", OperatorTy::Pointer},<br>
- {"D", "operator*", OperatorTy::Dereference},<br>
- {"E", "operator++", OperatorTy::Increment},<br>
- {"F", "operator--", OperatorTy::Decrement},<br>
- {"G", "operator-", OperatorTy::Minus},<br>
- {"H", "operator+", OperatorTy::Plus},<br>
- {"I", "operator&", OperatorTy::BitwiseAnd},<br>
- {"J", "operator->*", OperatorTy::MemberPointer},<br>
- {"K", "operator/", OperatorTy::Divide},<br>
- {"L", "operator%", OperatorTy::Modulus},<br>
- {"M", "operator<", OperatorTy::LessThan},<br>
- {"N", "operator<=", OperatorTy::LessThanEqual},<br>
- {"O", "operator>", OperatorTy::GreaterThan},<br>
- {"P", "operator>=", OperatorTy::GreaterThanEqual},<br>
- {"Q", "operator,", OperatorTy::Comma},<br>
- {"R", "operator()", OperatorTy::Parens},<br>
- {"S", "operator~", OperatorTy::BitwiseNot},<br>
- {"T", "operator^", OperatorTy::BitwiseXor},<br>
- {"U", "operator|", OperatorTy::BitwiseOr},<br>
- {"V", "operator&&", OperatorTy::LogicalAnd},<br>
- {"W", "operator||", OperatorTy::LogicalOr},<br>
- {"X", "operator*=", OperatorTy::TimesEqual},<br>
- {"Y", "operator+=", OperatorTy::PlusEqual},<br>
- {"Z", "operator-=", OperatorTy::MinusEqual},<br>
- {"_0", "operator/=", OperatorTy::DivEqual},<br>
- {"_1", "operator%=", OperatorTy::ModEqual},<br>
- {"_2", "operator>>=", OperatorTy::RshEqual},<br>
- {"_3", "operator<<=", OperatorTy::LshEqual},<br>
- {"_4", "operator&=", OperatorTy::BitwiseAndEqual},<br>
- {"_5", "operator|=", OperatorTy::BitwiseOrEqual},<br>
- {"_6", "operator^=", OperatorTy::BitwiseXorEqual},<br>
- {"_7", "`vftable'", OperatorTy::Vftable},<br>
- {"_8", "`vbtable'", OperatorTy::Vbtable},<br>
- {"_9", "`vcall'", OperatorTy::Vcall},<br>
- {"_A", "`typeof'", OperatorTy::Typeof},<br>
- {"_B", "`local static guard'", OperatorTy::LocalStaticGuard},<br>
- {"_C", "`string'", OperatorTy::StringLiteral},<br>
- {"_D", "`vbase dtor'", OperatorTy::VbaseDtor},<br>
- {"_E", "`vector deleting dtor'", OperatorTy::VecDelDtor},<br>
- {"_F", "`default ctor closure'", OperatorTy::DefaultCtorClosure},<br>
- {"_G", "`scalar deleting dtor'", OperatorTy::ScalarDelDtor},<br>
- {"_H", "`vector ctor iterator'", OperatorTy::VecCtorIter},<br>
- {"_I", "`vector dtor iterator'", OperatorTy::VecDtorIter},<br>
- {"_J", "`vector vbase ctor iterator'", OperatorTy::VecVbaseCtorIter},<br>
- {"_K", "`virtual displacement map'", OperatorTy::VdispMap},<br>
- {"_L", "`eh vector ctor iterator'", OperatorTy::EHVecCtorIter},<br>
- {"_M", "`eh vector dtor iterator'", OperatorTy::EHVecDtorIter},<br>
- {"_N", "`eh vector vbase ctor iterator'", OperatorTy::EHVecVbaseCtorIter},<br>
- {"_O", "`copy ctor closure'", OperatorTy::CopyCtorClosure},<br>
- {"_P", "`udt returning'", OperatorTy::UdtReturning},<br>
- {"_Q", "`unknown'", OperatorTy::Unknown},<br>
- {"_R0", "`RTTI Type Descriptor'", OperatorTy::RttiTypeDescriptor},<br>
- {"_R1", "RTTI Base Class Descriptor", OperatorTy::RttiBaseClassDescriptor},<br>
- {"_R2", "`RTTI Base Class Array'", OperatorTy::RttiBaseClassArray},<br>
- {"_R3", "`RTTI Class Hierarchy Descriptor'",<br>
- OperatorTy::RttiClassHierarchyDescriptor},<br>
- {"_R4", "`RTTI Complete Object Locator'",<br>
- OperatorTy::RttiCompleteObjLocator},<br>
- {"_S", "`local vftable'", OperatorTy::LocalVftable},<br>
- {"_T", "`local vftable ctor closure'", OperatorTy::LocalVftableCtorClosure},<br>
- {"_U", "operator new[]", OperatorTy::ArrayNew},<br>
- {"_V", "operator delete[]", OperatorTy::ArrayDelete},<br>
- {"__A", "managed vector ctor iterator", OperatorTy::ManVectorCtorIter},<br>
- {"__B", "managed vector dtor iterator", OperatorTy::ManVectorDtorIter},<br>
- {"__C", "EH vector copy ctor iterator", OperatorTy::EHVectorCopyCtorIter},<br>
- {"__D", "EH vector vbase copy ctor iterator",<br>
- OperatorTy::EHVectorVbaseCopyCtorIter},<br>
- {"__E", "dynamic initializer", OperatorTy::DynamicInitializer},<br>
- {"__F", "dynamic atexit destructor", OperatorTy::DynamicAtexitDestructor},<br>
- {"__G", "vector copy ctor iterator", OperatorTy::VectorCopyCtorIter},<br>
- {"__H", "vector vbase copy constructor iterator",<br>
- OperatorTy::VectorVbaseCopyCtorIter},<br>
- {"__I", "managed vector vbase copy constructor iterator",<br>
- OperatorTy::ManVectorVbaseCopyCtorIter},<br>
- {"__J", "local static thread guard", OperatorTy::LocalStaticThreadGuard},<br>
- {"__K", "operator \"\"", OperatorTy::LiteralOperator},<br>
- {"__L", "co_await", OperatorTy::CoAwait},<br>
-};<br>
-<br>
-// Function classes<br>
-enum FuncClass : uint16_t {<br>
- None = 0,<br>
- Public = 1 << 0,<br>
- Protected = 1 << 1,<br>
- Private = 1 << 2,<br>
- Global = 1 << 3,<br>
- Static = 1 << 4,<br>
- Virtual = 1 << 5,<br>
- Far = 1 << 6,<br>
- ExternC = 1 << 7,<br>
- NoPrototype = 1 << 8,<br>
- VirtualThisAdjust = 1 << 9,<br>
- VirtualThisAdjustEx = 1 << 10,<br>
- StaticThisAdjust = 1 << 11<br>
-};<br>
+enum class FunctionIdentifierCodeGroup { Basic, Under, DoubleUnder };<br>
<br>
enum NameBackrefBehavior : uint8_t {<br>
NBB_None = 0, // don't save any names as backrefs.<br>
@@ -412,237 +48,6 @@ enum NameBackrefBehavior : uint8_t {<br>
NBB_Simple = 1 << 1, // save simple names.<br>
};<br>
<br>
-enum class SymbolCategory {<br>
- Unknown,<br>
- NamedFunction,<br>
- NamedVariable,<br>
- UnnamedFunction,<br>
- UnnamedVariable,<br>
- SpecialOperator<br>
-};<br>
-<br>
-namespace {<br>
-<br>
-struct Type;<br>
-struct Name;<br>
-<br>
-struct FunctionParams {<br>
- bool IsVariadic = false;<br>
-<br>
- Type *Current = nullptr;<br>
-<br>
- FunctionParams *Next = nullptr;<br>
-};<br>
-<br>
-struct TemplateParams {<br>
- bool IsTemplateTemplate = false;<br>
- bool IsAliasTemplate = false;<br>
- bool IsIntegerLiteral = false;<br>
- bool IntegerLiteralIsNegative = false;<br>
- bool IsEmptyParameterPack = false;<br>
- bool PointerToSymbol = false;<br>
- bool NullptrLiteral = false;<br>
- bool DataMemberPointer = false;<br>
- bool ReferenceToSymbol = false;<br>
-<br>
- int ThunkOffsetCount = 0;<br>
- std::array<int64_t, 3> ThunkOffsets;<br>
-<br>
- // If IsIntegerLiteral is true, this is a non-type template parameter<br>
- // whose value is contained in this field.<br>
- uint64_t IntegralValue = 0;<br>
-<br>
- // Type can be null if this is a template template parameter. In that case<br>
- // only Name will be valid.<br>
- Type *ParamType = nullptr;<br>
-<br>
- // Name can be valid if this is a template template parameter (see above) or<br>
- // this is a function declaration (e.g. foo<&SomeFunc>). In the latter case<br>
- // Name contains the name of the function and Type contains the signature.<br>
- Name *ParamName = nullptr;<br>
-<br>
- TemplateParams *Next = nullptr;<br>
-};<br>
-<br>
-// The type class. Mangled symbols are first parsed and converted to<br>
-// this type and then converted to string.<br>
-struct Type {<br>
- virtual ~Type() {}<br>
-<br>
- virtual Type *clone(ArenaAllocator &Arena) const;<br>
-<br>
- // Write the "first half" of a given type. This is a static functions to<br>
- // give the code a chance to do processing that is common to a subset of<br>
- // subclasses<br>
- static void outputPre(OutputStream &OS, Type &Ty);<br>
-<br>
- // Write the "second half" of a given type. This is a static functions to<br>
- // give the code a chance to do processing that is common to a subset of<br>
- // subclasses<br>
- static void outputPost(OutputStream &OS, Type &Ty);<br>
-<br>
- virtual void outputPre(OutputStream &OS);<br>
- virtual void outputPost(OutputStream &OS);<br>
-<br>
- // Primitive type such as Int.<br>
- PrimTy Prim = PrimTy::Unknown;<br>
-<br>
- Qualifiers Quals = Q_None;<br>
- StringView Custom;<br>
- StorageClass Storage = StorageClass::None; // storage class<br>
-};<br>
-<br>
-// Represents an identifier which may be a template.<br>
-struct Name {<br>
- virtual ~Name() = default;<br>
-<br>
- bool IsTemplateInstantiation = false;<br>
- bool IsOperator = false;<br>
- bool IsBackReference = false;<br>
-<br>
- // Name read from an MangledName string.<br>
- StringView Str;<br>
-<br>
- // Template parameters. Only valid if IsTemplateInstantiation is true.<br>
- TemplateParams *TParams = nullptr;<br>
-<br>
- // Nested BackReferences (e.g. "A::B::C") are represented as a linked list.<br>
- Name *Next = nullptr;<br>
-};<br>
-<br>
-struct OperatorInfo : public Name {<br>
- explicit OperatorInfo(const OperatorMapEntry &Info) : Info(&Info) {<br>
- this->IsOperator = true;<br>
- }<br>
- explicit OperatorInfo(OperatorTy OpType)<br>
- : OperatorInfo(OperatorMap[(int)OpType]) {}<br>
-<br>
- const OperatorMapEntry *Info = nullptr;<br>
- bool IsIndirectTable = false;<br>
-};<br>
-<br>
-struct IndirectTable : public OperatorInfo {<br>
- explicit IndirectTable(const OperatorMapEntry &Info) : OperatorInfo(Info) {<br>
- this->IsOperator = true;<br>
- this->IsIndirectTable = true;<br>
- }<br>
- explicit IndirectTable(OperatorTy OpType)<br>
- : IndirectTable(OperatorMap[(int)OpType]) {}<br>
-<br>
- const Name *TableLocation = nullptr;<br>
- const Name *TableTarget = nullptr;<br>
-};<br>
-<br>
-struct StringLiteral : public OperatorInfo {<br>
- StringLiteral() : OperatorInfo(OperatorTy::StringLiteral) {}<br>
-<br>
- PrimTy CharType;<br>
- bool IsTruncated = false;<br>
-};<br>
-<br>
-struct RttiBaseClassDescriptor : public OperatorInfo {<br>
- RttiBaseClassDescriptor()<br>
- : OperatorInfo(OperatorTy::RttiBaseClassDescriptor) {}<br>
-<br>
- uint32_t NVOffset = 0;<br>
- int32_t VBPtrOffset = 0;<br>
- uint32_t VBTableOffset = 0;<br>
- uint32_t Flags = 0;<br>
-};<br>
-<br>
-struct LocalStaticGuardVariable : public OperatorInfo {<br>
- LocalStaticGuardVariable() : OperatorInfo(OperatorTy::LocalStaticGuard) {}<br>
-<br>
- uint32_t ScopeIndex = 0;<br>
- bool IsVisible = false;<br>
-};<br>
-<br>
-struct VirtualMemberPtrThunk : public OperatorInfo {<br>
- VirtualMemberPtrThunk() : OperatorInfo(OperatorTy::Vcall) {}<br>
-<br>
- uint64_t OffsetInVTable = 0;<br>
- CallingConv CC = CallingConv::Cdecl;<br>
-};<br>
-<br>
-struct PointerType : public Type {<br>
- Type *clone(ArenaAllocator &Arena) const override;<br>
- void outputPre(OutputStream &OS) override;<br>
- void outputPost(OutputStream &OS) override;<br>
-<br>
- PointerAffinity Affinity;<br>
-<br>
- // Represents a type X in "a pointer to X", "a reference to X",<br>
- // "an array of X", or "a function returning X".<br>
- Type *Pointee = nullptr;<br>
-};<br>
-<br>
-struct MemberPointerType : public Type {<br>
- Type *clone(ArenaAllocator &Arena) const override;<br>
- void outputPre(OutputStream &OS) override;<br>
- void outputPost(OutputStream &OS) override;<br>
-<br>
- Name *MemberName = nullptr;<br>
-<br>
- // Represents a type X in "a pointer to X", "a reference to X",<br>
- // "an array of X", or "a function returning X".<br>
- Type *Pointee = nullptr;<br>
-};<br>
-<br>
-struct FunctionType : public Type {<br>
- struct ThisAdjustor {<br>
- uint32_t StaticOffset = 0;<br>
- int32_t VBPtrOffset = 0;<br>
- int32_t VBOffsetOffset = 0;<br>
- int32_t VtordispOffset = 0;<br>
- };<br>
-<br>
- Type *clone(ArenaAllocator &Arena) const override;<br>
- void outputPre(OutputStream &OS) override;<br>
- void outputPost(OutputStream &OS) override;<br>
-<br>
- // True if this FunctionType instance is the Pointee of a PointerType or<br>
- // MemberPointerType.<br>
- bool IsFunctionPointer = false;<br>
- bool IsThunk = false;<br>
-<br>
- Type *ReturnType = nullptr;<br>
- // If this is a reference, the type of reference.<br>
- ReferenceKind RefKind;<br>
-<br>
- CallingConv CallConvention;<br>
- FuncClass FunctionClass;<br>
-<br>
- // Valid if IsThunk is true.<br>
- ThisAdjustor *ThisAdjust = nullptr;<br>
-<br>
- FunctionParams Params;<br>
-};<br>
-<br>
-struct UdtType : public Type {<br>
- Type *clone(ArenaAllocator &Arena) const override;<br>
- void outputPre(OutputStream &OS) override;<br>
-<br>
- Name *UdtName = nullptr;<br>
-};<br>
-<br>
-struct ArrayDimension {<br>
- uint64_t Dim = 0;<br>
- ArrayDimension *Next = nullptr;<br>
-};<br>
-<br>
-struct ArrayType : public Type {<br>
- Type *clone(ArenaAllocator &Arena) const override;<br>
- void outputPre(OutputStream &OS) override;<br>
- void outputPost(OutputStream &OS) override;<br>
-<br>
- // Either NextDimension or ElementType will be valid.<br>
- ArrayDimension *Dims = nullptr;<br>
-<br>
- Type *ElementType = nullptr;<br>
-};<br>
-<br>
-} // namespace<br>
-<br>
static bool isMemberPointer(StringView MangledName) {<br>
switch (MangledName.popFront()) {<br>
case '$':<br>
@@ -697,40 +102,41 @@ static bool isMemberPointer(StringView M<br>
return false;<br>
}<br>
<br>
-static void outputCallingConvention(OutputStream &OS, CallingConv CC) {<br>
- outputSpaceIfNecessary(OS);<br>
-<br>
- switch (CC) {<br>
- case CallingConv::Cdecl:<br>
- OS << "__cdecl";<br>
- break;<br>
- case CallingConv::Fastcall:<br>
- OS << "__fastcall";<br>
- break;<br>
- case CallingConv::Pascal:<br>
- OS << "__pascal";<br>
- break;<br>
- case CallingConv::Regcall:<br>
- OS << "__regcall";<br>
- break;<br>
- case CallingConv::Stdcall:<br>
- OS << "__stdcall";<br>
- break;<br>
- case CallingConv::Thiscall:<br>
- OS << "__thiscall";<br>
- break;<br>
- case CallingConv::Eabi:<br>
- OS << "__eabi";<br>
- break;<br>
- case CallingConv::Vectorcall:<br>
- OS << "__vectorcall";<br>
- break;<br>
- case CallingConv::Clrcall:<br>
- OS << "__clrcall";<br>
- break;<br>
- default:<br>
- break;<br>
- }<br>
+static SpecialIntrinsicKind<br>
+consumeSpecialIntrinsicKind(StringView &MangledName) {<br>
+ if (MangledName.consumeFront("?_7"))<br>
+ return SpecialIntrinsicKind::Vftable;<br>
+ if (MangledName.consumeFront("?_8"))<br>
+ return SpecialIntrinsicKind::Vbtable;<br>
+ if (MangledName.consumeFront("?_9"))<br>
+ return SpecialIntrinsicKind::VcallThunk;<br>
+ if (MangledName.consumeFront("?_A"))<br>
+ return SpecialIntrinsicKind::Typeof;<br>
+ if (MangledName.consumeFront("?_B"))<br>
+ return SpecialIntrinsicKind::LocalStaticGuard;<br>
+ if (MangledName.consumeFront("?_C"))<br>
+ return SpecialIntrinsicKind::StringLiteralSymbol;<br>
+ if (MangledName.consumeFront("?_P"))<br>
+ return SpecialIntrinsicKind::UdtReturning;<br>
+ if (MangledName.consumeFront("?_R0"))<br>
+ return SpecialIntrinsicKind::RttiTypeDescriptor;<br>
+ if (MangledName.consumeFront("?_R1"))<br>
+ return SpecialIntrinsicKind::RttiBaseClassDescriptor;<br>
+ if (MangledName.consumeFront("?_R2"))<br>
+ return SpecialIntrinsicKind::RttiBaseClassArray;<br>
+ if (MangledName.consumeFront("?_R3"))<br>
+ return SpecialIntrinsicKind::RttiClassHierarchyDescriptor;<br>
+ if (MangledName.consumeFront("?_R4"))<br>
+ return SpecialIntrinsicKind::RttiCompleteObjLocator;<br>
+ if (MangledName.consumeFront("?_S"))<br>
+ return SpecialIntrinsicKind::LocalVftable;<br>
+ if (MangledName.consumeFront("?__E"))<br>
+ return SpecialIntrinsicKind::DynamicInitializer;<br>
+ if (MangledName.consumeFront("?__F"))<br>
+ return SpecialIntrinsicKind::DynamicAtexitDestructor;<br>
+ if (MangledName.consumeFront("?__J"))<br>
+ return SpecialIntrinsicKind::LocalStaticThreadGuard;<br>
+ return SpecialIntrinsicKind::None;<br>
}<br>
<br>
static bool startsWithLocalScopePattern(StringView S) {<br>
@@ -774,623 +180,81 @@ static bool startsWithLocalScopePattern(<br>
return true;<br>
}<br>
<br>
-// Write a function or template parameter list.<br>
-static void outputParameterList(OutputStream &OS,<br>
- const FunctionParams &Params) {<br>
- if (!Params.Current) {<br>
- OS << "void";<br>
- return;<br>
- }<br>
-<br>
- const FunctionParams *Head = &Params;<br>
- while (Head) {<br>
- Type::outputPre(OS, *Head->Current);<br>
- Type::outputPost(OS, *Head->Current);<br>
-<br>
- Head = Head->Next;<br>
-<br>
- if (Head)<br>
- OS << ", ";<br>
- }<br>
-}<br>
-<br>
-static void outputStringLiteral(OutputStream &OS, const StringLiteral &Str) {<br>
- switch (Str.CharType) {<br>
- case PrimTy::Wchar:<br>
- OS << "const wchar_t * {L\"";<br>
- break;<br>
- case PrimTy::Char:<br>
- OS << "const char * {\"";<br>
- break;<br>
- case PrimTy::Char16:<br>
- OS << "const char16_t * {u\"";<br>
- break;<br>
- case PrimTy::Char32:<br>
- OS << "const char32_t * {U\"";<br>
- break;<br>
- default:<br>
- LLVM_BUILTIN_UNREACHABLE;<br>
- }<br>
- OS << Str.Str << "\"";<br>
- if (Str.IsTruncated)<br>
- OS << "...";<br>
- OS << "}";<br>
-}<br>
-<br>
-static void outputName(OutputStream &OS, const Name *TheName, const Type *Ty);<br>
-<br>
-static void outputParameterList(OutputStream &OS,<br>
- const TemplateParams &Params) {<br>
- if (Params.IsEmptyParameterPack) {<br>
- OS << "<>";<br>
- return;<br>
- }<br>
-<br>
- OS << "<";<br>
- const TemplateParams *Head = &Params;<br>
- while (Head) {<br>
- // Type can be null if this is a template template parameter,<br>
- // and Name can be null if this is a simple type.<br>
-<br>
- if (Head->IsIntegerLiteral) {<br>
- if (Head->IntegerLiteralIsNegative)<br>
- OS << '-';<br>
- OS << Head->IntegralValue;<br>
- } else if (Head->PointerToSymbol || Head->ReferenceToSymbol) {<br>
- if (Head->NullptrLiteral)<br>
- OS << "nullptr";<br>
- else {<br>
- if (Head->ThunkOffsetCount > 0)<br>
- OS << "{";<br>
- else if (Head->PointerToSymbol)<br>
- OS << "&";<br>
- if (Head->ParamType)<br>
- Type::outputPre(OS, *Head->ParamType);<br>
- outputName(OS, Head->ParamName, Head->ParamType);<br>
- if (Head->ParamType)<br>
- Type::outputPost(OS, *Head->ParamType);<br>
- if (Head->ThunkOffsetCount > 0) {<br>
- for (int I = 0; I < Head->ThunkOffsetCount; ++I) {<br>
- OS << ", " << Head->ThunkOffsets[I];<br>
- }<br>
- OS << "}";<br>
- }<br>
- }<br>
- } else if (Head->DataMemberPointer) {<br>
- OS << "{" << Head->ThunkOffsets[0];<br>
- for (int I = 1; I < Head->ThunkOffsetCount; ++I)<br>
- OS << ", " << Head->ThunkOffsets[I];<br>
- OS << "}";<br>
- } else if (Head->ParamType) {<br>
- // simple type.<br>
- Type::outputPre(OS, *Head->ParamType);<br>
- Type::outputPost(OS, *Head->ParamType);<br>
- } else {<br>
- // Template alias.<br>
- outputName(OS, Head->ParamName, Head->ParamType);<br>
- }<br>
-<br>
- Head = Head->Next;<br>
-<br>
- if (Head)<br>
- OS << ", ";<br>
- }<br>
- OS << ">";<br>
-}<br>
-<br>
-static void outputQualifiers(OutputStream &OS, Qualifiers Q) {<br>
- if (Q & Q_Const) {<br>
- outputSpaceIfNecessary(OS);<br>
- OS << "const";<br>
- }<br>
-<br>
- if (Q & Q_Volatile) {<br>
- outputSpaceIfNecessary(OS);<br>
- OS << "volatile";<br>
- }<br>
-<br>
- if (Q & Q_Restrict) {<br>
- outputSpaceIfNecessary(OS);<br>
- OS << "__restrict";<br>
- }<br>
-}<br>
-<br>
-static void outputNameComponent(OutputStream &OS, const Name &N) {<br>
- OS << N.Str;<br>
-<br>
- if (N.IsTemplateInstantiation && N.TParams)<br>
- outputParameterList(OS, *N.TParams);<br>
-}<br>
-<br>
-static const OperatorInfo *lastComponentAsOperator(const Name *TheName) {<br>
- if (!TheName)<br>
- return nullptr;<br>
- while (TheName->Next)<br>
- TheName = TheName->Next;<br>
- if (TheName->IsOperator)<br>
- return static_cast<const OperatorInfo *>(TheName);<br>
- return nullptr;<br>
-}<br>
-<br>
-static void outputName(OutputStream &OS, const Name *TheName, const Type *Ty) {<br>
- if (!TheName)<br>
- return;<br>
-<br>
- outputSpaceIfNecessary(OS);<br>
-<br>
- const OperatorInfo *Operator = lastComponentAsOperator(TheName);<br>
- const VirtualMemberPtrThunk *Thunk = nullptr;<br>
- bool PrintLastScopeSeparator = true;<br>
- if (Operator) {<br>
- if (Operator->IsIndirectTable) {<br>
- const IndirectTable *Table = static_cast<const IndirectTable *>(Operator);<br>
- outputName(OS, Table->TableLocation, nullptr);<br>
- OS << "{for `";<br>
- outputName(OS, Table->TableTarget, nullptr);<br>
- OS << "'}";<br>
- return;<br>
- }<br>
- if (Operator->Info->Operator == OperatorTy::Vcall) {<br>
- Thunk = static_cast<const VirtualMemberPtrThunk *>(Operator);<br>
- OS << "[thunk]: ";<br>
- outputCallingConvention(OS, Thunk->CC);<br>
- OS << " ";<br>
- } else if (Operator->Info->Operator == OperatorTy::DynamicInitializer) {<br>
- OS << "`dynamic initializer for '";<br>
- PrintLastScopeSeparator = false;<br>
- } else if (Operator->Info->Operator ==<br>
- OperatorTy::DynamicAtexitDestructor) {<br>
- OS << "`dynamic atexit destructor for '";<br>
- PrintLastScopeSeparator = false;<br>
- }<br>
- }<br>
-<br>
- const Name *Previous = nullptr;<br>
- // Print out namespaces or outer class BackReferences.<br>
- for (; TheName->Next; TheName = TheName->Next) {<br>
- Previous = TheName;<br>
- outputNameComponent(OS, *TheName);<br>
- if (TheName->Next != Operator || PrintLastScopeSeparator)<br>
- OS << "::";<br>
- }<br>
-<br>
- // Print out a regular name.<br>
- if (!TheName->IsOperator) {<br>
- outputNameComponent(OS, *TheName);<br>
- return;<br>
- }<br>
-<br>
-<br>
- // Print out ctor or dtor.<br>
- switch (Operator->Info->Operator) {<br>
- case OperatorTy::Dtor:<br>
- OS << "~";<br>
- LLVM_FALLTHROUGH;<br>
- case OperatorTy::Ctor:<br>
- // Output the class name with template arguments a second time.<br>
- outputNameComponent(OS, *Previous);<br>
-<br>
- // Structors don't have a name, so outputting the name here actually is a<br>
- // no-op. But for template constructors, it needs to output the template<br>
- // argument list. e.g.<br>
- //<br>
- // template<typename T><br>
- // struct Foo {<br>
- // template<typename U><br>
- // Foo(U);<br>
- // };<br>
- // should demangle as -- for example -- Foo<int><double>(double);<br>
- outputNameComponent(OS, *TheName);<br>
- break;<br>
- case OperatorTy::Conversion:<br>
- OS << "operator";<br>
- if (TheName->IsTemplateInstantiation && TheName->TParams)<br>
- outputParameterList(OS, *TheName->TParams);<br>
- OS << " ";<br>
- if (Ty) {<br>
- const FunctionType *FTy = static_cast<const FunctionType *>(Ty);<br>
- Type::outputPre(OS, *FTy->ReturnType);<br>
- Type::outputPost(OS, *FTy->ReturnType);<br>
- } else {<br>
- OS << "<conversion>";<br>
- }<br>
- break;<br>
- case OperatorTy::LiteralOperator:<br>
- OS << Operator->Info->Name;<br>
- outputNameComponent(OS, *TheName);<br>
- break;<br>
- case OperatorTy::RttiBaseClassDescriptor: {<br>
- const RttiBaseClassDescriptor &BCD =<br>
- static_cast<const RttiBaseClassDescriptor &>(*Operator);<br>
- OS << "`" << Operator->Info->Name << " at (";<br>
- OS << BCD.NVOffset << ", " << BCD.VBPtrOffset << ", " << BCD.VBTableOffset<br>
- << ", " << BCD.Flags;<br>
- OS << ")'";<br>
- break;<br>
- }<br>
- case OperatorTy::Vcall: {<br>
- OS << "`vcall'{";<br>
- OS << Thunk->OffsetInVTable << ", {flat}}";<br>
- break;<br>
- }<br>
- case OperatorTy::DynamicInitializer:<br>
- case OperatorTy::DynamicAtexitDestructor:<br>
- OS << "''";<br>
- break;<br>
-<br>
- case OperatorTy::LocalStaticGuard: {<br>
- const LocalStaticGuardVariable &LSG =<br>
- static_cast<const LocalStaticGuardVariable &>(*Operator);<br>
- OS << Operator->Info->Name;<br>
- if (LSG.ScopeIndex > 0)<br>
- OS << "{" << LSG.ScopeIndex << "}";<br>
- break;<br>
- }<br>
- default:<br>
- OS << Operator->Info->Name;<br>
- if (Operator->IsTemplateInstantiation)<br>
- outputParameterList(OS, *Operator->TParams);<br>
- break;<br>
- }<br>
-}<br>
-<br>
-static void outputSpecialOperator(OutputStream &OS, const Name *OuterName) {<br>
- assert(OuterName);<br>
- // The last component should be an operator.<br>
- const OperatorInfo *Operator = lastComponentAsOperator(OuterName);<br>
-<br>
- assert(Operator->IsOperator);<br>
- const OperatorInfo &Oper = static_cast<const OperatorInfo &>(*Operator);<br>
- switch (Oper.Info->Operator) {<br>
- case OperatorTy::StringLiteral: {<br>
- const StringLiteral &SL = static_cast<const StringLiteral &>(Oper);<br>
- outputStringLiteral(OS, SL);<br>
- break;<br>
- }<br>
- case OperatorTy::Vcall: {<br>
- const VirtualMemberPtrThunk &Thunk =<br>
- static_cast<const VirtualMemberPtrThunk &>(Oper);<br>
- OS << "[thunk]: ";<br>
- outputCallingConvention(OS, Thunk.CC);<br>
- OS << " ";<br>
- // Print out namespaces or outer class BackReferences.<br>
- const Name *N = OuterName;<br>
- for (; N->Next; N = N->Next) {<br>
- outputNameComponent(OS, *N);<br>
- OS << "::";<br>
- }<br>
- OS << "`vcall'{";<br>
- OS << Thunk.OffsetInVTable << ", {flat}}";<br>
- break;<br>
- }<br>
- default:<br>
- // There are no other special operator categories.<br>
- LLVM_BUILTIN_UNREACHABLE;<br>
- }<br>
-}<br>
-<br>
-namespace {<br>
-<br>
-Type *Type::clone(ArenaAllocator &Arena) const {<br>
- return Arena.alloc<Type>(*this);<br>
-}<br>
-<br>
-// Write the "first half" of a given type.<br>
-void Type::outputPre(OutputStream &OS, Type &Ty) {<br>
- // Function types require custom handling of const and static so we<br>
- // handle them separately. All other types use the same decoration<br>
- // for these modifiers, so handle them here in common code.<br>
- if (Ty.Prim == PrimTy::Function) {<br>
- Ty.outputPre(OS);<br>
- return;<br>
- }<br>
-<br>
- switch (Ty.Storage) {<br>
- case StorageClass::PrivateStatic:<br>
- case StorageClass::PublicStatic:<br>
- case StorageClass::ProtectedStatic:<br>
- OS << "static ";<br>
- default:<br>
- break;<br>
- }<br>
- Ty.outputPre(OS);<br>
-<br>
- outputQualifiers(OS, Ty.Quals);<br>
-}<br>
-<br>
-// Write the "second half" of a given type.<br>
-void Type::outputPost(OutputStream &OS, Type &Ty) { Ty.outputPost(OS); }<br>
-<br>
-void Type::outputPre(OutputStream &OS) {<br>
- switch (Prim) {<br>
- case PrimTy::Void:<br>
- OS << "void";<br>
- break;<br>
- case PrimTy::Bool:<br>
- OS << "bool";<br>
- break;<br>
- case PrimTy::Char:<br>
- OS << "char";<br>
- break;<br>
- case PrimTy::Schar:<br>
- OS << "signed char";<br>
- break;<br>
- case PrimTy::Uchar:<br>
- OS << "unsigned char";<br>
- break;<br>
- case PrimTy::Char16:<br>
- OS << "char16_t";<br>
- break;<br>
- case PrimTy::Char32:<br>
- OS << "char32_t";<br>
- break;<br>
- case PrimTy::Short:<br>
- OS << "short";<br>
- break;<br>
- case PrimTy::Ushort:<br>
- OS << "unsigned short";<br>
- break;<br>
- case PrimTy::Int:<br>
- OS << "int";<br>
- break;<br>
- case PrimTy::Uint:<br>
- OS << "unsigned int";<br>
- break;<br>
- case PrimTy::Long:<br>
- OS << "long";<br>
- break;<br>
- case PrimTy::Ulong:<br>
- OS << "unsigned long";<br>
- break;<br>
- case PrimTy::Int64:<br>
- OS << "__int64";<br>
- break;<br>
- case PrimTy::Uint64:<br>
- OS << "unsigned __int64";<br>
- break;<br>
- case PrimTy::Wchar:<br>
- OS << "wchar_t";<br>
- break;<br>
- case PrimTy::Float:<br>
- OS << "float";<br>
- break;<br>
- case PrimTy::Double:<br>
- OS << "double";<br>
- break;<br>
- case PrimTy::Ldouble:<br>
- OS << "long double";<br>
- break;<br>
- case PrimTy::Nullptr:<br>
- OS << "std::nullptr_t";<br>
- break;<br>
- case PrimTy::Custom:<br>
- OS << Custom;<br>
- break;<br>
- case PrimTy::Vbtable:<br>
- case PrimTy::Vftable:<br>
- break;<br>
- default:<br>
- assert(false && "Invalid primitive type!");<br>
+static bool isTagType(StringView S) {<br>
+ switch (S.front()) {<br>
+ case 'T': // union<br>
+ case 'U': // struct<br>
+ case 'V': // class<br>
+ case 'W': // enum<br>
+ return true;<br>
}<br>
-}<br>
-void Type::outputPost(OutputStream &OS) {}<br>
-<br>
-Type *PointerType::clone(ArenaAllocator &Arena) const {<br>
- return Arena.alloc<PointerType>(*this);<br>
+ return false;<br>
}<br>
<br>
-static void outputPointerIndicator(OutputStream &OS, PointerAffinity Affinity,<br>
- const Name *MemberName,<br>
- const Type *Pointee) {<br>
- // "[]" and "()" (for function parameters) take precedence over "*",<br>
- // so "int *x(int)" means "x is a function returning int *". We need<br>
- // parentheses to supercede the default precedence. (e.g. we want to<br>
- // emit something like "int (*x)(int)".)<br>
- if (Pointee->Prim == PrimTy::Function || Pointee->Prim == PrimTy::Array) {<br>
- OS << "(";<br>
- if (Pointee->Prim == PrimTy::Function) {<br>
- const FunctionType *FTy = static_cast<const FunctionType *>(Pointee);<br>
- assert(FTy->IsFunctionPointer);<br>
- outputCallingConvention(OS, FTy->CallConvention);<br>
- OS << " ";<br>
- }<br>
- }<br>
+static bool isPointerType(StringView S) {<br>
+ if (S.startsWith("$$Q")) // foo &&<br>
+ return true;<br>
<br>
- if (MemberName) {<br>
- outputName(OS, MemberName, Pointee);<br>
- OS << "::";<br>
+ switch (S.front()) {<br>
+ case 'A': // foo &<br>
+ case 'P': // foo *<br>
+ case 'Q': // foo *const<br>
+ case 'R': // foo *volatile<br>
+ case 'S': // foo *const volatile<br>
+ return true;<br>
}<br>
-<br>
- if (Affinity == PointerAffinity::Pointer)<br>
- OS << "*";<br>
- else if (Affinity == PointerAffinity::Reference)<br>
- OS << "&";<br>
- else<br>
- OS << "&&";<br>
-}<br>
-<br>
-void PointerType::outputPre(OutputStream &OS) {<br>
- Type::outputPre(OS, *Pointee);<br>
-<br>
- outputSpaceIfNecessary(OS);<br>
-<br>
- if (Quals & Q_Unaligned)<br>
- OS << "__unaligned ";<br>
-<br>
- outputPointerIndicator(OS, Affinity, nullptr, Pointee);<br>
-<br>
- // FIXME: We should output this, but it requires updating lots of tests.<br>
- // if (Ty.Quals & Q_Pointer64)<br>
- // OS << " __ptr64";<br>
-}<br>
-<br>
-void PointerType::outputPost(OutputStream &OS) {<br>
- if (Pointee->Prim == PrimTy::Function || Pointee->Prim == PrimTy::Array)<br>
- OS << ")";<br>
-<br>
- Type::outputPost(OS, *Pointee);<br>
-}<br>
-<br>
-Type *MemberPointerType::clone(ArenaAllocator &Arena) const {<br>
- return Arena.alloc<MemberPointerType>(*this);<br>
-}<br>
-<br>
-void MemberPointerType::outputPre(OutputStream &OS) {<br>
- Type::outputPre(OS, *Pointee);<br>
-<br>
- outputSpaceIfNecessary(OS);<br>
-<br>
- outputPointerIndicator(OS, PointerAffinity::Pointer, MemberName, Pointee);<br>
-<br>
- // FIXME: We should output this, but it requires updating lots of tests.<br>
- // if (Ty.Quals & Q_Pointer64)<br>
- // OS << " __ptr64";<br>
-}<br>
-<br>
-void MemberPointerType::outputPost(OutputStream &OS) {<br>
- if (Pointee->Prim == PrimTy::Function || Pointee->Prim == PrimTy::Array)<br>
- OS << ")";<br>
-<br>
- Type::outputPost(OS, *Pointee);<br>
-}<br>
-<br>
-Type *FunctionType::clone(ArenaAllocator &Arena) const {<br>
- return Arena.alloc<FunctionType>(*this);<br>
+ return false;<br>
}<br>
<br>
-void FunctionType::outputPre(OutputStream &OS) {<br>
- if ((FunctionClass & StaticThisAdjust) || (FunctionClass & VirtualThisAdjust))<br>
- OS << "[thunk]: ";<br>
-<br>
- if (!(FunctionClass & Global)) {<br>
- if (FunctionClass & Static)<br>
- OS << "static ";<br>
- }<br>
- if (FunctionClass & ExternC)<br>
- OS << "extern \"C\" ";<br>
-<br>
- if (FunctionClass & Virtual)<br>
- OS << "virtual ";<br>
-<br>
- if (ReturnType) {<br>
- Type::outputPre(OS, *ReturnType);<br>
- OS << " ";<br>
- }<br>
+static bool isArrayType(StringView S) { return S[0] == 'Y'; }<br>
<br>
- // Function pointers print the calling convention as void (__cdecl *)(params)<br>
- // rather than void __cdecl (*)(params). So we need to let the PointerType<br>
- // class handle this.<br>
- if (!IsFunctionPointer)<br>
- outputCallingConvention(OS, CallConvention);<br>
+static bool isFunctionType(StringView S) {<br>
+ return S.startsWith("$$A8@@") || S.startsWith("$$A6");<br>
}<br>
<br>
-void FunctionType::outputPost(OutputStream &OS) {<br>
- // extern "C" functions don't have a prototype.<br>
- if (FunctionClass & NoPrototype)<br>
- return;<br>
-<br>
- if (FunctionClass & StaticThisAdjust) {<br>
- OS << "`adjustor{" << ThisAdjust->StaticOffset << "}'";<br>
- } else if (FunctionClass & VirtualThisAdjust) {<br>
- if (FunctionClass & VirtualThisAdjustEx) {<br>
- OS << "`vtordispex{" << ThisAdjust->VBPtrOffset << ", "<br>
- << ThisAdjust->VBOffsetOffset << ", " << ThisAdjust->VtordispOffset<br>
- << ", " << ThisAdjust->StaticOffset << "}'";<br>
- } else {<br>
- OS << "`vtordisp{" << ThisAdjust->VtordispOffset << ", "<br>
- << ThisAdjust->StaticOffset << "}'";<br>
- }<br>
- }<br>
-<br>
- OS << "(";<br>
- outputParameterList(OS, Params);<br>
- OS << ")";<br>
- if (Quals & Q_Const)<br>
- OS << " const";<br>
- if (Quals & Q_Volatile)<br>
- OS << " volatile";<br>
- if (Quals & Q_Restrict)<br>
- OS << " __restrict";<br>
- if (Quals & Q_Unaligned)<br>
- OS << " __unaligned";<br>
-<br>
- if (RefKind == ReferenceKind::LValueRef)<br>
- OS << " &";<br>
- else if (RefKind == ReferenceKind::RValueRef)<br>
- OS << " &&";<br>
-<br>
- if (ReturnType)<br>
- Type::outputPost(OS, *ReturnType);<br>
- return;<br>
+static FunctionRefQualifier<br>
+demangleFunctionRefQualifier(StringView &MangledName) {<br>
+ if (MangledName.consumeFront('G'))<br>
+ return FunctionRefQualifier::Reference;<br>
+ else if (MangledName.consumeFront('H'))<br>
+ return FunctionRefQualifier::RValueReference;<br>
+ return FunctionRefQualifier::None;<br>
}<br>
<br>
-Type *UdtType::clone(ArenaAllocator &Arena) const {<br>
- return Arena.alloc<UdtType>(*this);<br>
-}<br>
+static std::pair<Qualifiers, PointerAffinity><br>
+demanglePointerCVQualifiers(StringView &MangledName) {<br>
+ if (MangledName.consumeFront("$$Q"))<br>
+ return std::make_pair(Q_None, PointerAffinity::RValueReference);<br>
<br>
-void UdtType::outputPre(OutputStream &OS) {<br>
- switch (Prim) {<br>
- case PrimTy::Class:<br>
- OS << "class ";<br>
- break;<br>
- case PrimTy::Struct:<br>
- OS << "struct ";<br>
- break;<br>
- case PrimTy::Union:<br>
- OS << "union ";<br>
- break;<br>
- case PrimTy::Enum:<br>
- OS << "enum ";<br>
- break;<br>
+ switch (MangledName.popFront()) {<br>
+ case 'A':<br>
+ return std::make_pair(Q_None, PointerAffinity::Reference);<br>
+ case 'P':<br>
+ return std::make_pair(Q_None, PointerAffinity::Pointer);<br>
+ case 'Q':<br>
+ return std::make_pair(Q_Const, PointerAffinity::Pointer);<br>
+ case 'R':<br>
+ return std::make_pair(Q_Volatile, PointerAffinity::Pointer);<br>
+ case 'S':<br>
+ return std::make_pair(Qualifiers(Q_Const | Q_Volatile),<br>
+ PointerAffinity::Pointer);<br>
default:<br>
- assert(false && "Not a udt type!");<br>
- }<br>
-<br>
- outputName(OS, UdtName, this);<br>
-}<br>
-<br>
-Type *ArrayType::clone(ArenaAllocator &Arena) const {<br>
- return Arena.alloc<ArrayType>(*this);<br>
-}<br>
-<br>
-void ArrayType::outputPre(OutputStream &OS) {<br>
- Type::outputPre(OS, *ElementType);<br>
-}<br>
-<br>
-void ArrayType::outputPost(OutputStream &OS) {<br>
- ArrayDimension *D = Dims;<br>
- while (D) {<br>
- OS << "[";<br>
- if (D->Dim > 0)<br>
- OS << D->Dim;<br>
- OS << "]";<br>
- D = D->Next;<br>
+ assert(false && "Ty is not a pointer type!");<br>
}<br>
-<br>
- Type::outputPost(OS, *ElementType);<br>
+ return std::make_pair(Q_None, PointerAffinity::Pointer);<br>
}<br>
<br>
-struct Symbol {<br>
- SymbolCategory Category;<br>
-<br>
- Qualifiers SymbolQuals = Q_None;<br>
- Name *SymbolName = nullptr;<br>
- Type *SymbolType = nullptr;<br>
-};<br>
-<br>
-} // namespace<br>
-<br>
namespace {<br>
<br>
struct BackrefContext {<br>
static constexpr size_t Max = 10;<br>
<br>
- Type *FunctionParams[Max];<br>
+ TypeNode *FunctionParams[Max];<br>
size_t FunctionParamCount = 0;<br>
<br>
// The first 10 BackReferences in a mangled name can be back-referenced by<br>
// special name @[0-9]. This is a storage for the first 10 BackReferences.<br>
- StringView Names[Max];<br>
+ NamedIdentifierNode *Names[Max];<br>
size_t NamesCount = 0;<br>
};<br>
<br>
@@ -1404,10 +268,7 @@ public:<br>
<br>
// You are supposed to call parse() first and then check if error is true. If<br>
// it is false, call output() to write the formatted name to the given stream.<br>
- Symbol *parse(StringView &MangledName);<br>
- Symbol *parseOperator(StringView &MangledName);<br>
-<br>
- void output(const Symbol *S, OutputStream &OS);<br>
+ SymbolNode *parse(StringView &MangledName);<br>
<br>
// True if an error occurred.<br>
bool Error = false;<br>
@@ -1415,28 +276,28 @@ public:<br>
void dumpBackReferences();<br>
<br>
private:<br>
- std::pair<SymbolCategory, Type *><br>
- demangleSymbolCategoryAndType(StringView &MangledName);<br>
+ SymbolNode *demangleEncodedSymbol(StringView &MangledName,<br>
+ QualifiedNameNode *QN);<br>
<br>
- Type *demangleVariableEncoding(StringView &MangledName, StorageClass SC);<br>
- Type *demangleFunctionEncoding(StringView &MangledName);<br>
- uint64_t demangleThunkThisAdjust(StringView &MangledName);<br>
+ VariableSymbolNode *demangleVariableEncoding(StringView &MangledName,<br>
+ StorageClass SC);<br>
+ FunctionSymbolNode *demangleFunctionEncoding(StringView &MangledName);<br>
<br>
Qualifiers demanglePointerExtQualifiers(StringView &MangledName);<br>
<br>
// Parser functions. This is a recursive-descent parser.<br>
- Type *demangleType(StringView &MangledName, QualifierMangleMode QMM);<br>
- Type *demangleBasicType(StringView &MangledName);<br>
- UdtType *demangleClassType(StringView &MangledName);<br>
- PointerType *demanglePointerType(StringView &MangledName);<br>
- MemberPointerType *demangleMemberPointerType(StringView &MangledName);<br>
- FunctionType *demangleFunctionType(StringView &MangledName, bool HasThisQuals,<br>
- bool IsFunctionPointer);<br>
+ TypeNode *demangleType(StringView &MangledName, QualifierMangleMode QMM);<br>
+ PrimitiveTypeNode *demanglePrimitiveType(StringView &MangledName);<br>
+ TagTypeNode *demangleClassType(StringView &MangledName);<br>
+ PointerTypeNode *demanglePointerType(StringView &MangledName);<br>
+ PointerTypeNode *demangleMemberPointerType(StringView &MangledName);<br>
+ FunctionSignatureNode *demangleFunctionType(StringView &MangledName,<br>
+ bool HasThisQuals);<br>
<br>
- ArrayType *demangleArrayType(StringView &MangledName);<br>
+ ArrayTypeNode *demangleArrayType(StringView &MangledName);<br>
<br>
- TemplateParams *demangleTemplateParameterList(StringView &MangledName);<br>
- FunctionParams demangleFunctionParameterList(StringView &MangledName);<br>
+ NodeArrayNode *demangleTemplateParameterList(StringView &MangledName);<br>
+ NodeArrayNode *demangleFunctionParameterList(StringView &MangledName);<br>
<br>
std::pair<uint64_t, bool> demangleNumber(StringView &MangledName);<br>
uint64_t demangleUnsigned(StringView &MangledName);<br>
@@ -1447,32 +308,59 @@ private:<br>
/// Allocate a copy of \p Borrowed into memory that we own.<br>
StringView copyString(StringView Borrowed);<br>
<br>
- Name *demangleFullyQualifiedTypeName(StringView &MangledName);<br>
- Name *demangleFullyQualifiedSymbolName(StringView &MangledName);<br>
+ QualifiedNameNode *demangleFullyQualifiedTypeName(StringView &MangledName);<br>
+ QualifiedNameNode *demangleFullyQualifiedSymbolName(StringView &MangledName);<br>
<br>
- Name *demangleUnqualifiedTypeName(StringView &MangledName, bool Memorize);<br>
- Name *demangleUnqualifiedSymbolName(StringView &MangledName,<br>
- NameBackrefBehavior NBB);<br>
-<br>
- Name *demangleNameScopeChain(StringView &MangledName, Name *UnqualifiedName);<br>
- Name *demangleNameScopePiece(StringView &MangledName);<br>
-<br>
- Name *demangleBackRefName(StringView &MangledName);<br>
- Name *demangleTemplateInstantiationName(StringView &MangledName,<br>
- NameBackrefBehavior NBB);<br>
- std::pair<OperatorTy, Name *> demangleOperatorName(StringView &MangledName,<br>
- bool FullyQualified);<br>
- Name *demangleSimpleName(StringView &MangledName, bool Memorize);<br>
- Name *demangleAnonymousNamespaceName(StringView &MangledName);<br>
- Name *demangleLocallyScopedNamePiece(StringView &MangledName);<br>
- StringLiteral *demangleStringLiteral(StringView &MangledName);<br>
+ IdentifierNode *demangleUnqualifiedTypeName(StringView &MangledName,<br>
+ bool Memorize);<br>
+ IdentifierNode *demangleUnqualifiedSymbolName(StringView &MangledName,<br>
+ NameBackrefBehavior NBB);<br>
+<br>
+ QualifiedNameNode *demangleNameScopeChain(StringView &MangledName,<br>
+ IdentifierNode *UnqualifiedName);<br>
+ IdentifierNode *demangleNameScopePiece(StringView &MangledName);<br>
+<br>
+ NamedIdentifierNode *demangleBackRefName(StringView &MangledName);<br>
+ IdentifierNode *demangleTemplateInstantiationName(StringView &MangledName,<br>
+ NameBackrefBehavior NBB);<br>
+ IdentifierNode *demangleFunctionIdentifierCode(StringView &MangledName);<br>
+ IdentifierNode *<br>
+ demangleFunctionIdentifierCode(StringView &MangledName,<br>
+ FunctionIdentifierCodeGroup Group);<br>
+ StructorIdentifierNode *demangleStructorIdentifier(StringView &MangledName,<br>
+ bool IsDestructor);<br>
+ ConversionOperatorIdentifierNode *<br>
+ demangleConversionOperatorIdentifier(StringView &MangledName);<br>
+ LiteralOperatorIdentifierNode *<br>
+ demangleLiteralOperatorIdentifier(StringView &MangledName);<br>
+<br>
+ SymbolNode *demangleSpecialIntrinsic(StringView &MangledName);<br>
+ SpecialTableSymbolNode *<br>
+ demangleSpecialTableSymbolNode(StringView &MangledName,<br>
+ SpecialIntrinsicKind SIK);<br>
+ LocalStaticGuardVariableNode *<br>
+ demangleLocalStaticGuard(StringView &MangledName);<br>
+ VariableSymbolNode *demangleUntypedVariable(ArenaAllocator &Arena,<br>
+ StringView &MangledName,<br>
+ StringView VariableName);<br>
+ VariableSymbolNode *<br>
+ demangleRttiBaseClassDescriptorNode(ArenaAllocator &Arena,<br>
+ StringView &MangledName);<br>
+ FunctionSymbolNode *demangleDynamicStructorFunction(StringView &MangledName,<br>
+ bool IsDestructor);<br>
+<br>
+ NamedIdentifierNode *demangleSimpleName(StringView &MangledName,<br>
+ bool Memorize);<br>
+ NamedIdentifierNode *demangleAnonymousNamespaceName(StringView &MangledName);<br>
+ NamedIdentifierNode *demangleLocallyScopedNamePiece(StringView &MangledName);<br>
+ EncodedStringLiteralNode *demangleStringLiteral(StringView &MangledName);<br>
+ FunctionSymbolNode *demangleVcallThunkNode(StringView &MangledName);<br>
<br>
StringView demangleSimpleString(StringView &MangledName, bool Memorize);<br>
<br>
FuncClass demangleFunctionClass(StringView &MangledName);<br>
CallingConv demangleCallingConvention(StringView &MangledName);<br>
StorageClass demangleVariableStorageClass(StringView &MangledName);<br>
- ReferenceKind demangleReferenceKind(StringView &MangledName);<br>
void demangleThrowSpecification(StringView &MangledName);<br>
wchar_t demangleWcharLiteral(StringView &MangledName);<br>
uint8_t demangleCharLiteral(StringView &MangledName);<br>
@@ -1506,121 +394,455 @@ StringView Demangler::copyString(StringV<br>
return {Stable, Borrowed.size()};<br>
}<br>
<br>
-Symbol *Demangler::parseOperator(StringView &MangledName) {<br>
- Symbol *S = Arena.alloc<Symbol>();<br>
-<br>
- bool IsMember = false;<br>
- OperatorTy OTy;<br>
- std::tie(OTy, S->SymbolName) = demangleOperatorName(MangledName, true);<br>
- switch (OTy) {<br>
- case OperatorTy::StringLiteral:<br>
- S->Category = SymbolCategory::SpecialOperator;<br>
+SpecialTableSymbolNode *<br>
+Demangler::demangleSpecialTableSymbolNode(StringView &MangledName,<br>
+ SpecialIntrinsicKind K) {<br>
+ NamedIdentifierNode *NI = Arena.alloc<NamedIdentifierNode>();<br>
+ switch (K) {<br>
+ case SpecialIntrinsicKind::Vftable:<br>
+ NI->Name = "`vftable'";<br>
break;<br>
- case OperatorTy::Vcall:<br>
- S->Category = SymbolCategory::UnnamedFunction;<br>
+ case SpecialIntrinsicKind::Vbtable:<br>
+ NI->Name = "`vbtable'";<br>
break;<br>
- case OperatorTy::LocalStaticGuard:<br>
- S->Category = SymbolCategory::UnnamedVariable;<br>
+ case SpecialIntrinsicKind::LocalVftable:<br>
+ NI->Name = "`local vftable'";<br>
break;<br>
- case OperatorTy::Vftable: // Foo@@6B@<br>
- case OperatorTy::LocalVftable: // Foo@@6B@<br>
- case OperatorTy::RttiCompleteObjLocator: // Foo@@6B@<br>
- case OperatorTy::Vbtable: // Foo@@7B@<br>
- S->Category = SymbolCategory::UnnamedVariable;<br>
- switch (MangledName.popFront()) {<br>
- case '6':<br>
- case '7': {<br>
- std::tie(S->SymbolQuals, IsMember) = demangleQualifiers(MangledName);<br>
- if (!MangledName.consumeFront('@')) {<br>
- IndirectTable *Table = Arena.alloc<IndirectTable>(OTy);<br>
- Table->TableTarget = demangleFullyQualifiedTypeName(MangledName);<br>
- Table->TableLocation = S->SymbolName;<br>
- S->SymbolName = Table;<br>
- }<br>
- break;<br>
- }<br>
- default:<br>
- Error = true;<br>
- break;<br>
- }<br>
+ case SpecialIntrinsicKind::RttiCompleteObjLocator:<br>
+ NI->Name = "`RTTI Complete Object Locator'";<br>
break;<br>
- case OperatorTy::RttiTypeDescriptor: // <type>@@8<br>
- S->Category = SymbolCategory::UnnamedVariable;<br>
- S->SymbolType = demangleType(MangledName, QualifierMangleMode::Result);<br>
+ default:<br>
+ LLVM_BUILTIN_UNREACHABLE;<br>
+ }<br>
+ QualifiedNameNode *QN = demangleNameScopeChain(MangledName, NI);<br>
+ SpecialTableSymbolNode *STSN = Arena.alloc<SpecialTableSymbolNode>();<br>
+ STSN->Name = QN;<br>
+ bool IsMember = false;<br>
+ char Front = MangledName.popFront();<br>
+ if (Front != '6' && Front != '7') {<br>
+ Error = true;<br>
+ return nullptr;<br>
+ }<br>
+<br>
+ std::tie(STSN->Quals, IsMember) = demangleQualifiers(MangledName);<br>
+ if (!MangledName.consumeFront('@'))<br>
+ STSN->TargetName = demangleFullyQualifiedTypeName(MangledName);<br>
+ return STSN;<br>
+}<br>
+<br>
+LocalStaticGuardVariableNode *<br>
+Demangler::demangleLocalStaticGuard(StringView &MangledName) {<br>
+ LocalStaticGuardIdentifierNode *LSGI =<br>
+ Arena.alloc<LocalStaticGuardIdentifierNode>();<br>
+ QualifiedNameNode *QN = demangleNameScopeChain(MangledName, LSGI);<br>
+ LocalStaticGuardVariableNode *LSGVN =<br>
+ Arena.alloc<LocalStaticGuardVariableNode>();<br>
+ LSGVN->Name = QN;<br>
+<br>
+ if (MangledName.consumeFront("4IA"))<br>
+ LSGVN->IsVisible = false;<br>
+ else if (MangledName.consumeFront("5"))<br>
+ LSGVN->IsVisible = true;<br>
+ else {<br>
+ Error = true;<br>
+ return nullptr;<br>
+ }<br>
+<br>
+ if (!MangledName.empty())<br>
+ LSGI->ScopeIndex = demangleUnsigned(MangledName);<br>
+ return LSGVN;<br>
+}<br>
+<br>
+static NamedIdentifierNode *synthesizeNamedIdentifier(ArenaAllocator &Arena,<br>
+ StringView Name) {<br>
+ NamedIdentifierNode *Id = Arena.alloc<NamedIdentifierNode>();<br>
+ Id->Name = Name;<br>
+ return Id;<br>
+}<br>
+<br>
+static QualifiedNameNode *synthesizeQualifiedName(ArenaAllocator &Arena,<br>
+ IdentifierNode *Identifier) {<br>
+ QualifiedNameNode *QN = Arena.alloc<QualifiedNameNode>();<br>
+ QN->Components = Arena.alloc<NodeArrayNode>();<br>
+ QN->Components->Count = 1;<br>
+ QN->Components->Nodes = Arena.allocArray<Node *>(1);<br>
+ QN->Components->Nodes[0] = Identifier;<br>
+ return QN;<br>
+}<br>
+<br>
+static QualifiedNameNode *synthesizeQualifiedName(ArenaAllocator &Arena,<br>
+ StringView Name) {<br>
+ NamedIdentifierNode *Id = synthesizeNamedIdentifier(Arena, Name);<br>
+ return synthesizeQualifiedName(Arena, Id);<br>
+}<br>
+<br>
+static VariableSymbolNode *synthesizeVariable(ArenaAllocator &Arena,<br>
+ TypeNode *Type,<br>
+ StringView VariableName) {<br>
+ VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>();<br>
+ VSN->Type = Type;<br>
+ VSN->Name = synthesizeQualifiedName(Arena, VariableName);<br>
+ return VSN;<br>
+}<br>
+<br>
+VariableSymbolNode *Demangler::demangleUntypedVariable(<br>
+ ArenaAllocator &Arena, StringView &MangledName, StringView VariableName) {<br>
+ NamedIdentifierNode *NI = synthesizeNamedIdentifier(Arena, VariableName);<br>
+ QualifiedNameNode *QN = demangleNameScopeChain(MangledName, NI);<br>
+ VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>();<br>
+ VSN->Name = QN;<br>
+ if (MangledName.consumeFront("8"))<br>
+ return VSN;<br>
+<br>
+ Error = true;<br>
+ return nullptr;<br>
+}<br>
+<br>
+VariableSymbolNode *<br>
+Demangler::demangleRttiBaseClassDescriptorNode(ArenaAllocator &Arena,<br>
+ StringView &MangledName) {<br>
+ RttiBaseClassDescriptorNode *RBCDN =<br>
+ Arena.alloc<RttiBaseClassDescriptorNode>();<br>
+ RBCDN->NVOffset = demangleUnsigned(MangledName);<br>
+ RBCDN->VBPtrOffset = demangleSigned(MangledName);<br>
+ RBCDN->VBTableOffset = demangleUnsigned(MangledName);<br>
+ RBCDN->Flags = demangleUnsigned(MangledName);<br>
+ if (Error)<br>
+ return nullptr;<br>
+<br>
+ VariableSymbolNode *VSN = Arena.alloc<VariableSymbolNode>();<br>
+ VSN->Name = demangleNameScopeChain(MangledName, RBCDN);<br>
+ MangledName.consumeFront('8');<br>
+ return VSN;<br>
+}<br>
+<br>
+FunctionSymbolNode *<br>
+Demangler::demangleDynamicStructorFunction(StringView &MangledName,<br>
+ bool IsDestructor) {<br>
+ DynamicStructorIdentifierNode *DSIN =<br>
+ Arena.alloc<DynamicStructorIdentifierNode>();<br>
+ DSIN->IsDestructor = IsDestructor;<br>
+ DSIN->Name = demangleFullyQualifiedTypeName(MangledName);<br>
+ QualifiedNameNode *QNN = synthesizeQualifiedName(Arena, DSIN);<br>
+ FunctionSymbolNode *FSN = demangleFunctionEncoding(MangledName);<br>
+ FSN->Name = QNN;<br>
+ return FSN;<br>
+}<br>
+<br>
+SymbolNode *Demangler::demangleSpecialIntrinsic(StringView &MangledName) {<br>
+ SpecialIntrinsicKind SIK = consumeSpecialIntrinsicKind(MangledName);<br>
+ if (SIK == SpecialIntrinsicKind::None)<br>
+ return nullptr;<br>
+<br>
+ switch (SIK) {<br>
+ case SpecialIntrinsicKind::StringLiteralSymbol:<br>
+ return demangleStringLiteral(MangledName);<br>
+ case SpecialIntrinsicKind::Vftable:<br>
+ case SpecialIntrinsicKind::Vbtable:<br>
+ case SpecialIntrinsicKind::LocalVftable:<br>
+ case SpecialIntrinsicKind::RttiCompleteObjLocator:<br>
+ return demangleSpecialTableSymbolNode(MangledName, SIK);<br>
+ case SpecialIntrinsicKind::VcallThunk:<br>
+ return demangleVcallThunkNode(MangledName);<br>
+ case SpecialIntrinsicKind::LocalStaticGuard:<br>
+ return demangleLocalStaticGuard(MangledName);<br>
+ case SpecialIntrinsicKind::RttiTypeDescriptor: {<br>
+ TypeNode *T = demangleType(MangledName, QualifierMangleMode::Result);<br>
if (Error)<br>
break;<br>
if (!MangledName.consumeFront("@8"))<br>
- Error = true;<br>
+ break;<br>
if (!MangledName.empty())<br>
- Error = true;<br>
- break;<br>
+ break;<br>
+ return synthesizeVariable(Arena, T, "`RTTI Type Descriptor'");<br>
+ }<br>
+ case SpecialIntrinsicKind::RttiBaseClassArray:<br>
+ return demangleUntypedVariable(Arena, MangledName,<br>
+ "`RTTI Base Class Array'");<br>
+ case SpecialIntrinsicKind::RttiClassHierarchyDescriptor:<br>
+ return demangleUntypedVariable(Arena, MangledName,<br>
+ "`RTTI Class Hierarchy Descriptor'");<br>
+ case SpecialIntrinsicKind::RttiBaseClassDescriptor:<br>
+ return demangleRttiBaseClassDescriptorNode(Arena, MangledName);<br>
+ case SpecialIntrinsicKind::DynamicInitializer:<br>
+ return demangleDynamicStructorFunction(MangledName, false);<br>
+ case SpecialIntrinsicKind::DynamicAtexitDestructor:<br>
+ return demangleDynamicStructorFunction(MangledName, true);<br>
default:<br>
- if (!Error)<br>
- std::tie(S->Category, S->SymbolType) =<br>
- demangleSymbolCategoryAndType(MangledName);<br>
break;<br>
}<br>
+ Error = true;<br>
+ return nullptr;<br>
+}<br>
+<br>
+IdentifierNode *<br>
+Demangler::demangleFunctionIdentifierCode(StringView &MangledName) {<br>
+ assert(MangledName.startsWith('?'));<br>
+ MangledName = MangledName.dropFront();<br>
+<br>
+ if (MangledName.consumeFront("__"))<br>
+ return demangleFunctionIdentifierCode(<br>
+ MangledName, FunctionIdentifierCodeGroup::DoubleUnder);<br>
+ else if (MangledName.consumeFront("_"))<br>
+ return demangleFunctionIdentifierCode(MangledName,<br>
+ FunctionIdentifierCodeGroup::Under);<br>
+ return demangleFunctionIdentifierCode(MangledName,<br>
+ FunctionIdentifierCodeGroup::Basic);<br>
+}<br>
+<br>
+StructorIdentifierNode *<br>
+Demangler::demangleStructorIdentifier(StringView &MangledName,<br>
+ bool IsDestructor) {<br>
+ StructorIdentifierNode *N = Arena.alloc<StructorIdentifierNode>();<br>
+ N->IsDestructor = IsDestructor;<br>
+ return N;<br>
+}<br>
+<br>
+ConversionOperatorIdentifierNode *<br>
+Demangler::demangleConversionOperatorIdentifier(StringView &MangledName) {<br>
+ ConversionOperatorIdentifierNode *N =<br>
+ Arena.alloc<ConversionOperatorIdentifierNode>();<br>
+ return N;<br>
+}<br>
+<br>
+LiteralOperatorIdentifierNode *<br>
+Demangler::demangleLiteralOperatorIdentifier(StringView &MangledName) {<br>
+ LiteralOperatorIdentifierNode *N =<br>
+ Arena.alloc<LiteralOperatorIdentifierNode>();<br>
+ N->Name = demangleSimpleString(MangledName, false);<br>
+ return N;<br>
+}<br>
+<br>
+IntrinsicFunctionKind<br>
+translateIntrinsicFunctionCode(char CH, FunctionIdentifierCodeGroup Group) {<br>
+ // Not all ? identifiers are intrinsics *functions*. This function only maps<br>
+ // operator codes for the special functions, all others are handled elsewhere,<br>
+ // hence the IFK::None entries in the table.<br>
+ using IFK = IntrinsicFunctionKind;<br>
+ static IFK Basic[36] = {<br>
+ IFK::None, // ?0 # Foo::Foo()<br>
+ IFK::None, // ?1 # Foo::~Foo()<br>
+ IFK::New, // ?2 # operator new<br>
+ IFK::Delete, // ?3 # operator delete<br>
+ IFK::Assign, // ?4 # operator=<br>
+ IFK::RightShift, // ?5 # operator>><br>
+ IFK::LeftShift, // ?6 # operator<<<br>
+ IFK::LogicalNot, // ?7 # operator!<br>
+ IFK::Equals, // ?8 # operator==<br>
+ IFK::NotEquals, // ?9 # operator!=<br>
+ IFK::ArraySubscript, // ?A # operator[]<br>
+ IFK::None, // ?B # Foo::operator <type>()<br>
+ IFK::Pointer, // ?C # operator-><br>
+ IFK::Dereference, // ?D # operator*<br>
+ IFK::Increment, // ?E # operator++<br>
+ IFK::Decrement, // ?F # operator--<br>
+ IFK::Minus, // ?G # operator-<br>
+ IFK::Plus, // ?H # operator+<br>
+ IFK::BitwiseA</blockquote></div>