Index: llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp =================================================================== --- llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp +++ llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp @@ -139,7 +139,7 @@ enum class QualifierMangleMode { Drop, Mangle, Result }; -enum class PointerAffinity { Pointer, Reference }; +enum class PointerAffinity { Pointer, Reference, RValueReference }; // Calling conventions enum class CallingConv : uint8_t { @@ -163,7 +163,6 @@ None, Function, Ptr, - Ref, MemberPtr, Array, @@ -177,6 +176,8 @@ Char, Schar, Uchar, + Char16, + Char32, Short, Ushort, Int, @@ -189,6 +190,7 @@ Float, Double, Ldouble, + Nullptr }; // Function classes @@ -205,14 +207,20 @@ namespace { struct Type; +struct Name; // Represents a list of parameters (template params or function arguments. // It's represented as a linked list. struct ParamList { bool IsVariadic = false; + // If this is a type, Current will be valid and AliasName will be null. Type *Current = nullptr; + // If this is an alias (e.g. using X = Y), Current will be null and AliasName + // will be valid. + Name *AliasName = nullptr; + ParamList *Next = nullptr; }; @@ -254,7 +262,7 @@ StringView Operator; // Template parameters. Null if not a template. - ParamList TemplateParams; + ParamList *TemplateParams = nullptr; // Nested BackReferences (e.g. "A::B::C") are represented as a linked list. Name *Next = nullptr; @@ -265,6 +273,8 @@ void outputPre(OutputStream &OS) override; void outputPost(OutputStream &OS) override; + PointerAffinity Affinity; + // 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; @@ -324,9 +334,13 @@ static bool isMemberPointer(StringView MangledName) { switch (MangledName.popFront()) { + case '$': + // This is probably an rvalue reference (e.g. $$Q), and you cannot have an + // rvalue reference to a member. + return false; case 'A': // 'A' indicates a reference, and you cannot have a reference to a member - // function or member variable. + // function or member. return false; case 'P': case 'Q': @@ -449,17 +463,25 @@ return true; } +static void outputName(OutputStream &OS, const Name *TheName); + // Write a function or template parameter list. -static void outputParameterList(OutputStream &OS, const ParamList &Params) { - if (!Params.Current) { - OS << "void"; +static void outputParameterList(OutputStream &OS, const ParamList &Params, + bool EmptyAsVoid) { + if (!Params.Current && !Params.AliasName) { + if (EmptyAsVoid) + OS << "void"; return; } const ParamList *Head = &Params; while (Head) { - Type::outputPre(OS, *Head->Current); - Type::outputPost(OS, *Head->Current); + if (Head->Current) { + Type::outputPre(OS, *Head->Current); + Type::outputPost(OS, *Head->Current); + } else if (Head->AliasName) { + outputName(OS, Head->AliasName); + } Head = Head->Next; @@ -469,11 +491,11 @@ } static void outputTemplateParams(OutputStream &OS, const Name &TheName) { - if (!TheName.TemplateParams.Current) + if (!TheName.TemplateParams) return; OS << "<"; - outputParameterList(OS, TheName.TemplateParams); + outputParameterList(OS, *TheName.TemplateParams, false); OS << ">"; } @@ -577,6 +599,12 @@ case PrimTy::Uchar: OS << "unsigned char"; break; + case PrimTy::Char16: + OS << "char16_t"; + break; + case PrimTy::Char32: + OS << "char32_t"; + break; case PrimTy::Short: OS << "short"; break; @@ -613,6 +641,9 @@ case PrimTy::Ldouble: OS << "long double"; break; + case PrimTy::Nullptr: + OS << "std::nullptr_t"; + break; default: assert(false && "Invalid primitive type!"); } @@ -647,8 +678,10 @@ if (Affinity == PointerAffinity::Pointer) OS << "*"; - else + else if (Affinity == PointerAffinity::Reference) OS << "&"; + else + OS << "&&"; } void PointerType::outputPre(OutputStream &OS) { @@ -659,9 +692,6 @@ if (Quals & Q_Unaligned) OS << "__unaligned "; - PointerAffinity Affinity = (Prim == PrimTy::Ptr) ? PointerAffinity::Pointer - : PointerAffinity::Reference; - outputPointerIndicator(OS, Affinity, nullptr, Pointee); // FIXME: We should output this, but it requires updating lots of tests. @@ -725,12 +755,21 @@ void FunctionType::outputPost(OutputStream &OS) { OS << "("; - outputParameterList(OS, Params); + outputParameterList(OS, Params, true); OS << ")"; if (Quals & Q_Const) OS << " const"; if (Quals & Q_Volatile) OS << " volatile"; + if (Quals & Q_Restrict) + OS << " __restrict"; + if (Quals & Q_Unaligned) + OS << " __unaligned"; + + if (RefKind == ReferenceKind::LValueRef) + OS << " &"; + else if (RefKind == ReferenceKind::RValueRef) + OS << " &&"; if (ReturnType) Type::outputPost(OS, *ReturnType); @@ -820,7 +859,7 @@ ArrayType *demangleArrayType(StringView &MangledName); - ParamList demangleTemplateParameterList(StringView &MangledName); + ParamList *demangleTemplateParameterList(StringView &MangledName); ParamList demangleFunctionParameterList(StringView &MangledName); int demangleNumber(StringView &MangledName); @@ -846,7 +885,8 @@ Name *demangleAnonymousNamespaceName(StringView &MangledName); Name *demangleLocallyScopedNamePiece(StringView &MangledName); - void demangleOperator(StringView &MangledName, Name *); + StringView demangleSimpleString(StringView &MangledName, bool Memorize); + FuncClass demangleFunctionClass(StringView &MangledName); CallingConv demangleCallingConvention(StringView &MangledName); StorageClass demangleVariableStorageClass(StringView &MangledName); @@ -931,7 +971,6 @@ // ::= # pointers, references switch (Ty->Prim) { case PrimTy::Ptr: - case PrimTy::Ref: case PrimTy::MemberPtr: { Qualifiers ExtraChildQuals = Q_None; Ty->Quals = @@ -1148,6 +1187,19 @@ case '_': if (MangledName.consumeFront("L")) return " co_await"; + if (MangledName.consumeFront("K")) { + size_t EndPos = MangledName.find('@'); + if (EndPos == StringView::npos) + break; + StringView OpName = demangleSimpleString(MangledName, false); + size_t FullSize = OpName.size() + 3; // ""OpName + char *Buffer = Arena.allocUnalignedBuffer(FullSize); + Buffer[0] = ' '; + Buffer[1] = '"'; + Buffer[2] = '"'; + std::memcpy(Buffer + 3, OpName.begin(), OpName.size()); + return {Buffer, FullSize}; + } } } } @@ -1161,20 +1213,31 @@ } Name *Demangler::demangleSimpleName(StringView &MangledName, bool Memorize) { + StringView S = demangleSimpleString(MangledName, Memorize); + if (Error) + return nullptr; + Name *Node = Arena.alloc(); + Node->Str = S; + return Node; +} + +StringView Demangler::demangleSimpleString(StringView &MangledName, + bool Memorize) { + StringView S; for (size_t i = 0; i < MangledName.size(); ++i) { if (MangledName[i] != '@') continue; - Node->Str = MangledName.substr(0, i); + S = MangledName.substr(0, i); MangledName = MangledName.dropFront(i + 1); if (Memorize) - memorizeString(Node->Str); - return Node; + memorizeString(S); + return S; } Error = true; - return nullptr; + return {}; } Name *Demangler::demangleAnonymousNamespaceName(StringView &MangledName) { @@ -1429,6 +1492,38 @@ return std::make_pair(Q_None, false); } +static bool isTagType(StringView S) { + switch (S.front()) { + case 'T': // union + case 'U': // struct + case 'V': // class + case 'W': // enum + return true; + } + return false; +} + +static bool isPointerType(StringView S) { + if (S.startsWith("$$Q")) // foo && + return true; + + switch (S.front()) { + case 'A': // foo & + case 'P': // foo * + case 'Q': // foo *const + case 'R': // foo *volatile + case 'S': // foo *const volatile + return true; + } + return false; +} + +static bool isArrayType(StringView S) { return S[0] == 'Y'; } + +static bool isFunctionType(StringView S) { + return S.startsWith("$$A8@@") || S.startsWith("$$A6"); +} + // ::= // ::= # pointers, references Type *Demangler::demangleType(StringView &MangledName, @@ -1447,32 +1542,33 @@ } Type *Ty = nullptr; - switch (MangledName.front()) { - case 'T': // union - case 'U': // struct - case 'V': // class - case 'W': // enum + if (isTagType(MangledName)) Ty = demangleClassType(MangledName); - break; - case 'A': // foo & - case 'P': // foo * - case 'Q': // foo *const - case 'R': // foo *volatile - case 'S': // foo *const volatile + else if (isPointerType(MangledName)) { if (!IsMemberKnown) IsMember = isMemberPointer(MangledName); + if (IsMember) Ty = demangleMemberPointerType(MangledName); else Ty = demanglePointerType(MangledName); - break; - case 'Y': + } else if (isArrayType(MangledName)) Ty = demangleArrayType(MangledName); - break; - default: + else if (isFunctionType(MangledName)) { + if (MangledName.consumeFront("$$A8@@")) + Ty = demangleFunctionType(MangledName, true, false); + else { + assert(MangledName.startsWith("$$A6")); + MangledName.consumeFront("$$A6"); + Ty = demangleFunctionType(MangledName, false, false); + } + } else { Ty = demangleBasicType(MangledName); - break; + assert(Ty && !Error); + if (!Ty || Error) + return Ty; } + Ty->Quals = Qualifiers(Ty->Quals | Quals); return Ty; } @@ -1535,6 +1631,11 @@ Type *Demangler::demangleBasicType(StringView &MangledName) { Type *Ty = Arena.alloc(); + if (MangledName.consumeFront("$$T")) { + Ty->Prim = PrimTy::Nullptr; + return Ty; + } + switch (MangledName.popFront()) { case 'X': Ty->Prim = PrimTy::Void; @@ -1593,11 +1694,21 @@ case 'W': Ty->Prim = PrimTy::Wchar; break; + case 'S': + Ty->Prim = PrimTy::Char16; + break; + case 'U': + Ty->Prim = PrimTy::Char32; + break; default: - assert(false); + Error = true; + return nullptr; } break; } + default: + Error = true; + return nullptr; } return Ty; } @@ -1632,6 +1743,9 @@ static std::pair demanglePointerCVQualifiers(StringView &MangledName) { + if (MangledName.consumeFront("$$Q")) + return std::make_pair(Q_None, PointerAffinity::RValueReference); + switch (MangledName.popFront()) { case 'A': return std::make_pair(Q_None, PointerAffinity::Reference); @@ -1655,11 +1769,10 @@ PointerType *Demangler::demanglePointerType(StringView &MangledName) { PointerType *Pointer = Arena.alloc(); - PointerAffinity Affinity; - std::tie(Pointer->Quals, Affinity) = demanglePointerCVQualifiers(MangledName); + std::tie(Pointer->Quals, Pointer->Affinity) = + demanglePointerCVQualifiers(MangledName); - Pointer->Prim = - (Affinity == PointerAffinity::Pointer) ? PrimTy::Ptr : PrimTy::Ref; + Pointer->Prim = PrimTy::Ptr; if (MangledName.consumeFront("6")) { Pointer->Pointee = demangleFunctionType(MangledName, false, true); return Pointer; @@ -1805,14 +1918,26 @@ return {}; } -ParamList Demangler::demangleTemplateParameterList(StringView &MangledName) { +ParamList *Demangler::demangleTemplateParameterList(StringView &MangledName) { ParamList *Head; ParamList **Current = &Head; while (!Error && !MangledName.startsWith('@')) { - // Template parameter lists don't participate in back-referencing. *Current = Arena.alloc(); - (*Current)->Current = demangleType(MangledName, QualifierMangleMode::Drop); + + // Empty parameter pack. + if (MangledName.consumeFront("$S") || MangledName.consumeFront("$$V") || + MangledName.consumeFront("$$$V")) { + if (!MangledName.startsWith('@')) + Error = true; + continue; + } + + if (MangledName.consumeFront("$$Y")) + (*Current)->AliasName = demangleFullyQualifiedTypeName(MangledName); + else + (*Current)->Current = + demangleType(MangledName, QualifierMangleMode::Drop); Current = &(*Current)->Next; } @@ -1823,7 +1948,7 @@ // Template parameter lists cannot be variadic, so it can only be terminated // by @. if (MangledName.consumeFront('@')) - return *Head; + return Head; Error = true; return {}; } Index: llvm/trunk/test/Demangle/ms-cxx11.test =================================================================== --- llvm/trunk/test/Demangle/ms-cxx11.test +++ llvm/trunk/test/Demangle/ms-cxx11.test @@ -0,0 +1,146 @@ +; RUN: llvm-undname < %s | FileCheck %s + +; CHECK-NOT: Invalid mangled name + +?a@FTypeWithQuals@@3U?$S@$$A8@@BAHXZ@1@A +; CHECK: struct FTypeWithQuals::S FTypeWithQuals::a + +?b@FTypeWithQuals@@3U?$S@$$A8@@CAHXZ@1@A +; CHECK: struct FTypeWithQuals::S FTypeWithQuals::b + +?c@FTypeWithQuals@@3U?$S@$$A8@@IAAHXZ@1@A +; CHECK: struct FTypeWithQuals::S FTypeWithQuals::c + +?d@FTypeWithQuals@@3U?$S@$$A8@@GBAHXZ@1@A +; CHECK: struct FTypeWithQuals::S FTypeWithQuals::d + +?e@FTypeWithQuals@@3U?$S@$$A8@@GCAHXZ@1@A +; CHECK: struct FTypeWithQuals::S FTypeWithQuals::e + +?f@FTypeWithQuals@@3U?$S@$$A8@@IGAAHXZ@1@A +; CHECK: struct FTypeWithQuals::S FTypeWithQuals::f + +?g@FTypeWithQuals@@3U?$S@$$A8@@HBAHXZ@1@A +; CHECK: struct FTypeWithQuals::S FTypeWithQuals::g + +?h@FTypeWithQuals@@3U?$S@$$A8@@HCAHXZ@1@A +; CHECK: struct FTypeWithQuals::S FTypeWithQuals::h + +?i@FTypeWithQuals@@3U?$S@$$A8@@IHAAHXZ@1@A +; CHECK: struct FTypeWithQuals::S FTypeWithQuals::i + +?j@FTypeWithQuals@@3U?$S@$$A6AHXZ@1@A +; CHECK: struct FTypeWithQuals::S FTypeWithQuals::j + +?k@FTypeWithQuals@@3U?$S@$$A8@@GAAHXZ@1@A +; CHECK: struct FTypeWithQuals::S FTypeWithQuals::k + +?l@FTypeWithQuals@@3U?$S@$$A8@@HAAHXZ@1@A +; CHECK: struct FTypeWithQuals::S FTypeWithQuals::l + +?Char16Var@@3_SA +; CHECK: char16_t Char16Var + +?Char32Var@@3_UA +; CHECK: char32_t Char32Var + +?LRef@@YAXAAH@Z +; CHECK: void __cdecl LRef(int &) + +?RRef@@YAH$$QAH@Z +; CHECK: int __cdecl RRef(int &&) + +?Null@@YAX$$T@Z +; CHECK: void __cdecl Null(std::nullptr_t) + +?fun@PR18022@@YA?AU@1@U21@0@Z +; CHECK: struct PR18022:: __cdecl PR18022::fun(struct PR18022::, struct PR18022::) + +; First, we have the static local variable of type "" inside of "define_lambda". +; decltype(lambda), where lambda = [] { static int local=42; return 42; }; +?lambda@?1??define_lambda@@YAHXZ@4V@?0??1@YAHXZ@A +; CHECK: class `int __cdecl define_lambda(void)'::`1':: `int __cdecl define_lambda(void)'::`2'::lambda + +; Next, we have the "operator()" for "" which is inside of "define_lambda". +??R@?0??define_lambda@@YAHXZ@QBE@XZ +; CHECK: __thiscall `int __cdecl define_lambda(void)'::`1'::::operator()(void) const + +; Finally, we have the local which is inside of "" which is inside of "define_lambda". +?local@?2???R@?0??define_lambda@@YAHXZ@QBE@XZ@4HA +; CHECK: __thiscall `int __cdecl define_lambda(void)'::`1'::::operator()(void) const + +??$use_lambda_arg@V@?0??call_with_lambda_arg1@@YAXXZ@@@YAXV@?0??call_with_lambda_arg1@@YAXXZ@@Z +; CHECK: void __cdecl use_lambda_arg>(class `void __cdecl call_with_lambda_arg1(void)'::`1'::) + +?foo@A@PR19361@@QIGAEXXZ +; CHECK: void __thiscall PR19361::A::foo(void) __restrict & + +?foo@A@PR19361@@QIHAEXXZ +; CHECK: void __thiscall PR19361::A::foo(void) __restrict && + +??__K_deg@@YAHO@Z +; CHECK: int __cdecl operator ""_deg(long double) + +??$templ_fun_with_pack@$S@@YAXXZ +; CHECK: void __cdecl templ_fun_with_pack<>(void) + +??$templ_fun_with_ty_pack@$$$V@@YAXXZ +; CHECK: void __cdecl templ_fun_with_ty_pack<>(void) +??$templ_fun_with_ty_pack@$$V@@YAXXZ +; CHECK: void __cdecl templ_fun_with_ty_pack<>(void) + +??$f@$$YAliasA@PR20047@@@PR20047@@YAXXZ +; CHECK: void __cdecl PR20047::f(void) + +?f@UnnamedType@@YAXAAU@A@1@@Z +; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::A:: &) + +?f@UnnamedType@@YAXPAW4@?$B@H@1@@Z +; CHECK: void __cdecl UnnamedType::f(enum UnnamedType::B:: *) + +??$f@W4@?1??g@PR24651@@YAXXZ@@PR24651@@YAXW4@?1??g@0@YAXXZ@@Z +; We have a back-referencing problem here, we print `void __cdecl ::g(void)` +; for the second occurrence of g. +; FIXME: void __cdecl PR24651::f>(enum `void __cdecl PR24651::g(void)'::`2'::) + +??$f@T@PR18204@@@PR18204@@YAHPAT@0@@Z +; FIXME: int __cdecl PR18204::f>(union PR18204:: *) + +??R@?0??PR26105@@YAHXZ@QBE@H@Z +; CHECK: __thiscall `int __cdecl PR26105(void)'::`1'::::operator()(int) const + +??R@?0???R@?0??PR26105@@YAHXZ@QBE@H@Z@QBE@H@Z +; CHECK: __thiscall `__thiscall `int __cdecl PR26105(void)'::`1'::::operator()(int) const'::`1'::::operator()(int) const + +?unaligned_foo1@@YAPFAHXZ +; CHECK: int __unaligned * __cdecl unaligned_foo1(void) + +?unaligned_foo2@@YAPFAPFAHXZ +; CHECK: int __unaligned *__unaligned * __cdecl unaligned_foo2(void) + +?unaligned_foo3@@YAHXZ +; CHECK: int __cdecl unaligned_foo3(void) + +?unaligned_foo4@@YAXPFAH@Z +; CHECK: void __cdecl unaligned_foo4(int __unaligned *) + +?unaligned_foo5@@YAXPIFAH@Z +; CHECK: void __cdecl unaligned_foo5(int __unaligned *__restrict) + +??$unaligned_foo6@PAH@@YAPAHPAH@Z +; CHECK: int * __cdecl unaligned_foo6(int *) + +??$unaligned_foo6@PFAH@@YAPFAHPFAH@Z +; CHECK: int __unaligned * __cdecl unaligned_foo6(int __unaligned *) + +?unaligned_foo8@unaligned_foo8_S@@QFCEXXZ +; CHECK: void __thiscall unaligned_foo8_S::unaligned_foo8(void) volatile __unaligned + +??R@x@A@PR31197@@QBE@XZ +; CHECK: __thiscall PR31197::A::x::::operator()(void) const + +?white@?1???R@x@A@PR31197@@QBE@XZ@4HA +; CHECK: int `__thiscall PR31197::A::x::::operator()(void) const'::`2'::white + +?f@@YAXW4@@@Z +; CHECK: void __cdecl f(enum )