[llvm] r338065 - [MS Demangler] Demangle pointers to member functions.

Zachary Turner via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 26 13:20:10 PDT 2018


Author: zturner
Date: Thu Jul 26 13:20:10 2018
New Revision: 338065

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

After this patch, we can now properly demangle pointers to member
functions.  The calling convention is located in the wrong place,
but this will be fixed in a followup since it also affects non
member function pointers.

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

Modified:
    llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp
    llvm/trunk/lib/Demangle/StringView.h
    llvm/trunk/test/Demangle/ms-basic.test
    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=338065&r1=338064&r2=338065&view=diff
==============================================================================
--- llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp (original)
+++ llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp Thu Jul 26 13:20:10 2018
@@ -187,6 +187,8 @@ struct Type;
 // Represents a list of parameters (template params or function arguments.
 // It's represented as a linked list.
 struct ParamList {
+  bool IsVariadic = false;
+
   Type *Current = nullptr;
 
   ParamList *Next = nullptr;
@@ -382,6 +384,11 @@ static void outputCallingConvention(Outp
 
 // Write a function or template parameter list.
 static void outputParameterList(OutputStream &OS, const ParamList &Params) {
+  if (!Params.Current) {
+    OS << "void";
+    return;
+  }
+
   const ParamList *Head = &Params;
   while (Head) {
     Type::outputPre(OS, *Head->Current);
@@ -621,8 +628,10 @@ void FunctionType::outputPre(OutputStrea
       OS << "static ";
   }
 
-  if (ReturnType)
+  if (ReturnType) {
     Type::outputPre(OS, *ReturnType);
+    OS << " ";
+  }
 
   outputCallingConvention(OS, CallConvention);
 }
@@ -635,6 +644,9 @@ void FunctionType::outputPost(OutputStre
     OS << " const";
   if (Quals & Q_Volatile)
     OS << " volatile";
+
+  if (ReturnType)
+    Type::outputPost(OS, *ReturnType);
   return;
 }
 
@@ -711,6 +723,7 @@ private:
   UdtType *demangleClassType();
   PointerType *demanglePointerType();
   MemberPointerType *demangleMemberPointerType();
+  FunctionType *demangleFunctionType(bool HasThisQuals);
 
   ArrayType *demangleArrayType();
 
@@ -724,10 +737,11 @@ private:
   Name *demangleName();
   void demangleOperator(Name *);
   StringView demangleOperatorName();
-  int demangleFunctionClass();
+  FuncClass demangleFunctionClass();
   CallingConv demangleCallingConvention();
   StorageClass demangleVariableStorageClass();
   ReferenceKind demangleReferenceKind();
+  void demangleThrowSpecification();
 
   std::pair<Qualifiers, bool> demangleQualifiers();
 
@@ -904,10 +918,6 @@ void Demangler::demangleNamePiece(Name &
     // Class template.
     Node.Str = demangleString(false);
     Node.TemplateParams = demangleParameterList();
-    if (!MangledName.consumeFront('@')) {
-      Error = true;
-      return;
-    }
   } else if (!IsHead && MangledName.consumeFront("?A")) {
     // Anonymous namespace starts with ?A.  So does overloaded operator[],
     // but the distinguishing factor is that namespace themselves are not
@@ -1067,7 +1077,7 @@ StringView Demangler::demangleOperatorNa
   return "";
 }
 
-int Demangler::demangleFunctionClass() {
+FuncClass Demangler::demangleFunctionClass() {
   SwapAndRestore<StringView> RestoreOnError(MangledName, MangledName);
   RestoreOnError.shouldRestore(false);
 
@@ -1075,48 +1085,48 @@ int Demangler::demangleFunctionClass() {
   case 'A':
     return Private;
   case 'B':
-    return Private | Far;
+    return FuncClass(Private | Far);
   case 'C':
-    return Private | Static;
+    return FuncClass(Private | Static);
   case 'D':
-    return Private | Static;
+    return FuncClass(Private | Static);
   case 'E':
-    return Private | Virtual;
+    return FuncClass(Private | Virtual);
   case 'F':
-    return Private | Virtual;
+    return FuncClass(Private | Virtual);
   case 'I':
     return Protected;
   case 'J':
-    return Protected | Far;
+    return FuncClass(Protected | Far);
   case 'K':
-    return Protected | Static;
+    return FuncClass(Protected | Static);
   case 'L':
-    return Protected | Static | Far;
+    return FuncClass(Protected | Static | Far);
   case 'M':
-    return Protected | Virtual;
+    return FuncClass(Protected | Virtual);
   case 'N':
-    return Protected | Virtual | Far;
+    return FuncClass(Protected | Virtual | Far);
   case 'Q':
     return Public;
   case 'R':
-    return Public | Far;
+    return FuncClass(Public | Far);
   case 'S':
-    return Public | Static;
+    return FuncClass(Public | Static);
   case 'T':
-    return Public | Static | Far;
+    return FuncClass(Public | Static | Far);
   case 'U':
-    return Public | Virtual;
+    return FuncClass(Public | Virtual);
   case 'V':
-    return Public | Virtual | Far;
+    return FuncClass(Public | Virtual | Far);
   case 'Y':
     return Global;
   case 'Z':
-    return Global | Far;
+    return FuncClass(Global | Far);
   }
 
   Error = true;
   RestoreOnError.shouldRestore(true);
-  return 0;
+  return Public;
 }
 
 CallingConv Demangler::demangleCallingConvention() {
@@ -1241,15 +1251,6 @@ Type *Demangler::demangleType(QualifierM
   return Ty;
 }
 
-static bool functionHasThisPtr(const FunctionType &Ty) {
-  assert(Ty.Prim == PrimTy::Function);
-  if (Ty.FunctionClass & Global)
-    return false;
-  if (Ty.FunctionClass & Static)
-    return false;
-  return true;
-}
-
 ReferenceKind Demangler::demangleReferenceKind() {
   if (MangledName.consumeFront('G'))
     return ReferenceKind::LValueRef;
@@ -1258,12 +1259,18 @@ ReferenceKind Demangler::demangleReferen
   return ReferenceKind::None;
 }
 
-Type *Demangler::demangleFunctionEncoding() {
-  FunctionType *FTy = Arena.alloc<FunctionType>();
+void Demangler::demangleThrowSpecification() {
+  if (MangledName.consumeFront('Z'))
+    return;
 
+  Error = true;
+}
+
+FunctionType *Demangler::demangleFunctionType(bool HasThisQuals) {
+  FunctionType *FTy = Arena.alloc<FunctionType>();
   FTy->Prim = PrimTy::Function;
-  FTy->FunctionClass = (FuncClass)demangleFunctionClass();
-  if (functionHasThisPtr(*FTy)) {
+
+  if (HasThisQuals) {
     FTy->Quals = demanglePointerExtQualifiers();
     FTy->RefKind = demangleReferenceKind();
     FTy->Quals = Qualifiers(FTy->Quals | demangleQualifiers().first);
@@ -1280,6 +1287,18 @@ Type *Demangler::demangleFunctionEncodin
 
   FTy->Params = demangleParameterList();
 
+  demangleThrowSpecification();
+
+  return FTy;
+}
+
+Type *Demangler::demangleFunctionEncoding() {
+  FuncClass FC = demangleFunctionClass();
+
+  bool HasThisQuals = !(FC & (Global | Static));
+  FunctionType *FTy = demangleFunctionType(HasThisQuals);
+  FTy->FunctionClass = FC;
+
   return FTy;
 }
 
@@ -1445,14 +1464,20 @@ MemberPointerType *Demangler::demangleMe
   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();
+  if (MangledName.consumeFront("8")) {
+    Pointer->MemberName = demangleName();
+    Pointer->Pointee = demangleFunctionType(true);
+  } else {
+    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;
+  }
 
-  Pointer->Pointee = demangleType(QualifierMangleMode::Drop);
-  Pointer->Pointee->Quals = PointeeQuals;
   return Pointer;
 }
 
@@ -1507,6 +1532,12 @@ ParamList Demangler::demangleParameterLi
   Type *BackRef[10];
   int Idx = 0;
 
+  // Empty parameter list.
+  // FIXME: Will this cause problems if demangleParameterList() is called in the
+  // context of a template parameter list?
+  if (MangledName.consumeFront('X'))
+    return {};
+
   ParamList *Head;
   ParamList **Current = &Head;
   while (!Error && !MangledName.startsWith('@') &&
@@ -1537,7 +1568,22 @@ ParamList Demangler::demangleParameterLi
     Current = &(*Current)->Next;
   }
 
-  return *Head;
+  if (Error)
+    return {};
+
+  // A non-empty parameter list is terminated by either 'Z' (variadic) parameter
+  // list or '@' (non variadic).  Careful not to consume "@Z", as in that case
+  // the following Z could be a throw specifier.
+  if (MangledName.consumeFront('@'))
+    return *Head;
+
+  if (MangledName.consumeFront('Z')) {
+    Head->IsVariadic = true;
+    return *Head;
+  }
+
+  Error = true;
+  return {};
 }
 
 void Demangler::output() {

Modified: llvm/trunk/lib/Demangle/StringView.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Demangle/StringView.h?rev=338065&r1=338064&r2=338065&view=diff
==============================================================================
--- llvm/trunk/lib/Demangle/StringView.h (original)
+++ llvm/trunk/lib/Demangle/StringView.h Thu Jul 26 13:20:10 2018
@@ -45,7 +45,7 @@ public:
 
   StringView dropFront(size_t N = 1) const {
     if (N >= size())
-      N = size() - 1;
+      N = size();
     return StringView(First + N, Last);
   }
 

Modified: llvm/trunk/test/Demangle/ms-basic.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Demangle/ms-basic.test?rev=338065&r1=338064&r2=338065&view=diff
==============================================================================
--- llvm/trunk/test/Demangle/ms-basic.test (original)
+++ llvm/trunk/test/Demangle/ms-basic.test Thu Jul 26 13:20:10 2018
@@ -106,7 +106,7 @@
 
 
 ??4klass@@QEAAAEBV0 at AEBV0@@Z
-; CHECK: class klass const &__cdecl klass::operator=(class klass const &)
+; CHECK: class klass const & __cdecl klass::operator=(class klass const &)
 
 ??7klass@@QEAA_NXZ
 ; CHECK: bool __cdecl klass::operator!(void)
@@ -211,16 +211,16 @@
 ; CHECK: int __cdecl klass::operator^=(int)
 
 ??6 at YAAEBVklass@@AEBV0 at H@Z
-; CHECK: class klass const &__cdecl operator<<(class klass const &, int)
+; CHECK: class klass const & __cdecl operator<<(class klass const &, int)
 
 ??5 at YAAEBVklass@@AEBV0 at _K@Z
-; CHECK: class klass const &__cdecl operator>>(class klass const &, unsigned __int64)
+; CHECK: class klass const & __cdecl operator>>(class klass const &, unsigned __int64)
 
 ??2 at YAPEAX_KAEAVklass@@@Z
-; CHECK: void *__cdecl operator new(unsigned __int64, class klass &)
+; CHECK: void * __cdecl operator new(unsigned __int64, class klass &)
 
 ??_U at YAPEAX_KAEAVklass@@@Z
-; CHECK: void *__cdecl operator new[](unsigned __int64, class klass &)
+; CHECK: void * __cdecl operator new[](unsigned __int64, class klass &)
 
 ??3 at YAXPEAXAEAVklass@@@Z
 ; CHECK: void __cdecl operator delete(void *, class klass &)

Modified: llvm/trunk/test/Demangle/ms-mangle.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Demangle/ms-mangle.test?rev=338065&r1=338064&r2=338065&view=diff
==============================================================================
--- llvm/trunk/test/Demangle/ms-mangle.test (original)
+++ llvm/trunk/test/Demangle/ms-mangle.test Thu Jul 26 13:20:10 2018
@@ -61,10 +61,10 @@
 ; CHECK: int __cdecl foo::operator+(int)
 
 ?static_method at foo@@SAPAV1 at XZ
-; CHECK: static class foo *__cdecl foo::static_method(void)
+; CHECK: static class foo * __cdecl foo::static_method(void)
 
 ?static_method at foo@@SAPEAV1 at XZ
-; CHECK: static class foo *__cdecl foo::static_method(void)
+; CHECK: static class foo * __cdecl foo::static_method(void)
 
 ?g at bar@@2HA
 ; CHECK: static int bar::g
@@ -92,15 +92,17 @@
 ?j@@3P6GHCE at ZA
 ; CHECK: int __stdcall (*j)(signed char, unsigned char)
 
+?funptr@@YAP6AHXZXZ
+; CHECK: int __cdecl (* __cdecl funptr(void))(void)
+
 ?k@@3PTfoo@@DT1@
 ; CHECK: char const volatile foo::*k
 
 ?k@@3PETfoo@@DET1@
 ; CHECK: char const volatile foo::*k
 
-; FIXME: We don't support member function pointers yet.
-; ?l@@3P8foo@@AEHH at ZQ1@
-; FIXME: int __thiscall (foo::*l)(int)
+?l@@3P8foo@@AEHH at ZQ1@
+; CHECK: int __thiscall (foo::*l)(int)
 
 ?g_cInt@@3HB
 ; CHECK: int const g_cInt
@@ -148,13 +150,13 @@
 ; CHECK: void __cdecl zeta(int __cdecl (*)(int, int))
 
 ??2 at YAPAXI@Z
-; CHECK: void *__cdecl operator new(unsigned int)
+; CHECK: void * __cdecl operator new(unsigned int)
 
 ??3 at YAXPAX@Z
 ; CHECK: void __cdecl operator delete(void *)
 
 ??_U at YAPAXI@Z
-; CHECK: void *__cdecl operator new[](unsigned int)
+; CHECK: void * __cdecl operator new[](unsigned int)
 
 ??_V at YAXPAX@Z
 ; CHECK: void __cdecl operator delete[](void *)
@@ -172,51 +174,50 @@
 ; ?color4@@3QAY02$$CBNA
 ; FIXME-EXTRACONST: double const (*color4)[3]
 
-; FIXME-MEMBERPTR: We don't support member pointers yet.
-; ?memptr1@@3RESB@@HES1
-; FIXME-MEMBERPTR: volatile int B::*memptr2
+?memptr1@@3RESB@@HES1@
+; CHECK: int volatile B::*volatile memptr1
 
-; ?memptr2@@3PESB@@HES1
-; FIXME: volatile int B::*memptr2
+?memptr2@@3PESB@@HES1@
+; CHECK: int volatile B::*memptr2
 
-; ?memptr3@@3REQB@@HEQ1
-; FIXME-MEMBERPTR: int B::* volatile memptr3
+?memptr3@@3REQB@@HEQ1@
+; CHECK: int B::*volatile memptr3
 
-; ?funmemptr1@@3RESB@@R6AHXZES1
-; FIXME-MEMBERPTR: int __cdecl (* volatile B::* volatile funmemptr1)(void)
+?funmemptr1@@3RESB@@R6AHXZES1@
+; CHECK: int __cdecl (*volatile B::*volatile funmemptr1)(void)
 
-; ?funmemptr2@@3PESB@@R6AHXZES1
-; FIXME-MEMBERPTR: int __cdecl (* volatile B::*funmemptr2)(void)
+?funmemptr2@@3PESB@@R6AHXZES1@
+; CHECK: int __cdecl (*volatile B::*funmemptr2)(void)
 
-; ?funmemptr3@@3REQB@@P6AHXZEQ1
-; FIXME-MEMBERPTR: int __cdecl (* B::*volatile funmemptr3)(void)
+?funmemptr3@@3REQB@@P6AHXZEQ1@
+; CHECK: int __cdecl (*B::*volatile funmemptr3)(void)
 
-; ?memptrtofun1@@3R8B@@EAAXXZEQ1
-; FIXME-MEMBERPTR: void __cdecl (B::*volatile memptrtofun1)(void)
+?memptrtofun1@@3R8B@@EAAXXZEQ1@
+; CHECK: void __cdecl (B::*volatile memptrtofun1)(void)
 
-; ?memptrtofun2@@3P8B@@EAAXXZEQ1
-; FIXME-MEMBERPTR: void __cdecl (B::*memptrtofun2)(void)
+?memptrtofun2@@3P8B@@EAAXXZEQ1@
+; CHECK: void __cdecl (B::*memptrtofun2)(void)
 
-; ?memptrtofun3@@3P8B@@EAAXXZEQ1
-; FIXME-MEMBERPTR: void __cdecl (B::*memptrtofun3)(void)
+?memptrtofun3@@3P8B@@EAAXXZEQ1@
+; CHECK: void __cdecl (B::*memptrtofun3)(void)
 
-; ?memptrtofun4@@3R8B@@EAAHXZEQ1
-; FIXME-MEMBERPTR: int __cdecl (B::* volatile memptrtofun4)(void)
+?memptrtofun4@@3R8B@@EAAHXZEQ1@
+; CHECK: int __cdecl (B::*volatile memptrtofun4)(void)
 
-; ?memptrtofun5@@3P8B@@EAA?CHXZEQ1
-; FIXME-MEMBERPTR: int volatile __cdecl (B::*memptrtofun5)(void)
+?memptrtofun5@@3P8B@@EAA?CHXZEQ1@
+; CHECK: int volatile __cdecl (B::*memptrtofun5)(void)
 
-; ?memptrtofun6@@3P8B@@EAA?BHXZEQ1
-; FIXME-MEMBERPTR: int const __cdecl (B::*memptrtofun6)(void)
+?memptrtofun6@@3P8B@@EAA?BHXZEQ1@
+; CHECK: int const __cdecl (B::*memptrtofun6)(void)
 
-; ?memptrtofun7@@3R8B@@EAAP6AHXZXZEQ1
-; FIXME-MEMBERPTR: int __cdecl (*(__cdecl B::*volatile memptrtofun7)(void))(void)
+?memptrtofun7@@3R8B@@EAAP6AHXZXZEQ1@
+; CHECK: int __cdecl (* __cdecl (B::*volatile memptrtofun7)(void))(void)
 
-; ?memptrtofun8@@3P8B@@EAAR6AHXZXZEQ1
-; FIXME-MEMBERPTR: int __cdecl (*(__cdecl B::*memptrtofun8)(void))(void)
+?memptrtofun8@@3P8B@@EAAR6AHXZXZEQ1@
+; CHECK: int __cdecl (*volatile __cdecl (B::*memptrtofun8)(void))(void)
 
-; ?memptrtofun9@@3P8B@@EAAQ6AHXZXZEQ1
-; FIXME-MEMBERPTR: int __cdecl(*(__cdecl B::*memptrtofun9)(void))(void)
+?memptrtofun9@@3P8B@@EAAQ6AHXZXZEQ1@
+; CHECK: int __cdecl (*const __cdecl (B::*memptrtofun9)(void))(void)
 
 
 ?fooE@@YA?AW4E@@XZ
@@ -261,11 +262,11 @@
 ; FIXME-EXTERNC: int `extern_c_func'::`2'::local
 
 ??2OverloadedNewDelete@@SAPAXI at Z
-; CHECK: static void *__cdecl OverloadedNewDelete::operator new(unsigned int)
+; CHECK: static void * __cdecl OverloadedNewDelete::operator new(unsigned int)
 
 
 ??_UOverloadedNewDelete@@SAPAXI at Z
-; CHECK: static void *__cdecl OverloadedNewDelete::operator new[](unsigned int)
+; CHECK: static void * __cdecl OverloadedNewDelete::operator new[](unsigned int)
 
 ??3OverloadedNewDelete@@SAXPAX at Z
 ; CHECK: static void __cdecl OverloadedNewDelete::operator delete(void *)
@@ -278,10 +279,10 @@
 ; CHECK: int __thiscall OverloadedNewDelete::operator+(int)
 
 ??2OverloadedNewDelete@@SAPEAX_K at Z
-; CHECK: static void *__cdecl OverloadedNewDelete::operator new(unsigned __int64)
+; CHECK: static void * __cdecl OverloadedNewDelete::operator new(unsigned __int64)
 
 ??_UOverloadedNewDelete@@SAPEAX_K at Z
-; CHECK: static void *__cdecl OverloadedNewDelete::operator new[](unsigned __int64)
+; CHECK: static void * __cdecl OverloadedNewDelete::operator new[](unsigned __int64)
 
 ??3OverloadedNewDelete@@SAXPEAX at Z
 ; CHECK: static void __cdecl OverloadedNewDelete::operator delete(void *)
@@ -295,11 +296,11 @@
 
 
 ??2TypedefNewDelete@@SAPAXI at Z
-; CHECK: static void *__cdecl TypedefNewDelete::operator new(unsigned int)
+; CHECK: static void * __cdecl TypedefNewDelete::operator new(unsigned int)
 
 
 ??_UTypedefNewDelete@@SAPAXI at Z
-; CHECK: static void *__cdecl TypedefNewDelete::operator new[](unsigned int)
+; CHECK: static void * __cdecl TypedefNewDelete::operator new[](unsigned int)
 
 ??3TypedefNewDelete@@SAXPAX at Z
 ; CHECK: static void __cdecl TypedefNewDelete::operator delete(void *)




More information about the llvm-commits mailing list