[llvm] r340083 - [MS Demangler] Demangle all remaining types of operators.

Zachary Turner via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 17 14:18:05 PDT 2018


Author: zturner
Date: Fri Aug 17 14:18:05 2018
New Revision: 340083

URL: http://llvm.org/viewvc/llvm-project?rev=340083&view=rev
Log:
[MS Demangler] Demangle all remaining types of operators.

This demangles all remaining special operators including thunks,
RTTI Descriptors, and local static guard variables.

Modified:
    llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp
    llvm/trunk/test/Demangle/ms-operators.test

Modified: llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp?rev=340083&r1=340082&r2=340083&view=diff
==============================================================================
--- llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp (original)
+++ llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp Fri Aug 17 14:18:05 2018
@@ -282,6 +282,8 @@ struct OperatorMapEntry {
   OperatorTy Operator;
 };
 
+// The entries here must be in the same order as the enumeration so that it can
+// be indexed by enum value.
 OperatorMapEntry OperatorMap[] = {
     {"0", " <ctor>", OperatorTy::Ctor},
     {"1", " <dtor>", OperatorTy::Dtor},
@@ -347,8 +349,7 @@ OperatorMapEntry OperatorMap[] = {
     {"_P", "`udt returning'", OperatorTy::UdtReturning},
     {"_Q", "`unknown'", OperatorTy::Unknown},
     {"_R0", "`RTTI Type Descriptor'", OperatorTy::RttiTypeDescriptor},
-    {"_R1", "`RTTI Base Class Descriptor'",
-     OperatorTy::RttiBaseClassDescriptor},
+    {"_R1", "RTTI Base Class Descriptor", OperatorTy::RttiBaseClassDescriptor},
     {"_R2", "`RTTI Base Class Array'", OperatorTy::RttiBaseClassArray},
     {"_R3", "`RTTI Class Hierarchy Descriptor'",
      OperatorTy::RttiClassHierarchyDescriptor},
@@ -364,6 +365,7 @@ OperatorMapEntry OperatorMap[] = {
 
 // Function classes
 enum FuncClass : uint16_t {
+  None = 0,
   Public = 1 << 0,
   Protected = 1 << 1,
   Private = 1 << 2,
@@ -373,6 +375,9 @@ enum FuncClass : uint16_t {
   Far = 1 << 6,
   ExternC = 1 << 7,
   NoPrototype = 1 << 8,
+  VirtualThisAdjust = 1 << 9,
+  VirtualThisAdjustEx = 1 << 10,
+  StaticThisAdjust = 1 << 11
 };
 
 enum NameBackrefBehavior : uint8_t {
@@ -381,7 +386,14 @@ enum NameBackrefBehavior : uint8_t {
   NBB_Simple = 1 << 1,   // save simple names.
 };
 
-enum class SymbolCategory { Unknown, Function, Variable };
+enum class SymbolCategory {
+  Unknown,
+  NamedFunction,
+  NamedVariable,
+  UnnamedFunction,
+  UnnamedVariable,
+  SpecialOperator
+};
 
 namespace {
 
@@ -474,14 +486,46 @@ struct Name {
 };
 
 struct OperatorInfo : public Name {
+  explicit OperatorInfo(const OperatorMapEntry &Info) : Info(&Info) {
+    this->IsOperator = true;
+  }
+  explicit OperatorInfo(OperatorTy OpType)
+      : OperatorInfo(OperatorMap[(int)OpType]) {}
+
   const OperatorMapEntry *Info = nullptr;
 };
 
 struct StringLiteral : public OperatorInfo {
+  StringLiteral() : OperatorInfo(OperatorTy::StringLiteral) {}
+
   PrimTy CharType;
   bool IsTruncated = false;
 };
 
+struct RttiBaseClassDescriptor : public OperatorInfo {
+  RttiBaseClassDescriptor()
+      : OperatorInfo(OperatorTy::RttiBaseClassDescriptor) {}
+
+  uint32_t NVOffset = 0;
+  int32_t VBPtrOffset = 0;
+  uint32_t VBTableOffset = 0;
+  uint32_t Flags = 0;
+};
+
+struct LocalStaticGuardVariable : public OperatorInfo {
+  LocalStaticGuardVariable() : OperatorInfo(OperatorTy::LocalStaticGuard) {}
+
+  uint32_t ScopeIndex = 0;
+  bool IsVisible = false;
+};
+
+struct VirtualMemberPtrThunk : public OperatorInfo {
+  VirtualMemberPtrThunk() : OperatorInfo(OperatorTy::Vcall) {}
+
+  uint64_t OffsetInVTable = 0;
+  CallingConv CC = CallingConv::Cdecl;
+};
+
 struct PointerType : public Type {
   Type *clone(ArenaAllocator &Arena) const override;
   void outputPre(OutputStream &OS, NameResolver &Resolver) override;
@@ -507,6 +551,13 @@ struct MemberPointerType : public Type {
 };
 
 struct FunctionType : public Type {
+  struct ThisAdjustor {
+    uint32_t StaticOffset = 0;
+    int32_t VBPtrOffset = 0;
+    int32_t VBOffsetOffset = 0;
+    int32_t VtordispOffset = 0;
+  };
+
   Type *clone(ArenaAllocator &Arena) const override;
   void outputPre(OutputStream &OS, NameResolver &Resolver) override;
   void outputPost(OutputStream &OS, NameResolver &Resolver) override;
@@ -514,6 +565,7 @@ struct FunctionType : public Type {
   // True if this FunctionType instance is the Pointee of a PointerType or
   // MemberPointerType.
   bool IsFunctionPointer = false;
+  bool IsThunk = false;
 
   Type *ReturnType = nullptr;
   // If this is a reference, the type of reference.
@@ -522,6 +574,9 @@ struct FunctionType : public Type {
   CallingConv CallConvention;
   FuncClass FunctionClass;
 
+  // Valid if IsThunk is true.
+  ThisAdjustor *ThisAdjust = nullptr;
+
   FunctionParams Params;
 };
 
@@ -767,6 +822,23 @@ static void outputParameterList(OutputSt
   OS << ">";
 }
 
+static void outputQualifiers(OutputStream &OS, Qualifiers Q) {
+  if (Q & Q_Const) {
+    outputSpaceIfNecessary(OS);
+    OS << "const";
+  }
+
+  if (Q & Q_Volatile) {
+    outputSpaceIfNecessary(OS);
+    OS << "volatile";
+  }
+
+  if (Q & Q_Restrict) {
+    outputSpaceIfNecessary(OS);
+    OS << "__restrict";
+  }
+}
+
 static void outputNameComponent(OutputStream &OS, bool IsBackReference,
                                 const TemplateParams *TParams, StringView Str,
                                 NameResolver &Resolver) {
@@ -827,15 +899,27 @@ static void outputName(OutputStream &OS,
       OS << "<conversion>";
     }
     break;
-  case OperatorTy::StringLiteral: {
-    const StringLiteral &SL = static_cast<const StringLiteral &>(Operator);
-    outputStringLiteral(OS, SL);
-    break;
-  }
   case OperatorTy::LiteralOperator:
     OS << Operator.Info->Name;
     outputNameComponent(OS, *TheName, Resolver);
     break;
+  case OperatorTy::RttiBaseClassDescriptor: {
+    const RttiBaseClassDescriptor &BCD =
+        static_cast<const RttiBaseClassDescriptor &>(Operator);
+    OS << "`" << Operator.Info->Name << " at (";
+    OS << BCD.NVOffset << ", " << BCD.VBPtrOffset << ", " << BCD.VBTableOffset
+       << ", " << BCD.Flags;
+    OS << ")'";
+    break;
+  }
+  case OperatorTy::LocalStaticGuard: {
+    const LocalStaticGuardVariable &LSG =
+        static_cast<const LocalStaticGuardVariable &>(Operator);
+    OS << Operator.Info->Name;
+    if (LSG.ScopeIndex > 0)
+      OS << "{" << LSG.ScopeIndex << "}";
+    break;
+  }
   default:
     OS << Operator.Info->Name;
     if (Operator.IsTemplateInstantiation)
@@ -844,6 +928,45 @@ static void outputName(OutputStream &OS,
   }
 }
 
+static void outputSpecialOperator(OutputStream &OS, const Name *OuterName,
+                                  NameResolver &Resolver) {
+  assert(OuterName);
+  // The last component should be an operator.
+  const Name *LastComponent = OuterName;
+  while (LastComponent->Next)
+    LastComponent = LastComponent->Next;
+
+  assert(LastComponent->IsOperator);
+  const OperatorInfo &Oper = static_cast<const OperatorInfo &>(*LastComponent);
+  switch (Oper.Info->Operator) {
+  case OperatorTy::StringLiteral: {
+    const StringLiteral &SL = static_cast<const StringLiteral &>(Oper);
+    outputStringLiteral(OS, SL);
+    break;
+  }
+  case OperatorTy::Vcall: {
+    // [thunk]: __cdecl Base::`vcall'{8, {flat}}' }'
+    const VirtualMemberPtrThunk &Thunk =
+        static_cast<const VirtualMemberPtrThunk &>(Oper);
+    OS << "[thunk]: ";
+    outputCallingConvention(OS, Thunk.CC);
+    OS << " ";
+    // Print out namespaces or outer class BackReferences.
+    const Name *N = OuterName;
+    for (; N->Next; N = N->Next) {
+      outputNameComponent(OS, *N, Resolver);
+      OS << "::";
+    }
+    OS << "`vcall'{";
+    OS << Thunk.OffsetInVTable << ", {flat}}";
+    break;
+  }
+  default:
+    // There are no other special operator categories.
+    LLVM_BUILTIN_UNREACHABLE;
+  }
+}
+
 namespace {
 
 bool Name::isStringLiteralOperatorInfo() const {
@@ -877,20 +1000,7 @@ void Type::outputPre(OutputStream &OS, T
   }
   Ty.outputPre(OS, Resolver);
 
-  if (Ty.Quals & Q_Const) {
-    outputSpaceIfNecessary(OS);
-    OS << "const";
-  }
-
-  if (Ty.Quals & Q_Volatile) {
-    outputSpaceIfNecessary(OS);
-    OS << "volatile";
-  }
-
-  if (Ty.Quals & Q_Restrict) {
-    outputSpaceIfNecessary(OS);
-    OS << "__restrict";
-  }
+  outputQualifiers(OS, Ty.Quals);
 }
 
 // Write the "second half" of a given type.
@@ -1054,6 +1164,9 @@ Type *FunctionType::clone(ArenaAllocator
 }
 
 void FunctionType::outputPre(OutputStream &OS, NameResolver &Resolver) {
+  if ((FunctionClass & StaticThisAdjust) || (FunctionClass & VirtualThisAdjust))
+    OS << "[thunk]: ";
+
   if (!(FunctionClass & Global)) {
     if (FunctionClass & Static)
       OS << "static ";
@@ -1081,6 +1194,11 @@ void FunctionType::outputPost(OutputStre
   if (FunctionClass & NoPrototype)
     return;
 
+  if (FunctionClass & VirtualThisAdjust) {
+    OS << "`vtordisp{" << ThisAdjust->VtordispOffset << ", "
+       << ThisAdjust->StaticOffset << "}'";
+  }
+
   OS << "(";
   outputParameterList(OS, Params, Resolver);
   OS << ")";
@@ -1152,6 +1270,7 @@ void ArrayType::outputPost(OutputStream
 struct Symbol {
   SymbolCategory Category;
 
+  Qualifiers SymbolQuals = Q_None;
   Name *SymbolName = nullptr;
   Type *SymbolType = nullptr;
 };
@@ -1183,6 +1302,8 @@ public:
   // You are supposed to call parse() first and then check if error is true.  If
   // it is false, call output() to write the formatted name to the given stream.
   Symbol *parse(StringView &MangledName);
+  Symbol *parseOperator(StringView &MangledName);
+
   void output(const Symbol *S, OutputStream &OS);
 
   StringView resolve(StringView N) override;
@@ -1193,9 +1314,12 @@ public:
   void dumpBackReferences();
 
 private:
-  Type *demangleVariableEncoding(StringView &MangledName);
+  std::pair<SymbolCategory, Type *>
+  demangleSymbolCategoryAndType(StringView &MangledName);
+
+  Type *demangleVariableEncoding(StringView &MangledName, StorageClass SC);
   Type *demangleFunctionEncoding(StringView &MangledName);
-  Type *demangleVtableEncoding(StringView &MangledName);
+  uint64_t demangleThunkThisAdjust(StringView &MangledName);
 
   Qualifiers demanglePointerExtQualifiers(StringView &MangledName);
 
@@ -1214,6 +1338,8 @@ private:
   FunctionParams demangleFunctionParameterList(StringView &MangledName);
 
   std::pair<uint64_t, bool> demangleNumber(StringView &MangledName);
+  uint64_t demangleUnsigned(StringView &MangledName);
+  int64_t demangleSigned(StringView &MangledName);
 
   void memorizeString(StringView s);
 
@@ -1233,7 +1359,8 @@ private:
   Name *demangleBackRefName(StringView &MangledName);
   Name *demangleTemplateInstantiationName(StringView &MangledName,
                                           NameBackrefBehavior NBB);
-  OperatorInfo *demangleOperatorName(StringView &MangledName);
+  std::pair<OperatorTy, Name *> demangleOperatorName(StringView &MangledName,
+                                                     bool FullyQualified);
   Name *demangleSimpleName(StringView &MangledName, bool Memorize);
   Name *demangleAnonymousNamespaceName(StringView &MangledName);
   Name *demangleLocallyScopedNamePiece(StringView &MangledName);
@@ -1278,12 +1405,86 @@ StringView Demangler::copyString(StringV
   return {Stable, Borrowed.size()};
 }
 
-// Parser entry point.
-Symbol *Demangler::parse(StringView &MangledName) {
+Symbol *Demangler::parseOperator(StringView &MangledName) {
   Symbol *S = Arena.alloc<Symbol>();
 
+  bool IsMember = false;
+  OperatorTy OTy;
+  std::tie(OTy, S->SymbolName) = demangleOperatorName(MangledName, true);
+  switch (OTy) {
+  case OperatorTy::StringLiteral:
+  case OperatorTy::Vcall:
+    S->Category = SymbolCategory::SpecialOperator;
+    break;
+  case OperatorTy::Vftable:                // Foo@@6B@
+  case OperatorTy::LocalVftable:           // Foo@@6B@
+  case OperatorTy::RttiCompleteObjLocator: // Foo@@6B@
+  case OperatorTy::Vbtable:                // Foo@@7B@
+    S->Category = SymbolCategory::UnnamedVariable;
+    switch (MangledName.popFront()) {
+    case '6':
+    case '7':
+      std::tie(S->SymbolQuals, IsMember) = demangleQualifiers(MangledName);
+      if (!MangledName.consumeFront('@'))
+        Error = true;
+      break;
+    default:
+      Error = true;
+      break;
+    }
+    break;
+  case OperatorTy::RttiTypeDescriptor: // <type>@@8
+    S->Category = SymbolCategory::UnnamedVariable;
+    S->SymbolType = demangleType(MangledName, QualifierMangleMode::Result);
+    if (Error)
+      break;
+    if (!MangledName.consumeFront("@8"))
+      Error = true;
+    if (!MangledName.empty())
+      Error = true;
+    break;
+  case OperatorTy::LocalStaticGuard: {
+    S->Category = SymbolCategory::UnnamedVariable;
+    break;
+  }
+  default:
+    if (!Error)
+      std::tie(S->Category, S->SymbolType) =
+          demangleSymbolCategoryAndType(MangledName);
+    break;
+  }
+
+  return (Error) ? nullptr : S;
+}
+
+std::pair<SymbolCategory, Type *>
+Demangler::demangleSymbolCategoryAndType(StringView &MangledName) {
+  // Read a variable.
+  switch (MangledName.front()) {
+  case '0':
+  case '1':
+  case '2':
+  case '3':
+  case '4':
+    return std::make_pair(
+        SymbolCategory::NamedVariable,
+        demangleVariableEncoding(MangledName,
+                                 demangleVariableStorageClass(MangledName)));
+  case '8':
+    MangledName.consumeFront('8');
+    return std::pair<SymbolCategory, Type *>(SymbolCategory::UnnamedVariable,
+                                             nullptr);
+  }
+  return std::make_pair(SymbolCategory::NamedFunction,
+                        demangleFunctionEncoding(MangledName));
+}
+
+// Parser entry point.
+Symbol *Demangler::parse(StringView &MangledName) {
   // We can't demangle MD5 names, just output them as-is.
-  if (MangledName.startsWith("??@")) {
+  // Also, MSVC-style mangled symbols must start with '?'.
+  if (MangledName.startsWith("??@") || !MangledName.startsWith('?')) {
+    Symbol *S = Arena.alloc<Symbol>();
     S->Category = SymbolCategory::Unknown;
     S->SymbolName = Arena.alloc<Name>();
     S->SymbolName->Str = MangledName;
@@ -1292,43 +1493,22 @@ Symbol *Demangler::parse(StringView &Man
     return S;
   }
 
-  // MSVC-style mangled symbols must start with '?'.
-  if (!MangledName.consumeFront("?")) {
-    S->Category = SymbolCategory::Unknown;
-    S->SymbolName = Arena.alloc<Name>();
-    S->SymbolName->Str = MangledName;
-    S->SymbolType = nullptr;
-    return S;
-  }
+  MangledName.consumeFront('?');
+
+  // ?$ is a template instantiation, but all other names that start with ? are
+  // operators / special names.
+  if (MangledName.startsWith('?') && !MangledName.startsWith("?$"))
+    return parseOperator(MangledName);
 
-  // What follows is a main symbol name. This may include
-  // namespaces or class BackReferences.
+  Symbol *S = Arena.alloc<Symbol>();
+  // What follows is a main symbol name. This may include namespaces or class
+  // back references.
   S->SymbolName = demangleFullyQualifiedSymbolName(MangledName);
   if (Error)
     return nullptr;
 
-  if (S->SymbolName->isStringLiteralOperatorInfo())
-    return S;
-
-  // Read a variable.
-  switch (MangledName.front()) {
-  case '0':
-  case '1':
-  case '2':
-  case '3':
-  case '4':
-    S->Category = SymbolCategory::Variable;
-    S->SymbolType = demangleVariableEncoding(MangledName);
-    break;
-  case '6':
-  case '7':
-    S->Category = SymbolCategory::Variable;
-    S->SymbolType = demangleVtableEncoding(MangledName);
-    break;
-  default:
-    S->Category = SymbolCategory::Function;
-    S->SymbolType = demangleFunctionEncoding(MangledName);
-  }
+  std::tie(S->Category, S->SymbolType) =
+      demangleSymbolCategoryAndType(MangledName);
 
   if (Error)
     return nullptr;
@@ -1336,23 +1516,6 @@ Symbol *Demangler::parse(StringView &Man
   return S;
 }
 
-Type *Demangler::demangleVtableEncoding(StringView &MangledName) {
-  Type *Ty = Arena.alloc<Type>();
-  switch (MangledName.popFront()) {
-  case '6':
-    Ty->Prim = PrimTy::Vftable;
-    break;
-  case '7':
-    Ty->Prim = PrimTy::Vbtable;
-    break;
-  }
-  bool IsMember = false;
-  std::tie(Ty->Quals, IsMember) = demangleQualifiers(MangledName);
-  Ty->Storage = StorageClass::None;
-  MangledName.consumeFront('@');
-  return Ty;
-}
-
 // <type-encoding> ::= <storage-class> <variable-type>
 // <storage-class> ::= 0  # private static member
 //                 ::= 1  # protected static member
@@ -1360,9 +1523,8 @@ Type *Demangler::demangleVtableEncoding(
 //                 ::= 3  # global
 //                 ::= 4  # static local
 
-Type *Demangler::demangleVariableEncoding(StringView &MangledName) {
-  StorageClass SC = demangleVariableStorageClass(MangledName);
-
+Type *Demangler::demangleVariableEncoding(StringView &MangledName,
+                                          StorageClass SC) {
   Type *Ty = demangleType(MangledName, QualifierMangleMode::Drop);
 
   Ty->Storage = SC;
@@ -1438,6 +1600,25 @@ std::pair<uint64_t, bool> Demangler::dem
   return {0ULL, false};
 }
 
+uint64_t Demangler::demangleUnsigned(StringView &MangledName) {
+  bool IsNegative = false;
+  uint64_t Number = 0;
+  std::tie(Number, IsNegative) = demangleNumber(MangledName);
+  if (IsNegative)
+    Error = true;
+  return Number;
+}
+
+int64_t Demangler::demangleSigned(StringView &MangledName) {
+  bool IsNegative = false;
+  uint64_t Number = 0;
+  std::tie(Number, IsNegative) = demangleNumber(MangledName);
+  if (Number > INT64_MAX)
+    Error = true;
+  int64_t I = static_cast<int64_t>(Number);
+  return IsNegative ? -I : I;
+}
+
 // First 10 strings can be referenced by special BackReferences ?0, ?1, ..., ?9.
 // Memorize it.
 void Demangler::memorizeString(StringView S) {
@@ -1492,7 +1673,8 @@ Name *Demangler::demangleTemplateInstant
   return Node;
 }
 
-OperatorInfo *Demangler::demangleOperatorName(StringView &MangledName) {
+std::pair<OperatorTy, Name *>
+Demangler::demangleOperatorName(StringView &MangledName, bool FullyQualified) {
   assert(MangledName.startsWith('?'));
   MangledName.consumeFront('?');
 
@@ -1505,28 +1687,77 @@ OperatorInfo *Demangler::demangleOperato
   }
   if (!Entry) {
     Error = true;
-    return nullptr;
+    return std::make_pair(OperatorTy::Unknown, nullptr);
   }
 
-  OperatorInfo *Oper = nullptr;
+  Name *N = nullptr;
   switch (Entry->Operator) {
+  case OperatorTy::Vftable:                // Foo@@6B@
+  case OperatorTy::LocalVftable:           // Foo@@6B@
+  case OperatorTy::RttiCompleteObjLocator: // Foo@@6B@
+  case OperatorTy::Vbtable: {              // Foo@@7B@
+    OperatorInfo *Oper = Arena.alloc<OperatorInfo>(*Entry);
+    N = (FullyQualified) ? demangleNameScopeChain(MangledName, Oper) : Oper;
+    break;
+  }
+
   case OperatorTy::StringLiteral:
-    Oper = demangleStringLiteral(MangledName);
+    N = demangleStringLiteral(MangledName);
     break;
   case OperatorTy::LiteralOperator:
-    Oper = Arena.alloc<OperatorInfo>();
-    Oper->Str = demangleSimpleString(MangledName, false);
+    N = Arena.alloc<OperatorInfo>(*Entry);
+    N->Str = demangleSimpleString(MangledName, false);
+    if (!MangledName.consumeFront('@'))
+      Error = true;
     break;
+  case OperatorTy::RttiBaseClassDescriptor: {
+    RttiBaseClassDescriptor *Temp = Arena.alloc<RttiBaseClassDescriptor>();
+    Temp->NVOffset = demangleUnsigned(MangledName);
+    Temp->VBPtrOffset = demangleSigned(MangledName);
+    Temp->VBTableOffset = demangleUnsigned(MangledName);
+    Temp->Flags = demangleUnsigned(MangledName);
+    N = (FullyQualified) ? demangleNameScopeChain(MangledName, Temp) : Temp;
+    break;
+  }
+  case OperatorTy::Vcall: {
+    VirtualMemberPtrThunk *Temp = Arena.alloc<VirtualMemberPtrThunk>();
+    N = demangleNameScopeChain(MangledName, Temp);
+    if (Error)
+      break;
+    if (!MangledName.consumeFront("$B"))
+      Error = true;
+    Temp->OffsetInVTable = demangleUnsigned(MangledName);
+    if (!MangledName.consumeFront('A'))
+      Error = true;
+    Temp->CC = demangleCallingConvention(MangledName);
+    break;
+  }
+  case OperatorTy::RttiTypeDescriptor:
+    // This one is just followed by a type, not a name scope.
+    N = Arena.alloc<OperatorInfo>(*Entry);
+    break;
+  case OperatorTy::LocalStaticGuard: {
+    LocalStaticGuardVariable *Temp = Arena.alloc<LocalStaticGuardVariable>();
+    N = (FullyQualified) ? demangleNameScopeChain(MangledName, Temp) : Temp;
+    if (MangledName.consumeFront("4IA"))
+      Temp->IsVisible = false;
+    else if (MangledName.consumeFront("5"))
+      Temp->IsVisible = true;
+    else
+      Error = true;
+    if (!MangledName.empty())
+      Temp->ScopeIndex = demangleUnsigned(MangledName);
+    break;
+  }
   default:
-    Oper = Arena.alloc<OperatorInfo>();
+    N = Arena.alloc<OperatorInfo>(*Entry);
+    N = (FullyQualified) ? demangleNameScopeChain(MangledName, N) : N;
+    break;
   }
-
-  Oper->Info = Entry;
-  Oper->IsOperator = true;
   if (Error)
-    return nullptr;
+    return std::make_pair(OperatorTy::Unknown, nullptr);
 
-  return Oper;
+  return std::make_pair(Entry->Operator, N);
 }
 
 Name *Demangler::demangleSimpleName(StringView &MangledName, bool Memorize) {
@@ -1956,11 +2187,6 @@ Name *Demangler::demangleFullyQualifiedS
   if (Error)
     return nullptr;
 
-  // This is a special case that isn't followed by a scope.
-  assert(SymbolName);
-  if (SymbolName->isStringLiteralOperatorInfo())
-    return SymbolName;
-
   Name *QualName = demangleNameScopeChain(MangledName, SymbolName);
   if (Error)
     return nullptr;
@@ -1990,7 +2216,7 @@ Name *Demangler::demangleUnqualifiedSymb
   if (MangledName.startsWith("?$"))
     return demangleTemplateInstantiationName(MangledName, NBB);
   if (MangledName.startsWith('?'))
-    return demangleOperatorName(MangledName);
+    return demangleOperatorName(MangledName, false).second;
   return demangleSimpleName(MangledName, (NBB & NBB_Simple) != 0);
 }
 
@@ -2035,53 +2261,77 @@ FuncClass Demangler::demangleFunctionCla
   SwapAndRestore<StringView> RestoreOnError(MangledName, MangledName);
   RestoreOnError.shouldRestore(false);
 
-  FuncClass TempFlags = FuncClass(0);
-  if (MangledName.consumeFront("$$J0"))
-    TempFlags = ExternC;
-
   switch (MangledName.popFront()) {
   case '9':
-    return FuncClass(TempFlags | ExternC | NoPrototype);
+    return FuncClass(ExternC | NoPrototype);
   case 'A':
     return Private;
   case 'B':
-    return FuncClass(TempFlags | Private | Far);
+    return FuncClass(Private | Far);
   case 'C':
-    return FuncClass(TempFlags | Private | Static);
+    return FuncClass(Private | Static);
   case 'D':
-    return FuncClass(TempFlags | Private | Static);
+    return FuncClass(Private | Static);
   case 'E':
-    return FuncClass(TempFlags | Private | Virtual);
+    return FuncClass(Private | Virtual);
   case 'F':
-    return FuncClass(TempFlags | Private | Virtual);
+    return FuncClass(Private | Virtual);
   case 'I':
-    return FuncClass(TempFlags | Protected);
+    return FuncClass(Protected);
   case 'J':
-    return FuncClass(TempFlags | Protected | Far);
+    return FuncClass(Protected | Far);
   case 'K':
-    return FuncClass(TempFlags | Protected | Static);
+    return FuncClass(Protected | Static);
   case 'L':
-    return FuncClass(TempFlags | Protected | Static | Far);
+    return FuncClass(Protected | Static | Far);
   case 'M':
-    return FuncClass(TempFlags | Protected | Virtual);
+    return FuncClass(Protected | Virtual);
   case 'N':
-    return FuncClass(TempFlags | Protected | Virtual | Far);
+    return FuncClass(Protected | Virtual | Far);
+  case 'O':
+    return FuncClass(Protected | Virtual | StaticThisAdjust);
+  case 'P':
+    return FuncClass(Protected | Virtual | StaticThisAdjust | Far);
   case 'Q':
-    return FuncClass(TempFlags | Public);
+    return FuncClass(Public);
   case 'R':
-    return FuncClass(TempFlags | Public | Far);
+    return FuncClass(Public | Far);
   case 'S':
-    return FuncClass(TempFlags | Public | Static);
+    return FuncClass(Public | Static);
   case 'T':
-    return FuncClass(TempFlags | Public | Static | Far);
+    return FuncClass(Public | Static | Far);
   case 'U':
-    return FuncClass(TempFlags | Public | Virtual);
+    return FuncClass(Public | Virtual);
   case 'V':
-    return FuncClass(TempFlags | Public | Virtual | Far);
+    return FuncClass(Public | Virtual | Far);
+  case 'W':
+    return FuncClass(Public | Virtual | StaticThisAdjust);
+  case 'X':
+    return FuncClass(Public | Virtual | StaticThisAdjust | Far);
   case 'Y':
-    return FuncClass(TempFlags | Global);
+    return FuncClass(Global);
   case 'Z':
-    return FuncClass(TempFlags | Global | Far);
+    return FuncClass(Global | Far);
+  case '$': {
+    FuncClass VFlag = VirtualThisAdjust;
+    if (MangledName.consumeFront('R'))
+      VFlag = FuncClass(VFlag | VirtualThisAdjustEx);
+
+    switch (MangledName.popFront()) {
+    case '0':
+      return FuncClass(Private | Virtual | VFlag);
+    case '1':
+      return FuncClass(Private | Virtual | VFlag | Far);
+    case '2':
+      return FuncClass(Protected | Virtual | VFlag);
+    case '3':
+      return FuncClass(Protected | Virtual | VFlag | Far);
+    case '4':
+      return FuncClass(Public | Virtual | VFlag);
+    case '5':
+      return FuncClass(Public | Virtual | VFlag | Far);
+    }
+  }
   }
 
   Error = true;
@@ -2291,7 +2541,27 @@ FunctionType *Demangler::demangleFunctio
 }
 
 Type *Demangler::demangleFunctionEncoding(StringView &MangledName) {
+  FuncClass ExtraFlags = FuncClass::None;
+  if (MangledName.consumeFront("$$J0"))
+    ExtraFlags = FuncClass::ExternC;
+
   FuncClass FC = demangleFunctionClass(MangledName);
+  FC = FuncClass(ExtraFlags | FC);
+
+  FunctionType::ThisAdjustor *Adjustor = nullptr;
+  if (FC & FuncClass::StaticThisAdjust) {
+    Adjustor = Arena.alloc<FunctionType::ThisAdjustor>();
+    Adjustor->StaticOffset = demangleSigned(MangledName);
+  } else if (FC & FuncClass::VirtualThisAdjust) {
+    Adjustor = Arena.alloc<FunctionType::ThisAdjustor>();
+    if (FC & FuncClass::VirtualThisAdjustEx) {
+      Adjustor->VBPtrOffset = demangleSigned(MangledName);
+      Adjustor->VBOffsetOffset = demangleSigned(MangledName);
+    }
+    Adjustor->VtordispOffset = demangleSigned(MangledName);
+    Adjustor->StaticOffset = demangleSigned(MangledName);
+  }
+
   FunctionType *FTy = nullptr;
   if (FC & NoPrototype) {
     // This is an extern "C" function whose full signature hasn't been mangled.
@@ -2302,6 +2572,7 @@ Type *Demangler::demangleFunctionEncodin
     bool HasThisQuals = !(FC & (Global | Static));
     FTy = demangleFunctionType(MangledName, HasThisQuals, false);
   }
+  FTy->ThisAdjust = Adjustor;
   FTy->FunctionClass = FC;
 
   return FTy;
@@ -2694,6 +2965,11 @@ void Demangler::output(const Symbol *S,
     return;
   }
 
+  if (S->Category == SymbolCategory::SpecialOperator) {
+    outputSpecialOperator(OS, S->SymbolName, *this);
+    return;
+  }
+
   // Converts an AST to a string.
   //
   // Converting an AST representing a C++ type to a string is tricky due
@@ -2715,8 +2991,10 @@ void Demangler::output(const Symbol *S,
     Type::outputPre(OS, *S->SymbolType, *this);
     outputName(OS, S->SymbolName, S->SymbolType, *this);
     Type::outputPost(OS, *S->SymbolType, *this);
-  } else
+  } else {
+    outputQualifiers(OS, S->SymbolQuals);
     outputName(OS, S->SymbolName, nullptr, *this);
+  }
 }
 
 void Demangler::dumpBackReferences() {

Modified: llvm/trunk/test/Demangle/ms-operators.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Demangle/ms-operators.test?rev=340083&r1=340082&r2=340083&view=diff
==============================================================================
--- llvm/trunk/test/Demangle/ms-operators.test (original)
+++ llvm/trunk/test/Demangle/ms-operators.test Fri Aug 17 14:18:05 2018
@@ -143,11 +143,11 @@
 ??_8Middle2@@7B@
 ; CHECK: const Middle2::`vbtable'
 
-; ??_9Base@@$B7AA
-; FIXME: [thunk]: __cdecl Base::`vcall'{8, {flat}}' }'
+??_9Base@@$B7AA
+; CHECK: [thunk]: __cdecl Base::`vcall'{8, {flat}}
 
-; ??_B?1??getS@@YAAAUS@@XZ at 51
-; FIXME: `struct S & __cdecl getS(void)'::`2'::`local static guard'{2}'
+??_B?1??getS@@YAAAUS@@XZ at 51
+; CHECK: `struct S & __cdecl getS(void)'::`2'::`local static guard'{2}
 
 ??_C at _02PCEFGMJL@hi?$AA@
 ; CHECK: const char * {"hi"}
@@ -158,8 +158,8 @@
 ??_EBase@@UEAAPEAXI at Z
 ; CHECK: virtual void * __cdecl Base::`vector deleting dtor'(unsigned int)
 
-; ??_EDerived@@$4PPPPPPPM at A@EAAPEAXI at Z
-; FIXME: [thunk]:virtual void * __cdecl Derived::`vector deleting dtor'`vtordisp{4294967292, 0}' (unsigned int)
+??_EDerived@@$4PPPPPPPM at A@EAAPEAXI at Z
+; CHECK: [thunk]: virtual void * __cdecl Derived::`vector deleting dtor'`vtordisp{-4, 0}'(unsigned int)
 
 ??_F?$SomeTemplate at H@@QAEXXZ
 ; CHECK: void __thiscall SomeTemplate<int>::`default ctor closure'(void)
@@ -203,17 +203,17 @@
 ??_V at YAXPEAXAEAVklass@@@Z
 ; CHECK: void __cdecl operator delete[](void *, class klass &)
 
-; ??_R0?AUBase@@@8
-; FIXME: struct Base `RTTI Type Descriptor'
+??_R0?AUBase@@@8
+; CHECK: struct Base `RTTI Type Descriptor'
 
-; ??_R1A@?0A at EA@Base@@8
-; FIXME: Base::`RTTI Base Class Descriptor at (0, -1, 0, 64)'
+??_R1A@?0A at EA@Base@@8
+; CHECK: Base::`RTTI Base Class Descriptor at (0, -1, 0, 64)'
 
-; ??_R2Base@@8
-; FIXME: Base::`RTTI Base Class Array'
+??_R2Base@@8
+; CHECK: Base::`RTTI Base Class Array'
 
-; ??_R3Base@@8
-; FIXME: Base::`RTTI Class Hierarchy Descriptor'
+??_R3Base@@8
+; CHECK: Base::`RTTI Class Hierarchy Descriptor'
 
 ??_R4Base@@6B@
 ; CHECK: const Base::`RTTI Complete Object Locator'




More information about the llvm-commits mailing list