[MS Demangler] Demangle member pointer template parameters.
authorZachary Turner <zturner@google.com>
Mon, 20 Aug 2018 19:15:35 +0000 (19:15 +0000)
committerZachary Turner <zturner@google.com>
Mon, 20 Aug 2018 19:15:35 +0000 (19:15 +0000)
llvm-svn: 340199

llvm/lib/Demangle/MicrosoftDemangle.cpp
llvm/test/Demangle/ms-templates-memptrs-2.test [new file with mode: 0644]
llvm/test/Demangle/ms-templates-memptrs.test [new file with mode: 0644]

index 6f38209..58678e9 100644 (file)
@@ -20,6 +20,7 @@
 #include "StringView.h"
 #include "Utility.h"
 
+#include <array>
 #include <cctype>
 #include <cstdio>
 #include <tuple>
@@ -415,8 +416,13 @@ struct TemplateParams {
   bool IntegerLiteralIsNegative = false;
   bool IsEmptyParameterPack = false;
   bool PointerToSymbol = false;
+  bool NullptrLiteral = false;
+  bool DataMemberPointer = false;
   bool ReferenceToSymbol = false;
 
+  int ThunkOffsetCount = 0;
+  std::array<int64_t, 3> ThunkOffsets;
+
   // If IsIntegerLiteral is true, this is a non-type template parameter
   // whose value is contained in this field.
   uint64_t IntegralValue = 0;
@@ -794,11 +800,30 @@ static void outputParameterList(OutputStream &OS,
         OS << '-';
       OS << Head->IntegralValue;
     } else if (Head->PointerToSymbol || Head->ReferenceToSymbol) {
-      if (Head->PointerToSymbol)
-        OS << "&";
-      Type::outputPre(OS, *Head->ParamType);
-      outputName(OS, Head->ParamName, Head->ParamType);
-      Type::outputPost(OS, *Head->ParamType);
+      if (Head->NullptrLiteral)
+        OS << "nullptr";
+      else {
+        if (Head->ThunkOffsetCount > 0)
+          OS << "{";
+        else if (Head->PointerToSymbol)
+          OS << "&";
+        if (Head->ParamType)
+          Type::outputPre(OS, *Head->ParamType);
+        outputName(OS, Head->ParamName, Head->ParamType);
+        if (Head->ParamType)
+          Type::outputPost(OS, *Head->ParamType);
+        if (Head->ThunkOffsetCount > 0) {
+          for (int I = 0; I < Head->ThunkOffsetCount; ++I) {
+            OS << ", " << Head->ThunkOffsets[I];
+          }
+          OS << "}";
+        }
+      }
+    } else if (Head->DataMemberPointer) {
+      OS << "{" << Head->ThunkOffsets[0];
+      for (int I = 1; I < Head->ThunkOffsetCount; ++I)
+        OS << ", " << Head->ThunkOffsets[I];
+      OS << "}";
     } else if (Head->ParamType) {
       // simple type.
       Type::outputPre(OS, *Head->ParamType);
@@ -840,12 +865,33 @@ static void outputNameComponent(OutputStream &OS, const Name &N) {
     outputParameterList(OS, *N.TParams);
 }
 
+static const OperatorInfo *lastComponentAsOperator(const Name *TheName) {
+  if (!TheName)
+    return nullptr;
+  while (TheName->Next)
+    TheName = TheName->Next;
+  if (TheName->IsOperator)
+    return static_cast<const OperatorInfo *>(TheName);
+  return nullptr;
+}
+
 static void outputName(OutputStream &OS, const Name *TheName, const Type *Ty) {
   if (!TheName)
     return;
 
   outputSpaceIfNecessary(OS);
 
+  const OperatorInfo *Operator = lastComponentAsOperator(TheName);
+  const VirtualMemberPtrThunk *Thunk = nullptr;
+  if (Operator) {
+    if (Operator->Info->Operator == OperatorTy::Vcall) {
+      Thunk = static_cast<const VirtualMemberPtrThunk *>(Operator);
+      OS << "[thunk]: ";
+      outputCallingConvention(OS, Thunk->CC);
+      OS << " ";
+    }
+  }
+
   const Name *Previous = nullptr;
   // Print out namespaces or outer class BackReferences.
   for (; TheName->Next; TheName = TheName->Next) {
@@ -860,10 +906,9 @@ static void outputName(OutputStream &OS, const Name *TheName, const Type *Ty) {
     return;
   }
 
-  const OperatorInfo &Operator = static_cast<const OperatorInfo &>(*TheName);
 
   // Print out ctor or dtor.
-  switch (Operator.Info->Operator) {
+  switch (Operator->Info->Operator) {
   case OperatorTy::Dtor:
     OS << "~";
     LLVM_FALLTHROUGH;
@@ -884,30 +929,36 @@ static void outputName(OutputStream &OS, const Name *TheName, const Type *Ty) {
     }
     break;
   case OperatorTy::LiteralOperator:
-    OS << Operator.Info->Name;
+    OS << Operator->Info->Name;
     outputNameComponent(OS, *TheName);
     break;
   case OperatorTy::RttiBaseClassDescriptor: {
     const RttiBaseClassDescriptor &BCD =
-        static_cast<const RttiBaseClassDescriptor &>(Operator);
-    OS << "`" << Operator.Info->Name << " at (";
+        static_cast<const RttiBaseClassDescriptor &>(*Operator);
+    OS << "`" << Operator->Info->Name << " at (";
     OS << BCD.NVOffset << ", " << BCD.VBPtrOffset << ", " << BCD.VBTableOffset
        << ", " << BCD.Flags;
     OS << ")'";
     break;
   }
+  case OperatorTy::Vcall: {
+    OS << "`vcall'{";
+    OS << Thunk->OffsetInVTable << ", {flat}}";
+    break;
+  }
+
   case OperatorTy::LocalStaticGuard: {
     const LocalStaticGuardVariable &LSG =
-        static_cast<const LocalStaticGuardVariable &>(Operator);
-    OS << Operator.Info->Name;
+        static_cast<const LocalStaticGuardVariable &>(*Operator);
+    OS << Operator->Info->Name;
     if (LSG.ScopeIndex > 0)
       OS << "{" << LSG.ScopeIndex << "}";
     break;
   }
   default:
-    OS << Operator.Info->Name;
-    if (Operator.IsTemplateInstantiation)
-      outputParameterList(OS, *Operator.TParams);
+    OS << Operator->Info->Name;
+    if (Operator->IsTemplateInstantiation)
+      outputParameterList(OS, *Operator->TParams);
     break;
   }
 }
@@ -915,12 +966,10 @@ static void outputName(OutputStream &OS, const Name *TheName, const Type *Ty) {
 static void outputSpecialOperator(OutputStream &OS, const Name *OuterName) {
   assert(OuterName);
   // The last component should be an operator.
-  const Name *LastComponent = OuterName;
-  while (LastComponent->Next)
-    LastComponent = LastComponent->Next;
+  const OperatorInfo *Operator = lastComponentAsOperator(OuterName);
 
-  assert(LastComponent->IsOperator);
-  const OperatorInfo &Oper = static_cast<const OperatorInfo &>(*LastComponent);
+  assert(Operator->IsOperator);
+  const OperatorInfo &Oper = static_cast<const OperatorInfo &>(*Operator);
   switch (Oper.Info->Operator) {
   case OperatorTy::StringLiteral: {
     const StringLiteral &SL = static_cast<const StringLiteral &>(Oper);
@@ -1398,9 +1447,14 @@ Symbol *Demangler::parseOperator(StringView &MangledName) {
   std::tie(OTy, S->SymbolName) = demangleOperatorName(MangledName, true);
   switch (OTy) {
   case OperatorTy::StringLiteral:
-  case OperatorTy::Vcall:
     S->Category = SymbolCategory::SpecialOperator;
     break;
+  case OperatorTy::Vcall:
+    S->Category = SymbolCategory::UnnamedFunction;
+    break;
+  case OperatorTy::LocalStaticGuard:
+    S->Category = SymbolCategory::UnnamedVariable;
+    break;
   case OperatorTy::Vftable:                // Foo@@6B@
   case OperatorTy::LocalVftable:           // Foo@@6B@
   case OperatorTy::RttiCompleteObjLocator: // Foo@@6B@
@@ -1428,10 +1482,6 @@ Symbol *Demangler::parseOperator(StringView &MangledName) {
     if (!MangledName.empty())
       Error = true;
     break;
-  case OperatorTy::LocalStaticGuard: {
-    S->Category = SymbolCategory::UnnamedVariable;
-    break;
-  }
   default:
     if (!Error)
       std::tie(S->Category, S->SymbolType) =
@@ -2878,57 +2928,102 @@ Demangler::demangleTemplateParameterList(StringView &MangledName) {
     // Template parameter lists don't participate in back-referencing.
     *Current = Arena.alloc<TemplateParams>();
 
+    TemplateParams &TP = **Current;
+
     // Empty parameter pack.
     if (MangledName.consumeFront("$S") || MangledName.consumeFront("$$V") ||
         MangledName.consumeFront("$$$V")) {
-      (*Current)->IsEmptyParameterPack = true;
+      TP.IsEmptyParameterPack = true;
       break;
     }
 
     if (MangledName.consumeFront("$$Y")) {
       // Template alias
-      (*Current)->IsTemplateTemplate = true;
-      (*Current)->IsAliasTemplate = true;
-      (*Current)->ParamName = demangleFullyQualifiedTypeName(MangledName);
+      TP.IsTemplateTemplate = true;
+      TP.IsAliasTemplate = true;
+      TP.ParamName = demangleFullyQualifiedTypeName(MangledName);
     } else if (MangledName.consumeFront("$$B")) {
       // Array
-      (*Current)->ParamType =
-          demangleType(MangledName, QualifierMangleMode::Drop);
+      TP.ParamType = demangleType(MangledName, QualifierMangleMode::Drop);
     } else if (MangledName.consumeFront("$$C")) {
       // Type has qualifiers.
-      (*Current)->ParamType =
-          demangleType(MangledName, QualifierMangleMode::Mangle);
-    } else if (MangledName.startsWith("$1?")) {
-      MangledName.consumeFront("$1");
-      // Pointer to symbol
-      Symbol *S = parse(MangledName);
-      (*Current)->ParamName = S->SymbolName;
-      (*Current)->ParamType = S->SymbolType;
-      (*Current)->PointerToSymbol = true;
+      TP.ParamType = demangleType(MangledName, QualifierMangleMode::Mangle);
+    } else if (MangledName.startsWith("$1") || MangledName.startsWith("$H") ||
+               MangledName.startsWith("$I") || MangledName.startsWith("$J")) {
+      MangledName = MangledName.dropFront();
+      // 1 - single inheritance       <name>
+      // H - multiple inheritance     <name> <number>
+      // I - virtual inheritance      <name> <number> <number> <number>
+      // J - unspecified inheritance  <name> <number> <number> <number>
+      char InheritanceSpecifier = MangledName.popFront();
+      // Pointer to member
+      Symbol *S = MangledName.startsWith('?') ? parse(MangledName) : nullptr;
+      switch (InheritanceSpecifier) {
+      case 'J':
+        TP.ThunkOffsets[TP.ThunkOffsetCount++] = demangleSigned(MangledName);
+        LLVM_FALLTHROUGH;
+      case 'I':
+        TP.ThunkOffsets[TP.ThunkOffsetCount++] = demangleSigned(MangledName);
+        LLVM_FALLTHROUGH;
+      case 'H':
+        TP.ThunkOffsets[TP.ThunkOffsetCount++] = demangleSigned(MangledName);
+        LLVM_FALLTHROUGH;
+      case '1':
+        break;
+      default:
+        Error = true;
+        break;
+      }
+      TP.PointerToSymbol = true;
+      if (S) {
+        TP.ParamName = S->SymbolName;
+        TP.ParamType = S->SymbolType;
+      } else
+        TP.NullptrLiteral = true;
     } else if (MangledName.startsWith("$E?")) {
       MangledName.consumeFront("$E");
       // Reference to symbol
       Symbol *S = parse(MangledName);
-      (*Current)->ParamName = S->SymbolName;
-      (*Current)->ParamType = S->SymbolType;
-      (*Current)->ReferenceToSymbol = true;
+      TP.ParamName = S->SymbolName;
+      TP.ParamType = S->SymbolType;
+      TP.ReferenceToSymbol = true;
+    } else if (MangledName.startsWith("$F") || MangledName.startsWith("$G")) {
+      // Data member pointer.
+      MangledName = MangledName.dropFront();
+      char InheritanceSpecifier = MangledName.popFront();
+
+      switch (InheritanceSpecifier) {
+      case 'G':
+        TP.ThunkOffsets[TP.ThunkOffsetCount++] = demangleSigned(MangledName);
+        LLVM_FALLTHROUGH;
+      case 'F':
+        TP.ThunkOffsets[TP.ThunkOffsetCount++] = demangleSigned(MangledName);
+        TP.ThunkOffsets[TP.ThunkOffsetCount++] = demangleSigned(MangledName);
+        LLVM_FALLTHROUGH;
+      case '0':
+        break;
+      default:
+        Error = true;
+        break;
+      }
+      TP.DataMemberPointer = true;
+
     } else if (MangledName.consumeFront("$0")) {
       // Integral non-type template parameter
       bool IsNegative = false;
       uint64_t Value = 0;
       std::tie(Value, IsNegative) = demangleNumber(MangledName);
 
-      (*Current)->IsIntegerLiteral = true;
-      (*Current)->IntegerLiteralIsNegative = IsNegative;
-      (*Current)->IntegralValue = Value;
+      TP.IsIntegerLiteral = true;
+      TP.IntegerLiteralIsNegative = IsNegative;
+      TP.IntegralValue = Value;
     } else {
-      (*Current)->ParamType =
-          demangleType(MangledName, QualifierMangleMode::Drop);
+      TP.ParamType = demangleType(MangledName, QualifierMangleMode::Drop);
     }
     if (Error)
       return nullptr;
 
-    Current = &(*Current)->Next;
+    Current = &TP.Next;
   }
 
   if (Error)
diff --git a/llvm/test/Demangle/ms-templates-memptrs-2.test b/llvm/test/Demangle/ms-templates-memptrs-2.test
new file mode 100644 (file)
index 0000000..d06ea03
--- /dev/null
@@ -0,0 +1,31 @@
+; RUN: llvm-undname < %s | FileCheck %s
+
+; CHECK-NOT: Invalid mangled name
+
+
+?m@@3U?$J@UM@@$0A@@@A
+; CHECK: struct J<struct M, 0> m
+
+?m2@@3U?$K@UM@@$0?0@@A
+; CHECK: struct K<struct M, -1> m2
+
+?n@@3U?$J@UN@@$HA@@@A
+; CHECK: struct J<struct N, nullptr> n
+
+?n2@@3U?$K@UN@@$0?0@@A
+; CHECK: struct K<struct N, -1> n2
+
+?o@@3U?$J@UO@@$IA@A@@@A
+; CHECK: struct J<struct O, nullptr> o
+
+?o2@@3U?$K@UO@@$FA@?0@@A
+; CHECK: struct K<struct O, {0, -1}> o2
+
+?p@@3U?$J@UP@@$JA@A@?0@@A
+; CHECK: struct J<struct P, nullptr> p
+
+?p2@@3U?$K@UP@@$GA@A@?0@@A
+; CHECK: struct K<struct P, {0, 0, -1}> p2
+
+??0?$ClassTemplate@$J??_9MostGeneral@@$BA@AEA@M@3@@QAE@XZ
+; CHECK: __thiscall ClassTemplate<{[thunk]: __thiscall MostGeneral::`vcall'{0, {flat}}, 0, 12, 4}>::ClassTemplate<{[thunk]: __thiscall MostGeneral::`vcall'{0, {flat}}, 0, 12, 4}>(void)
\ No newline at end of file
diff --git a/llvm/test/Demangle/ms-templates-memptrs.test b/llvm/test/Demangle/ms-templates-memptrs.test
new file mode 100644 (file)
index 0000000..3647a89
--- /dev/null
@@ -0,0 +1,95 @@
+; RUN: llvm-undname < %s | FileCheck %s
+
+; CHECK-NOT: Invalid mangled name
+
+; There's a back-referencing problem here
+??$CallMethod@UC@NegativeNVOffset@@$I??_912@$BA@AEPPPPPPPM@A@@@YAXAAUC@NegativeNVOffset@@@Z
+; FIXME: void __cdecl CallMethod<struct NegativeNVOffset::C, {[thunk]: __thiscall NegativeNVOffset::C::`vcall'{0, {flat}}, 4294967292, 0}>(struct NegativeNVOffset::C &)
+
+??$CallMethod@UM@@$0A@@@YAXAAUM@@@Z
+; CHECK: void __cdecl CallMethod<struct M, 0>(struct M &)
+
+??$CallMethod@UM@@$H??_91@$BA@AEA@@@YAXAAUM@@@Z
+; FIXME: void __cdecl CallMethod<struct M, {[thunk]: __thiscall M::`vcall'{0, {flat}}', 0}>(struct M &)
+
+??$CallMethod@UM@@$H?f@1@QAEXXZA@@@YAXAAUM@@@Z
+; FIXME: void __cdecl CallMethod<struct M, {void __thiscall M::f(void), 0}>(struct M &)
+
+??$CallMethod@UO@@$H??_91@$BA@AE3@@YAXAAUO@@@Z
+; FIXME: void __cdecl CallMethod<struct O, {[thunk]: __thiscall O::`vcall'{0, {flat}}, 4}>(struct O &)
+
+??$CallMethod@US@@$0A@@@YAXAAUS@@@Z
+; CHECK: void __cdecl CallMethod<struct S, 0>(struct S &)
+
+??$CallMethod@US@@$1??_91@$BA@AE@@YAXAAUS@@@Z
+; CHECK: void __cdecl CallMethod<struct S, &[thunk]: __thiscall S::`vcall'{0, {flat}}>(struct S &)
+
+??$CallMethod@US@@$1?f@1@QAEXXZ@@YAXAAUS@@@Z
+; CHECK: void __cdecl CallMethod<struct S, &void __thiscall S::f(void)>(struct S &)
+
+??$CallMethod@UU@@$0A@@@YAXAAUU@@@Z
+; CHECK: void __cdecl CallMethod<struct U, 0>(struct U &)
+
+??$CallMethod@UU@@$J??_91@$BA@AEA@A@A@@@YAXAAUU@@@Z
+; CHECK: void __cdecl CallMethod<struct U, {[thunk]: __thiscall U::`vcall'{0, {flat}}, 0, 0, 0}>(struct U &)
+
+??$CallMethod@UU@@$J?f@1@QAEXXZA@A@A@@@YAXAAUU@@@Z
+; CHECK: void __cdecl CallMethod<struct U, {void __thiscall U::f(void), 0, 0, 0}>(struct U &)
+
+??$CallMethod@UV@@$0A@@@YAXAAUV@@@Z
+; CHECK: void __cdecl CallMethod<struct V, 0>(struct V &)
+
+??$CallMethod@UV@@$I??_91@$BA@AEA@A@@@YAXAAUV@@@Z
+; CHECK: void __cdecl CallMethod<struct V, {[thunk]: __thiscall V::`vcall'{0, {flat}}, 0, 0}>(struct V &)
+
+??$CallMethod@UV@@$I?f@1@QAEXXZA@A@@@YAXAAUV@@@Z
+; CHECK: void __cdecl CallMethod<struct V, {void __thiscall V::f(void), 0, 0}>(struct V &)
+
+??$ReadField@UA@@$0?0@@YAHAAUA@@@Z
+; CHECK: int __cdecl ReadField<struct A, -1>(struct A &)
+
+??$ReadField@UA@@$0A@@@YAHAAUA@@@Z
+; CHECK: int __cdecl ReadField<struct A, 0>(struct A &)
+
+??$ReadField@UI@@$03@@YAHAAUI@@@Z
+; CHECK: int __cdecl ReadField<struct I, 4>(struct I &)
+
+??$ReadField@UI@@$0A@@@YAHAAUI@@@Z
+; CHECK: int __cdecl ReadField<struct I, 0>(struct I &)
+
+??$ReadField@UM@@$0A@@@YAHAAUM@@@Z
+; CHECK: int __cdecl ReadField<struct M, 0>(struct M &)
+
+??$ReadField@UM@@$0BA@@@YAHAAUM@@@Z
+; CHECK: int __cdecl ReadField<struct M, 16>(struct M &)
+
+??$ReadField@UM@@$0M@@@YAHAAUM@@@Z
+; CHECK: int __cdecl ReadField<struct M, 12>(struct M &)
+
+??$ReadField@US@@$03@@YAHAAUS@@@Z
+; CHECK: int __cdecl ReadField<struct S, 4>(struct S &)
+
+??$ReadField@US@@$07@@YAHAAUS@@@Z
+; CHECK: int __cdecl ReadField<struct S, 8>(struct S &)
+
+??$ReadField@US@@$0A@@@YAHAAUS@@@Z
+; CHECK: int __cdecl ReadField<struct S, 0>(struct S &)
+
+??$ReadField@UU@@$0A@@@YAHAAUU@@@Z
+; CHECK: int __cdecl ReadField<struct U, 0>(struct U &)
+
+??$ReadField@UU@@$G3A@A@@@YAHAAUU@@@Z
+; CHECK: int __cdecl ReadField<struct U, {4, 0, 0}>(struct U &)
+
+??$ReadField@UU@@$G7A@A@@@YAHAAUU@@@Z
+; CHECK: int __cdecl ReadField<struct U, {8, 0, 0}>(struct U &)
+
+??$ReadField@UV@@$0A@@@YAHAAUV@@@Z
+; CHECK: int __cdecl ReadField<struct V, 0>(struct V &)
+
+??$ReadField@UV@@$F7A@@@YAHAAUV@@@Z
+; CHECK: int __cdecl ReadField<struct V, {8, 0}>(struct V &)
+
+??$ReadField@UV@@$FM@A@@@YAHAAUV@@@Z
+; CHECK: int __cdecl ReadField<struct V, {12, 0}>(struct V &)
+