summaryrefslogtreecommitdiff
path: root/lib/Demangle/MicrosoftDemangle.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Demangle/MicrosoftDemangle.cpp')
-rw-r--r--lib/Demangle/MicrosoftDemangle.cpp1684
1 files changed, 1684 insertions, 0 deletions
diff --git a/lib/Demangle/MicrosoftDemangle.cpp b/lib/Demangle/MicrosoftDemangle.cpp
new file mode 100644
index 000000000000..596359b7d990
--- /dev/null
+++ b/lib/Demangle/MicrosoftDemangle.cpp
@@ -0,0 +1,1684 @@
+//===- MicrosoftDemangle.cpp ----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a demangler for MSVC-style mangled symbols.
+//
+// This file has no dependencies on the rest of LLVM so that it can be
+// easily reused in other programs such as libcxxabi.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Demangle/Demangle.h"
+
+#include "Compiler.h"
+#include "StringView.h"
+#include "Utility.h"
+
+#include <cctype>
+#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 {
+class ArenaAllocator {
+ struct AllocatorNode {
+ uint8_t *Buf = nullptr;
+ size_t Used = 0;
+ AllocatorNode *Next = nullptr;
+ };
+
+public:
+ ArenaAllocator() : Head(new AllocatorNode) { Head->Buf = new uint8_t[Unit]; }
+
+ ~ArenaAllocator() {
+ while (Head) {
+ assert(Head->Buf);
+ delete[] Head->Buf;
+ AllocatorNode *Next = Head->Next;
+ delete Head;
+ Head = Next;
+ }
+ }
+
+ template <typename T, typename... Args> T *alloc(Args &&... ConstructorArgs) {
+
+ size_t Size = sizeof(T);
+ assert(Size < Unit);
+ 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 < Unit)
+ return new (PP) T(std::forward<Args>(ConstructorArgs)...);
+
+ AllocatorNode *NewHead = new AllocatorNode;
+ NewHead->Buf = new uint8_t[ArenaAllocator::Unit];
+ NewHead->Next = Head;
+ Head = NewHead;
+ NewHead->Used = Size;
+ return new (NewHead->Buf) T(std::forward<Args>(ConstructorArgs)...);
+ }
+
+private:
+ static constexpr size_t Unit = 4096;
+
+ AllocatorNode *Head = nullptr;
+};
+} // namespace
+
+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 };
+
+// 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,
+ Ref,
+ MemberPtr,
+ Array,
+
+ Struct,
+ Union,
+ Class,
+ Enum,
+
+ Void,
+ Bool,
+ Char,
+ Schar,
+ Uchar,
+ Short,
+ Ushort,
+ Int,
+ Uint,
+ Long,
+ Ulong,
+ Int64,
+ Uint64,
+ Wchar,
+ Float,
+ Double,
+ Ldouble,
+};
+
+// Function classes
+enum FuncClass : uint8_t {
+ Public = 1 << 0,
+ Protected = 1 << 1,
+ Private = 1 << 2,
+ Global = 1 << 3,
+ Static = 1 << 4,
+ Virtual = 1 << 5,
+ Far = 1 << 6,
+};
+
+namespace {
+
+struct Type;
+
+// Represents a list of parameters (template params or function arguments.
+// It's represented as a linked list.
+struct ParamList {
+ bool IsVariadic = false;
+
+ Type *Current = nullptr;
+
+ ParamList *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;
+ StorageClass Storage = StorageClass::None; // storage class
+};
+
+// Represents an identifier which may be a template.
+struct Name {
+ // Name read from an MangledName string.
+ StringView Str;
+
+ // Overloaded operators are represented as special BackReferences in mangled
+ // symbols. If this is an operator name, "op" has an operator name (e.g.
+ // ">>"). Otherwise, empty.
+ StringView Operator;
+
+ // Template parameters. Null if not a template.
+ ParamList TemplateParams;
+
+ // Nested BackReferences (e.g. "A::B::C") are represented as a linked list.
+ Name *Next = nullptr;
+};
+
+struct PointerType : public Type {
+ Type *clone(ArenaAllocator &Arena) const override;
+ void outputPre(OutputStream &OS) override;
+ void outputPost(OutputStream &OS) override;
+
+ // 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 {
+ 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;
+
+ Type *ReturnType = nullptr;
+ // If this is a reference, the type of reference.
+ ReferenceKind RefKind;
+
+ CallingConv CallConvention;
+ FuncClass FunctionClass;
+
+ ParamList Params;
+};
+
+struct UdtType : public Type {
+ Type *clone(ArenaAllocator &Arena) const override;
+ void outputPre(OutputStream &OS) override;
+
+ Name *UdtName = 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.
+ ArrayType *NextDimension = nullptr;
+ uint32_t ArrayDimension = 0;
+
+ Type *ElementType = nullptr;
+};
+
+} // namespace
+
+static bool isMemberPointer(StringView MangledName) {
+ switch (MangledName.popFront()) {
+ case 'A':
+ // 'A' indicates a reference, and you cannot have a reference to a member
+ // function or member variable.
+ return false;
+ case 'P':
+ case 'Q':
+ case 'R':
+ case 'S':
+ // These 4 values indicate some kind of pointer, but we still don't know
+ // what.
+ break;
+ default:
+ assert(false && "Ty is not a pointer type!");
+ }
+
+ // If it starts with a number, then 6 indicates a non-member function
+ // pointer, and 8 indicates a member function pointer.
+ if (startsWithDigit(MangledName)) {
+ assert(MangledName[0] == '6' || MangledName[0] == '8');
+ return (MangledName[0] == '8');
+ }
+
+ // Remove ext qualifiers since those can appear on either type and are
+ // therefore not indicative.
+ MangledName.consumeFront('E'); // 64-bit
+ MangledName.consumeFront('I'); // restrict
+ MangledName.consumeFront('F'); // unaligned
+
+ assert(!MangledName.empty());
+
+ // The next value should be either ABCD (non-member) or QRST (member).
+ switch (MangledName.front()) {
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ return false;
+ case 'Q':
+ case 'R':
+ case 'S':
+ case 'T':
+ return true;
+ default:
+ assert(false);
+ }
+ 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;
+ }
+}
+
+// Write a function or template parameter list.
+static void outputParameterList(OutputStream &OS, const ParamList &Params) {
+ if (!Params.Current) {
+ OS << "void";
+ return;
+ }
+
+ const ParamList *Head = &Params;
+ while (Head) {
+ Type::outputPre(OS, *Head->Current);
+ Type::outputPost(OS, *Head->Current);
+
+ Head = Head->Next;
+
+ if (Head)
+ OS << ", ";
+ }
+}
+
+static void outputTemplateParams(OutputStream &OS, const Name &TheName) {
+ if (!TheName.TemplateParams.Current)
+ return;
+
+ OS << "<";
+ outputParameterList(OS, TheName.TemplateParams);
+ OS << ">";
+}
+
+static void outputName(OutputStream &OS, const Name *TheName) {
+ if (!TheName)
+ return;
+
+ outputSpaceIfNecessary(OS);
+
+ // Print out namespaces or outer class BackReferences.
+ for (; TheName->Next; TheName = TheName->Next) {
+ OS << TheName->Str;
+ outputTemplateParams(OS, *TheName);
+ OS << "::";
+ }
+
+ // Print out a regular name.
+ if (TheName->Operator.empty()) {
+ OS << TheName->Str;
+ outputTemplateParams(OS, *TheName);
+ return;
+ }
+
+ // Print out ctor or dtor.
+ if (TheName->Operator == "ctor" || TheName->Operator == "dtor") {
+ OS << TheName->Str;
+ outputTemplateParams(OS, *TheName);
+ OS << "::";
+ if (TheName->Operator == "dtor")
+ OS << "~";
+ OS << TheName->Str;
+ outputTemplateParams(OS, *TheName);
+ return;
+ }
+
+ // Print out an overloaded operator.
+ if (!TheName->Str.empty())
+ OS << TheName->Str << "::";
+ OS << "operator" << TheName->Operator;
+}
+
+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);
+
+ if (Ty.Quals & Q_Const) {
+ outputSpaceIfNecessary(OS);
+ OS << "const";
+ }
+
+ if (Ty.Quals & Q_Volatile) {
+ outputSpaceIfNecessary(OS);
+ OS << "volatile";
+ }
+
+ if (Ty.Quals & Q_Restrict) {
+ outputSpaceIfNecessary(OS);
+ OS << "__restrict";
+ }
+}
+
+// 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::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;
+ default:
+ assert(false && "Invalid primitive type!");
+ }
+}
+void Type::outputPost(OutputStream &OS) {}
+
+Type *PointerType::clone(ArenaAllocator &Arena) const {
+ return Arena.alloc<PointerType>(*this);
+}
+
+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 << " ";
+ }
+ }
+
+ if (MemberName) {
+ outputName(OS, MemberName);
+ OS << "::";
+ }
+
+ if (Affinity == PointerAffinity::Pointer)
+ OS << "*";
+ else
+ OS << "&";
+}
+
+void PointerType::outputPre(OutputStream &OS) {
+ Type::outputPre(OS, *Pointee);
+
+ outputSpaceIfNecessary(OS);
+
+ if (Quals & Q_Unaligned)
+ OS << "__unaligned ";
+
+ PointerAffinity Affinity = (Prim == PrimTy::Ptr) ? PointerAffinity::Pointer
+ : PointerAffinity::Reference;
+
+ 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";
+ if (Quals & Q_Restrict)
+ OS << " __restrict";
+}
+
+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);
+}
+
+void FunctionType::outputPre(OutputStream &OS) {
+ if (!(FunctionClass & Global)) {
+ if (FunctionClass & Static)
+ OS << "static ";
+ }
+
+ if (ReturnType) {
+ Type::outputPre(OS, *ReturnType);
+ OS << " ";
+ }
+
+ // 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);
+}
+
+void FunctionType::outputPost(OutputStream &OS) {
+ OS << "(";
+ outputParameterList(OS, Params);
+ OS << ")";
+ if (Quals & Q_Const)
+ OS << " const";
+ if (Quals & Q_Volatile)
+ OS << " volatile";
+
+ if (ReturnType)
+ Type::outputPost(OS, *ReturnType);
+ return;
+}
+
+Type *UdtType::clone(ArenaAllocator &Arena) const {
+ return Arena.alloc<UdtType>(*this);
+}
+
+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;
+ default:
+ assert(false && "Not a udt type!");
+ }
+
+ outputName(OS, UdtName);
+}
+
+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) {
+ if (ArrayDimension > 0)
+ OS << "[" << ArrayDimension << "]";
+ if (NextDimension)
+ Type::outputPost(OS, *NextDimension);
+ else if (ElementType)
+ Type::outputPost(OS, *ElementType);
+}
+
+} // namespace
+
+namespace {
+
+// Demangler class takes the main role in demangling symbols.
+// It has a set of functions to parse mangled symbols into Type instances.
+// It also has a set of functions to cnovert Type instances to strings.
+class Demangler {
+public:
+ Demangler(OutputStream &OS, StringView s) : OS(OS), MangledName(s) {}
+
+ // 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.
+ void parse();
+ void output();
+
+ // True if an error occurred.
+ bool Error = false;
+
+private:
+ Type *demangleVariableEncoding();
+ Type *demangleFunctionEncoding();
+
+ Qualifiers demanglePointerExtQualifiers();
+
+ // Parser functions. This is a recursive-descent parser.
+ Type *demangleType(QualifierMangleMode QMM);
+ Type *demangleBasicType();
+ UdtType *demangleClassType();
+ PointerType *demanglePointerType();
+ MemberPointerType *demangleMemberPointerType();
+ FunctionType *demangleFunctionType(bool HasThisQuals, bool IsFunctionPointer);
+
+ ArrayType *demangleArrayType();
+
+ ParamList demangleTemplateParameterList();
+ ParamList demangleFunctionParameterList();
+
+ int demangleNumber();
+ void demangleNamePiece(Name &Node, bool IsHead);
+
+ StringView demangleString(bool memorize);
+ void memorizeString(StringView s);
+ Name *demangleName();
+ void demangleOperator(Name *);
+ StringView demangleOperatorName();
+ FuncClass demangleFunctionClass();
+ CallingConv demangleCallingConvention();
+ StorageClass demangleVariableStorageClass();
+ ReferenceKind demangleReferenceKind();
+ void demangleThrowSpecification();
+
+ std::pair<Qualifiers, bool> demangleQualifiers();
+
+ // The result is written to this stream.
+ OutputStream OS;
+
+ // Mangled symbol. demangle* functions shorten this string
+ // as they parse it.
+ StringView MangledName;
+
+ // A parsed mangled symbol.
+ Type *SymbolType = nullptr;
+
+ // The main symbol name. (e.g. "ns::foo" in "int ns::foo()".)
+ Name *SymbolName = nullptr;
+
+ // Memory allocator.
+ ArenaAllocator Arena;
+
+ // A single type uses one global back-ref table for all function params.
+ // This means back-refs can even go "into" other types. Examples:
+ //
+ // // Second int* is a back-ref to first.
+ // void foo(int *, int*);
+ //
+ // // Second int* is not a back-ref to first (first is not a function param).
+ // int* foo(int*);
+ //
+ // // Second int* is a back-ref to first (ALL function types share the same
+ // // back-ref map.
+ // using F = void(*)(int*);
+ // F G(int *);
+ Type *FunctionParamBackRefs[10];
+ size_t FunctionParamBackRefCount = 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 BackReferences[10];
+ size_t BackRefCount = 0;
+};
+} // namespace
+
+// Parser entry point.
+void Demangler::parse() {
+ // MSVC-style mangled symbols must start with '?'.
+ if (!MangledName.consumeFront("?")) {
+ SymbolName = Arena.alloc<Name>();
+ SymbolName->Str = MangledName;
+ SymbolType = Arena.alloc<Type>();
+ SymbolType->Prim = PrimTy::Unknown;
+ }
+
+ // What follows is a main symbol name. This may include
+ // namespaces or class BackReferences.
+ SymbolName = demangleName();
+
+ // Read a variable.
+ if (startsWithDigit(MangledName)) {
+ SymbolType = demangleVariableEncoding();
+ return;
+ }
+
+ // Read a function.
+ SymbolType = demangleFunctionEncoding();
+}
+
+// <type-encoding> ::= <storage-class> <variable-type>
+// <storage-class> ::= 0 # private static member
+// ::= 1 # protected static member
+// ::= 2 # public static member
+// ::= 3 # global
+// ::= 4 # static local
+
+Type *Demangler::demangleVariableEncoding() {
+ StorageClass SC = demangleVariableStorageClass();
+
+ Type *Ty = demangleType(QualifierMangleMode::Drop);
+
+ Ty->Storage = SC;
+
+ // <variable-type> ::= <type> <cvr-qualifiers>
+ // ::= <type> <pointee-cvr-qualifiers> # pointers, references
+ switch (Ty->Prim) {
+ case PrimTy::Ptr:
+ case PrimTy::Ref:
+ case PrimTy::MemberPtr: {
+ Qualifiers ExtraChildQuals = Q_None;
+ Ty->Quals = Qualifiers(Ty->Quals | demanglePointerExtQualifiers());
+
+ bool IsMember = false;
+ std::tie(ExtraChildQuals, IsMember) = demangleQualifiers();
+
+ if (Ty->Prim == PrimTy::MemberPtr) {
+ assert(IsMember);
+ Name *BackRefName = demangleName();
+ (void)BackRefName;
+ MemberPointerType *MPTy = static_cast<MemberPointerType *>(Ty);
+ MPTy->Pointee->Quals = Qualifiers(MPTy->Pointee->Quals | ExtraChildQuals);
+ } else {
+ PointerType *PTy = static_cast<PointerType *>(Ty);
+ PTy->Pointee->Quals = Qualifiers(PTy->Pointee->Quals | ExtraChildQuals);
+ }
+
+ break;
+ }
+ default:
+ Ty->Quals = demangleQualifiers().first;
+ break;
+ }
+
+ return Ty;
+}
+
+// Sometimes numbers are encoded in mangled symbols. For example,
+// "int (*x)[20]" is a valid C type (x is a pointer to an array of
+// length 20), so we need some way to embed numbers as part of symbols.
+// This function parses it.
+//
+// <number> ::= [?] <non-negative integer>
+//
+// <non-negative integer> ::= <decimal digit> # when 1 <= Number <= 10
+// ::= <hex digit>+ @ # when Numbrer == 0 or >= 10
+//
+// <hex-digit> ::= [A-P] # A = 0, B = 1, ...
+int Demangler::demangleNumber() {
+ bool neg = MangledName.consumeFront("?");
+
+ if (startsWithDigit(MangledName)) {
+ int32_t Ret = MangledName[0] - '0' + 1;
+ MangledName = MangledName.dropFront(1);
+ return neg ? -Ret : Ret;
+ }
+
+ int Ret = 0;
+ for (size_t i = 0; i < MangledName.size(); ++i) {
+ char C = MangledName[i];
+ if (C == '@') {
+ MangledName = MangledName.dropFront(i + 1);
+ return neg ? -Ret : Ret;
+ }
+ if ('A' <= C && C <= 'P') {
+ Ret = (Ret << 4) + (C - 'A');
+ continue;
+ }
+ break;
+ }
+
+ Error = true;
+ return 0;
+}
+
+// Read until the next '@'.
+StringView Demangler::demangleString(bool Memorize) {
+ for (size_t i = 0; i < MangledName.size(); ++i) {
+ if (MangledName[i] != '@')
+ continue;
+ StringView ret = MangledName.substr(0, i);
+ MangledName = MangledName.dropFront(i + 1);
+
+ if (Memorize)
+ memorizeString(ret);
+ return ret;
+ }
+
+ Error = true;
+ return "";
+}
+
+// First 10 strings can be referenced by special BackReferences ?0, ?1, ..., ?9.
+// Memorize it.
+void Demangler::memorizeString(StringView S) {
+ if (BackRefCount >= sizeof(BackReferences) / sizeof(*BackReferences))
+ return;
+ for (size_t i = 0; i < BackRefCount; ++i)
+ if (S == BackReferences[i])
+ return;
+ BackReferences[BackRefCount++] = S;
+}
+
+void Demangler::demangleNamePiece(Name &Node, bool IsHead) {
+ if (startsWithDigit(MangledName)) {
+ size_t I = MangledName[0] - '0';
+ if (I >= BackRefCount) {
+ Error = true;
+ return;
+ }
+ MangledName = MangledName.dropFront();
+ Node.Str = BackReferences[I];
+ } else if (MangledName.consumeFront("?$")) {
+ // Class template.
+ Node.Str = demangleString(false);
+ Node.TemplateParams = demangleTemplateParameterList();
+ } else if (!IsHead && MangledName.consumeFront("?A")) {
+ // Anonymous namespace starts with ?A. So does overloaded operator[],
+ // but the distinguishing factor is that namespace themselves are not
+ // mangled, only the variables and functions inside of them are. So
+ // an anonymous namespace will never occur as the first item in the
+ // name.
+ Node.Str = "`anonymous namespace'";
+ if (!MangledName.consumeFront('@')) {
+ Error = true;
+ return;
+ }
+ } else if (MangledName.consumeFront("?")) {
+ // Overloaded operator.
+ demangleOperator(&Node);
+ } else {
+ // Non-template functions or classes.
+ Node.Str = demangleString(true);
+ }
+}
+
+// Parses a name in the form of A@B@C@@ which represents C::B::A.
+Name *Demangler::demangleName() {
+ Name *Head = nullptr;
+
+ while (!MangledName.consumeFront("@")) {
+ Name *Elem = Arena.alloc<Name>();
+
+ assert(!Error);
+ demangleNamePiece(*Elem, Head == nullptr);
+ if (Error)
+ return nullptr;
+
+ Elem->Next = Head;
+ Head = Elem;
+ if (MangledName.empty()) {
+ Error = true;
+ return nullptr;
+ }
+ }
+
+ return Head;
+}
+
+void Demangler::demangleOperator(Name *OpName) {
+ OpName->Operator = demangleOperatorName();
+ if (!Error && !MangledName.empty() && MangledName.front() != '@')
+ demangleNamePiece(*OpName, false);
+}
+
+StringView Demangler::demangleOperatorName() {
+ SwapAndRestore<StringView> RestoreOnError(MangledName, MangledName);
+ RestoreOnError.shouldRestore(false);
+
+ switch (MangledName.popFront()) {
+ case '0':
+ return "ctor";
+ case '1':
+ return "dtor";
+ case '2':
+ return " new";
+ case '3':
+ return " delete";
+ case '4':
+ return "=";
+ case '5':
+ return ">>";
+ case '6':
+ return "<<";
+ case '7':
+ return "!";
+ case '8':
+ return "==";
+ case '9':
+ return "!=";
+ case 'A':
+ return "[]";
+ case 'C':
+ return "->";
+ case 'D':
+ return "*";
+ case 'E':
+ return "++";
+ case 'F':
+ return "--";
+ case 'G':
+ return "-";
+ case 'H':
+ return "+";
+ case 'I':
+ return "&";
+ case 'J':
+ return "->*";
+ case 'K':
+ return "/";
+ case 'L':
+ return "%";
+ case 'M':
+ return "<";
+ case 'N':
+ return "<=";
+ case 'O':
+ return ">";
+ case 'P':
+ return ">=";
+ case 'Q':
+ return ",";
+ case 'R':
+ return "()";
+ case 'S':
+ return "~";
+ case 'T':
+ return "^";
+ case 'U':
+ return "|";
+ case 'V':
+ return "&&";
+ case 'W':
+ return "||";
+ case 'X':
+ return "*=";
+ case 'Y':
+ return "+=";
+ case 'Z':
+ return "-=";
+ case '_': {
+ if (MangledName.empty())
+ break;
+
+ switch (MangledName.popFront()) {
+ case '0':
+ return "/=";
+ case '1':
+ return "%=";
+ case '2':
+ return ">>=";
+ case '3':
+ return "<<=";
+ case '4':
+ return "&=";
+ case '5':
+ return "|=";
+ case '6':
+ return "^=";
+ case 'U':
+ return " new[]";
+ case 'V':
+ return " delete[]";
+ case '_':
+ if (MangledName.consumeFront("L"))
+ return " co_await";
+ }
+ }
+ }
+
+ Error = true;
+ RestoreOnError.shouldRestore(true);
+ return "";
+}
+
+FuncClass Demangler::demangleFunctionClass() {
+ SwapAndRestore<StringView> RestoreOnError(MangledName, MangledName);
+ RestoreOnError.shouldRestore(false);
+
+ switch (MangledName.popFront()) {
+ case 'A':
+ return Private;
+ case 'B':
+ return FuncClass(Private | Far);
+ case 'C':
+ return FuncClass(Private | Static);
+ case 'D':
+ return FuncClass(Private | Static);
+ case 'E':
+ return FuncClass(Private | Virtual);
+ case 'F':
+ return FuncClass(Private | Virtual);
+ case 'I':
+ return Protected;
+ case 'J':
+ return FuncClass(Protected | Far);
+ case 'K':
+ return FuncClass(Protected | Static);
+ case 'L':
+ return FuncClass(Protected | Static | Far);
+ case 'M':
+ return FuncClass(Protected | Virtual);
+ case 'N':
+ return FuncClass(Protected | Virtual | Far);
+ case 'Q':
+ return Public;
+ case 'R':
+ return FuncClass(Public | Far);
+ case 'S':
+ return FuncClass(Public | Static);
+ case 'T':
+ return FuncClass(Public | Static | Far);
+ case 'U':
+ return FuncClass(Public | Virtual);
+ case 'V':
+ return FuncClass(Public | Virtual | Far);
+ case 'Y':
+ return Global;
+ case 'Z':
+ return FuncClass(Global | Far);
+ }
+
+ Error = true;
+ RestoreOnError.shouldRestore(true);
+ return Public;
+}
+
+CallingConv Demangler::demangleCallingConvention() {
+ switch (MangledName.popFront()) {
+ case 'A':
+ case 'B':
+ return CallingConv::Cdecl;
+ case 'C':
+ case 'D':
+ return CallingConv::Pascal;
+ case 'E':
+ case 'F':
+ return CallingConv::Thiscall;
+ case 'G':
+ case 'H':
+ return CallingConv::Stdcall;
+ case 'I':
+ case 'J':
+ return CallingConv::Fastcall;
+ case 'M':
+ case 'N':
+ return CallingConv::Clrcall;
+ case 'O':
+ case 'P':
+ return CallingConv::Eabi;
+ case 'Q':
+ return CallingConv::Vectorcall;
+ }
+
+ return CallingConv::None;
+}
+
+StorageClass Demangler::demangleVariableStorageClass() {
+ assert(std::isdigit(MangledName.front()));
+
+ switch (MangledName.popFront()) {
+ case '0':
+ return StorageClass::PrivateStatic;
+ case '1':
+ return StorageClass::ProtectedStatic;
+ case '2':
+ return StorageClass::PublicStatic;
+ case '3':
+ return StorageClass::Global;
+ case '4':
+ return StorageClass::FunctionLocalStatic;
+ }
+ Error = true;
+ return StorageClass::None;
+}
+
+std::pair<Qualifiers, bool> Demangler::demangleQualifiers() {
+
+ switch (MangledName.popFront()) {
+ // Member qualifiers
+ case 'Q':
+ return std::make_pair(Q_None, true);
+ case 'R':
+ return std::make_pair(Q_Const, true);
+ case 'S':
+ return std::make_pair(Q_Volatile, true);
+ case 'T':
+ return std::make_pair(Qualifiers(Q_Const | Q_Volatile), true);
+ // Non-Member qualifiers
+ case 'A':
+ return std::make_pair(Q_None, false);
+ case 'B':
+ return std::make_pair(Q_Const, false);
+ case 'C':
+ return std::make_pair(Q_Volatile, false);
+ case 'D':
+ return std::make_pair(Qualifiers(Q_Const | Q_Volatile), false);
+ }
+ Error = true;
+ return std::make_pair(Q_None, false);
+}
+
+// <variable-type> ::= <type> <cvr-qualifiers>
+// ::= <type> <pointee-cvr-qualifiers> # pointers, references
+Type *Demangler::demangleType(QualifierMangleMode QMM) {
+ Qualifiers Quals = Q_None;
+ bool IsMember = false;
+ bool IsMemberKnown = false;
+ if (QMM == QualifierMangleMode::Mangle) {
+ std::tie(Quals, IsMember) = demangleQualifiers();
+ IsMemberKnown = true;
+ } else if (QMM == QualifierMangleMode::Result) {
+ if (MangledName.consumeFront('?')) {
+ std::tie(Quals, IsMember) = demangleQualifiers();
+ IsMemberKnown = true;
+ }
+ }
+
+ Type *Ty = nullptr;
+ switch (MangledName.front()) {
+ case 'T': // union
+ case 'U': // struct
+ case 'V': // class
+ case 'W': // enum
+ Ty = demangleClassType();
+ break;
+ case 'A': // foo &
+ case 'P': // foo *
+ case 'Q': // foo *const
+ case 'R': // foo *volatile
+ case 'S': // foo *const volatile
+ if (!IsMemberKnown)
+ IsMember = isMemberPointer(MangledName);
+ if (IsMember)
+ Ty = demangleMemberPointerType();
+ else
+ Ty = demanglePointerType();
+ break;
+ case 'Y':
+ Ty = demangleArrayType();
+ break;
+ default:
+ Ty = demangleBasicType();
+ break;
+ }
+ Ty->Quals = Qualifiers(Ty->Quals | Quals);
+ return Ty;
+}
+
+ReferenceKind Demangler::demangleReferenceKind() {
+ if (MangledName.consumeFront('G'))
+ return ReferenceKind::LValueRef;
+ else if (MangledName.consumeFront('H'))
+ return ReferenceKind::RValueRef;
+ return ReferenceKind::None;
+}
+
+void Demangler::demangleThrowSpecification() {
+ if (MangledName.consumeFront('Z'))
+ return;
+
+ Error = true;
+}
+
+FunctionType *Demangler::demangleFunctionType(bool HasThisQuals,
+ bool IsFunctionPointer) {
+ FunctionType *FTy = Arena.alloc<FunctionType>();
+ FTy->Prim = PrimTy::Function;
+ FTy->IsFunctionPointer = IsFunctionPointer;
+
+ if (HasThisQuals) {
+ FTy->Quals = demanglePointerExtQualifiers();
+ FTy->RefKind = demangleReferenceKind();
+ FTy->Quals = Qualifiers(FTy->Quals | demangleQualifiers().first);
+ }
+
+ // Fields that appear on both member and non-member functions.
+ FTy->CallConvention = demangleCallingConvention();
+
+ // <return-type> ::= <type>
+ // ::= @ # structors (they have no declared return type)
+ bool IsStructor = MangledName.consumeFront('@');
+ if (!IsStructor)
+ FTy->ReturnType = demangleType(QualifierMangleMode::Result);
+
+ FTy->Params = demangleFunctionParameterList();
+
+ demangleThrowSpecification();
+
+ return FTy;
+}
+
+Type *Demangler::demangleFunctionEncoding() {
+ FuncClass FC = demangleFunctionClass();
+
+ bool HasThisQuals = !(FC & (Global | Static));
+ FunctionType *FTy = demangleFunctionType(HasThisQuals, false);
+ FTy->FunctionClass = FC;
+
+ return FTy;
+}
+
+// Reads a primitive type.
+Type *Demangler::demangleBasicType() {
+ Type *Ty = Arena.alloc<Type>();
+
+ switch (MangledName.popFront()) {
+ case 'X':
+ Ty->Prim = PrimTy::Void;
+ break;
+ case 'D':
+ Ty->Prim = PrimTy::Char;
+ break;
+ case 'C':
+ Ty->Prim = PrimTy::Schar;
+ break;
+ case 'E':
+ Ty->Prim = PrimTy::Uchar;
+ break;
+ case 'F':
+ Ty->Prim = PrimTy::Short;
+ break;
+ case 'G':
+ Ty->Prim = PrimTy::Ushort;
+ break;
+ case 'H':
+ Ty->Prim = PrimTy::Int;
+ break;
+ case 'I':
+ Ty->Prim = PrimTy::Uint;
+ break;
+ case 'J':
+ Ty->Prim = PrimTy::Long;
+ break;
+ case 'K':
+ Ty->Prim = PrimTy::Ulong;
+ break;
+ case 'M':
+ Ty->Prim = PrimTy::Float;
+ break;
+ case 'N':
+ Ty->Prim = PrimTy::Double;
+ break;
+ case 'O':
+ Ty->Prim = PrimTy::Ldouble;
+ break;
+ case '_': {
+ if (MangledName.empty()) {
+ Error = true;
+ return nullptr;
+ }
+ switch (MangledName.popFront()) {
+ case 'N':
+ Ty->Prim = PrimTy::Bool;
+ break;
+ case 'J':
+ Ty->Prim = PrimTy::Int64;
+ break;
+ case 'K':
+ Ty->Prim = PrimTy::Uint64;
+ break;
+ case 'W':
+ Ty->Prim = PrimTy::Wchar;
+ break;
+ default:
+ assert(false);
+ }
+ break;
+ }
+ }
+ return Ty;
+}
+
+UdtType *Demangler::demangleClassType() {
+ UdtType *UTy = Arena.alloc<UdtType>();
+
+ switch (MangledName.popFront()) {
+ case 'T':
+ UTy->Prim = PrimTy::Union;
+ break;
+ case 'U':
+ UTy->Prim = PrimTy::Struct;
+ break;
+ case 'V':
+ UTy->Prim = PrimTy::Class;
+ break;
+ case 'W':
+ if (MangledName.popFront() != '4') {
+ Error = true;
+ return nullptr;
+ }
+ UTy->Prim = PrimTy::Enum;
+ break;
+ default:
+ assert(false);
+ }
+
+ UTy->UdtName = demangleName();
+ return UTy;
+}
+
+static std::pair<Qualifiers, PointerAffinity>
+demanglePointerCVQualifiers(StringView &MangledName) {
+ 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 && "Ty is not a pointer type!");
+ }
+ return std::make_pair(Q_None, PointerAffinity::Pointer);
+}
+
+// <pointer-type> ::= E? <pointer-cvr-qualifiers> <ext-qualifiers> <type>
+// # the E is required for 64-bit non-static pointers
+PointerType *Demangler::demanglePointerType() {
+ PointerType *Pointer = Arena.alloc<PointerType>();
+
+ PointerAffinity Affinity;
+ std::tie(Pointer->Quals, Affinity) = demanglePointerCVQualifiers(MangledName);
+
+ Pointer->Prim =
+ (Affinity == PointerAffinity::Pointer) ? PrimTy::Ptr : PrimTy::Ref;
+ if (MangledName.consumeFront("6")) {
+ Pointer->Pointee = demangleFunctionType(false, true);
+ return Pointer;
+ }
+
+ Qualifiers ExtQuals = demanglePointerExtQualifiers();
+ Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals);
+
+ Pointer->Pointee = demangleType(QualifierMangleMode::Mangle);
+ return Pointer;
+}
+
+MemberPointerType *Demangler::demangleMemberPointerType() {
+ MemberPointerType *Pointer = Arena.alloc<MemberPointerType>();
+ Pointer->Prim = PrimTy::MemberPtr;
+
+ PointerAffinity Affinity;
+ std::tie(Pointer->Quals, Affinity) = demanglePointerCVQualifiers(MangledName);
+ assert(Affinity == PointerAffinity::Pointer);
+
+ Qualifiers ExtQuals = demanglePointerExtQualifiers();
+ Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals);
+
+ if (MangledName.consumeFront("8")) {
+ Pointer->MemberName = demangleName();
+ Pointer->Pointee = demangleFunctionType(true, true);
+ } else {
+ Qualifiers PointeeQuals = Q_None;
+ bool IsMember = false;
+ std::tie(PointeeQuals, IsMember) = demangleQualifiers();
+ assert(IsMember);
+ Pointer->MemberName = demangleName();
+
+ Pointer->Pointee = demangleType(QualifierMangleMode::Drop);
+ Pointer->Pointee->Quals = PointeeQuals;
+ }
+
+ return Pointer;
+}
+
+Qualifiers Demangler::demanglePointerExtQualifiers() {
+ Qualifiers Quals = Q_None;
+ if (MangledName.consumeFront('E'))
+ Quals = Qualifiers(Quals | Q_Pointer64);
+ if (MangledName.consumeFront('I'))
+ Quals = Qualifiers(Quals | Q_Restrict);
+ if (MangledName.consumeFront('F'))
+ Quals = Qualifiers(Quals | Q_Unaligned);
+
+ return Quals;
+}
+
+ArrayType *Demangler::demangleArrayType() {
+ assert(MangledName.front() == 'Y');
+ MangledName.popFront();
+
+ int Dimension = demangleNumber();
+ if (Dimension <= 0) {
+ Error = true;
+ return nullptr;
+ }
+
+ ArrayType *ATy = Arena.alloc<ArrayType>();
+ ArrayType *Dim = ATy;
+ for (int I = 0; I < Dimension; ++I) {
+ Dim->Prim = PrimTy::Array;
+ Dim->ArrayDimension = demangleNumber();
+ Dim->NextDimension = Arena.alloc<ArrayType>();
+ Dim = Dim->NextDimension;
+ }
+
+ if (MangledName.consumeFront("$$C")) {
+ if (MangledName.consumeFront("B"))
+ ATy->Quals = Q_Const;
+ else if (MangledName.consumeFront("C") || MangledName.consumeFront("D"))
+ ATy->Quals = Qualifiers(Q_Const | Q_Volatile);
+ else if (!MangledName.consumeFront("A"))
+ Error = true;
+ }
+
+ ATy->ElementType = demangleType(QualifierMangleMode::Drop);
+ Dim->ElementType = ATy->ElementType;
+ return ATy;
+}
+
+// Reads a function or a template parameters.
+ParamList Demangler::demangleFunctionParameterList() {
+ // Empty parameter list.
+ if (MangledName.consumeFront('X'))
+ return {};
+
+ ParamList *Head;
+ ParamList **Current = &Head;
+ while (!Error && !MangledName.startsWith('@') &&
+ !MangledName.startsWith('Z')) {
+
+ if (startsWithDigit(MangledName)) {
+ size_t N = MangledName[0] - '0';
+ if (N >= FunctionParamBackRefCount) {
+ Error = true;
+ return {};
+ }
+ MangledName = MangledName.dropFront();
+
+ *Current = Arena.alloc<ParamList>();
+ (*Current)->Current = FunctionParamBackRefs[N]->clone(Arena);
+ Current = &(*Current)->Next;
+ continue;
+ }
+
+ size_t OldSize = MangledName.size();
+
+ *Current = Arena.alloc<ParamList>();
+ (*Current)->Current = demangleType(QualifierMangleMode::Drop);
+
+ size_t CharsConsumed = OldSize - MangledName.size();
+ assert(CharsConsumed != 0);
+
+ // Single-letter types are ignored for backreferences because memorizing
+ // them doesn't save anything.
+ if (FunctionParamBackRefCount <= 9 && CharsConsumed > 1)
+ FunctionParamBackRefs[FunctionParamBackRefCount++] = (*Current)->Current;
+
+ Current = &(*Current)->Next;
+ }
+
+ if (Error)
+ return {};
+
+ // A non-empty parameter list is terminated by either 'Z' (variadic) parameter
+ // list or '@' (non variadic). Careful not to consume "@Z", as in that case
+ // the following Z could be a throw specifier.
+ if (MangledName.consumeFront('@'))
+ return *Head;
+
+ if (MangledName.consumeFront('Z')) {
+ Head->IsVariadic = true;
+ return *Head;
+ }
+
+ Error = true;
+ return {};
+}
+
+ParamList Demangler::demangleTemplateParameterList() {
+ ParamList *Head;
+ ParamList **Current = &Head;
+ while (!Error && !MangledName.startsWith('@')) {
+
+ // Template parameter lists don't participate in back-referencing.
+ *Current = Arena.alloc<ParamList>();
+ (*Current)->Current = demangleType(QualifierMangleMode::Drop);
+
+ Current = &(*Current)->Next;
+ }
+
+ if (Error)
+ return {};
+
+ // Template parameter lists cannot be variadic, so it can only be terminated
+ // by @.
+ if (MangledName.consumeFront('@'))
+ return *Head;
+ Error = true;
+ return {};
+}
+
+void Demangler::output() {
+ // Converts an AST to a string.
+ //
+ // Converting an AST representing a C++ type to a string is tricky due
+ // to the bad grammar of the C++ declaration inherited from C. You have
+ // to construct a string from inside to outside. For example, if a type
+ // X is a pointer to a function returning int, the order you create a
+ // string becomes something like this:
+ //
+ // (1) X is a pointer: *X
+ // (2) (1) is a function returning int: int (*X)()
+ //
+ // So you cannot construct a result just by appending strings to a result.
+ //
+ // To deal with this, we split the function into two. outputPre() writes
+ // the "first half" of type declaration, and outputPost() writes the
+ // "second half". For example, outputPre() writes a return type for a
+ // function and outputPost() writes an parameter list.
+ Type::outputPre(OS, *SymbolType);
+ outputName(OS, SymbolName);
+ Type::outputPost(OS, *SymbolType);
+
+ // Null terminate the buffer.
+ OS << '\0';
+}
+
+char *llvm::microsoftDemangle(const char *MangledName, char *Buf, size_t *N,
+ int *Status) {
+ OutputStream OS = OutputStream::create(Buf, N, 1024);
+
+ Demangler D(OS, StringView(MangledName));
+ D.parse();
+
+ if (D.Error)
+ *Status = llvm::demangle_invalid_mangled_name;
+ else
+ *Status = llvm::demangle_success;
+
+ D.output();
+ return OS.getBuffer();
+}