[llvm] r337584 - Add a Microsoft Demangler.

Zachary Turner via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 20 11:14:33 PDT 2018


Yea, you are right.  I'll fix it for now but eventually I want to migrate
to the one you added to the Itanium Demangler.

On Fri, Jul 20, 2018 at 10:48 AM Erik Pilkington <erik.pilkington at gmail.com>
wrote:

>
>
> On 7/20/18 10:27 AM, Zachary Turner via llvm-commits wrote:
> > Author: zturner
> > Date: Fri Jul 20 10:27:48 2018
> > New Revision: 337584
> >
> > URL: http://llvm.org/viewvc/llvm-project?rev=337584&view=rev
> > Log:
> > Add a Microsoft Demangler.
> >
> > This adds initial support for a demangling library (LLVMDemangle)
> > and tool (llvm-undname) for demangling Microsoft names.  This
> > doesn't cover 100% of cases and there are some known limitations
> > which I intend to address in followup patches, at least until such
> > time that we have (near) 100% test coverage matching up with all
> > of the test cases in clang/test/CodeGenCXX/mangle-ms-*.
> >
> > Differential Revision: https://reviews.llvm.org/D49552
> >
> > Added:
> >      llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp
> >      llvm/trunk/test/Demangle/ms-basic.test
> >      llvm/trunk/test/Demangle/ms-mangle.test
> >      llvm/trunk/test/Demangle/ms-windows.test
> >      llvm/trunk/tools/llvm-undname/
> >      llvm/trunk/tools/llvm-undname/CMakeLists.txt
> >      llvm/trunk/tools/llvm-undname/LLVMBuild.txt
> >      llvm/trunk/tools/llvm-undname/llvm-undname.cpp
> > Modified:
> >      llvm/trunk/include/llvm/Demangle/Demangle.h
> >      llvm/trunk/lib/Demangle/CMakeLists.txt
> >      llvm/trunk/tools/LLVMBuild.txt
> >
> > Modified: llvm/trunk/include/llvm/Demangle/Demangle.h
> > URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Demangle/Demangle.h?rev=337584&r1=337583&r2=337584&view=diff
> >
> ==============================================================================
> > --- llvm/trunk/include/llvm/Demangle/Demangle.h (original)
> > +++ llvm/trunk/include/llvm/Demangle/Demangle.h Fri Jul 20 10:27:48 2018
> > @@ -16,7 +16,7 @@ namespace llvm {
> >   /// The mangled_name is demangled into buf and returned. If the buffer
> is not
> >   /// large enough, realloc is used to expand it.
> >   ///
> > -/// The *status will be set to a value from the enumeration
> > +/// The *status will be set to a value from the following enumeration
> >   enum : int {
> >     demangle_unknown_error = -4,
> >     demangle_invalid_args = -3,
> > @@ -27,6 +27,8 @@ enum : int {
> >
> >   char *itaniumDemangle(const char *mangled_name, char *buf, size_t *n,
> >                         int *status);
> > +char *microsoftDemangle(const char *mangled_name, char *buf, size_t *n,
> > +                        int *status);
> >
> >   /// "Partial" demangler. This supports demangling a string into an AST
> >   /// (typically an intermediate stage in itaniumDemangle) and querying
> certain
> >
> > Modified: llvm/trunk/lib/Demangle/CMakeLists.txt
> > URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Demangle/CMakeLists.txt?rev=337584&r1=337583&r2=337584&view=diff
> >
> ==============================================================================
> > --- llvm/trunk/lib/Demangle/CMakeLists.txt (original)
> > +++ llvm/trunk/lib/Demangle/CMakeLists.txt Fri Jul 20 10:27:48 2018
> > @@ -1,6 +1,7 @@
> >   add_llvm_library(LLVMDemangle
> >     ItaniumDemangle.cpp
> > -
> > +  MicrosoftDemangle.cpp
> > +
> >     ADDITIONAL_HEADER_DIRS
> >     "${LLVM_MAIN_INCLUDE_DIR}/llvm/Demangle"
> >   )
> >
> > Added: llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp?rev=337584&view=auto
> >
> ==============================================================================
> > --- llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp (added)
> > +++ llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp Fri Jul 20 10:27:48
> 2018
> > @@ -0,0 +1,1533 @@
> > +//===- 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>
> > +
> > +// 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;
> > +      Head = Head->Next;
> > +    }
> > +  }
> > +
> > +  void *alloc(size_t Size) {
> > +    assert(Size < Unit);
> > +    assert(Head && Head->Buf);
> > +
> > +    uint8_t *P = Head->Buf + Head->Used;
> > +    Head->Used += Size;
> Don't you need to handle alignment here?
> > +    if (Head->Used < Unit)
> > +      return P;
> > +
> > +    AllocatorNode *NewHead = new AllocatorNode;
> > +    NewHead->Buf = new uint8_t[ArenaAllocator::Unit];
> > +    NewHead->Next = Head;
> > +    Head = NewHead;
> > +    NewHead->Used = Size;
> > +    return NewHead->Buf;
> > +  }
> > +
> > +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 << " ";
> > +}
> > +
> > +void *operator new(size_t Size, ArenaAllocator &A) { return
> A.alloc(Size); }
> > +
> > +// 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 QualifierMangleLocation { Member, NonMember, Detect };
> > +
> > +// 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,
> > +  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,
> > +  FFar = 1 << 6,
> > +};
> > +
> > +namespace {
> > +
> > +struct Type;
> > +
> > +// Represents a list of parameters (template params or function
> arguments.
> > +// It's represented as a linked list.
> > +struct ParamList {
> > +  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);
> > +  void outputPost(OutputStream &OS) override;
> > +
> > +  bool isMemberPointer() const { return false; }
> > +
> > +  // 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);
> > +  void outputPost(OutputStream &OS);
> > +
> > +  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 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) {
> > +  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 new (Arena) 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";
> > +  }
> > +}
> > +
> > +// 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 new (Arena) PointerType(*this);
> > +}
> > +
> > +void PointerType::outputPre(OutputStream &OS) {
> > +  Type::outputPre(OS, *Pointee);
> > +
> > +  outputSpaceIfNecessary(OS);
> > +
> > +  if (Quals & Q_Unaligned)
> > +    OS << "__unaligned ";
> > +
> > +  // "[]" 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 (Prim == PrimTy::Ptr)
> > +    OS << "*";
> > +  else
> > +    OS << "&";
> > +
> > +  // if (Ty.Quals & Q_Pointer64)
> > +  //  OS << " __ptr64";
> > +  if (Quals & Q_Restrict)
> > +    OS << " __restrict";
> > +}
> > +
> > +void PointerType::outputPost(OutputStream &OS) {
> > +  if (Pointee->Prim == PrimTy::Function || Pointee->Prim ==
> PrimTy::Array)
> > +    OS << ")";
> > +
> > +  Type::outputPost(OS, *Pointee);
> > +}
> > +
> > +Type *FunctionType::clone(ArenaAllocator &Arena) const {
> > +  return new (Arena) FunctionType(*this);
> > +}
> > +
> > +void FunctionType::outputPre(OutputStream &OS) {
> > +  if (!(FunctionClass & Global)) {
> > +    if (FunctionClass & Static)
> > +      OS << "static ";
> > +  }
> > +
> > +  if (ReturnType)
> > +    Type::outputPre(OS, *ReturnType);
> > +
> > +  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";
> > +  return;
> > +}
> > +
> > +Type *UdtType::clone(ArenaAllocator &Arena) const {
> > +  return new (Arena) 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 new (Arena) 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();
> > +
> > +  ArrayType *demangleArrayType();
> > +
> > +  ParamList demangleParameterList();
> > +
> > +  int demangleNumber();
> > +  void demangleNamePiece(Name &Node, bool IsHead);
> > +
> > +  StringView demangleString(bool memorize);
> > +  void memorizeString(StringView s);
> > +  Name *demangleName();
> > +  void demangleOperator(Name *);
> > +  StringView demangleOperatorName();
> > +  int demangleFunctionClass();
> > +  CallingConv demangleCallingConvention();
> > +  StorageClass demangleVariableStorageClass();
> > +  ReferenceKind demangleReferenceKind();
> > +
> > +  Qualifiers demangleFunctionQualifiers();
> > +  Qualifiers demangleVariablQ_ifiers();
> > +  Qualifiers demangleReturnTypQ_ifiers();
> > +
> > +  Qualifiers demangleQualifiers(
> > +      QualifierMangleLocation Location =
> QualifierMangleLocation::Detect);
> > +
> > +  // Mangled symbol. demangle* functions shorten this string
> > +  // as they parse it.
> > +  StringView MangledName;
> > +
> > +  // A parsed mangled symbol.
> > +  Type *SymbolType;
> > +
> > +  // The main symbol name. (e.g. "ns::foo" in "int ns::foo()".)
> > +  Name *SymbolName = nullptr;
> > +
> > +  // Memory allocator.
> > +  ArenaAllocator Arena;
> > +
> > +  // 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;
> > +
> > +  // The result is written to this stream.
> > +  OutputStream OS;
> > +};
> > +} // namespace
> > +
> > +// Parser entry point.
> > +void Demangler::parse() {
> > +  // MSVC-style mangled symbols must start with '?'.
> > +  if (!MangledName.consumeFront("?")) {
> > +    SymbolName = new (Arena) Name;
> > +    SymbolName->Str = MangledName;
> > +    SymbolType = new (Arena) 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: {
> > +    Qualifiers ExtraChildQuals = Q_None;
> > +    Ty->Quals = Qualifiers(Ty->Quals | demanglePointerExtQualifiers());
> > +
> > +    PointerType *PTy = static_cast<PointerType *>(Ty);
> > +    QualifierMangleLocation Location = PTy->isMemberPointer()
> > +                                           ?
> QualifierMangleLocation::Member
> > +                                           :
> QualifierMangleLocation::NonMember;
> > +
> > +    ExtraChildQuals = demangleQualifiers(Location);
> > +
> > +    if (PTy->isMemberPointer()) {
> > +      Name *BackRefName = demangleName();
> > +      (void)BackRefName;
> > +    }
> > +
> > +    PTy->Pointee->Quals = Qualifiers(PTy->Pointee->Quals |
> ExtraChildQuals);
> > +    break;
> > +  }
> > +  default:
> > +    Ty->Quals = demangleQualifiers();
> > +    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 = demangleParameterList();
> > +    if (!MangledName.consumeFront('@')) {
> > +      Error = true;
> > +      return;
> > +    }
> > +  } 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 at B@C@@ which represents C::B::A.
> > +Name *Demangler::demangleName() {
> > +  Name *Head = nullptr;
> > +
> > +  while (!MangledName.consumeFront("@")) {
> > +    Name *Elem = new (Arena) Name;
> > +
> > +    assert(!Error);
> > +    demangleNamePiece(*Elem, Head == nullptr);
> > +    if (Error)
> > +      return nullptr;
> > +
> > +    Elem->Next = Head;
> > +    Head = Elem;
> > +  }
> > +
> > +  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 "";
> > +}
> > +
> > +int Demangler::demangleFunctionClass() {
> > +  SwapAndRestore<StringView> RestoreOnError(MangledName, MangledName);
> > +  RestoreOnError.shouldRestore(false);
> > +
> > +  switch (MangledName.popFront()) {
> > +  case 'A':
> > +    return Private;
> > +  case 'B':
> > +    return Private | FFar;
> > +  case 'C':
> > +    return Private | Static;
> > +  case 'D':
> > +    return Private | Static;
> > +  case 'E':
> > +    return Private | Virtual;
> > +  case 'F':
> > +    return Private | Virtual;
> > +  case 'I':
> > +    return Protected;
> > +  case 'J':
> > +    return Protected | FFar;
> > +  case 'K':
> > +    return Protected | Static;
> > +  case 'L':
> > +    return Protected | Static | FFar;
> > +  case 'M':
> > +    return Protected | Virtual;
> > +  case 'N':
> > +    return Protected | Virtual | FFar;
> > +  case 'Q':
> > +    return Public;
> > +  case 'R':
> > +    return Public | FFar;
> > +  case 'S':
> > +    return Public | Static;
> > +  case 'T':
> > +    return Public | Static | FFar;
> > +  case 'U':
> > +    return Public | Virtual;
> > +  case 'V':
> > +    return Public | Virtual | FFar;
> > +  case 'Y':
> > +    return Global;
> > +  case 'Z':
> > +    return Global | FFar;
> > +  }
> > +
> > +  Error = true;
> > +  RestoreOnError.shouldRestore(true);
> > +  return 0;
> > +}
> > +
> > +Qualifiers Demangler::demangleFunctionQualifiers() {
> > +  SwapAndRestore<StringView> RestoreOnError(MangledName, MangledName);
> > +  RestoreOnError.shouldRestore(false);
> > +
> > +  switch (MangledName.popFront()) {
> > +  case 'A':
> > +    return Q_None;
> > +  case 'B':
> > +    return Q_Const;
> > +  case 'C':
> > +    return Q_Volatile;
> > +  case 'D':
> > +    return Qualifiers(Q_Const | Q_Volatile);
> > +  }
> > +
> > +  Error = true;
> > +  RestoreOnError.shouldRestore(true);
> > +  return Q_None;
> > +}
> > +
> > +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;
> > +}
> > +
> > +Qualifiers Demangler::demangleVariablQ_ifiers() {
> > +  SwapAndRestore<StringView> RestoreOnError(MangledName, MangledName);
> > +  RestoreOnError.shouldRestore(false);
> > +
> > +  switch (MangledName.popFront()) {
> > +  case 'A':
> > +    return Q_None;
> > +  case 'B':
> > +    return Q_Const;
> > +  case 'C':
> > +    return Q_Volatile;
> > +  case 'D':
> > +    return Qualifiers(Q_Const | Q_Volatile);
> > +  case 'E':
> > +    return Q_Far;
> > +  case 'F':
> > +    return Qualifiers(Q_Const | Q_Far);
> > +  case 'G':
> > +    return Qualifiers(Q_Volatile | Q_Far);
> > +  case 'H':
> > +    return Qualifiers(Q_Const | Q_Volatile | Q_Far);
> > +  }
> > +
> > +  Error = true;
> > +  RestoreOnError.shouldRestore(true);
> > +  return Q_None;
> > +}
> > +
> > +Qualifiers Demangler::demangleReturnTypQ_ifiers() {
> > +  if (!MangledName.consumeFront("?"))
> > +    return Q_None;
> > +
> > +  SwapAndRestore<StringView> RestoreOnError(MangledName, MangledName);
> > +  RestoreOnError.shouldRestore(false);
> > +
> > +  switch (MangledName.popFront()) {
> > +  case 'A':
> > +    return Q_None;
> > +  case 'B':
> > +    return Q_Const;
> > +  case 'C':
> > +    return Q_Volatile;
> > +  case 'D':
> > +    return Qualifiers(Q_Const | Q_Volatile);
> > +  }
> > +
> > +  Error = true;
> > +  RestoreOnError.shouldRestore(true);
> > +  return Q_None;
> > +}
> > +
> > +Qualifiers Demangler::demangleQualifiers(QualifierMangleLocation
> Location) {
> > +  if (Location == QualifierMangleLocation::Detect) {
> > +    switch (MangledName.front()) {
> > +    case 'Q':
> > +    case 'R':
> > +    case 'S':
> > +    case 'T':
> > +      Location = QualifierMangleLocation::Member;
> > +      break;
> > +    case 'A':
> > +    case 'B':
> > +    case 'C':
> > +    case 'D':
> > +      Location = QualifierMangleLocation::NonMember;
> > +      break;
> > +    default:
> > +      Error = true;
> > +      return Q_None;
> > +    }
> > +  }
> > +
> > +  if (Location == QualifierMangleLocation::Member) {
> > +    switch (MangledName.popFront()) {
> > +    // Member qualifiers
> > +    case 'Q':
> > +      return Q_None;
> > +    case 'R':
> > +      return Q_Const;
> > +    case 'S':
> > +      return Q_Volatile;
> > +    case 'T':
> > +      return Qualifiers(Q_Const | Q_Volatile);
> > +    }
> > +  } else {
> > +    switch (MangledName.popFront()) {
> > +    // Non-Member qualifiers
> > +    case 'A':
> > +      return Q_None;
> > +    case 'B':
> > +      return Q_Const;
> > +    case 'C':
> > +      return Q_Volatile;
> > +    case 'D':
> > +      return Qualifiers(Q_Const | Q_Volatile);
> > +    }
> > +  }
> > +  Error = true;
> > +  return Q_None;
> > +}
> > +
> > +// <variable-type> ::= <type> <cvr-qualifiers>
> > +//                 ::= <type> <pointee-cvr-qualifiers> # pointers,
> references
> > +Type *Demangler::demangleType(QualifierMangleMode QMM) {
> > +  Qualifiers Quals = Q_None;
> > +  if (QMM == QualifierMangleMode::Mangle)
> > +    Quals = Qualifiers(Quals | demangleQualifiers());
> > +  else if (QMM == QualifierMangleMode::Result) {
> > +    if (MangledName.consumeFront('?'))
> > +      Quals = Qualifiers(Quals | demangleQualifiers());
> > +  }
> > +
> > +  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
> > +    Ty = demanglePointerType();
> > +    break;
> > +  case 'Y':
> > +    Ty = demangleArrayType();
> > +    break;
> > +  default:
> > +    Ty = demangleBasicType();
> > +    break;
> > +  }
> > +  Ty->Quals = Qualifiers(Ty->Quals | Quals);
> > +  return Ty;
> > +}
> > +
> > +static bool functionHasThisPtr(const FunctionType &Ty) {
> > +  assert(Ty.Prim == PrimTy::Function);
> > +  if (Ty.FunctionClass & Global)
> > +    return false;
> > +  if (Ty.FunctionClass & Static)
> > +    return false;
> > +  return true;
> > +}
> > +
> > +ReferenceKind Demangler::demangleReferenceKind() {
> > +  if (MangledName.consumeFront('G'))
> > +    return ReferenceKind::LValueRef;
> > +  else if (MangledName.consumeFront('H'))
> > +    return ReferenceKind::RValueRef;
> > +  return ReferenceKind::None;
> > +}
> > +
> > +Type *Demangler::demangleFunctionEncoding() {
> > +  FunctionType *FTy = new (Arena) FunctionType;
> > +
> > +  FTy->Prim = PrimTy::Function;
> > +  FTy->FunctionClass = (FuncClass)demangleFunctionClass();
> > +  if (functionHasThisPtr(*FTy)) {
> > +    FTy->Quals = demanglePointerExtQualifiers();
> > +    FTy->RefKind = demangleReferenceKind();
> > +    FTy->Quals = Qualifiers(FTy->Quals | demangleQualifiers());
> > +  }
> > +
> > +  // 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 = demangleParameterList();
> > +
> > +  return FTy;
> > +}
> > +
> > +// Reads a primitive type.
> > +Type *Demangler::demangleBasicType() {
> > +  Type *Ty = new (Arena) 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 '_': {
> > +    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;
> > +    }
> > +    break;
> > +  }
> > +  }
> > +  return Ty;
> > +}
> > +
> > +UdtType *Demangler::demangleClassType() {
> > +  UdtType *UTy = new (Arena) 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;
> > +}
> > +
> > +// <pointer-type> ::= E? <pointer-cvr-qualifiers> <ext-qualifiers>
> <type>
> > +//                       # the E is required for 64-bit non-static
> pointers
> > +PointerType *Demangler::demanglePointerType() {
> > +  PointerType *Pointer = new (Arena) PointerType;
> > +
> > +  Pointer->Quals = Q_None;
> > +  switch (MangledName.popFront()) {
> > +  case 'A':
> > +    Pointer->Prim = PrimTy::Ref;
> > +    break;
> > +  case 'P':
> > +    Pointer->Prim = PrimTy::Ptr;
> > +    break;
> > +  case 'Q':
> > +    Pointer->Prim = PrimTy::Ptr;
> > +    Pointer->Quals = Q_Const;
> > +    break;
> > +  case 'R':
> > +    Pointer->Quals = Q_Volatile;
> > +    Pointer->Prim = PrimTy::Ptr;
> > +    break;
> > +  case 'S':
> > +    Pointer->Quals = Qualifiers(Q_Const | Q_Volatile);
> > +    Pointer->Prim = PrimTy::Ptr;
> > +    break;
> > +  default:
> > +    assert(false && "Ty is not a pointer type!");
> > +  }
> > +
> > +  if (MangledName.consumeFront("6")) {
> > +    FunctionType *FTy = new (Arena) FunctionType;
> > +    FTy->Prim = PrimTy::Function;
> > +    FTy->CallConvention = demangleCallingConvention();
> > +
> > +    FTy->ReturnType = demangleType(QualifierMangleMode::Drop);
> > +    FTy->Params = demangleParameterList();
> > +
> > +    if (!MangledName.consumeFront("@Z"))
> > +      MangledName.consumeFront("Z");
> > +
> > +    Pointer->Pointee = FTy;
> > +    return Pointer;
> > +  }
> > +
> > +  Qualifiers ExtQuals = demanglePointerExtQualifiers();
> > +  Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals);
> > +
> > +  Pointer->Pointee = demangleType(QualifierMangleMode::Mangle);
> > +  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 = new (Arena) ArrayType;
> > +  ArrayType *Dim = ATy;
> > +  for (int I = 0; I < Dimension; ++I) {
> > +    Dim->Prim = PrimTy::Array;
> > +    Dim->ArrayDimension = demangleNumber();
> > +    Dim->NextDimension = new (Arena) 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::demangleParameterList() {
> > +  // Within the same parameter list, you can backreference the first 10
> types.
> > +  Type *BackRef[10];
> > +  int Idx = 0;
> > +
> > +  ParamList *Head;
> > +  ParamList **Current = &Head;
> > +  while (!Error && !MangledName.startsWith('@') &&
> > +         !MangledName.startsWith('Z')) {
> > +    if (startsWithDigit(MangledName)) {
> > +      int N = MangledName[0] - '0';
> > +      if (N >= Idx) {
> > +        Error = true;
> > +        return {};
> > +      }
> > +      MangledName = MangledName.dropFront();
> > +
> > +      *Current = new (Arena) ParamList;
> > +      (*Current)->Current = BackRef[N]->clone(Arena);
> > +      Current = &(*Current)->Next;
> > +      continue;
> > +    }
> > +
> > +    size_t ArrayDimension = MangledName.size();
> > +
> > +    *Current = new (Arena) ParamList;
> > +    (*Current)->Current = demangleType(QualifierMangleMode::Drop);
> > +
> > +    // Single-letter types are ignored for backreferences because
> > +    // memorizing them doesn't save anything.
> > +    if (Idx <= 9 && ArrayDimension - MangledName.size() > 1)
> > +      BackRef[Idx++] = (*Current)->Current;
> > +    Current = &(*Current)->Next;
> > +  }
> > +
> > +  return *Head;
> > +}
> > +
> > +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();
> > +}
> >
> > Added: llvm/trunk/test/Demangle/ms-basic.test
> > URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Demangle/ms-basic.test?rev=337584&view=auto
> >
> ==============================================================================
> > --- llvm/trunk/test/Demangle/ms-basic.test (added)
> > +++ llvm/trunk/test/Demangle/ms-basic.test Fri Jul 20 10:27:48 2018
> > @@ -0,0 +1,230 @@
> > +; RUN: llvm-undname < %s | FileCheck %s
> > +
> > +; CHECK-NOT: Invalid mangled name
> > +
> > +?x@@3HA
> > +; CHECK: int x
> > +
> > +?x@@3PEAHEA
> > +; CHECK: int *x
> > +
> > +?x@@3PEAPEAHEA
> > +; CHECK: int **x
> > +
> > +?x@@3PEAY02HEA
> > +; CHECK: int (*x)[3]
> > +
> > +?x@@3PEAY124HEA
> > +; CHECK: int (*x)[3][5]
> > +
> > +?x@@3PEAY02$$CBHEA
> > +; CHECK: int const (*x)[3]
> > +
> > +?x@@3PEAEEA
> > +; CHECK: unsigned char *x
> > +
> > +?x@@3PEAY1NKM at 5HEA
> > +; CHECK: int (*x)[3500][6]
> > +
> > +?x@@YAXMH at Z
> > +; CHECK: void __cdecl x(float, int)
> > +
> > +?x@@3P6AHMNH at ZEA
> > +; CHECK: int __cdecl (*x)(float, double, int)
> > +
> > +?x@@3P6AHP6AHM at ZN@ZEA
> > +; CHECK: int __cdecl (*x)(int __cdecl (*)(float), double)
> > +
> > +?x@@3P6AHP6AHM at Z0@ZEA
> > +; CHECK: int __cdecl (*x)(int __cdecl (*)(float), int __cdecl
> (*)(float))
> > +
> > +?x at ns@@3HA
> > +; CHECK: int ns::x
> > +
> > +; Microsoft's undname doesn't handle Q correctly or the multiple
> occurrences
> > +; of the const modifier.  So the results here differ, but ours are
> correct.
> > +?x@@3PEAHEA
> > +; CHECK: int *x
> > +
> > +?x@@3PEBHEB
> > +; CHECK: int const *x
> > +
> > +?x@@3QEAHEA
> > +; CHECK: int *const x
> > +
> > +?x@@3QEBHEB
> > +; CHECK: int const *const x
> > +
> > +
> > +?x@@3AEBHEB
> > +; CHECK: int const &x
> > +
> > +?x@@3PEAUty@@EA
> > +; CHECK: struct ty *x
> > +
> > +?x@@3PEATty@@EA
> > +; CHECK: union ty *x
> > +
> > +?x@@3PEAUty@@EA
> > +; CHECK: struct ty *x
> > +
> > +?x@@3PEAW4ty@@EA
> > +; CHECK: enum ty *x
> > +
> > +?x@@3PEAVty@@EA
> > +; CHECK: class ty *x
> > +
> > +?x@@3PEAV?$tmpl at H@@EA
> > +; CHECK: class tmpl<int> *x
> > +
> > +?x@@3PEAU?$tmpl at H@@EA
> > +; CHECK: struct tmpl<int> *x
> > +
> > +?x@@3PEAT?$tmpl at H@@EA
> > +; CHECK: union tmpl<int> *x
> > +
> > +?instance@@3Vklass@@A
> > +; CHECK: class klass instance
> > +
> > +?instance$initializer$@@3P6AXXZEA
> > +; CHECK: void __cdecl (*instance$initializer$)(void)
> > +
> > +??0klass@@QEAA at XZ
> > +; CHECK: __cdecl klass::klass(void)
> > +
> > +??1klass@@QEAA at XZ
> > +; CHECK: __cdecl klass::~klass(void)
> > +
> > +?x@@YAHPEAVklass@@AEAV1@@Z
> > +; CHECK: int __cdecl x(class klass *, class klass &)
> > +
> > +?x at ns@@3PEAV?$klass at HH@1 at EA
> > +; CHECK: class ns::klass<int, int> *ns::x
> > +
> > +?fn@?$klass at H@ns@@QEBAIXZ
> > +; CHECK: unsigned int __cdecl ns::klass<int>::fn(void) const
> > +
> > +
> > +??4klass@@QEAAAEBV0 at AEBV0@@Z
> > +; CHECK: class klass const &__cdecl klass::operator=(class klass const
> &)
> > +
> > +??7klass@@QEAA_NXZ
> > +; CHECK: bool __cdecl klass::operator!(void)
> > +
> > +??8klass@@QEAA_NAEBV0@@Z
> > +; CHECK: bool __cdecl klass::operator==(class klass const &)
> > +
> > +??9klass@@QEAA_NAEBV0@@Z
> > +; CHECK: bool __cdecl klass::operator!=(class klass const &)
> > +
> > +??Aklass@@QEAAH_K at Z
> > +; CHECK: int __cdecl klass::operator[](unsigned __int64)
> > +
> > +??Cklass@@QEAAHXZ
> > +; CHECK: int __cdecl klass::operator->(void)
> > +
> > +??Dklass@@QEAAHXZ
> > +; CHECK: int __cdecl klass::operator*(void)
> > +
> > +??Eklass@@QEAAHXZ
> > +; CHECK: int __cdecl klass::operator++(void)
> > +
> > +??Eklass@@QEAAHH at Z
> > +; CHECK: int __cdecl klass::operator++(int)
> > +
> > +??Fklass@@QEAAHXZ
> > +; CHECK: int __cdecl klass::operator--(void)
> > +
> > +??Fklass@@QEAAHH at Z
> > +; CHECK: int __cdecl klass::operator--(int)
> > +
> > +??Hklass@@QEAAHH at Z
> > +; CHECK: int __cdecl klass::operator+(int)
> > +
> > +??Gklass@@QEAAHH at Z
> > +; CHECK: int __cdecl klass::operator-(int)
> > +
> > +??Iklass@@QEAAHH at Z
> > +; CHECK: int __cdecl klass::operator&(int)
> > +
> > +??Jklass@@QEAAHH at Z
> > +; CHECK: int __cdecl klass::operator->*(int)
> > +
> > +??Kklass@@QEAAHH at Z
> > +; CHECK: int __cdecl klass::operator/(int)
> > +
> > +??Mklass@@QEAAHH at Z
> > +; CHECK: int __cdecl klass::operator<(int)
> > +
> > +??Nklass@@QEAAHH at Z
> > +; CHECK: int __cdecl klass::operator<=(int)
> > +
> > +??Oklass@@QEAAHH at Z
> > +; CHECK: int __cdecl klass::operator>(int)
> > +
> > +??Pklass@@QEAAHH at Z
> > +; CHECK: int __cdecl klass::operator>=(int)
> > +
> > +??Qklass@@QEAAHH at Z
> > +; CHECK: int __cdecl klass::operator,(int)
> > +
> > +??Rklass@@QEAAHH at Z
> > +; CHECK: int __cdecl klass::operator()(int)
> > +
> > +??Sklass@@QEAAHXZ
> > +; CHECK: int __cdecl klass::operator~(void)
> > +
> > +??Tklass@@QEAAHH at Z
> > +; CHECK: int __cdecl klass::operator^(int)
> > +
> > +??Uklass@@QEAAHH at Z
> > +; CHECK: int __cdecl klass::operator|(int)
> > +
> > +??Vklass@@QEAAHH at Z
> > +; CHECK: int __cdecl klass::operator&&(int)
> > +
> > +??Wklass@@QEAAHH at Z
> > +; CHECK: int __cdecl klass::operator||(int)
> > +
> > +??Xklass@@QEAAHH at Z
> > +; CHECK: int __cdecl klass::operator*=(int)
> > +
> > +??Yklass@@QEAAHH at Z
> > +; CHECK: int __cdecl klass::operator+=(int)
> > +
> > +??Zklass@@QEAAHH at Z
> > +; CHECK: int __cdecl klass::operator-=(int)
> > +
> > +??_0klass@@QEAAHH at Z
> > +; CHECK: int __cdecl klass::operator/=(int)
> > +
> > +??_1klass@@QEAAHH at Z
> > +; CHECK: int __cdecl klass::operator%=(int)
> > +
> > +??_2klass@@QEAAHH at Z
> > +; CHECK: int __cdecl klass::operator>>=(int)
> > +
> > +??_3klass@@QEAAHH at Z
> > +; CHECK: int __cdecl klass::operator<<=(int)
> > +
> > +??_6klass@@QEAAHH at Z
> > +; CHECK: int __cdecl klass::operator^=(int)
> > +
> > +??6 at YAAEBVklass@@AEBV0 at H@Z
> > +; CHECK: class klass const &__cdecl operator<<(class klass const &, int)
> > +
> > +??5 at YAAEBVklass@@AEBV0 at _K@Z
> > +; CHECK: class klass const &__cdecl operator>>(class klass const &,
> unsigned __int64)
> > +
> > +??2 at YAPEAX_KAEAVklass@@@Z
> > +; CHECK: void *__cdecl operator new(unsigned __int64, class klass &)
> > +
> > +??_U at YAPEAX_KAEAVklass@@@Z
> > +; CHECK: void *__cdecl operator new[](unsigned __int64, class klass &)
> > +
> > +??3 at YAXPEAXAEAVklass@@@Z
> > +; CHECK: void __cdecl operator delete(void *, class klass &)
> > +
> > +??_V at YAXPEAXAEAVklass@@@Z
> > +; CHECK: void __cdecl operator delete[](void *, class klass &)
> > +
> >
> > Added: llvm/trunk/test/Demangle/ms-mangle.test
> > URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Demangle/ms-mangle.test?rev=337584&view=auto
> >
> ==============================================================================
> > --- llvm/trunk/test/Demangle/ms-mangle.test (added)
> > +++ llvm/trunk/test/Demangle/ms-mangle.test Fri Jul 20 10:27:48 2018
> > @@ -0,0 +1,363 @@
> > +; These tests are based on clang/test/CodeGenCXX/mangle-ms.cpp
> > +; RUN: llvm-undname < %s | FileCheck %s
> > +
> > +; CHECK-NOT: Invalid mangled name
> > +
> > +?k@@3PTfoo@@DT1
> > +
> > +
> > +?a@@3HA
> > +; CHECK: int a
> > +
> > +?b at N@@3HA
> > +; CHECK: int N::b
> > +
> > +?anonymous@?A at N@@3HA
> > +; CHECK: int N::`anonymous namespace'::anonymous
> > +
> > +?_c@@YAHXZ
> > +; CHECK: int __cdecl _c(void)
> > +
> > +?d at foo@@0FB
> > +; CHECK: static short const foo::d
> > +
> > +?e at foo@@1JC
> > +; CHECK: static long volatile foo::e
> > +
> > +?f at foo@@2DD
> > +; CHECK: static char const volatile foo::f
> > +
> > +??0foo@@QAE at XZ
> > +; CHECK: __thiscall foo::foo(void)
> > +
> > +??0foo@@QEAA at XZ
> > +; CHECK: __cdecl foo::foo(void)
> > +
> > +??1foo@@QAE at XZ
> > +; CHECK: __thiscall foo::~foo(void)
> > +
> > +??1foo@@QEAA at XZ
> > +; CHECK: __cdecl foo::~foo(void)
> > +
> > +??0foo@@QAE at H@Z
> > +; CHECK: __thiscall foo::foo(int)
> > +
> > +??0foo@@QEAA at H@Z
> > +; CHECK: __cdecl foo::foo(int)
> > +
> > +??0foo@@QAE at PAD@Z
> > +; CHECK: __thiscall foo::foo(char *)
> > +
> > +??0foo@@QEAA at PEAD@Z
> > +; CHECK: __cdecl foo::foo(char *)
> > +
> > +?bar@@YA?AVfoo@@XZ
> > +; CHECK: class foo __cdecl bar(void)
> > +
> > +?bar@@YA?AVfoo@@XZ
> > +; CHECK: class foo __cdecl bar(void)
> > +
> > +??Hfoo@@QAEHH at Z
> > +; CHECK: int __thiscall foo::operator+(int)
> > +
> > +??Hfoo@@QEAAHH at Z
> > +; CHECK: int __cdecl foo::operator+(int)
> > +
> > +?static_method at foo@@SAPAV1 at XZ
> > +; CHECK: static class foo *__cdecl foo::static_method(void)
> > +
> > +?static_method at foo@@SAPEAV1 at XZ
> > +; CHECK: static class foo *__cdecl foo::static_method(void)
> > +
> > +?g at bar@@2HA
> > +; CHECK: static int bar::g
> > +
> > +; undname returns `int *h1`, but it is a bug in their demangler.  Their
> mangler
> > +; correctly mangles `int *h1` as ?h1 at 3PAHA and `int * const h1` as
> ?h1 at 3QAHA
> > +?h1@@3QAHA
> > +; CHECK: int *const h1
> > +
> > +?h2@@3QBHB
> > +; CHECK: int const *const h2
> > +
> > +?h3@@3QIAHIA
> > +; CHECK: int * __restrict const h3
> > +
> > +?h3@@3QEIAHEIA
> > +; CHECK: int * __restrict const h3
> > +
> > +?i@@3PAY0BE at HA
> > +; CHECK: int (*i)[20]
> > +
> > +?FunArr@@3PAY0BE at P6AHHH@ZA
> > +; CHECK: int __cdecl (*(*FunArr)[20])(int, int)
> > +
> > +?j@@3P6GHCE at ZA
> > +; CHECK: int __stdcall (*j)(signed char, unsigned char)
> > +
> > +
> > +; FIXME: We don't handle member pointers yet.
> > +; ?k@@3PTfoo@@DT1
> > +; FIXME: char const volatile foo::*k
> > +
> > +; ?k@@3PETfoo@@DET1
> > +; FIXME: char const volatile foo::*k
> > +
> > +; ?l@@3P8foo@@AEHH at ZQ1
> > +; FIXME: int __thiscall (foo::*l)(int)
> > +
> > +?g_cInt@@3HB
> > +; CHECK: int const g_cInt
> > +
> > +?g_vInt@@3HC
> > +; CHECK: int volatile g_vInt
> > +
> > +?g_cvInt@@3HD
> > +; CHECK: int const volatile g_cvInt
> > +
> > +?beta@@YI_N_J_W at Z
> > +; CHECK: bool __fastcall beta(__int64, wchar_t)
> > +
> > +?beta@@YA_N_J_W at Z
> > +; CHECK: bool __cdecl beta(__int64, wchar_t)
> > +
> > +?alpha@@YGXMN at Z
> > +; CHECK: void __stdcall alpha(float, double)
> > +
> > +?alpha@@YAXMN at Z
> > +; CHECK: void __cdecl alpha(float, double)
> > +
> > +?gamma@@YAXVfoo@@Ubar@@Tbaz@@W4quux@@@Z
> > +; CHECK: void __cdecl gamma(class foo, struct bar, union baz, enum quux)
> > +
> > +?gamma@@YAXVfoo@@Ubar@@Tbaz@@W4quux@@@Z
> > +; CHECK: void __cdecl gamma(class foo, struct bar, union baz, enum quux)
> > +
> > +?delta@@YAXQAHABJ at Z
> > +; CHECK: void __cdecl delta(int *const, long const &)
> > +
> > +?delta@@YAXQEAHAEBJ at Z
> > +; CHECK: void __cdecl delta(int *const, long const &)
> > +
> > +?epsilon@@YAXQAY19BE at H@Z
> > +; CHECK: void __cdecl epsilon(int (*const)[10][20])
> > +
> > +?epsilon@@YAXQEAY19BE at H@Z
> > +; CHECK: void __cdecl epsilon(int (*const)[10][20])
> > +
> > +?zeta@@YAXP6AHHH at Z@Z
> > +; CHECK: void __cdecl zeta(int __cdecl (*)(int, int))
> > +
> > +?zeta@@YAXP6AHHH at Z@Z
> > +; CHECK: void __cdecl zeta(int __cdecl (*)(int, int))
> > +
> > +??2 at YAPAXI@Z
> > +; CHECK: void *__cdecl operator new(unsigned int)
> > +
> > +??3 at YAXPAX@Z
> > +; CHECK: void __cdecl operator delete(void *)
> > +
> > +??_U at YAPAXI@Z
> > +; CHECK: void *__cdecl operator new[](unsigned int)
> > +
> > +??_V at YAXPAX@Z
> > +; CHECK: void __cdecl operator delete[](void *)
> > +
> > +?color1@@3PANA
> > +; CHECK: double *color1
> > +
> > +?color2@@3QBNB
> > +; CHECK: double const *const color2
> > +
> > +; FIXME-EXTRACONST: These tests fails because we print an extra const
> inside the parens.
> > +; ?color3@@3QAY02$$CBNA
> > +; FIXME-EXTRACONST: double const (*color3)[3]
> > +
> > +; ?color4@@3QAY02$$CBNA
> > +; FIXME-EXTRACONST: double const (*color4)[3]
> > +
> > +; FIXME-MEMBERPTR: We don't support member pointers yet.
> > +; ?memptr1@@3RESB@@HES1
> > +; FIXME-MEMBERPTR: volatile int B::*memptr2
> > +
> > +; ?memptr2@@3PESB@@HES1
> > +; FIXME: volatile int B::*memptr2
> > +
> > +; ?memptr3@@3REQB@@HEQ1
> > +; FIXME-MEMBERPTR: int B::* volatile memptr3
> > +
> > +; ?funmemptr1@@3RESB@@R6AHXZES1
> > +; FIXME-MEMBERPTR: int __cdecl (* volatile B::* volatile
> funmemptr1)(void)
> > +
> > +; ?funmemptr2@@3PESB@@R6AHXZES1
> > +; FIXME-MEMBERPTR: int __cdecl (* volatile B::*funmemptr2)(void)
> > +
> > +; ?funmemptr3@@3REQB@@P6AHXZEQ1
> > +; FIXME-MEMBERPTR: int __cdecl (* B::*volatile funmemptr3)(void)
> > +
> > +; ?memptrtofun1@@3R8B@@EAAXXZEQ1
> > +; FIXME-MEMBERPTR: void __cdecl (B::*volatile memptrtofun1)(void)
> > +
> > +; ?memptrtofun2@@3P8B@@EAAXXZEQ1
> > +; FIXME-MEMBERPTR: void __cdecl (B::*memptrtofun2)(void)
> > +
> > +; ?memptrtofun3@@3P8B@@EAAXXZEQ1
> > +; FIXME-MEMBERPTR: void __cdecl (B::*memptrtofun3)(void)
> > +
> > +; ?memptrtofun4@@3R8B@@EAAHXZEQ1
> > +; FIXME-MEMBERPTR: int __cdecl (B::* volatile memptrtofun4)(void)
> > +
> > +; ?memptrtofun5@@3P8B@@EAA?CHXZEQ1
> > +; FIXME-MEMBERPTR: int volatile __cdecl (B::*memptrtofun5)(void)
> > +
> > +; ?memptrtofun6@@3P8B@@EAA?BHXZEQ1
> > +; FIXME-MEMBERPTR: int const __cdecl (B::*memptrtofun6)(void)
> > +
> > +; ?memptrtofun7@@3R8B@@EAAP6AHXZXZEQ1
> > +; FIXME-MEMBERPTR: int __cdecl (*(__cdecl B::*volatile
> memptrtofun7)(void))(void)
> > +
> > +; ?memptrtofun8@@3P8B@@EAAR6AHXZXZEQ1
> > +; FIXME-MEMBERPTR: int __cdecl (*(__cdecl B::*memptrtofun8)(void))(void)
> > +
> > +; ?memptrtofun9@@3P8B@@EAAQ6AHXZXZEQ1
> > +; FIXME-MEMBERPTR: int __cdecl(*(__cdecl B::*memptrtofun9)(void))(void)
> > +
> > +
> > +?fooE@@YA?AW4E@@XZ
> > +; CHECK: enum E __cdecl fooE(void)
> > +
> > +?fooE@@YA?AW4E@@XZ
> > +; CHECK: enum E __cdecl fooE(void)
> > +
> > +?fooX@@YA?AVX@@XZ
> > +; CHECK: class X __cdecl fooX(void)
> > +
> > +?fooX@@YA?AVX@@XZ
> > +; CHECK: class X __cdecl fooX(void)
> > +
> > +?s0 at PR13182@@3PADA
> > +; CHECK: char *PR13182::s0
> > +
> > +?s1 at PR13182@@3PADA
> > +; CHECK: char *PR13182::s1
> > +
> > +?s2 at PR13182@@3QBDB
> > +; CHECK: char const *const PR13182::s2
> > +
> > +?s3 at PR13182@@3QBDB
> > +; CHECK: char const *const PR13182::s3
> > +
> > +?s4 at PR13182@@3RCDC
> > +; CHECK: char volatile *volatile PR13182::s4
> > +
> > +?s5 at PR13182@@3SDDD
> > +; CHECK: char const volatile *const volatile PR13182::s5
> > +
> > +; undname adds an extra const in here, but it seems like their bug.
> > +?s6 at PR13182@@3PBQBDB
> > +; CHECK: char const *const *PR13182::s6
> > +
> > +; FIXME-EXTERNC: We don't properly support static locals in extern c
> functions yet.
> > +; ?local@?1??extern_c_func@@9 at 4HA
> > +; FIXME-EXTERNC: int `extern_c_func'::`2'::local
> > +
> > +; ?local@?1??extern_c_func@@9 at 4HA
> > +; FIXME-EXTERNC: int `extern_c_func'::`2'::local
> > +
> > +??2OverloadedNewDelete@@SAPAXI at Z
> > +; CHECK: static void *__cdecl OverloadedNewDelete::operator
> new(unsigned int)
> > +
> > +
> > +??_UOverloadedNewDelete@@SAPAXI at Z
> > +; CHECK: static void *__cdecl OverloadedNewDelete::operator
> new[](unsigned int)
> > +
> > +??3OverloadedNewDelete@@SAXPAX at Z
> > +; CHECK: static void __cdecl OverloadedNewDelete::operator delete(void
> *)
> > +
> > +
> > +??_VOverloadedNewDelete@@SAXPAX at Z
> > +; CHECK: static void __cdecl OverloadedNewDelete::operator
> delete[](void *)
> > +
> > +??HOverloadedNewDelete@@QAEHH at Z
> > +; CHECK: int __thiscall OverloadedNewDelete::operator+(int)
> > +
> > +??2OverloadedNewDelete@@SAPEAX_K at Z
> > +; CHECK: static void *__cdecl OverloadedNewDelete::operator
> new(unsigned __int64)
> > +
> > +??_UOverloadedNewDelete@@SAPEAX_K at Z
> > +; CHECK: static void *__cdecl OverloadedNewDelete::operator
> new[](unsigned __int64)
> > +
> > +??3OverloadedNewDelete@@SAXPEAX at Z
> > +; CHECK: static void __cdecl OverloadedNewDelete::operator delete(void
> *)
> > +
> > +
> > +??_VOverloadedNewDelete@@SAXPEAX at Z
> > +; CHECK: static void __cdecl OverloadedNewDelete::operator
> delete[](void *)
> > +
> > +??HOverloadedNewDelete@@QEAAHH at Z
> > +; CHECK: int __cdecl OverloadedNewDelete::operator+(int)
> > +
> > +
> > +??2TypedefNewDelete@@SAPAXI at Z
> > +; CHECK: static void *__cdecl TypedefNewDelete::operator new(unsigned
> int)
> > +
> > +
> > +??_UTypedefNewDelete@@SAPAXI at Z
> > +; CHECK: static void *__cdecl TypedefNewDelete::operator new[](unsigned
> int)
> > +
> > +??3TypedefNewDelete@@SAXPAX at Z
> > +; CHECK: static void __cdecl TypedefNewDelete::operator delete(void *)
> > +
> > +??_VTypedefNewDelete@@SAXPAX at Z
> > +; CHECK: static void __cdecl TypedefNewDelete::operator delete[](void *)
> > +
> > +?vector_func@@YQXXZ
> > +; CHECK: void __vectorcall vector_func(void)
> > +
> > +; FIXME-EXTERNC: We don't support extern C funcs currently.
> > +; ??$fn_tmpl@$1?extern_c_func@@YAXXZ@@YAXXZ
> > +; FIXME-EXTERNC: void __cdecl fn_tmpl<&void __cdecl
> extern_c_func(void)>(void)
> > +
> > +; ?overloaded_fn@@$$J0YAXXZ
> > +; FIXME-EXTERNC: extern \"C\" void __cdecl overloaded_fn(void)
> > +
> > +
> > +?f at UnnamedType@@YAXUT2 at S@1@@Z
> > +; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::S::T2)
> > +
> > +?f at UnnamedType@@YAXPAUT4 at S@1@@Z
> > +; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::S::T4 *)
> > +
> > +?f at UnnamedType@@YAXUT4 at S@1@@Z
> > +; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::S::T4)
> > +
> > +?f at UnnamedType@@YAXUT5 at S@1@@Z
> > +; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::S::T5)
> > +
> > +?f at UnnamedType@@YAXUT2 at S@1@@Z
> > +; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::S::T2)
> > +
> > +?f at UnnamedType@@YAXUT4 at S@1@@Z
> > +; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::S::T4)
> > +
> > +?f at UnnamedType@@YAXUT5 at S@1@@Z
> > +; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::S::T5)
> > +
> > +?f at Atomic@@YAXU?$_Atomic at H@__clang@@@Z
> > +; CHECK: void __cdecl Atomic::f(struct __clang::_Atomic<int>)
> > +
> > +?f at Complex@@YAXU?$_Complex at H@__clang@@@Z
> > +; CHECK: void __cdecl Complex::f(struct __clang::_Complex<int>)
> > +
> > +?f at Float16@@YAXU_Float16 at __clang@@@Z
> > +; CHECK: void __cdecl Float16::f(struct __clang::_Float16)
> > +
> > +
> > +??0?$L at H@NS@@QEAA at XZ
> > +; CHECK: __cdecl NS::L<int>::L<int>(void)
> > +
> > +??0Bar at Foo@@QEAA at XZ
> > +; CHECK: __cdecl Foo::Bar::Bar(void)
> > +
> > +??0?$L at V?$H at PAH@PR26029@@@PR26029@@QAE at XZ
> > +; CHECK: __thiscall PR26029::L<class PR26029::H<int *>>::L<class
> PR26029::H<int *>>(void)
> >
> > Added: llvm/trunk/test/Demangle/ms-windows.test
> > URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Demangle/ms-windows.test?rev=337584&view=auto
> >
> ==============================================================================
> > --- llvm/trunk/test/Demangle/ms-windows.test (added)
> > +++ llvm/trunk/test/Demangle/ms-windows.test Fri Jul 20 10:27:48 2018
> > @@ -0,0 +1,17 @@
> > +; See clang/test/CodeGenCXX/mangle-windows.cpp
> > +; These tests are based on clang/test/CodeGenCXX/mangle-ms.cpp
> > +; RUN: llvm-undname < %s | FileCheck %s
> > +
> > +; CHECK-NOT: Invalid mangled name
> > +
> > +?bar at Foo@@SGXXZ
> > +; CHECK: static void __stdcall Foo::bar(void)
> > +
> > +?bar at Foo@@QAGXXZ
> > +; CHECK: void __stdcall Foo::bar(void)
> > +
> > +?f2@@YIXXZ
> > +; CHECK: void __fastcall f2(void)
> > +
> > +?f1@@YGXXZ
> > +; CHECK: void __stdcall f1(void)
> >
> > Modified: llvm/trunk/tools/LLVMBuild.txt
> > URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/LLVMBuild.txt?rev=337584&r1=337583&r2=337584&view=diff
> >
> ==============================================================================
> > --- llvm/trunk/tools/LLVMBuild.txt (original)
> > +++ llvm/trunk/tools/LLVMBuild.txt Fri Jul 20 10:27:48 2018
> > @@ -50,6 +50,7 @@ subdirectories =
> >    llvm-rtdyld
> >    llvm-size
> >    llvm-split
> > + llvm-undname
> >    opt
> >    verify-uselistorder
> >
> >
> > Added: llvm/trunk/tools/llvm-undname/CMakeLists.txt
> > URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-undname/CMakeLists.txt?rev=337584&view=auto
> >
> ==============================================================================
> > --- llvm/trunk/tools/llvm-undname/CMakeLists.txt (added)
> > +++ llvm/trunk/tools/llvm-undname/CMakeLists.txt Fri Jul 20 10:27:48 2018
> > @@ -0,0 +1,8 @@
> > +set(LLVM_LINK_COMPONENTS
> > +  Demangle
> > +  Support
> > +  )
> > +
> > +add_llvm_tool(llvm-undname
> > +  llvm-undname.cpp
> > +  )
> >
> > Added: llvm/trunk/tools/llvm-undname/LLVMBuild.txt
> > URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-undname/LLVMBuild.txt?rev=337584&view=auto
> >
> ==============================================================================
> > --- llvm/trunk/tools/llvm-undname/LLVMBuild.txt (added)
> > +++ llvm/trunk/tools/llvm-undname/LLVMBuild.txt Fri Jul 20 10:27:48 2018
> > @@ -0,0 +1,23 @@
> > +;===- ./tools/llvm-undname/LLVMBuild.txt -----------------------*- Conf
> -*--===;
> > +;
> > +;                     The LLVM Compiler Infrastructure
> > +;
> > +; This file is distributed under the University of Illinois Open Source
> > +; License. See LICENSE.TXT for details.
> > +;
> >
> +;===------------------------------------------------------------------------===;
> > +;
> > +; This is an LLVMBuild description file for the components in this
> subdirectory.
> > +;
> > +
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20180720/89e1edc0/attachment-0001.html>


More information about the llvm-commits mailing list