Index: llvm/lib/Demangle/MicrosoftDemangle.cpp =================================================================== --- llvm/lib/Demangle/MicrosoftDemangle.cpp +++ llvm/lib/Demangle/MicrosoftDemangle.cpp @@ -185,6 +185,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); @@ -712,6 +719,7 @@ UdtType *demangleClassType(); PointerType *demanglePointerType(); MemberPointerType *demangleMemberPointerType(); + FunctionType *demangleFunctionType(bool HasThisQuals); ArrayType *demangleArrayType(); @@ -725,10 +733,11 @@ Name *demangleName(); void demangleOperator(Name *); StringView demangleOperatorName(); - int demangleFunctionClass(); + FuncClass demangleFunctionClass(); CallingConv demangleCallingConvention(); StorageClass demangleVariableStorageClass(); ReferenceKind demangleReferenceKind(); + void demangleThrowSpecification(); std::pair demangleQualifiers(); @@ -905,10 +914,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 @@ -1068,7 +1073,7 @@ return ""; } -int Demangler::demangleFunctionClass() { +FuncClass Demangler::demangleFunctionClass() { SwapAndRestore RestoreOnError(MangledName, MangledName); RestoreOnError.shouldRestore(false); @@ -1076,48 +1081,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() { @@ -1242,15 +1247,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; @@ -1259,12 +1255,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); @@ -1281,6 +1283,18 @@ FTy->Params = demangleParameterList(); + demangleThrowSpecification(); + + return FTy; +} + +Type *Demangler::demangleFunctionEncoding() { + FuncClass FC = (FuncClass)demangleFunctionClass(); + + bool HasThisQuals = !(FC & (Global | Static)); + FunctionType *FTy = demangleFunctionType(HasThisQuals); + FTy->FunctionClass = FC; + return FTy; } @@ -1446,14 +1460,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; } @@ -1508,6 +1528,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('@') && @@ -1538,7 +1564,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/lib/Demangle/StringView.h =================================================================== --- llvm/lib/Demangle/StringView.h +++ llvm/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/test/Demangle/ms-mangle.test =================================================================== --- llvm/test/Demangle/ms-mangle.test +++ llvm/test/Demangle/ms-mangle.test @@ -98,9 +98,8 @@ ?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