diff --git a/llvm/lib/Demangle/MicrosoftDemangle.cpp b/llvm/lib/Demangle/MicrosoftDemangle.cpp index a3079149deff..6f382098b27b 100644 --- a/llvm/lib/Demangle/MicrosoftDemangle.cpp +++ b/llvm/lib/Demangle/MicrosoftDemangle.cpp @@ -397,11 +397,6 @@ enum class SymbolCategory { namespace { -struct NameResolver { - virtual ~NameResolver() = default; - virtual StringView resolve(StringView S) = 0; -}; - struct Type; struct Name; @@ -448,15 +443,15 @@ struct Type { // Write the "first half" of a given type. This is a static functions to // give the code a chance to do processing that is common to a subset of // subclasses - static void outputPre(OutputStream &OS, Type &Ty, NameResolver &Resolver); + static void outputPre(OutputStream &OS, Type &Ty); // Write the "second half" of a given type. This is a static functions to // give the code a chance to do processing that is common to a subset of // subclasses - static void outputPost(OutputStream &OS, Type &Ty, NameResolver &Resolver); + static void outputPost(OutputStream &OS, Type &Ty); - virtual void outputPre(OutputStream &OS, NameResolver &Resolver); - virtual void outputPost(OutputStream &OS, NameResolver &Resolver); + virtual void outputPre(OutputStream &OS); + virtual void outputPost(OutputStream &OS); // Primitive type such as Int. PrimTy Prim = PrimTy::Unknown; @@ -528,8 +523,8 @@ struct VirtualMemberPtrThunk : public OperatorInfo { struct PointerType : public Type { Type *clone(ArenaAllocator &Arena) const override; - void outputPre(OutputStream &OS, NameResolver &Resolver) override; - void outputPost(OutputStream &OS, NameResolver &Resolver) override; + void outputPre(OutputStream &OS) override; + void outputPost(OutputStream &OS) override; PointerAffinity Affinity; @@ -540,8 +535,8 @@ struct PointerType : public Type { struct MemberPointerType : public Type { Type *clone(ArenaAllocator &Arena) const override; - void outputPre(OutputStream &OS, NameResolver &Resolver) override; - void outputPost(OutputStream &OS, NameResolver &Resolver) override; + void outputPre(OutputStream &OS) override; + void outputPost(OutputStream &OS) override; Name *MemberName = nullptr; @@ -559,8 +554,8 @@ struct FunctionType : public Type { }; Type *clone(ArenaAllocator &Arena) const override; - void outputPre(OutputStream &OS, NameResolver &Resolver) override; - void outputPost(OutputStream &OS, NameResolver &Resolver) override; + void outputPre(OutputStream &OS) override; + void outputPost(OutputStream &OS) override; // True if this FunctionType instance is the Pointee of a PointerType or // MemberPointerType. @@ -582,7 +577,7 @@ struct FunctionType : public Type { struct UdtType : public Type { Type *clone(ArenaAllocator &Arena) const override; - void outputPre(OutputStream &OS, NameResolver &Resolver) override; + void outputPre(OutputStream &OS) override; Name *UdtName = nullptr; }; @@ -594,8 +589,8 @@ struct ArrayDimension { struct ArrayType : public Type { Type *clone(ArenaAllocator &Arena) const override; - void outputPre(OutputStream &OS, NameResolver &Resolver) override; - void outputPost(OutputStream &OS, NameResolver &Resolver) override; + void outputPre(OutputStream &OS) override; + void outputPost(OutputStream &OS) override; // Either NextDimension or ElementType will be valid. ArrayDimension *Dims = nullptr; @@ -737,8 +732,8 @@ static bool startsWithLocalScopePattern(StringView S) { } // Write a function or template parameter list. -static void outputParameterList(OutputStream &OS, const FunctionParams &Params, - NameResolver &Resolver) { +static void outputParameterList(OutputStream &OS, + const FunctionParams &Params) { if (!Params.Current) { OS << "void"; return; @@ -746,8 +741,8 @@ static void outputParameterList(OutputStream &OS, const FunctionParams &Params, const FunctionParams *Head = &Params; while (Head) { - Type::outputPre(OS, *Head->Current, Resolver); - Type::outputPost(OS, *Head->Current, Resolver); + Type::outputPre(OS, *Head->Current); + Type::outputPost(OS, *Head->Current); Head = Head->Next; @@ -779,11 +774,10 @@ static void outputStringLiteral(OutputStream &OS, const StringLiteral &Str) { OS << "}"; } -static void outputName(OutputStream &OS, const Name *TheName, const Type *Ty, - NameResolver &Resolver); +static void outputName(OutputStream &OS, const Name *TheName, const Type *Ty); -static void outputParameterList(OutputStream &OS, const TemplateParams &Params, - NameResolver &Resolver) { +static void outputParameterList(OutputStream &OS, + const TemplateParams &Params) { if (Params.IsEmptyParameterPack) { OS << "<>"; return; @@ -802,16 +796,16 @@ static void outputParameterList(OutputStream &OS, const TemplateParams &Params, } else if (Head->PointerToSymbol || Head->ReferenceToSymbol) { if (Head->PointerToSymbol) OS << "&"; - Type::outputPre(OS, *Head->ParamType, Resolver); - outputName(OS, Head->ParamName, Head->ParamType, Resolver); - Type::outputPost(OS, *Head->ParamType, Resolver); + Type::outputPre(OS, *Head->ParamType); + outputName(OS, Head->ParamName, Head->ParamType); + Type::outputPost(OS, *Head->ParamType); } else if (Head->ParamType) { // simple type. - Type::outputPre(OS, *Head->ParamType, Resolver); - Type::outputPost(OS, *Head->ParamType, Resolver); + Type::outputPre(OS, *Head->ParamType); + Type::outputPost(OS, *Head->ParamType); } else { // Template alias. - outputName(OS, Head->ParamName, Head->ParamType, Resolver); + outputName(OS, Head->ParamName, Head->ParamType); } Head = Head->Next; @@ -839,24 +833,14 @@ static void outputQualifiers(OutputStream &OS, Qualifiers Q) { } } -static void outputNameComponent(OutputStream &OS, bool IsBackReference, - const TemplateParams *TParams, StringView Str, - NameResolver &Resolver) { - if (IsBackReference) - Str = Resolver.resolve(Str); - OS << Str; +static void outputNameComponent(OutputStream &OS, const Name &N) { + OS << N.Str; - if (TParams) - outputParameterList(OS, *TParams, Resolver); + if (N.IsTemplateInstantiation && N.TParams) + outputParameterList(OS, *N.TParams); } -static void outputNameComponent(OutputStream &OS, const Name &N, - NameResolver &Resolver) { - outputNameComponent(OS, N.IsBackReference, N.TParams, N.Str, Resolver); -} - -static void outputName(OutputStream &OS, const Name *TheName, const Type *Ty, - NameResolver &Resolver) { +static void outputName(OutputStream &OS, const Name *TheName, const Type *Ty) { if (!TheName) return; @@ -866,13 +850,13 @@ static void outputName(OutputStream &OS, const Name *TheName, const Type *Ty, // Print out namespaces or outer class BackReferences. for (; TheName->Next; TheName = TheName->Next) { Previous = TheName; - outputNameComponent(OS, *TheName, Resolver); + outputNameComponent(OS, *TheName); OS << "::"; } // Print out a regular name. if (!TheName->IsOperator) { - outputNameComponent(OS, *TheName, Resolver); + outputNameComponent(OS, *TheName); return; } @@ -884,24 +868,24 @@ static void outputName(OutputStream &OS, const Name *TheName, const Type *Ty, OS << "~"; LLVM_FALLTHROUGH; case OperatorTy::Ctor: - outputNameComponent(OS, *Previous, Resolver); + outputNameComponent(OS, *Previous); break; case OperatorTy::Conversion: OS << "operator"; if (TheName->IsTemplateInstantiation && TheName->TParams) - outputParameterList(OS, *TheName->TParams, Resolver); + outputParameterList(OS, *TheName->TParams); OS << " "; if (Ty) { const FunctionType *FTy = static_cast(Ty); - Type::outputPre(OS, *FTy->ReturnType, Resolver); - Type::outputPost(OS, *FTy->ReturnType, Resolver); + Type::outputPre(OS, *FTy->ReturnType); + Type::outputPost(OS, *FTy->ReturnType); } else { OS << ""; } break; case OperatorTy::LiteralOperator: OS << Operator.Info->Name; - outputNameComponent(OS, *TheName, Resolver); + outputNameComponent(OS, *TheName); break; case OperatorTy::RttiBaseClassDescriptor: { const RttiBaseClassDescriptor &BCD = @@ -923,13 +907,12 @@ static void outputName(OutputStream &OS, const Name *TheName, const Type *Ty, default: OS << Operator.Info->Name; if (Operator.IsTemplateInstantiation) - outputParameterList(OS, *Operator.TParams, Resolver); + outputParameterList(OS, *Operator.TParams); break; } } -static void outputSpecialOperator(OutputStream &OS, const Name *OuterName, - NameResolver &Resolver) { +static void outputSpecialOperator(OutputStream &OS, const Name *OuterName) { assert(OuterName); // The last component should be an operator. const Name *LastComponent = OuterName; @@ -953,7 +936,7 @@ static void outputSpecialOperator(OutputStream &OS, const Name *OuterName, // Print out namespaces or outer class BackReferences. const Name *N = OuterName; for (; N->Next; N = N->Next) { - outputNameComponent(OS, *N, Resolver); + outputNameComponent(OS, *N); OS << "::"; } OS << "`vcall'{"; @@ -980,12 +963,12 @@ Type *Type::clone(ArenaAllocator &Arena) const { } // Write the "first half" of a given type. -void Type::outputPre(OutputStream &OS, Type &Ty, NameResolver &Resolver) { +void Type::outputPre(OutputStream &OS, Type &Ty) { // Function types require custom handling of const and static so we // handle them separately. All other types use the same decoration // for these modifiers, so handle them here in common code. if (Ty.Prim == PrimTy::Function) { - Ty.outputPre(OS, Resolver); + Ty.outputPre(OS); return; } @@ -997,17 +980,15 @@ void Type::outputPre(OutputStream &OS, Type &Ty, NameResolver &Resolver) { default: break; } - Ty.outputPre(OS, Resolver); + Ty.outputPre(OS); outputQualifiers(OS, Ty.Quals); } // Write the "second half" of a given type. -void Type::outputPost(OutputStream &OS, Type &Ty, NameResolver &Resolver) { - Ty.outputPost(OS, Resolver); -} +void Type::outputPost(OutputStream &OS, Type &Ty) { Ty.outputPost(OS); } -void Type::outputPre(OutputStream &OS, NameResolver &Resolver) { +void Type::outputPre(OutputStream &OS) { switch (Prim) { case PrimTy::Void: OS << "void"; @@ -1076,15 +1057,15 @@ void Type::outputPre(OutputStream &OS, NameResolver &Resolver) { assert(false && "Invalid primitive type!"); } } -void Type::outputPost(OutputStream &OS, NameResolver &Resolver) {} +void Type::outputPost(OutputStream &OS) {} Type *PointerType::clone(ArenaAllocator &Arena) const { return Arena.alloc(*this); } static void outputPointerIndicator(OutputStream &OS, PointerAffinity Affinity, - const Name *MemberName, const Type *Pointee, - NameResolver &Resolver) { + const Name *MemberName, + const Type *Pointee) { // "[]" 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 @@ -1100,7 +1081,7 @@ static void outputPointerIndicator(OutputStream &OS, PointerAffinity Affinity, } if (MemberName) { - outputName(OS, MemberName, Pointee, Resolver); + outputName(OS, MemberName, Pointee); OS << "::"; } @@ -1112,57 +1093,56 @@ static void outputPointerIndicator(OutputStream &OS, PointerAffinity Affinity, OS << "&&"; } -void PointerType::outputPre(OutputStream &OS, NameResolver &Resolver) { - Type::outputPre(OS, *Pointee, Resolver); +void PointerType::outputPre(OutputStream &OS) { + Type::outputPre(OS, *Pointee); outputSpaceIfNecessary(OS); if (Quals & Q_Unaligned) OS << "__unaligned "; - outputPointerIndicator(OS, Affinity, nullptr, Pointee, Resolver); + outputPointerIndicator(OS, Affinity, nullptr, Pointee); // FIXME: We should output this, but it requires updating lots of tests. // if (Ty.Quals & Q_Pointer64) // OS << " __ptr64"; } -void PointerType::outputPost(OutputStream &OS, NameResolver &Resolver) { +void PointerType::outputPost(OutputStream &OS) { if (Pointee->Prim == PrimTy::Function || Pointee->Prim == PrimTy::Array) OS << ")"; - Type::outputPost(OS, *Pointee, Resolver); + Type::outputPost(OS, *Pointee); } Type *MemberPointerType::clone(ArenaAllocator &Arena) const { return Arena.alloc(*this); } -void MemberPointerType::outputPre(OutputStream &OS, NameResolver &Resolver) { - Type::outputPre(OS, *Pointee, Resolver); +void MemberPointerType::outputPre(OutputStream &OS) { + Type::outputPre(OS, *Pointee); outputSpaceIfNecessary(OS); - outputPointerIndicator(OS, PointerAffinity::Pointer, MemberName, Pointee, - Resolver); + outputPointerIndicator(OS, PointerAffinity::Pointer, MemberName, Pointee); // FIXME: We should output this, but it requires updating lots of tests. // if (Ty.Quals & Q_Pointer64) // OS << " __ptr64"; } -void MemberPointerType::outputPost(OutputStream &OS, NameResolver &Resolver) { +void MemberPointerType::outputPost(OutputStream &OS) { if (Pointee->Prim == PrimTy::Function || Pointee->Prim == PrimTy::Array) OS << ")"; - Type::outputPost(OS, *Pointee, Resolver); + Type::outputPost(OS, *Pointee); } Type *FunctionType::clone(ArenaAllocator &Arena) const { return Arena.alloc(*this); } -void FunctionType::outputPre(OutputStream &OS, NameResolver &Resolver) { +void FunctionType::outputPre(OutputStream &OS) { if ((FunctionClass & StaticThisAdjust) || (FunctionClass & VirtualThisAdjust)) OS << "[thunk]: "; @@ -1177,7 +1157,7 @@ void FunctionType::outputPre(OutputStream &OS, NameResolver &Resolver) { OS << "virtual "; if (ReturnType) { - Type::outputPre(OS, *ReturnType, Resolver); + Type::outputPre(OS, *ReturnType); OS << " "; } @@ -1188,7 +1168,7 @@ void FunctionType::outputPre(OutputStream &OS, NameResolver &Resolver) { outputCallingConvention(OS, CallConvention); } -void FunctionType::outputPost(OutputStream &OS, NameResolver &Resolver) { +void FunctionType::outputPost(OutputStream &OS) { // extern "C" functions don't have a prototype. if (FunctionClass & NoPrototype) return; @@ -1207,7 +1187,7 @@ void FunctionType::outputPost(OutputStream &OS, NameResolver &Resolver) { } OS << "("; - outputParameterList(OS, Params, Resolver); + outputParameterList(OS, Params); OS << ")"; if (Quals & Q_Const) OS << " const"; @@ -1224,7 +1204,7 @@ void FunctionType::outputPost(OutputStream &OS, NameResolver &Resolver) { OS << " &&"; if (ReturnType) - Type::outputPost(OS, *ReturnType, Resolver); + Type::outputPost(OS, *ReturnType); return; } @@ -1232,7 +1212,7 @@ Type *UdtType::clone(ArenaAllocator &Arena) const { return Arena.alloc(*this); } -void UdtType::outputPre(OutputStream &OS, NameResolver &Resolver) { +void UdtType::outputPre(OutputStream &OS) { switch (Prim) { case PrimTy::Class: OS << "class "; @@ -1250,18 +1230,18 @@ void UdtType::outputPre(OutputStream &OS, NameResolver &Resolver) { assert(false && "Not a udt type!"); } - outputName(OS, UdtName, this, Resolver); + outputName(OS, UdtName, this); } Type *ArrayType::clone(ArenaAllocator &Arena) const { return Arena.alloc(*this); } -void ArrayType::outputPre(OutputStream &OS, NameResolver &Resolver) { - Type::outputPre(OS, *ElementType, Resolver); +void ArrayType::outputPre(OutputStream &OS) { + Type::outputPre(OS, *ElementType); } -void ArrayType::outputPost(OutputStream &OS, NameResolver &Resolver) { +void ArrayType::outputPost(OutputStream &OS) { ArrayDimension *D = Dims; while (D) { OS << "["; @@ -1271,7 +1251,7 @@ void ArrayType::outputPost(OutputStream &OS, NameResolver &Resolver) { D = D->Next; } - Type::outputPost(OS, *ElementType, Resolver); + Type::outputPost(OS, *ElementType); } struct Symbol { @@ -1301,7 +1281,7 @@ struct BackrefContext { // Demangler class takes the main role in demangling symbols. // It has a set of functions to parse mangled symbols into Type instances. // It also has a set of functions to cnovert Type instances to strings. -class Demangler : public NameResolver { +class Demangler { public: Demangler() = default; virtual ~Demangler() = default; @@ -1313,8 +1293,6 @@ public: void output(const Symbol *S, OutputStream &OS); - StringView resolve(StringView N) override; - // True if an error occurred. bool Error = false; @@ -1639,10 +1617,16 @@ void Demangler::memorizeString(StringView S) { Name *Demangler::demangleBackRefName(StringView &MangledName) { assert(startsWithDigit(MangledName)); - Name *Node = Arena.alloc(); - Node->IsBackReference = true; - Node->Str = {MangledName.begin(), 1}; + + size_t I = MangledName[0] - '0'; + if (I >= Backrefs.NamesCount) { + Error = true; + return nullptr; + } + MangledName = MangledName.dropFront(); + Name *Node = Arena.alloc(); + Node->Str = Backrefs.Names[I]; return Node; } @@ -1654,7 +1638,7 @@ Name *Demangler::demangleTemplateInstantiationName(StringView &MangledName, BackrefContext OuterContext; std::swap(OuterContext, Backrefs); - Name *Node = demangleUnqualifiedSymbolName(MangledName, NBB_None); + Name *Node = demangleUnqualifiedSymbolName(MangledName, NBB_Simple); if (!Error) Node->TParams = demangleTemplateParameterList(MangledName); @@ -1668,7 +1652,7 @@ Name *Demangler::demangleTemplateInstantiationName(StringView &MangledName, // Render this class template name into a string buffer so that we can // memorize it for the purpose of back-referencing. OutputStream OS = OutputStream::create(nullptr, nullptr, 1024); - outputName(OS, Node, nullptr, *this); + outputName(OS, Node, nullptr); OS << '\0'; char *Name = OS.getBuffer(); @@ -2958,22 +2942,14 @@ Demangler::demangleTemplateParameterList(StringView &MangledName) { return nullptr; } -StringView Demangler::resolve(StringView N) { - assert(N.size() == 1 && isdigit(N[0])); - size_t Digit = N[0] - '0'; - if (Digit >= Backrefs.NamesCount) - return N; - return Backrefs.Names[Digit]; -} - void Demangler::output(const Symbol *S, OutputStream &OS) { if (S->Category == SymbolCategory::Unknown) { - outputName(OS, S->SymbolName, S->SymbolType, *this); + outputName(OS, S->SymbolName, S->SymbolType); return; } if (S->Category == SymbolCategory::SpecialOperator) { - outputSpecialOperator(OS, S->SymbolName, *this); + outputSpecialOperator(OS, S->SymbolName); return; } @@ -2995,12 +2971,12 @@ void Demangler::output(const Symbol *S, OutputStream &OS) { // "second half". For example, outputPre() writes a return type for a // function and outputPost() writes an parameter list. if (S->SymbolType) { - Type::outputPre(OS, *S->SymbolType, *this); - outputName(OS, S->SymbolName, S->SymbolType, *this); - Type::outputPost(OS, *S->SymbolType, *this); + Type::outputPre(OS, *S->SymbolType); + outputName(OS, S->SymbolName, S->SymbolType); + Type::outputPost(OS, *S->SymbolType); } else { outputQualifiers(OS, S->SymbolQuals); - outputName(OS, S->SymbolName, nullptr, *this); + outputName(OS, S->SymbolName, nullptr); } } @@ -3014,8 +2990,8 @@ void Demangler::dumpBackReferences() { OS.setCurrentPosition(0); Type *T = Backrefs.FunctionParams[I]; - Type::outputPre(OS, *T, *this); - Type::outputPost(OS, *T, *this); + Type::outputPre(OS, *T); + Type::outputPost(OS, *T); std::printf(" [%d] - %.*s\n", (int)I, (int)OS.getCurrentPosition(), OS.getBuffer()); diff --git a/llvm/test/Demangle/ms-back-references.test b/llvm/test/Demangle/ms-back-references.test index 553d2ff62929..b9ce7c21520b 100644 --- a/llvm/test/Demangle/ms-back-references.test +++ b/llvm/test/Demangle/ms-back-references.test @@ -51,4 +51,118 @@ ; CHECK: void __cdecl foo::foo(void) ??$?HH@S@@QEAAAEAU0@H@Z -struct S & __cdecl S::operator+(int) \ No newline at end of file +; CHECK: struct S & __cdecl S::operator+(int) + +?foo_abbb@@YAXV?$A@V?$B@D@@V1@V1@@@@Z +; CHECK: void __cdecl foo_abbb(class A, class B, class B>) + +?foo_abb@@YAXV?$A@DV?$B@D@@V1@@@@Z +; CHECK: void __cdecl foo_abb(class A, class B>) + +?foo_abc@@YAXV?$A@DV?$B@D@@V?$C@D@@@@@Z +; CHECK: void __cdecl foo_abc(class A, class C>) + +?foo_bt@@YAX_NV?$B@$$A6A_N_N@Z@@@Z +; CHECK: void __cdecl foo_bt(bool, class B) + +?foo_abbb@@YAXV?$A@V?$B@D@N@@V12@V12@@N@@@Z +; CHECK: void __cdecl foo_abbb(class N::A, class N::B, class N::B>) + +?foo_abb@@YAXV?$A@DV?$B@D@N@@V12@@N@@@Z +; CHECK: void __cdecl foo_abb(class N::A, class N::B>) + +?foo_abc@@YAXV?$A@DV?$B@D@N@@V?$C@D@2@@N@@@Z +; CHECK: void __cdecl foo_abc(class N::A, class N::C>) + +?abc_foo@@YA?AV?$A@DV?$B@D@N@@V?$C@D@2@@N@@XZ +; CHECK: class N::A, class N::C> __cdecl abc_foo(void) + +?z_foo@@YA?AVZ@N@@V12@@Z +; CHECK: class N::Z __cdecl z_foo(class N::Z) + +?b_foo@@YA?AV?$B@D@N@@V12@@Z +; CHECK: class N::B __cdecl b_foo(class N::B) + +?d_foo@@YA?AV?$D@DD@N@@V12@@Z +; CHECK: class N::D __cdecl d_foo(class N::D) + +?abc_foo_abc@@YA?AV?$A@DV?$B@D@N@@V?$C@D@2@@N@@V12@@Z +; CHECK: class N::A, class N::C> __cdecl abc_foo_abc(class N::A, class N::C>) + +?foo5@@YAXV?$Y@V?$Y@V?$Y@V?$Y@VX@NA@@@NB@@@NA@@@NB@@@NA@@@Z +; CHECK: void __cdecl foo5(class NA::Y>>>) + +?foo11@@YAXV?$Y@VX@NA@@@NA@@V1NB@@@Z +; CHECK: void __cdecl foo11(class NA::Y, class NB::Y) + +?foo112@@YAXV?$Y@VX@NA@@@NA@@V?$Y@VX@NB@@@NB@@@Z +; CHECK: void __cdecl foo112(class NA::Y, class NB::Y) + +?foo22@@YAXV?$Y@V?$Y@VX@NA@@@NB@@@NA@@V?$Y@V?$Y@VX@NA@@@NA@@@NB@@@Z +; CHECK: void __cdecl foo22(class NA::Y>, class NB::Y>) + +?foo@L@PR13207@@QAEXV?$I@VA@PR13207@@@2@@Z +; CHECK: void __thiscall PR13207::L::foo(class PR13207::I) + +?foo@PR13207@@YAXV?$I@VA@PR13207@@@1@@Z +; CHECK: void __cdecl PR13207::foo(class PR13207::I) + +?foo2@PR13207@@YAXV?$I@VA@PR13207@@@1@0@Z +; CHECK: void __cdecl PR13207::foo2(class PR13207::I, class PR13207::I) + +?bar@PR13207@@YAXV?$J@VA@PR13207@@VB@2@@1@@Z +; CHECK: void __cdecl PR13207::bar(class PR13207::J) + +?spam@PR13207@@YAXV?$K@VA@PR13207@@VB@2@VC@2@@1@@Z +; CHECK: void __cdecl PR13207::spam(class PR13207::K) + +?baz@PR13207@@YAXV?$K@DV?$F@D@PR13207@@V?$I@D@2@@1@@Z +; CHECK: void __cdecl PR13207::baz(class PR13207::K, class PR13207::I>) + +?qux@PR13207@@YAXV?$K@DV?$I@D@PR13207@@V12@@1@@Z +; CHECK: void __cdecl PR13207::qux(class PR13207::K, class PR13207::I>) + +?foo@NA@PR13207@@YAXV?$Y@VX@NA@PR13207@@@12@@Z +; CHECK: void __cdecl PR13207::NA::foo(class PR13207::NA::Y) + +?foofoo@NA@PR13207@@YAXV?$Y@V?$Y@VX@NA@PR13207@@@NA@PR13207@@@12@@Z +; CHECK: void __cdecl PR13207::NA::foofoo(class PR13207::NA::Y>) + +?foo@NB@PR13207@@YAXV?$Y@VX@NA@PR13207@@@12@@Z +; CHECK: void __cdecl PR13207::NB::foo(class PR13207::NB::Y) + +?bar@NB@PR13207@@YAXV?$Y@VX@NB@PR13207@@@NA@2@@Z +; CHECK: void __cdecl PR13207::NB::bar(class PR13207::NA::Y) + +?spam@NB@PR13207@@YAXV?$Y@VX@NA@PR13207@@@NA@2@@Z +; CHECK: void __cdecl PR13207::NB::spam(class PR13207::NA::Y) + +?foobar@NB@PR13207@@YAXV?$Y@V?$Y@VX@NB@PR13207@@@NB@PR13207@@@NA@2@V312@@Z +; CHECK: void __cdecl PR13207::NB::foobar(class PR13207::NA::Y>, class PR13207::NB::Y>) + +?foobarspam@NB@PR13207@@YAXV?$Y@VX@NB@PR13207@@@12@V?$Y@V?$Y@VX@NB@PR13207@@@NB@PR13207@@@NA@2@V412@@Z +; CHECK: void __cdecl PR13207::NB::foobarspam(class PR13207::NB::Y, class PR13207::NA::Y>, class PR13207::NB::Y>) + +?foobarbaz@NB@PR13207@@YAXV?$Y@VX@NB@PR13207@@@12@V?$Y@V?$Y@VX@NB@PR13207@@@NB@PR13207@@@NA@2@V412@2@Z +; CHECK: void __cdecl PR13207::NB::foobarbaz(class PR13207::NB::Y, class PR13207::NA::Y>, class PR13207::NB::Y>, class PR13207::NB::Y>) + +?foobarbazqux@NB@PR13207@@YAXV?$Y@VX@NB@PR13207@@@12@V?$Y@V?$Y@VX@NB@PR13207@@@NB@PR13207@@@NA@2@V412@2V?$Y@V?$Y@V?$Y@VX@NB@PR13207@@@NB@PR13207@@@NB@PR13207@@@52@@Z +; CHECK: void __cdecl PR13207::NB::foobarbazqux(class PR13207::NB::Y, class PR13207::NA::Y>, class PR13207::NB::Y>, class PR13207::NB::Y>, class PR13207::NA::Y>>) + +?foo@NC@PR13207@@YAXV?$Y@VX@NB@PR13207@@@12@@Z +; CHECK: void __cdecl PR13207::NC::foo(class PR13207::NC::Y) + +?foobar@NC@PR13207@@YAXV?$Y@V?$Y@V?$Y@VX@NA@PR13207@@@NA@PR13207@@@NB@PR13207@@@12@@Z +; CHECK: void __cdecl PR13207::NC::foobar(class PR13207::NC::Y>>) + +?fun_normal@fn_space@@YA?AURetVal@1@H@Z +; CHECK: struct fn_space::RetVal __cdecl fn_space::fun_normal(int) + +??$fun_tmpl@H@fn_space@@YA?AURetVal@0@ABH@Z +; CHECK: struct fn_space::RetVal __cdecl fn_space::fun_tmpl(int const &) + +??$fun_tmpl_recurse@H$1??$fun_tmpl_recurse@H$1?ident@fn_space@@YA?AURetVal@2@H@Z@fn_space@@YA?AURetVal@1@H@Z@fn_space@@YA?AURetVal@0@H@Z +; CHECK: struct fn_space::RetVal __cdecl fn_space::fun_tmpl_recurse(int)>(int) + +??$fun_tmpl_recurse@H$1?ident@fn_space@@YA?AURetVal@2@H@Z@fn_space@@YA?AURetVal@0@H@Z +; CHECK: struct fn_space::RetVal __cdecl fn_space::fun_tmpl_recurse(int) diff --git a/llvm/test/Demangle/ms-templates.test b/llvm/test/Demangle/ms-templates.test index bfb5988649c7..09995b36f52c 100644 --- a/llvm/test/Demangle/ms-templates.test +++ b/llvm/test/Demangle/ms-templates.test @@ -192,4 +192,7 @@ ; CHECK: void __cdecl FunctionDefinedWithInjectedName(struct TypeWithFriendDefinition) ?bar@?$UUIDType4@$1?_GUID_12345678_1234_1234_1234_1234567890ab@@3U__s_GUID@@B@@QAEXXZ -; CHECK: void __thiscall UUIDType4<&struct __s_GUID const _GUID_12345678_1234_1234_1234_1234567890ab>::bar(void) \ No newline at end of file +; CHECK: void __thiscall UUIDType4<&struct __s_GUID const _GUID_12345678_1234_1234_1234_1234567890ab>::bar(void) + +??$f@US@@$1?g@1@QEAAXXZ@@YAXXZ +; CHECK: void __cdecl f(void)