diff options
Diffstat (limited to 'lib/Demangle/MicrosoftDemangle.cpp')
| -rw-r--r-- | lib/Demangle/MicrosoftDemangle.cpp | 1048 | 
1 files changed, 700 insertions, 348 deletions
| diff --git a/lib/Demangle/MicrosoftDemangle.cpp b/lib/Demangle/MicrosoftDemangle.cpp index 596359b7d990..3eac87d61011 100644 --- a/lib/Demangle/MicrosoftDemangle.cpp +++ b/lib/Demangle/MicrosoftDemangle.cpp @@ -29,15 +29,27 @@  // the demangler is 3x faster with this allocator compared to one with  // STL containers.  namespace { +  constexpr size_t AllocUnit = 4096; +  class ArenaAllocator {    struct AllocatorNode {      uint8_t *Buf = nullptr;      size_t Used = 0; +    size_t Capacity = 0;      AllocatorNode *Next = nullptr;    }; +  void addNode(size_t Capacity) { +    AllocatorNode *NewHead = new AllocatorNode; +    NewHead->Buf = new uint8_t[Capacity]; +    NewHead->Next = Head; +    NewHead->Capacity = Capacity; +    Head = NewHead; +    NewHead->Used = 0; +  } +  public: -  ArenaAllocator() : Head(new AllocatorNode) { Head->Buf = new uint8_t[Unit]; } +  ArenaAllocator() { addNode(AllocUnit); }    ~ArenaAllocator() {      while (Head) { @@ -49,10 +61,25 @@ public:      }    } +  char *allocUnalignedBuffer(size_t Length) { +    uint8_t *Buf = Head->Buf + Head->Used; + +    Head->Used += Length; +    if (Head->Used > Head->Capacity) { +      // It's possible we need a buffer which is larger than our default unit +      // size, so we need to be careful to add a node with capacity that is at +      // least as large as what we need. +      addNode(std::max(AllocUnit, Length)); +      Head->Used = Length; +      Buf = Head->Buf; +    } + +    return reinterpret_cast<char *>(Buf); +  } +    template <typename T, typename... Args> T *alloc(Args &&... ConstructorArgs) {      size_t Size = sizeof(T); -    assert(Size < Unit);      assert(Head && Head->Buf);      size_t P = (size_t)Head->Buf + Head->Used; @@ -62,20 +89,15 @@ public:      size_t Adjustment = AlignedP - P;      Head->Used += Size + Adjustment; -    if (Head->Used < Unit) +    if (Head->Used < Head->Capacity)        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)...); +    addNode(AllocUnit); +    Head->Used = Size; +    return new (Head->Buf) T(std::forward<Args>(ConstructorArgs)...);    }  private: -  static constexpr size_t Unit = 4096; -    AllocatorNode *Head = nullptr;  };  } // namespace @@ -117,7 +139,7 @@ enum class StorageClass : uint8_t {  enum class QualifierMangleMode { Drop, Mangle, Result }; -enum class PointerAffinity { Pointer, Reference }; +enum class PointerAffinity { Pointer, Reference, RValueReference };  // Calling conventions  enum class CallingConv : uint8_t { @@ -141,7 +163,6 @@ enum class PrimTy : uint8_t {    None,    Function,    Ptr, -  Ref,    MemberPtr,    Array, @@ -155,6 +176,8 @@ enum class PrimTy : uint8_t {    Char,    Schar,    Uchar, +  Char16, +  Char32,    Short,    Ushort,    Int, @@ -167,6 +190,7 @@ enum class PrimTy : uint8_t {    Float,    Double,    Ldouble, +  Nullptr  };  // Function classes @@ -183,15 +207,30 @@ enum FuncClass : uint8_t {  namespace {  struct Type; +struct Name; -// Represents a list of parameters (template params or function arguments. -// It's represented as a linked list. -struct ParamList { +struct FunctionParams {    bool IsVariadic = false;    Type *Current = nullptr; -  ParamList *Next = nullptr; +  FunctionParams *Next = nullptr; +}; + +struct TemplateParams { +  bool IsTemplateTemplate = false; +  bool IsAliasTemplate = false; + +  // Type can be null if this is a template template parameter.  In that case +  // only Name will be valid. +  Type *ParamType = nullptr; + +  // Name can be valid if this is a template template parameter (see above) or +  // this is a function declaration (e.g. foo<&SomeFunc>).  In the latter case +  // Name contains the name of the function and Type contains the signature. +  Name *ParamName = nullptr; + +  TemplateParams *Next = nullptr;  };  // The type class. Mangled symbols are first parsed and converted to @@ -232,7 +271,7 @@ struct Name {    StringView Operator;    // Template parameters. Null if not a template. -  ParamList TemplateParams; +  TemplateParams *TParams = nullptr;    // Nested BackReferences (e.g. "A::B::C") are represented as a linked list.    Name *Next = nullptr; @@ -243,6 +282,8 @@ struct PointerType : public Type {    void outputPre(OutputStream &OS) override;    void outputPost(OutputStream &OS) override; +  PointerAffinity Affinity; +    // Represents a type X in "a pointer to X", "a reference to X",    // "an array of X", or "a function returning X".    Type *Pointee = nullptr; @@ -276,7 +317,7 @@ struct FunctionType : public Type {    CallingConv CallConvention;    FuncClass FunctionClass; -  ParamList Params; +  FunctionParams Params;  };  struct UdtType : public Type { @@ -302,9 +343,13 @@ struct ArrayType : public Type {  static bool isMemberPointer(StringView MangledName) {    switch (MangledName.popFront()) { +  case '$': +    // This is probably an rvalue reference (e.g. $$Q), and you cannot have an +    // rvalue reference to a member. +    return false;    case 'A':      // 'A' indicates a reference, and you cannot have a reference to a member -    // function or member variable. +    // function or member.      return false;    case 'P':    case 'Q': @@ -386,14 +431,58 @@ static void outputCallingConvention(OutputStream &OS, CallingConv CC) {    }  } +static bool startsWithLocalScopePattern(StringView S) { +  if (!S.consumeFront('?')) +    return false; +  if (S.size() < 2) +    return false; + +  size_t End = S.find('?'); +  if (End == StringView::npos) +    return false; +  StringView Candidate = S.substr(0, End); +  if (Candidate.empty()) +    return false; + +  // \?[0-9]\? +  // ?@? is the discriminator 0. +  if (Candidate.size() == 1) +    return Candidate[0] == '@' || (Candidate[0] >= '0' && Candidate[0] <= '9'); + +  // If it's not 0-9, then it's an encoded number terminated with an @ +  if (Candidate.back() != '@') +    return false; +  Candidate = Candidate.dropBack(); + +  // An encoded number starts with B-P and all subsequent digits are in A-P. +  // Note that the reason the first digit cannot be A is two fold.  First, it +  // would create an ambiguity with ?A which delimits the beginning of an +  // anonymous namespace.  Second, A represents 0, and you don't start a multi +  // digit number with a leading 0.  Presumably the anonymous namespace +  // ambiguity is also why single digit encoded numbers use 0-9 rather than A-J. +  if (Candidate[0] < 'B' || Candidate[0] > 'P') +    return false; +  Candidate = Candidate.dropFront(); +  while (!Candidate.empty()) { +    if (Candidate[0] < 'A' || Candidate[0] > 'P') +      return false; +    Candidate = Candidate.dropFront(); +  } + +  return true; +} + +static void outputName(OutputStream &OS, const Name *TheName); +  // Write a function or template parameter list. -static void outputParameterList(OutputStream &OS, const ParamList &Params) { +static void outputParameterList(OutputStream &OS, +                                const FunctionParams &Params) {    if (!Params.Current) {      OS << "void";      return;    } -  const ParamList *Head = &Params; +  const FunctionParams *Head = &Params;    while (Head) {      Type::outputPre(OS, *Head->Current);      Type::outputPost(OS, *Head->Current); @@ -405,12 +494,39 @@ static void outputParameterList(OutputStream &OS, const ParamList &Params) {    }  } -static void outputTemplateParams(OutputStream &OS, const Name &TheName) { -  if (!TheName.TemplateParams.Current) +static void outputParameterList(OutputStream &OS, +                                const TemplateParams &Params) { +  if (!Params.ParamType && !Params.ParamName) { +    OS << "<>";      return; +  }    OS << "<"; -  outputParameterList(OS, TheName.TemplateParams); +  const TemplateParams *Head = &Params; +  while (Head) { +    // Type can be null if this is a template template parameter, +    // and Name can be null if this is a simple type. + +    if (Head->ParamType && Head->ParamName) { +      // Function pointer. +      OS << "&"; +      Type::outputPre(OS, *Head->ParamType); +      outputName(OS, Head->ParamName); +      Type::outputPost(OS, *Head->ParamType); +    } else if (Head->ParamType) { +      // simple type. +      Type::outputPre(OS, *Head->ParamType); +      Type::outputPost(OS, *Head->ParamType); +    } else { +      // Template alias. +      outputName(OS, Head->ParamName); +    } + +    Head = Head->Next; + +    if (Head) +      OS << ", "; +  }    OS << ">";  } @@ -420,29 +536,32 @@ static void outputName(OutputStream &OS, const Name *TheName) {    outputSpaceIfNecessary(OS); +  const Name *Previous = nullptr;    // Print out namespaces or outer class BackReferences.    for (; TheName->Next; TheName = TheName->Next) { +    Previous = TheName;      OS << TheName->Str; -    outputTemplateParams(OS, *TheName); +    if (TheName->TParams) +      outputParameterList(OS, *TheName->TParams);      OS << "::";    }    // Print out a regular name.    if (TheName->Operator.empty()) {      OS << TheName->Str; -    outputTemplateParams(OS, *TheName); +    if (TheName->TParams) +      outputParameterList(OS, *TheName->TParams);      return;    }    // Print out ctor or dtor. +  if (TheName->Operator == "dtor") +    OS << "~"; +    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); +    OS << Previous->Str; +    if (Previous->TParams) +      outputParameterList(OS, *Previous->TParams);      return;    } @@ -514,6 +633,12 @@ void Type::outputPre(OutputStream &OS) {    case PrimTy::Uchar:      OS << "unsigned char";      break; +  case PrimTy::Char16: +    OS << "char16_t"; +    break; +  case PrimTy::Char32: +    OS << "char32_t"; +    break;    case PrimTy::Short:      OS << "short";      break; @@ -550,6 +675,9 @@ void Type::outputPre(OutputStream &OS) {    case PrimTy::Ldouble:      OS << "long double";      break; +  case PrimTy::Nullptr: +    OS << "std::nullptr_t"; +    break;    default:      assert(false && "Invalid primitive type!");    } @@ -584,8 +712,10 @@ static void outputPointerIndicator(OutputStream &OS, PointerAffinity Affinity,    if (Affinity == PointerAffinity::Pointer)      OS << "*"; -  else +  else if (Affinity == PointerAffinity::Reference)      OS << "&"; +  else +    OS << "&&";  }  void PointerType::outputPre(OutputStream &OS) { @@ -596,9 +726,6 @@ void PointerType::outputPre(OutputStream &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. @@ -668,6 +795,15 @@ void FunctionType::outputPost(OutputStream &OS) {      OS << " const";    if (Quals & Q_Volatile)      OS << " volatile"; +  if (Quals & Q_Restrict) +    OS << " __restrict"; +  if (Quals & Q_Unaligned) +    OS << " __unaligned"; + +  if (RefKind == ReferenceKind::LValueRef) +    OS << " &"; +  else if (RefKind == ReferenceKind::RValueRef) +    OS << " &&";    if (ReturnType)      Type::outputPost(OS, *ReturnType); @@ -716,6 +852,11 @@ void ArrayType::outputPost(OutputStream &OS) {      Type::outputPost(OS, *ElementType);  } +struct Symbol { +  Name *SymbolName = nullptr; +  Type *SymbolType = nullptr; +}; +  } // namespace  namespace { @@ -725,63 +866,68 @@ namespace {  // 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) {} +  Demangler() = default;    // 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(); +  Symbol *parse(StringView &MangledName); +  void output(const Symbol *S, OutputStream &OS);    // True if an error occurred.    bool Error = false;  private: -  Type *demangleVariableEncoding(); -  Type *demangleFunctionEncoding(); +  Type *demangleVariableEncoding(StringView &MangledName); +  Type *demangleFunctionEncoding(StringView &MangledName); -  Qualifiers demanglePointerExtQualifiers(); +  Qualifiers demanglePointerExtQualifiers(StringView &MangledName);    // 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); +  Type *demangleType(StringView &MangledName, QualifierMangleMode QMM); +  Type *demangleBasicType(StringView &MangledName); +  UdtType *demangleClassType(StringView &MangledName); +  PointerType *demanglePointerType(StringView &MangledName); +  MemberPointerType *demangleMemberPointerType(StringView &MangledName); +  FunctionType *demangleFunctionType(StringView &MangledName, bool HasThisQuals, +                                     bool IsFunctionPointer); -  ArrayType *demangleArrayType(); +  ArrayType *demangleArrayType(StringView &MangledName); -  ParamList demangleTemplateParameterList(); -  ParamList demangleFunctionParameterList(); +  TemplateParams *demangleTemplateParameterList(StringView &MangledName); +  FunctionParams demangleFunctionParameterList(StringView &MangledName); -  int demangleNumber(); -  void demangleNamePiece(Name &Node, bool IsHead); +  int demangleNumber(StringView &MangledName); -  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(); +  /// Allocate a copy of \p Borrowed into memory that we own. +  StringView copyString(StringView Borrowed); -  // The result is written to this stream. -  OutputStream OS; +  Name *demangleFullyQualifiedTypeName(StringView &MangledName); +  Name *demangleFullyQualifiedSymbolName(StringView &MangledName); -  // Mangled symbol. demangle* functions shorten this string -  // as they parse it. -  StringView MangledName; +  Name *demangleUnqualifiedTypeName(StringView &MangledName); +  Name *demangleUnqualifiedSymbolName(StringView &MangledName); -  // A parsed mangled symbol. -  Type *SymbolType = nullptr; +  Name *demangleNameScopeChain(StringView &MangledName, Name *UnqualifiedName); +  Name *demangleNameScopePiece(StringView &MangledName); -  // The main symbol name. (e.g. "ns::foo" in "int ns::foo()".) -  Name *SymbolName = nullptr; +  Name *demangleBackRefName(StringView &MangledName); +  Name *demangleClassTemplateName(StringView &MangledName); +  Name *demangleOperatorName(StringView &MangledName); +  Name *demangleSimpleName(StringView &MangledName, bool Memorize); +  Name *demangleAnonymousNamespaceName(StringView &MangledName); +  Name *demangleLocallyScopedNamePiece(StringView &MangledName); + +  StringView demangleSimpleString(StringView &MangledName, bool Memorize); + +  FuncClass demangleFunctionClass(StringView &MangledName); +  CallingConv demangleCallingConvention(StringView &MangledName); +  StorageClass demangleVariableStorageClass(StringView &MangledName); +  ReferenceKind demangleReferenceKind(StringView &MangledName); +  void demangleThrowSpecification(StringView &MangledName); + +  std::pair<Qualifiers, bool> demangleQualifiers(StringView &MangledName);    // Memory allocator.    ArenaAllocator Arena; @@ -809,28 +955,36 @@ private:  };  } // namespace +StringView Demangler::copyString(StringView Borrowed) { +  char *Stable = Arena.allocUnalignedBuffer(Borrowed.size() + 1); +  std::strcpy(Stable, Borrowed.begin()); + +  return {Stable, Borrowed.size()}; +} +  // Parser entry point. -void Demangler::parse() { +Symbol *Demangler::parse(StringView &MangledName) { +  Symbol *S = Arena.alloc<Symbol>(); +    // 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; +    S->SymbolName = Arena.alloc<Name>(); +    S->SymbolName->Str = MangledName; +    S->SymbolType = Arena.alloc<Type>(); +    S->SymbolType->Prim = PrimTy::Unknown; +    return S;    }    // What follows is a main symbol name. This may include    // namespaces or class BackReferences. -  SymbolName = demangleName(); +  S->SymbolName = demangleFullyQualifiedSymbolName(MangledName);    // Read a variable. -  if (startsWithDigit(MangledName)) { -    SymbolType = demangleVariableEncoding(); -    return; -  } +  S->SymbolType = startsWithDigit(MangledName) +                      ? demangleVariableEncoding(MangledName) +                      : demangleFunctionEncoding(MangledName); -  // Read a function. -  SymbolType = demangleFunctionEncoding(); +  return S;  }  // <type-encoding> ::= <storage-class> <variable-type> @@ -840,10 +994,10 @@ void Demangler::parse() {  //                 ::= 3  # global  //                 ::= 4  # static local -Type *Demangler::demangleVariableEncoding() { -  StorageClass SC = demangleVariableStorageClass(); +Type *Demangler::demangleVariableEncoding(StringView &MangledName) { +  StorageClass SC = demangleVariableStorageClass(MangledName); -  Type *Ty = demangleType(QualifierMangleMode::Drop); +  Type *Ty = demangleType(MangledName, QualifierMangleMode::Drop);    Ty->Storage = SC; @@ -851,17 +1005,17 @@ Type *Demangler::demangleVariableEncoding() {    //                 ::= <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()); +    Ty->Quals = +        Qualifiers(Ty->Quals | demanglePointerExtQualifiers(MangledName));      bool IsMember = false; -    std::tie(ExtraChildQuals, IsMember) = demangleQualifiers(); +    std::tie(ExtraChildQuals, IsMember) = demangleQualifiers(MangledName);      if (Ty->Prim == PrimTy::MemberPtr) {        assert(IsMember); -      Name *BackRefName = demangleName(); +      Name *BackRefName = demangleFullyQualifiedTypeName(MangledName);        (void)BackRefName;        MemberPointerType *MPTy = static_cast<MemberPointerType *>(Ty);        MPTy->Pointee->Quals = Qualifiers(MPTy->Pointee->Quals | ExtraChildQuals); @@ -873,7 +1027,7 @@ Type *Demangler::demangleVariableEncoding() {      break;    }    default: -    Ty->Quals = demangleQualifiers().first; +    Ty->Quals = demangleQualifiers(MangledName).first;      break;    } @@ -891,7 +1045,7 @@ Type *Demangler::demangleVariableEncoding() {  //                        ::= <hex digit>+ @  # when Numbrer == 0 or >= 10  //  // <hex-digit>            ::= [A-P]           # A = 0, B = 1, ... -int Demangler::demangleNumber() { +int Demangler::demangleNumber(StringView &MangledName) {    bool neg = MangledName.consumeFront("?");    if (startsWithDigit(MangledName)) { @@ -918,23 +1072,6 @@ int Demangler::demangleNumber() {    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) { @@ -946,179 +1083,322 @@ void Demangler::memorizeString(StringView S) {    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); +Name *Demangler::demangleBackRefName(StringView &MangledName) { +  assert(startsWithDigit(MangledName)); + +  size_t I = MangledName[0] - '0'; +  if (I >= BackRefCount) { +    Error = true; +    return nullptr;    } -} -// Parses a name in the form of A@B@C@@ which represents C::B::A. -Name *Demangler::demangleName() { -  Name *Head = nullptr; +  MangledName = MangledName.dropFront(); +  Name *Node = Arena.alloc<Name>(); +  Node->Str = BackReferences[I]; +  return Node; +} -  while (!MangledName.consumeFront("@")) { -    Name *Elem = Arena.alloc<Name>(); +Name *Demangler::demangleClassTemplateName(StringView &MangledName) { +  assert(MangledName.startsWith("?$")); +  MangledName.consumeFront("?$"); -    assert(!Error); -    demangleNamePiece(*Elem, Head == nullptr); -    if (Error) -      return nullptr; +  Name *Node = demangleSimpleName(MangledName, false); +  Node->TParams = demangleTemplateParameterList(MangledName); -    Elem->Next = Head; -    Head = Elem; -    if (MangledName.empty()) { -      Error = true; -      return nullptr; -    } -  } +  // Render this class template name into a string buffer so that we can +  // memorize it for the purpose of back-referencing. +  OutputStream OS = OutputStream::create(nullptr, nullptr, 1024); +  outputName(OS, Node); +  OS << '\0'; +  char *Name = OS.getBuffer(); -  return Head; -} +  StringView Owned = copyString(Name); +  memorizeString(Owned); +  std::free(Name); -void Demangler::demangleOperator(Name *OpName) { -  OpName->Operator = demangleOperatorName(); -  if (!Error && !MangledName.empty() && MangledName.front() != '@') -    demangleNamePiece(*OpName, false); +  return Node;  } -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; +Name *Demangler::demangleOperatorName(StringView &MangledName) { +  assert(MangledName.startsWith('?')); +  MangledName.consumeFront('?'); +  auto NameString = [this, &MangledName]() -> StringView {      switch (MangledName.popFront()) {      case '0': -      return "/="; +      return "ctor";      case '1': -      return "%="; +      return "dtor";      case '2': -      return ">>="; +      return " new";      case '3': -      return "<<="; +      return " delete";      case '4': -      return "&="; +      return "=";      case '5': -      return "|="; +      return ">>";      case '6': -      return "^="; +      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 " new[]"; +      return "|";      case 'V': -      return " delete[]"; -    case '_': -      if (MangledName.consumeFront("L")) -        return " co_await"; +      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"; +        if (MangledName.consumeFront("K")) { +          size_t EndPos = MangledName.find('@'); +          if (EndPos == StringView::npos) +            break; +          StringView OpName = demangleSimpleString(MangledName, false); +          size_t FullSize = OpName.size() + 3; // <space>""OpName +          char *Buffer = Arena.allocUnalignedBuffer(FullSize); +          Buffer[0] = ' '; +          Buffer[1] = '"'; +          Buffer[2] = '"'; +          std::memcpy(Buffer + 3, OpName.begin(), OpName.size()); +          return {Buffer, FullSize}; +        } +      }      } -  } +    } +    Error = true; +    return ""; +  }; + +  Name *Node = Arena.alloc<Name>(); +  Node->Operator = NameString(); +  return Node; +} + +Name *Demangler::demangleSimpleName(StringView &MangledName, bool Memorize) { +  StringView S = demangleSimpleString(MangledName, Memorize); +  if (Error) +    return nullptr; + +  Name *Node = Arena.alloc<Name>(); +  Node->Str = S; +  return Node; +} + +StringView Demangler::demangleSimpleString(StringView &MangledName, +                                           bool Memorize) { +  StringView S; +  for (size_t i = 0; i < MangledName.size(); ++i) { +    if (MangledName[i] != '@') +      continue; +    S = MangledName.substr(0, i); +    MangledName = MangledName.dropFront(i + 1); + +    if (Memorize) +      memorizeString(S); +    return S;    }    Error = true; -  RestoreOnError.shouldRestore(true); -  return ""; +  return {}; +} + +Name *Demangler::demangleAnonymousNamespaceName(StringView &MangledName) { +  assert(MangledName.startsWith("?A")); +  MangledName.consumeFront("?A"); + +  Name *Node = Arena.alloc<Name>(); +  Node->Str = "`anonymous namespace'"; +  if (MangledName.consumeFront('@')) +    return Node; + +  Error = true; +  return nullptr; +} + +Name *Demangler::demangleLocallyScopedNamePiece(StringView &MangledName) { +  assert(startsWithLocalScopePattern(MangledName)); + +  Name *Node = Arena.alloc<Name>(); +  MangledName.consumeFront('?'); +  int ScopeIdentifier = demangleNumber(MangledName); + +  // One ? to terminate the number +  MangledName.consumeFront('?'); + +  assert(!Error); +  Symbol *Scope = parse(MangledName); +  if (Error) +    return nullptr; + +  // Render the parent symbol's name into a buffer. +  OutputStream OS = OutputStream::create(nullptr, nullptr, 1024); +  OS << '`'; +  output(Scope, OS); +  OS << '\''; +  OS << "::`" << ScopeIdentifier << "'"; +  OS << '\0'; +  char *Result = OS.getBuffer(); +  Node->Str = copyString(Result); +  std::free(Result); +  return Node; +} + +// Parses a type name in the form of A@B@C@@ which represents C::B::A. +Name *Demangler::demangleFullyQualifiedTypeName(StringView &MangledName) { +  Name *TypeName = demangleUnqualifiedTypeName(MangledName); +  assert(TypeName); + +  Name *QualName = demangleNameScopeChain(MangledName, TypeName); +  assert(QualName); +  return QualName; +} + +// Parses a symbol name in the form of A@B@C@@ which represents C::B::A. +// Symbol names have slightly different rules regarding what can appear +// so we separate out the implementations for flexibility. +Name *Demangler::demangleFullyQualifiedSymbolName(StringView &MangledName) { +  Name *SymbolName = demangleUnqualifiedSymbolName(MangledName); +  assert(SymbolName); + +  Name *QualName = demangleNameScopeChain(MangledName, SymbolName); +  assert(QualName); +  return QualName; +} + +Name *Demangler::demangleUnqualifiedTypeName(StringView &MangledName) { +  // An inner-most name can be a back-reference, because a fully-qualified name +  // (e.g. Scope + Inner) can contain other fully qualified names inside of +  // them (for example template parameters), and these nested parameters can +  // refer to previously mangled types. +  if (startsWithDigit(MangledName)) +    return demangleBackRefName(MangledName); + +  if (MangledName.startsWith("?$")) +    return demangleClassTemplateName(MangledName); + +  return demangleSimpleName(MangledName, true); +} + +Name *Demangler::demangleUnqualifiedSymbolName(StringView &MangledName) { +  if (startsWithDigit(MangledName)) +    return demangleBackRefName(MangledName); +  if (MangledName.startsWith("?$")) +    return demangleClassTemplateName(MangledName); +  if (MangledName.startsWith('?')) +    return demangleOperatorName(MangledName); +  return demangleSimpleName(MangledName, true); +} + +Name *Demangler::demangleNameScopePiece(StringView &MangledName) { +  if (startsWithDigit(MangledName)) +    return demangleBackRefName(MangledName); + +  if (MangledName.startsWith("?$")) +    return demangleClassTemplateName(MangledName); + +  if (MangledName.startsWith("?A")) +    return demangleAnonymousNamespaceName(MangledName); + +  if (startsWithLocalScopePattern(MangledName)) +    return demangleLocallyScopedNamePiece(MangledName); + +  return demangleSimpleName(MangledName, true); +} + +Name *Demangler::demangleNameScopeChain(StringView &MangledName, +                                        Name *UnqualifiedName) { +  Name *Head = UnqualifiedName; + +  while (!MangledName.consumeFront("@")) { +    if (MangledName.empty()) { +      Error = true; +      return nullptr; +    } + +    assert(!Error); +    Name *Elem = demangleNameScopePiece(MangledName); +    if (Error) +      return nullptr; + +    Elem->Next = Head; +    Head = Elem; +  } +  return Head;  } -FuncClass Demangler::demangleFunctionClass() { +FuncClass Demangler::demangleFunctionClass(StringView &MangledName) {    SwapAndRestore<StringView> RestoreOnError(MangledName, MangledName);    RestoreOnError.shouldRestore(false); @@ -1170,7 +1450,7 @@ FuncClass Demangler::demangleFunctionClass() {    return Public;  } -CallingConv Demangler::demangleCallingConvention() { +CallingConv Demangler::demangleCallingConvention(StringView &MangledName) {    switch (MangledName.popFront()) {    case 'A':    case 'B': @@ -1200,7 +1480,7 @@ CallingConv Demangler::demangleCallingConvention() {    return CallingConv::None;  } -StorageClass Demangler::demangleVariableStorageClass() { +StorageClass Demangler::demangleVariableStorageClass(StringView &MangledName) {    assert(std::isdigit(MangledName.front()));    switch (MangledName.popFront()) { @@ -1219,7 +1499,8 @@ StorageClass Demangler::demangleVariableStorageClass() {    return StorageClass::None;  } -std::pair<Qualifiers, bool> Demangler::demangleQualifiers() { +std::pair<Qualifiers, bool> +Demangler::demangleQualifiers(StringView &MangledName) {    switch (MangledName.popFront()) {    // Member qualifiers @@ -1245,54 +1526,88 @@ std::pair<Qualifiers, bool> Demangler::demangleQualifiers() {    return std::make_pair(Q_None, false);  } +static bool isTagType(StringView S) { +  switch (S.front()) { +  case 'T': // union +  case 'U': // struct +  case 'V': // class +  case 'W': // enum +    return true; +  } +  return false; +} + +static bool isPointerType(StringView S) { +  if (S.startsWith("$$Q")) // foo && +    return true; + +  switch (S.front()) { +  case 'A': // foo & +  case 'P': // foo * +  case 'Q': // foo *const +  case 'R': // foo *volatile +  case 'S': // foo *const volatile +    return true; +  } +  return false; +} + +static bool isArrayType(StringView S) { return S[0] == 'Y'; } + +static bool isFunctionType(StringView S) { +  return S.startsWith("$$A8@@") || S.startsWith("$$A6"); +} +  // <variable-type> ::= <type> <cvr-qualifiers>  //                 ::= <type> <pointee-cvr-qualifiers> # pointers, references -Type *Demangler::demangleType(QualifierMangleMode QMM) { +Type *Demangler::demangleType(StringView &MangledName, +                              QualifierMangleMode QMM) {    Qualifiers Quals = Q_None;    bool IsMember = false;    bool IsMemberKnown = false;    if (QMM == QualifierMangleMode::Mangle) { -    std::tie(Quals, IsMember) = demangleQualifiers(); +    std::tie(Quals, IsMember) = demangleQualifiers(MangledName);      IsMemberKnown = true;    } else if (QMM == QualifierMangleMode::Result) {      if (MangledName.consumeFront('?')) { -      std::tie(Quals, IsMember) = demangleQualifiers(); +      std::tie(Quals, IsMember) = demangleQualifiers(MangledName);        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 (isTagType(MangledName)) +    Ty = demangleClassType(MangledName); +  else if (isPointerType(MangledName)) {      if (!IsMemberKnown)        IsMember = isMemberPointer(MangledName); +      if (IsMember) -      Ty = demangleMemberPointerType(); +      Ty = demangleMemberPointerType(MangledName);      else -      Ty = demanglePointerType(); -    break; -  case 'Y': -    Ty = demangleArrayType(); -    break; -  default: -    Ty = demangleBasicType(); -    break; +      Ty = demanglePointerType(MangledName); +  } else if (isArrayType(MangledName)) +    Ty = demangleArrayType(MangledName); +  else if (isFunctionType(MangledName)) { +    if (MangledName.consumeFront("$$A8@@")) +      Ty = demangleFunctionType(MangledName, true, false); +    else { +      assert(MangledName.startsWith("$$A6")); +      MangledName.consumeFront("$$A6"); +      Ty = demangleFunctionType(MangledName, false, false); +    } +  } else { +    Ty = demangleBasicType(MangledName); +    assert(Ty && !Error); +    if (!Ty || Error) +      return Ty;    } +    Ty->Quals = Qualifiers(Ty->Quals | Quals);    return Ty;  } -ReferenceKind Demangler::demangleReferenceKind() { +ReferenceKind Demangler::demangleReferenceKind(StringView &MangledName) {    if (MangledName.consumeFront('G'))      return ReferenceKind::LValueRef;    else if (MangledName.consumeFront('H')) @@ -1300,55 +1615,61 @@ ReferenceKind Demangler::demangleReferenceKind() {    return ReferenceKind::None;  } -void Demangler::demangleThrowSpecification() { +void Demangler::demangleThrowSpecification(StringView &MangledName) {    if (MangledName.consumeFront('Z'))      return;    Error = true;  } -FunctionType *Demangler::demangleFunctionType(bool HasThisQuals, +FunctionType *Demangler::demangleFunctionType(StringView &MangledName, +                                              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); +    FTy->Quals = demanglePointerExtQualifiers(MangledName); +    FTy->RefKind = demangleReferenceKind(MangledName); +    FTy->Quals = Qualifiers(FTy->Quals | demangleQualifiers(MangledName).first);    }    // Fields that appear on both member and non-member functions. -  FTy->CallConvention = demangleCallingConvention(); +  FTy->CallConvention = demangleCallingConvention(MangledName);    // <return-type> ::= <type>    //               ::= @ # structors (they have no declared return type)    bool IsStructor = MangledName.consumeFront('@');    if (!IsStructor) -    FTy->ReturnType = demangleType(QualifierMangleMode::Result); +    FTy->ReturnType = demangleType(MangledName, QualifierMangleMode::Result); -  FTy->Params = demangleFunctionParameterList(); +  FTy->Params = demangleFunctionParameterList(MangledName); -  demangleThrowSpecification(); +  demangleThrowSpecification(MangledName);    return FTy;  } -Type *Demangler::demangleFunctionEncoding() { -  FuncClass FC = demangleFunctionClass(); +Type *Demangler::demangleFunctionEncoding(StringView &MangledName) { +  FuncClass FC = demangleFunctionClass(MangledName);    bool HasThisQuals = !(FC & (Global | Static)); -  FunctionType *FTy = demangleFunctionType(HasThisQuals, false); +  FunctionType *FTy = demangleFunctionType(MangledName, HasThisQuals, false);    FTy->FunctionClass = FC;    return FTy;  }  // Reads a primitive type. -Type *Demangler::demangleBasicType() { +Type *Demangler::demangleBasicType(StringView &MangledName) {    Type *Ty = Arena.alloc<Type>(); +  if (MangledName.consumeFront("$$T")) { +    Ty->Prim = PrimTy::Nullptr; +    return Ty; +  } +    switch (MangledName.popFront()) {    case 'X':      Ty->Prim = PrimTy::Void; @@ -1407,16 +1728,26 @@ Type *Demangler::demangleBasicType() {      case 'W':        Ty->Prim = PrimTy::Wchar;        break; +    case 'S': +      Ty->Prim = PrimTy::Char16; +      break; +    case 'U': +      Ty->Prim = PrimTy::Char32; +      break;      default: -      assert(false); +      Error = true; +      return nullptr;      }      break;    } +  default: +    Error = true; +    return nullptr;    }    return Ty;  } -UdtType *Demangler::demangleClassType() { +UdtType *Demangler::demangleClassType(StringView &MangledName) {    UdtType *UTy = Arena.alloc<UdtType>();    switch (MangledName.popFront()) { @@ -1440,12 +1771,15 @@ UdtType *Demangler::demangleClassType() {      assert(false);    } -  UTy->UdtName = demangleName(); +  UTy->UdtName = demangleFullyQualifiedTypeName(MangledName);    return UTy;  }  static std::pair<Qualifiers, PointerAffinity>  demanglePointerCVQualifiers(StringView &MangledName) { +  if (MangledName.consumeFront("$$Q")) +    return std::make_pair(Q_None, PointerAffinity::RValueReference); +    switch (MangledName.popFront()) {    case 'A':      return std::make_pair(Q_None, PointerAffinity::Reference); @@ -1466,27 +1800,27 @@ demanglePointerCVQualifiers(StringView &MangledName) {  // <pointer-type> ::= E? <pointer-cvr-qualifiers> <ext-qualifiers> <type>  //                       # the E is required for 64-bit non-static pointers -PointerType *Demangler::demanglePointerType() { +PointerType *Demangler::demanglePointerType(StringView &MangledName) {    PointerType *Pointer = Arena.alloc<PointerType>(); -  PointerAffinity Affinity; -  std::tie(Pointer->Quals, Affinity) = demanglePointerCVQualifiers(MangledName); +  std::tie(Pointer->Quals, Pointer->Affinity) = +      demanglePointerCVQualifiers(MangledName); -  Pointer->Prim = -      (Affinity == PointerAffinity::Pointer) ? PrimTy::Ptr : PrimTy::Ref; +  Pointer->Prim = PrimTy::Ptr;    if (MangledName.consumeFront("6")) { -    Pointer->Pointee = demangleFunctionType(false, true); +    Pointer->Pointee = demangleFunctionType(MangledName, false, true);      return Pointer;    } -  Qualifiers ExtQuals = demanglePointerExtQualifiers(); +  Qualifiers ExtQuals = demanglePointerExtQualifiers(MangledName);    Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals); -  Pointer->Pointee = demangleType(QualifierMangleMode::Mangle); +  Pointer->Pointee = demangleType(MangledName, QualifierMangleMode::Mangle);    return Pointer;  } -MemberPointerType *Demangler::demangleMemberPointerType() { +MemberPointerType * +Demangler::demangleMemberPointerType(StringView &MangledName) {    MemberPointerType *Pointer = Arena.alloc<MemberPointerType>();    Pointer->Prim = PrimTy::MemberPtr; @@ -1494,27 +1828,27 @@ MemberPointerType *Demangler::demangleMemberPointerType() {    std::tie(Pointer->Quals, Affinity) = demanglePointerCVQualifiers(MangledName);    assert(Affinity == PointerAffinity::Pointer); -  Qualifiers ExtQuals = demanglePointerExtQualifiers(); +  Qualifiers ExtQuals = demanglePointerExtQualifiers(MangledName);    Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals);    if (MangledName.consumeFront("8")) { -    Pointer->MemberName = demangleName(); -    Pointer->Pointee = demangleFunctionType(true, true); +    Pointer->MemberName = demangleFullyQualifiedSymbolName(MangledName); +    Pointer->Pointee = demangleFunctionType(MangledName, true, true);    } else {      Qualifiers PointeeQuals = Q_None;      bool IsMember = false; -    std::tie(PointeeQuals, IsMember) = demangleQualifiers(); +    std::tie(PointeeQuals, IsMember) = demangleQualifiers(MangledName);      assert(IsMember); -    Pointer->MemberName = demangleName(); +    Pointer->MemberName = demangleFullyQualifiedSymbolName(MangledName); -    Pointer->Pointee = demangleType(QualifierMangleMode::Drop); +    Pointer->Pointee = demangleType(MangledName, QualifierMangleMode::Drop);      Pointer->Pointee->Quals = PointeeQuals;    }    return Pointer;  } -Qualifiers Demangler::demanglePointerExtQualifiers() { +Qualifiers Demangler::demanglePointerExtQualifiers(StringView &MangledName) {    Qualifiers Quals = Q_None;    if (MangledName.consumeFront('E'))      Quals = Qualifiers(Quals | Q_Pointer64); @@ -1526,11 +1860,11 @@ Qualifiers Demangler::demanglePointerExtQualifiers() {    return Quals;  } -ArrayType *Demangler::demangleArrayType() { +ArrayType *Demangler::demangleArrayType(StringView &MangledName) {    assert(MangledName.front() == 'Y');    MangledName.popFront(); -  int Dimension = demangleNumber(); +  int Dimension = demangleNumber(MangledName);    if (Dimension <= 0) {      Error = true;      return nullptr; @@ -1540,7 +1874,7 @@ ArrayType *Demangler::demangleArrayType() {    ArrayType *Dim = ATy;    for (int I = 0; I < Dimension; ++I) {      Dim->Prim = PrimTy::Array; -    Dim->ArrayDimension = demangleNumber(); +    Dim->ArrayDimension = demangleNumber(MangledName);      Dim->NextDimension = Arena.alloc<ArrayType>();      Dim = Dim->NextDimension;    } @@ -1554,19 +1888,20 @@ ArrayType *Demangler::demangleArrayType() {        Error = true;    } -  ATy->ElementType = demangleType(QualifierMangleMode::Drop); +  ATy->ElementType = demangleType(MangledName, QualifierMangleMode::Drop);    Dim->ElementType = ATy->ElementType;    return ATy;  }  // Reads a function or a template parameters. -ParamList Demangler::demangleFunctionParameterList() { +FunctionParams +Demangler::demangleFunctionParameterList(StringView &MangledName) {    // Empty parameter list.    if (MangledName.consumeFront('X'))      return {}; -  ParamList *Head; -  ParamList **Current = &Head; +  FunctionParams *Head; +  FunctionParams **Current = &Head;    while (!Error && !MangledName.startsWith('@') &&           !MangledName.startsWith('Z')) { @@ -1578,7 +1913,7 @@ ParamList Demangler::demangleFunctionParameterList() {        }        MangledName = MangledName.dropFront(); -      *Current = Arena.alloc<ParamList>(); +      *Current = Arena.alloc<FunctionParams>();        (*Current)->Current = FunctionParamBackRefs[N]->clone(Arena);        Current = &(*Current)->Next;        continue; @@ -1586,8 +1921,8 @@ ParamList Demangler::demangleFunctionParameterList() {      size_t OldSize = MangledName.size(); -    *Current = Arena.alloc<ParamList>(); -    (*Current)->Current = demangleType(QualifierMangleMode::Drop); +    *Current = Arena.alloc<FunctionParams>(); +    (*Current)->Current = demangleType(MangledName, QualifierMangleMode::Drop);      size_t CharsConsumed = OldSize - MangledName.size();      assert(CharsConsumed != 0); @@ -1618,14 +1953,33 @@ ParamList Demangler::demangleFunctionParameterList() {    return {};  } -ParamList Demangler::demangleTemplateParameterList() { -  ParamList *Head; -  ParamList **Current = &Head; +TemplateParams * +Demangler::demangleTemplateParameterList(StringView &MangledName) { +  TemplateParams *Head; +  TemplateParams **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 = Arena.alloc<TemplateParams>(); + +    // Empty parameter pack. +    if (MangledName.consumeFront("$S") || MangledName.consumeFront("$$V") || +        MangledName.consumeFront("$$$V")) { +      if (!MangledName.startsWith('@')) +        Error = true; +      continue; +    } + +    if (MangledName.consumeFront("$$Y")) { +      (*Current)->IsTemplateTemplate = true; +      (*Current)->IsAliasTemplate = true; +      (*Current)->ParamName = demangleFullyQualifiedTypeName(MangledName); +    } else if (MangledName.consumeFront("$1?")) { +      (*Current)->ParamName = demangleFullyQualifiedSymbolName(MangledName); +      (*Current)->ParamType = demangleFunctionEncoding(MangledName); +    } else { +      (*Current)->ParamType = +          demangleType(MangledName, QualifierMangleMode::Drop); +    }      Current = &(*Current)->Next;    } @@ -1636,12 +1990,12 @@ ParamList Demangler::demangleTemplateParameterList() {    // Template parameter lists cannot be variadic, so it can only be terminated    // by @.    if (MangledName.consumeFront('@')) -    return *Head; +    return Head;    Error = true;    return {};  } -void Demangler::output() { +void Demangler::output(const Symbol *S, OutputStream &OS) {    // Converts an AST to a string.    //    // Converting an AST representing a C++ type to a string is tricky due @@ -1659,26 +2013,24 @@ void Demangler::output() {    // 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'; +  Type::outputPre(OS, *S->SymbolType); +  outputName(OS, S->SymbolName); +  Type::outputPost(OS, *S->SymbolType);  }  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(); +  Demangler D; +  StringView Name{MangledName}; +  Symbol *S = D.parse(Name);    if (D.Error)      *Status = llvm::demangle_invalid_mangled_name;    else      *Status = llvm::demangle_success; -  D.output(); +  OutputStream OS = OutputStream::create(Buf, N, 1024); +  D.output(S, OS); +  OS << '\0';    return OS.getBuffer();  } | 
