Index: llvm/lib/Demangle/MicrosoftDemangle.cpp =================================================================== --- llvm/lib/Demangle/MicrosoftDemangle.cpp +++ llvm/lib/Demangle/MicrosoftDemangle.cpp @@ -21,6 +21,7 @@ #include "Utility.h" #include +#include // 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 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 @@ Function, Ptr, Ref, + MemberPtr, Array, Struct, @@ -238,7 +241,17 @@ 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 @@ } // 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 @@ Type::outputPost(OS, *Pointee); } +Type *MemberPointerType::clone(ArenaAllocator &Arena) const { + return Arena.alloc(*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(*this); } @@ -614,6 +710,7 @@ Type *demangleBasicType(); UdtType *demangleClassType(); PointerType *demanglePointerType(); + MemberPointerType *demangleMemberPointerType(); ArrayType *demangleArrayType(); @@ -632,12 +729,7 @@ StorageClass demangleVariableStorageClass(); ReferenceKind demangleReferenceKind(); - Qualifiers demangleFunctionQualifiers(); - Qualifiers demangleVariablQualifiers(); - Qualifiers demangleReturnTypQualifiers(); - - Qualifiers demangleQualifiers( - QualifierMangleLocation Location = QualifierMangleLocation::Detect); + std::pair demangleQualifiers(); // The result is written to this stream. OutputStream OS; @@ -704,27 +796,29 @@ // ::= # 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(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(Ty); + MPTy->Pointee->Quals = Qualifiers(MPTy->Pointee->Quals | ExtraChildQuals); + } else { + PointerType *PTy = static_cast(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 @@ Elem->Next = Head; Head = Elem; + if (MangledName.empty()) { + Error = true; + return nullptr; + } } return Head; @@ -1021,26 +1119,6 @@ return 0; } -Qualifiers Demangler::demangleFunctionQualifiers() { - SwapAndRestore 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 @@ return StorageClass::None; } -Qualifiers Demangler::demangleVariablQualifiers() { - SwapAndRestore 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 RestoreOnError(MangledName, MangledName); - RestoreOnError.shouldRestore(false); +std::pair 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); } // ::= // ::= # 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 @@ 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 @@ 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 @@ return UTy; } -// ::= E? -// # the E is required for 64-bit non-static pointers -PointerType *Demangler::demanglePointerType() { - PointerType *Pointer = Arena.alloc(); - - Pointer->Quals = Q_None; +static std::pair +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); +} + +// ::= E? +// # the E is required for 64-bit non-static pointers +PointerType *Demangler::demanglePointerType() { + PointerType *Pointer = Arena.alloc(); + + 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(); FTy->Prim = PrimTy::Function; @@ -1420,6 +1434,28 @@ return Pointer; } +MemberPointerType *Demangler::demangleMemberPointerType() { + MemberPointerType *Pointer = Arena.alloc(); + 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')) Index: llvm/test/Demangle/ms-mangle.test =================================================================== --- llvm/test/Demangle/ms-mangle.test +++ llvm/test/Demangle/ms-mangle.test @@ -92,15 +92,14 @@ ?j@@3P6GHCE@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@ZQ1 +; FIXME: We don't support member function pointers yet. +; ?l@@3P8foo@@AEHH@ZQ1@ ; FIXME: int __thiscall (foo::*l)(int) ?g_cInt@@3HB