[llvm] r338061 - [MS Demangler] Demangle data member pointers.

Zachary Turner via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 26 12:56:09 PDT 2018


Author: zturner
Date: Thu Jul 26 12:56:09 2018
New Revision: 338061

URL: http://llvm.org/viewvc/llvm-project?rev=338061&view=rev
Log:
[MS Demangler] Demangle data member pointers.

Differential Revision: https://reviews.llvm.org/D49630

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

Modified: llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp?rev=338061&r1=338060&r2=338061&view=diff
==============================================================================
--- llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp (original)
+++ llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp Thu Jul 26 12:56:09 2018
@@ -21,6 +21,7 @@
 #include "Utility.h"
 
 #include <cctype>
+#include <tuple>
 
 // This memory allocator is extremely fast, but it doesn't call dtors
 // for allocated objects. That means you can't use STL containers
@@ -115,7 +116,8 @@ enum class StorageClass : uint8_t {
 };
 
 enum class QualifierMangleMode { Drop, Mangle, Result };
-enum class QualifierMangleLocation { Member, NonMember, Detect };
+
+enum class PointerAffinity { Pointer, Reference };
 
 // Calling conventions
 enum class CallingConv : uint8_t {
@@ -140,6 +142,7 @@ enum class PrimTy : uint8_t {
   Function,
   Ptr,
   Ref,
+  MemberPtr,
   Array,
 
   Struct,
@@ -238,7 +241,17 @@ struct PointerType : public Type {
   void outputPre(OutputStream &OS) override;
   void outputPost(OutputStream &OS) override;
 
-  bool isMemberPointer() const { return false; }
+  // Represents a type X in "a pointer to X", "a reference to X",
+  // "an array of X", or "a function returning X".
+  Type *Pointee = nullptr;
+};
+
+struct MemberPointerType : public Type {
+  Type *clone(ArenaAllocator &Arena) const override;
+  void outputPre(OutputStream &OS) override;
+  void outputPost(OutputStream &OS) override;
+
+  Name *MemberName = nullptr;
 
   // Represents a type X in "a pointer to X", "a reference to X",
   // "an array of X", or "a function returning X".
@@ -281,6 +294,56 @@ struct ArrayType : public Type {
 
 } // namespace
 
+static bool isMemberPointer(StringView MangledName) {
+  switch (MangledName.popFront()) {
+  case 'A':
+    // 'A' indicates a reference, and you cannot have a reference to a member
+    // function or member variable.
+    return false;
+  case 'P':
+  case 'Q':
+  case 'R':
+  case 'S':
+    // These 4 values indicate some kind of pointer, but we still don't know
+    // what.
+    break;
+  default:
+    assert(false && "Ty is not a pointer type!");
+  }
+
+  // If it starts with a number, then 6 indicates a non-member function
+  // pointer, and 8 indicates a member function pointer.
+  if (startsWithDigit(MangledName)) {
+    assert(MangledName[0] == '6' || MangledName[0] == '8');
+    return (MangledName[0] == '8');
+  }
+
+  // Remove ext qualifiers since those can appear on either type and are
+  // therefore not indicative.
+  MangledName.consumeFront('E'); // 64-bit
+  MangledName.consumeFront('I'); // restrict
+  MangledName.consumeFront('F'); // unaligned
+
+  assert(!MangledName.empty());
+
+  // The next value should be either ABCD (non-member) or QRST (member).
+  switch (MangledName.front()) {
+  case 'A':
+  case 'B':
+  case 'C':
+  case 'D':
+    return false;
+  case 'Q':
+  case 'R':
+  case 'S':
+  case 'T':
+    return true;
+  default:
+    assert(false);
+  }
+  return false;
+}
+
 static void outputCallingConvention(OutputStream &OS, CallingConv CC) {
   outputSpaceIfNecessary(OS);
 
@@ -515,6 +578,39 @@ void PointerType::outputPost(OutputStrea
   Type::outputPost(OS, *Pointee);
 }
 
+Type *MemberPointerType::clone(ArenaAllocator &Arena) const {
+  return Arena.alloc<MemberPointerType>(*this);
+}
+
+void MemberPointerType::outputPre(OutputStream &OS) {
+  Type::outputPre(OS, *Pointee);
+
+  outputSpaceIfNecessary(OS);
+
+  // "[]" and "()" (for function parameters) take precedence over "*",
+  // so "int *x(int)" means "x is a function returning int *". We need
+  // parentheses to supercede the default precedence. (e.g. we want to
+  // emit something like "int (*x)(int)".)
+  if (Pointee->Prim == PrimTy::Function || Pointee->Prim == PrimTy::Array)
+    OS << "(";
+
+  outputName(OS, MemberName);
+  OS << "::*";
+
+  // FIXME: We should output this, but it requires updating lots of tests.
+  // if (Ty.Quals & Q_Pointer64)
+  //  OS << " __ptr64";
+  if (Quals & Q_Restrict)
+    OS << " __restrict";
+}
+
+void MemberPointerType::outputPost(OutputStream &OS) {
+  if (Pointee->Prim == PrimTy::Function || Pointee->Prim == PrimTy::Array)
+    OS << ")";
+
+  Type::outputPost(OS, *Pointee);
+}
+
 Type *FunctionType::clone(ArenaAllocator &Arena) const {
   return Arena.alloc<FunctionType>(*this);
 }
@@ -614,6 +710,7 @@ private:
   Type *demangleBasicType();
   UdtType *demangleClassType();
   PointerType *demanglePointerType();
+  MemberPointerType *demangleMemberPointerType();
 
   ArrayType *demangleArrayType();
 
@@ -632,12 +729,7 @@ private:
   StorageClass demangleVariableStorageClass();
   ReferenceKind demangleReferenceKind();
 
-  Qualifiers demangleFunctionQualifiers();
-  Qualifiers demangleVariablQualifiers();
-  Qualifiers demangleReturnTypQualifiers();
-
-  Qualifiers demangleQualifiers(
-      QualifierMangleLocation Location = QualifierMangleLocation::Detect);
+  std::pair<Qualifiers, bool> demangleQualifiers();
 
   // The result is written to this stream.
   OutputStream OS;
@@ -704,27 +796,29 @@ Type *Demangler::demangleVariableEncodin
   //                 ::= <type> <pointee-cvr-qualifiers> # pointers, references
   switch (Ty->Prim) {
   case PrimTy::Ptr:
-  case PrimTy::Ref: {
+  case PrimTy::Ref:
+  case PrimTy::MemberPtr: {
     Qualifiers ExtraChildQuals = Q_None;
     Ty->Quals = Qualifiers(Ty->Quals | demanglePointerExtQualifiers());
 
-    PointerType *PTy = static_cast<PointerType *>(Ty);
-    QualifierMangleLocation Location = PTy->isMemberPointer()
-                                           ? QualifierMangleLocation::Member
-                                           : QualifierMangleLocation::NonMember;
+    bool IsMember = false;
+    std::tie(ExtraChildQuals, IsMember) = demangleQualifiers();
 
-    ExtraChildQuals = demangleQualifiers(Location);
-
-    if (PTy->isMemberPointer()) {
+    if (Ty->Prim == PrimTy::MemberPtr) {
+      assert(IsMember);
       Name *BackRefName = demangleName();
       (void)BackRefName;
+      MemberPointerType *MPTy = static_cast<MemberPointerType *>(Ty);
+      MPTy->Pointee->Quals = Qualifiers(MPTy->Pointee->Quals | ExtraChildQuals);
+    } else {
+      PointerType *PTy = static_cast<PointerType *>(Ty);
+      PTy->Pointee->Quals = Qualifiers(PTy->Pointee->Quals | ExtraChildQuals);
     }
 
-    PTy->Pointee->Quals = Qualifiers(PTy->Pointee->Quals | ExtraChildQuals);
     break;
   }
   default:
-    Ty->Quals = demangleQualifiers();
+    Ty->Quals = demangleQualifiers().first;
     break;
   }
 
@@ -848,6 +942,10 @@ Name *Demangler::demangleName() {
 
     Elem->Next = Head;
     Head = Elem;
+    if (MangledName.empty()) {
+      Error = true;
+      return nullptr;
+    }
   }
 
   return Head;
@@ -1021,26 +1119,6 @@ int Demangler::demangleFunctionClass() {
   return 0;
 }
 
-Qualifiers Demangler::demangleFunctionQualifiers() {
-  SwapAndRestore<StringView> RestoreOnError(MangledName, MangledName);
-  RestoreOnError.shouldRestore(false);
-
-  switch (MangledName.popFront()) {
-  case 'A':
-    return Q_None;
-  case 'B':
-    return Q_Const;
-  case 'C':
-    return Q_Volatile;
-  case 'D':
-    return Qualifiers(Q_Const | Q_Volatile);
-  }
-
-  Error = true;
-  RestoreOnError.shouldRestore(true);
-  return Q_None;
-}
-
 CallingConv Demangler::demangleCallingConvention() {
   switch (MangledName.popFront()) {
   case 'A':
@@ -1090,116 +1168,46 @@ StorageClass Demangler::demangleVariable
   return StorageClass::None;
 }
 
-Qualifiers Demangler::demangleVariablQualifiers() {
-  SwapAndRestore<StringView> RestoreOnError(MangledName, MangledName);
-  RestoreOnError.shouldRestore(false);
-
-  switch (MangledName.popFront()) {
-  case 'A':
-    return Q_None;
-  case 'B':
-    return Q_Const;
-  case 'C':
-    return Q_Volatile;
-  case 'D':
-    return Qualifiers(Q_Const | Q_Volatile);
-  case 'E':
-    return Q_Far;
-  case 'F':
-    return Qualifiers(Q_Const | Q_Far);
-  case 'G':
-    return Qualifiers(Q_Volatile | Q_Far);
-  case 'H':
-    return Qualifiers(Q_Const | Q_Volatile | Q_Far);
-  }
-
-  Error = true;
-  RestoreOnError.shouldRestore(true);
-  return Q_None;
-}
-
-Qualifiers Demangler::demangleReturnTypQualifiers() {
-  if (!MangledName.consumeFront("?"))
-    return Q_None;
-
-  SwapAndRestore<StringView> RestoreOnError(MangledName, MangledName);
-  RestoreOnError.shouldRestore(false);
+std::pair<Qualifiers, bool> Demangler::demangleQualifiers() {
 
   switch (MangledName.popFront()) {
+  // Member qualifiers
+  case 'Q':
+    return std::make_pair(Q_None, true);
+  case 'R':
+    return std::make_pair(Q_Const, true);
+  case 'S':
+    return std::make_pair(Q_Volatile, true);
+  case 'T':
+    return std::make_pair(Qualifiers(Q_Const | Q_Volatile), true);
+  // Non-Member qualifiers
   case 'A':
-    return Q_None;
+    return std::make_pair(Q_None, false);
   case 'B':
-    return Q_Const;
+    return std::make_pair(Q_Const, false);
   case 'C':
-    return Q_Volatile;
+    return std::make_pair(Q_Volatile, false);
   case 'D':
-    return Qualifiers(Q_Const | Q_Volatile);
+    return std::make_pair(Qualifiers(Q_Const | Q_Volatile), false);
   }
-
   Error = true;
-  RestoreOnError.shouldRestore(true);
-  return Q_None;
-}
-
-Qualifiers Demangler::demangleQualifiers(QualifierMangleLocation Location) {
-  if (Location == QualifierMangleLocation::Detect) {
-    switch (MangledName.front()) {
-    case 'Q':
-    case 'R':
-    case 'S':
-    case 'T':
-      Location = QualifierMangleLocation::Member;
-      break;
-    case 'A':
-    case 'B':
-    case 'C':
-    case 'D':
-      Location = QualifierMangleLocation::NonMember;
-      break;
-    default:
-      Error = true;
-      return Q_None;
-    }
-  }
-
-  if (Location == QualifierMangleLocation::Member) {
-    switch (MangledName.popFront()) {
-    // Member qualifiers
-    case 'Q':
-      return Q_None;
-    case 'R':
-      return Q_Const;
-    case 'S':
-      return Q_Volatile;
-    case 'T':
-      return Qualifiers(Q_Const | Q_Volatile);
-    }
-  } else {
-    switch (MangledName.popFront()) {
-    // Non-Member qualifiers
-    case 'A':
-      return Q_None;
-    case 'B':
-      return Q_Const;
-    case 'C':
-      return Q_Volatile;
-    case 'D':
-      return Qualifiers(Q_Const | Q_Volatile);
-    }
-  }
-  Error = true;
-  return Q_None;
+  return std::make_pair(Q_None, false);
 }
 
 // <variable-type> ::= <type> <cvr-qualifiers>
 //                 ::= <type> <pointee-cvr-qualifiers> # pointers, references
 Type *Demangler::demangleType(QualifierMangleMode QMM) {
   Qualifiers Quals = Q_None;
-  if (QMM == QualifierMangleMode::Mangle)
-    Quals = Qualifiers(Quals | demangleQualifiers());
-  else if (QMM == QualifierMangleMode::Result) {
-    if (MangledName.consumeFront('?'))
-      Quals = Qualifiers(Quals | demangleQualifiers());
+  bool IsMember = false;
+  bool IsMemberKnown = false;
+  if (QMM == QualifierMangleMode::Mangle) {
+    std::tie(Quals, IsMember) = demangleQualifiers();
+    IsMemberKnown = true;
+  } else if (QMM == QualifierMangleMode::Result) {
+    if (MangledName.consumeFront('?')) {
+      std::tie(Quals, IsMember) = demangleQualifiers();
+      IsMemberKnown = true;
+    }
   }
 
   Type *Ty = nullptr;
@@ -1215,7 +1223,12 @@ Type *Demangler::demangleType(QualifierM
   case 'Q': // foo *const
   case 'R': // foo *volatile
   case 'S': // foo *const volatile
-    Ty = demanglePointerType();
+    if (!IsMemberKnown)
+      IsMember = isMemberPointer(MangledName);
+    if (IsMember)
+      Ty = demangleMemberPointerType();
+    else
+      Ty = demanglePointerType();
     break;
   case 'Y':
     Ty = demangleArrayType();
@@ -1253,7 +1266,7 @@ Type *Demangler::demangleFunctionEncodin
   if (functionHasThisPtr(*FTy)) {
     FTy->Quals = demanglePointerExtQualifiers();
     FTy->RefKind = demangleReferenceKind();
-    FTy->Quals = Qualifiers(FTy->Quals | demangleQualifiers());
+    FTy->Quals = Qualifiers(FTy->Quals | demangleQualifiers().first);
   }
 
   // Fields that appear on both member and non-member functions.
@@ -1369,35 +1382,36 @@ UdtType *Demangler::demangleClassType()
   return UTy;
 }
 
-// <pointer-type> ::= E? <pointer-cvr-qualifiers> <ext-qualifiers> <type>
-//                       # the E is required for 64-bit non-static pointers
-PointerType *Demangler::demanglePointerType() {
-  PointerType *Pointer = Arena.alloc<PointerType>();
-
-  Pointer->Quals = Q_None;
+static std::pair<Qualifiers, PointerAffinity>
+demanglePointerCVQualifiers(StringView &MangledName) {
   switch (MangledName.popFront()) {
   case 'A':
-    Pointer->Prim = PrimTy::Ref;
-    break;
+    return std::make_pair(Q_None, PointerAffinity::Reference);
   case 'P':
-    Pointer->Prim = PrimTy::Ptr;
-    break;
+    return std::make_pair(Q_None, PointerAffinity::Pointer);
   case 'Q':
-    Pointer->Prim = PrimTy::Ptr;
-    Pointer->Quals = Q_Const;
-    break;
+    return std::make_pair(Q_Const, PointerAffinity::Pointer);
   case 'R':
-    Pointer->Quals = Q_Volatile;
-    Pointer->Prim = PrimTy::Ptr;
-    break;
+    return std::make_pair(Q_Volatile, PointerAffinity::Pointer);
   case 'S':
-    Pointer->Quals = Qualifiers(Q_Const | Q_Volatile);
-    Pointer->Prim = PrimTy::Ptr;
-    break;
+    return std::make_pair(Qualifiers(Q_Const | Q_Volatile),
+                          PointerAffinity::Pointer);
   default:
     assert(false && "Ty is not a pointer type!");
   }
+  return std::make_pair(Q_None, PointerAffinity::Pointer);
+}
+
+// <pointer-type> ::= E? <pointer-cvr-qualifiers> <ext-qualifiers> <type>
+//                       # the E is required for 64-bit non-static pointers
+PointerType *Demangler::demanglePointerType() {
+  PointerType *Pointer = Arena.alloc<PointerType>();
 
+  PointerAffinity Affinity;
+  std::tie(Pointer->Quals, Affinity) = demanglePointerCVQualifiers(MangledName);
+
+  Pointer->Prim =
+      (Affinity == PointerAffinity::Pointer) ? PrimTy::Ptr : PrimTy::Ref;
   if (MangledName.consumeFront("6")) {
     FunctionType *FTy = Arena.alloc<FunctionType>();
     FTy->Prim = PrimTy::Function;
@@ -1420,6 +1434,28 @@ PointerType *Demangler::demanglePointerT
   return Pointer;
 }
 
+MemberPointerType *Demangler::demangleMemberPointerType() {
+  MemberPointerType *Pointer = Arena.alloc<MemberPointerType>();
+  Pointer->Prim = PrimTy::MemberPtr;
+
+  PointerAffinity Affinity;
+  std::tie(Pointer->Quals, Affinity) = demanglePointerCVQualifiers(MangledName);
+  assert(Affinity == PointerAffinity::Pointer);
+
+  Qualifiers ExtQuals = demanglePointerExtQualifiers();
+  Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals);
+
+  Qualifiers PointeeQuals = Q_None;
+  bool IsMember = false;
+  std::tie(PointeeQuals, IsMember) = demangleQualifiers();
+  assert(IsMember);
+  Pointer->MemberName = demangleName();
+
+  Pointer->Pointee = demangleType(QualifierMangleMode::Drop);
+  Pointer->Pointee->Quals = PointeeQuals;
+  return Pointer;
+}
+
 Qualifiers Demangler::demanglePointerExtQualifiers() {
   Qualifiers Quals = Q_None;
   if (MangledName.consumeFront('E'))

Modified: llvm/trunk/test/Demangle/ms-mangle.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Demangle/ms-mangle.test?rev=338061&r1=338060&r2=338061&view=diff
==============================================================================
--- llvm/trunk/test/Demangle/ms-mangle.test (original)
+++ llvm/trunk/test/Demangle/ms-mangle.test Thu Jul 26 12:56:09 2018
@@ -92,15 +92,14 @@
 ?j@@3P6GHCE at ZA
 ; CHECK: int __stdcall (*j)(signed char, unsigned char)
 
+?k@@3PTfoo@@DT1@
+; CHECK: char const volatile foo::*k
 
-; FIXME: We don't handle member pointers yet.
-; ?k@@3PTfoo@@DT1
-; FIXME: char const volatile foo::*k
+?k@@3PETfoo@@DET1@
+; CHECK: char const volatile foo::*k
 
-; ?k@@3PETfoo@@DET1
-; FIXME: char const volatile foo::*k
-
-; ?l@@3P8foo@@AEHH at ZQ1
+; FIXME: We don't support member function pointers yet.
+; ?l@@3P8foo@@AEHH at ZQ1@
 ; FIXME: int __thiscall (foo::*l)(int)
 
 ?g_cInt@@3HB




More information about the llvm-commits mailing list