Index: llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp =================================================================== --- llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp +++ llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp @@ -187,6 +187,8 @@ // 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 @@ // 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 @@ OS << "static "; } - if (ReturnType) + if (ReturnType) { Type::outputPre(OS, *ReturnType); + OS << " "; + } outputCallingConvention(OS, CallConvention); } @@ -635,6 +644,9 @@ OS << " const"; if (Quals & Q_Volatile) OS << " volatile"; + + if (ReturnType) + Type::outputPost(OS, *ReturnType); return; } @@ -711,6 +723,7 @@ UdtType *demangleClassType(); PointerType *demanglePointerType(); MemberPointerType *demangleMemberPointerType(); + FunctionType *demangleFunctionType(bool HasThisQuals); ArrayType *demangleArrayType(); @@ -724,10 +737,11 @@ Name *demangleName(); void demangleOperator(Name *); StringView demangleOperatorName(); - int demangleFunctionClass(); + FuncClass demangleFunctionClass(); CallingConv demangleCallingConvention(); StorageClass demangleVariableStorageClass(); ReferenceKind demangleReferenceKind(); + void demangleThrowSpecification(); std::pair demangleQualifiers(); @@ -904,10 +918,6 @@ // 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 @@ return ""; } -int Demangler::demangleFunctionClass() { +FuncClass Demangler::demangleFunctionClass() { SwapAndRestore RestoreOnError(MangledName, MangledName); RestoreOnError.shouldRestore(false); @@ -1075,48 +1085,48 @@ 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 @@ 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 @@ return ReferenceKind::None; } -Type *Demangler::demangleFunctionEncoding() { - FunctionType *FTy = Arena.alloc(); +void Demangler::demangleThrowSpecification() { + if (MangledName.consumeFront('Z')) + return; + Error = true; +} + +FunctionType *Demangler::demangleFunctionType(bool HasThisQuals) { + FunctionType *FTy = Arena.alloc(); 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 @@ 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 @@ 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 @@ 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 @@ 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() { Index: llvm/trunk/lib/Demangle/StringView.h =================================================================== --- llvm/trunk/lib/Demangle/StringView.h +++ llvm/trunk/lib/Demangle/StringView.h @@ -45,7 +45,7 @@ StringView dropFront(size_t N = 1) const { if (N >= size()) - N = size() - 1; + N = size(); return StringView(First + N, Last); } Index: llvm/trunk/test/Demangle/ms-basic.test =================================================================== --- llvm/trunk/test/Demangle/ms-basic.test +++ llvm/trunk/test/Demangle/ms-basic.test @@ -106,7 +106,7 @@ ??4klass@@QEAAAEBV0@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@YAAEBVklass@@AEBV0@H@Z -; CHECK: class klass const &__cdecl operator<<(class klass const &, int) +; CHECK: class klass const & __cdecl operator<<(class klass const &, int) ??5@YAAEBVklass@@AEBV0@_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@YAPEAX_KAEAVklass@@@Z -; CHECK: void *__cdecl operator new(unsigned __int64, class klass &) +; CHECK: void * __cdecl operator new(unsigned __int64, class klass &) ??_U@YAPEAX_KAEAVklass@@@Z -; CHECK: void *__cdecl operator new[](unsigned __int64, class klass &) +; CHECK: void * __cdecl operator new[](unsigned __int64, class klass &) ??3@YAXPEAXAEAVklass@@@Z ; CHECK: void __cdecl operator delete(void *, class klass &) Index: llvm/trunk/test/Demangle/ms-mangle.test =================================================================== --- llvm/trunk/test/Demangle/ms-mangle.test +++ llvm/trunk/test/Demangle/ms-mangle.test @@ -61,10 +61,10 @@ ; CHECK: int __cdecl foo::operator+(int) ?static_method@foo@@SAPAV1@XZ -; CHECK: static class foo *__cdecl foo::static_method(void) +; CHECK: static class foo * __cdecl foo::static_method(void) ?static_method@foo@@SAPEAV1@XZ -; CHECK: static class foo *__cdecl foo::static_method(void) +; CHECK: static class foo * __cdecl foo::static_method(void) ?g@bar@@2HA ; CHECK: static int bar::g @@ -92,15 +92,17 @@ ?j@@3P6GHCE@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@ZQ1@ -; FIXME: int __thiscall (foo::*l)(int) +?l@@3P8foo@@AEHH@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@YAPAXI@Z -; CHECK: void *__cdecl operator new(unsigned int) +; CHECK: void * __cdecl operator new(unsigned int) ??3@YAXPAX@Z ; CHECK: void __cdecl operator delete(void *) ??_U@YAPAXI@Z -; CHECK: void *__cdecl operator new[](unsigned int) +; CHECK: void * __cdecl operator new[](unsigned int) ??_V@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@Z -; CHECK: static void *__cdecl OverloadedNewDelete::operator new(unsigned int) +; CHECK: static void * __cdecl OverloadedNewDelete::operator new(unsigned int) ??_UOverloadedNewDelete@@SAPAXI@Z -; CHECK: static void *__cdecl OverloadedNewDelete::operator new[](unsigned int) +; CHECK: static void * __cdecl OverloadedNewDelete::operator new[](unsigned int) ??3OverloadedNewDelete@@SAXPAX@Z ; CHECK: static void __cdecl OverloadedNewDelete::operator delete(void *) @@ -278,10 +279,10 @@ ; CHECK: int __thiscall OverloadedNewDelete::operator+(int) ??2OverloadedNewDelete@@SAPEAX_K@Z -; CHECK: static void *__cdecl OverloadedNewDelete::operator new(unsigned __int64) +; CHECK: static void * __cdecl OverloadedNewDelete::operator new(unsigned __int64) ??_UOverloadedNewDelete@@SAPEAX_K@Z -; CHECK: static void *__cdecl OverloadedNewDelete::operator new[](unsigned __int64) +; CHECK: static void * __cdecl OverloadedNewDelete::operator new[](unsigned __int64) ??3OverloadedNewDelete@@SAXPEAX@Z ; CHECK: static void __cdecl OverloadedNewDelete::operator delete(void *) @@ -295,11 +296,11 @@ ??2TypedefNewDelete@@SAPAXI@Z -; CHECK: static void *__cdecl TypedefNewDelete::operator new(unsigned int) +; CHECK: static void * __cdecl TypedefNewDelete::operator new(unsigned int) ??_UTypedefNewDelete@@SAPAXI@Z -; CHECK: static void *__cdecl TypedefNewDelete::operator new[](unsigned int) +; CHECK: static void * __cdecl TypedefNewDelete::operator new[](unsigned int) ??3TypedefNewDelete@@SAXPAX@Z ; CHECK: static void __cdecl TypedefNewDelete::operator delete(void *)