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