diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index e0fd8abe5e3b8..d70f1a19acbbd 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -29,12 +29,14 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/CRC.h" #include "llvm/Support/MD5.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/StringSaver.h" #include "llvm/Support/xxhash.h" +#include #include using namespace clang; @@ -368,9 +370,13 @@ class MicrosoftCXXNameMangler { void mangleVariableEncoding(const VarDecl *VD); void mangleMemberDataPointer(const CXXRecordDecl *RD, const ValueDecl *VD, StringRef Prefix = "$"); + void mangleMemberDataPointerInClassNTTP(const CXXRecordDecl *, + const ValueDecl *); void mangleMemberFunctionPointer(const CXXRecordDecl *RD, const CXXMethodDecl *MD, StringRef Prefix = "$"); + void mangleMemberFunctionPointerInClassNTTP(const CXXRecordDecl *RD, + const CXXMethodDecl *MD); void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD, const MethodVFTableLocation &ML); void mangleNumber(int64_t Number); @@ -711,6 +717,28 @@ void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD, mangleNumber(VBTableOffset); } +void MicrosoftCXXNameMangler::mangleMemberDataPointerInClassNTTP( + const CXXRecordDecl *RD, const ValueDecl *VD) { + MSInheritanceModel IM = RD->getMSInheritanceModel(); + // ::= + // ::= N + // ::= 8 @ @ + + if (IM != MSInheritanceModel::Single && IM != MSInheritanceModel::Multiple) + return mangleMemberDataPointer(RD, VD, ""); + + if (!VD) { + Out << 'N'; + return; + } + + Out << '8'; + mangleNestedName(VD); + Out << '@'; + mangleUnqualifiedName(VD); + Out << '@'; +} + void MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD, const CXXMethodDecl *MD, @@ -775,6 +803,34 @@ MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD, mangleNumber(VBTableOffset); } +void MicrosoftCXXNameMangler::mangleMemberFunctionPointerInClassNTTP( + const CXXRecordDecl *RD, const CXXMethodDecl *MD) { + // ::= + // ::= N + // ::= E? + // ::= E? + + if (!MD) { + if (RD->getMSInheritanceModel() != MSInheritanceModel::Single) + return mangleMemberFunctionPointer(RD, MD, ""); + + Out << 'N'; + return; + } + + Out << "E?"; + if (MD->isVirtual()) { + MicrosoftVTableContext *VTContext = + cast(getASTContext().getVTableContext()); + MethodVFTableLocation ML = + VTContext->getMethodVFTableLocation(GlobalDecl(MD)); + mangleVirtualMemPtrThunk(MD, ML); + } else { + mangleName(MD); + mangleFunctionEncoding(MD, /*ShouldMangle=*/true); + } +} + void MicrosoftCXXNameMangler::mangleVirtualMemPtrThunk( const CXXMethodDecl *MD, const MethodVFTableLocation &ML) { // Get the vftable offset. @@ -1188,6 +1244,11 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(GlobalDecl GD, // ::= [] void MicrosoftCXXNameMangler::mangleNestedName(GlobalDecl GD) { const NamedDecl *ND = cast(GD.getDecl()); + + if (const auto *ID = dyn_cast(ND)) + for (unsigned I = 1, IE = ID->getChainingSize(); I < IE; ++I) + mangleSourceName(""); + const DeclContext *DC = getEffectiveDeclContext(ND); while (!DC->isTranslationUnit()) { if (isa(ND) || isa(ND)) { @@ -1570,7 +1631,6 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD, // ::= 8 @ // ::= A # float // ::= B # double - // ::= E # reference to D // # pointer to member, by component value // ::= F // ::= G @@ -1615,7 +1675,7 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD, mangleTemplateArgValue(TPO->getType().getUnqualifiedType(), TPO->getValue()); } else { - mangle(ND, TA.getParamTypeForDecl()->isReferenceType() ? "$E?" : "$1?"); + mangle(ND, "$1?"); } break; } @@ -1744,46 +1804,62 @@ void MicrosoftCXXNameMangler::mangleTemplateArgValue(QualType T, // FIXME: This can only happen as an extension. Invent a mangling. break; } else if (auto *VD = Base.dyn_cast()) { - Out << (T->isReferenceType() ? "E" : "1"); + Out << "E"; mangle(VD); } else { break; } } else { - unsigned NumAts = 0; - if (T->isPointerType()) { + if (T->isPointerType()) Out << "5"; - ++NumAts; - } - QualType T = Base.getType(); + SmallVector EntryTypes; + SmallVector, 2> EntryManglers; + QualType ET = Base.getType(); for (APValue::LValuePathEntry E : V.getLValuePath()) { - // We don't know how to mangle array subscripting yet. - if (T->isArrayType()) - goto mangling_unknown; + if (auto *AT = ET->getAsArrayTypeUnsafe()) { + EntryTypes.push_back('C'); + EntryManglers.push_back([this, I = E.getAsArrayIndex()] { + Out << '0'; + mangleNumber(I); + Out << '@'; + }); + ET = AT->getElementType(); + continue; + } const Decl *D = E.getAsBaseOrMember().getPointer(); - auto *FD = dyn_cast(D); - // We don't know how to mangle derived-to-base conversions yet. - if (!FD) - goto mangling_unknown; - - Out << "6"; - ++NumAts; - T = FD->getType(); + if (auto *FD = dyn_cast(D)) { + ET = FD->getType(); + if (const auto *RD = ET->getAsRecordDecl()) + if (RD->isAnonymousStructOrUnion()) + continue; + } else { + ET = getASTContext().getRecordType(cast(D)); + // Bug in MSVC: fully qualified name of base class should be used for + // mangling to prevent collisions e.g. on base classes with same names + // in different namespaces. + } + + EntryTypes.push_back('6'); + EntryManglers.push_back([this, D] { + mangleUnqualifiedName(cast(D)); + Out << '@'; + }); } + for (auto I = EntryTypes.rbegin(), E = EntryTypes.rend(); I != E; ++I) + Out << *I; + auto *VD = Base.dyn_cast(); if (!VD) break; Out << "E"; mangle(VD); - for (APValue::LValuePathEntry E : V.getLValuePath()) { - const Decl *D = E.getAsBaseOrMember().getPointer(); - mangleUnqualifiedName(cast(D)); - } - for (unsigned I = 0; I != NumAts; ++I) + for (const std::function &Mangler : EntryManglers) + Mangler(); + if (T->isPointerType()) Out << '@'; } @@ -1794,20 +1870,14 @@ void MicrosoftCXXNameMangler::mangleTemplateArgValue(QualType T, if (WithScalarType) mangleType(T, SourceRange(), QMM_Escape); - // FIXME: The below manglings don't include a conversion, so bail if there - // would be one. MSVC mangles the (possibly converted) value of the - // pointer-to-member object as if it were a struct, leading to collisions - // in some cases. - if (!V.getMemberPointerPath().empty()) - break; - const CXXRecordDecl *RD = T->castAs()->getMostRecentCXXRecordDecl(); const ValueDecl *D = V.getMemberPointerDecl(); if (T->isMemberDataPointerType()) - mangleMemberDataPointer(RD, D, ""); + mangleMemberDataPointerInClassNTTP(RD, D); else - mangleMemberFunctionPointer(RD, cast_or_null(D), ""); + mangleMemberFunctionPointerInClassNTTP(RD, + cast_or_null(D)); return; } @@ -1895,7 +1965,6 @@ void MicrosoftCXXNameMangler::mangleTemplateArgValue(QualType T, break; } -mangling_unknown: DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID( DiagnosticsEngine::Error, "cannot mangle this template argument yet"); diff --git a/clang/test/CodeGenCXX/mangle-class-nttp.cpp b/clang/test/CodeGenCXX/mangle-class-nttp.cpp index 70e5be8456cc0..12c81f2ba0514 100644 --- a/clang/test/CodeGenCXX/mangle-class-nttp.cpp +++ b/clang/test/CodeGenCXX/mangle-class-nttp.cpp @@ -15,7 +15,7 @@ template void f() {} int n = 0; // CHECK: define weak_odr void @_Z1fIXtl1BadL_Z1nEEEEvv( -// MSABI: define {{.*}} @"??$f@$2UB@@PEBH1?n@@3HAH0A@@@@YAXXZ" +// MSABI: define {{.*}} @"??$f@$2UB@@PEBHE?n@@3HAH0A@@@@YAXXZ" template void f(); // CHECK: define weak_odr void @_Z1fIXtl1BLPKi0ELi1EEEEvv( // MSABI: define {{.*}} @"??$f@$2UB@@PEBH0A@H00@@@YAXXZ" @@ -36,15 +36,19 @@ template void f(0))}>(); // Pointers to subobjects. struct Nested { union { int k; int arr[2]; }; } nested[2]; -struct Derived : A, Nested { int z; } extern derived; +struct Derived : A, Nested { int z; A a_field; } extern derived; // CHECK: define weak_odr void @_Z1fIXtl1BadsoKiL_Z7derivedE16EEEEvv // MSABI: define {{.*}} void @"??$f@$2UB@@PEBH56E?derived@@3UDerived@@Az@@@H0A@@@@YAXXZ" template void f(); -// FIXME: We don't know the MS ABI mangling for array subscripting and -// past-the-end pointers yet. -#ifndef _WIN32 +// CHECK: define weak_odr void @_Z1fIXtl1BadsoKiL_Z7derivedE20EEEEvv +// MSABI: define {{.*}} void @"??$f@$2UB@@PEBH566E?derived@@3UDerived@@Aa_field@@a@@@H0A@@@@YAXXZ" +template void f(); // CHECK: define weak_odr void @_Z1fIXtl1BadsoKiL_Z6nestedE_EEEEvv +// MSABI: define {{.*}} void @"??$f@$2UB@@PEBH56CE?nested@@3PAUNested@@A0A@@k@@@H0A@@@@YAXXZ" template void f(); +// Mangling of pointers to nested array elements and past-the-end pointers +// is still incorrect in MSVC. +#ifndef _WIN32 // CHECK: define weak_odr void @_Z1fIXtl1BadsoKiL_Z6nestedE16_0pEEEEvv template void f(); // CHECK: define weak_odr void @_Z1fIXtl1BadsoKiL_Z7derivedE8pEEEEvv @@ -59,14 +63,16 @@ template
void f() {} // CHECK: define weak_odr void @_Z1fIXtl2BRsoKiL_Z7derivedE16EEEEvv // MSABI: define {{.*}} void @"??$f@$2UBR@@AEBH6E?derived@@3UDerived@@Az@@@@@YAXXZ" template void f(); -// FIXME: We don't know the MS ABI mangling for array subscripting yet. -#ifndef _WIN32 // CHECK: define weak_odr void @_Z1fIXtl2BRsoKiL_Z6nestedE_EEEEvv +// MSABI: define {{.*}} void @"??$f@$2UBR@@AEBH6CE?nested@@3PAUNested@@A0A@@k@@@@@YAXXZ" template void f(); // CHECK: define weak_odr void @_Z1fIXtl2BRsoKiL_Z6nestedE12_0EEEEvv +// MSABI: define {{.*}} void @"??$f@$2UBR@@AEBHC6CE?nested@@3PAUNested@@A00@arr@@00@@@@YAXXZ" template void f(); // CHECK: define weak_odr void @_Z1fIXtl2BRsoKiL_Z7derivedE4EEEEvv +// MSABI: define {{.*}} void @"??$f@$2UBR@@AEBH66E?derived@@3UDerived@@AA@@b@@@@@YAXXZ" template void f(); +#ifndef _WIN32 // CHECK: define weak_odr void @_Z1fIXtl2BRdecvPKiplcvPcadL_Z7derivedELl16EEEEvv template void f(); #endif @@ -77,42 +83,93 @@ template void f() {} // CHECK: define weak_odr void @_Z1fIXtl1CadsoKiL_Z7derivedE16EEEEvv // MSABI: define {{.*}} void @"??$f@$2UC@@PEBH56E?derived@@3UDerived@@Az@@@@@@YAXXZ" template void f(); -#ifndef _WIN32 // CHECK: define weak_odr void @_Z1fIXtl1CadsoKiL_Z7derivedE4EEEEvv +// MSABI: define {{.*}} void @"??$f@$2UC@@PEBH566E?derived@@3UDerived@@AA@@b@@@@@@YAXXZ" template void f(); -#endif // Pointers to members. struct D { const int Derived::*p; int k; }; template void f() {} // CHECK: define weak_odr void @_Z1fIXtl1DLM7DerivedKi0ELi1EEEEvv -// MSABI: define {{.*}} @"??$f@$2UD@@PERDerived@@H0?0H00@@@YAXXZ" +// MSABI: define {{.*}} @"??$f@$2UD@@PERDerived@@HNH00@@@YAXXZ" template void f(); // CHECK: define weak_odr void @_Z1fIXtl1DEEEvv -// MSABI: define {{.*}} @"??$f@$2UD@@PERDerived@@H0?0H0A@@@@YAXXZ" +// MSABI: define {{.*}} @"??$f@$2UD@@PERDerived@@HNH0A@@@@YAXXZ" template void f(); // CHECK: define weak_odr void @_Z1fIXtl1DadL_ZN7Derived1zEEEEEvv -// MSABI: define {{.*}} @"??$f@$2UD@@PERDerived@@H0BA@H0A@@@@YAXXZ" +// MSABI: define {{.*}} @"??$f@$2UD@@PERDerived@@H82@z@@H0A@@@@YAXXZ" template void f(); -#ifndef _WIN32 // CHECK: define weak_odr void @_Z1fIXtl1DmcM7DerivedKiadL_ZN1A1aEEEEEEvv -// MSABI-FIXME: define {{.*}} @"??$f@$2UD@@PERDerived@@H0A@H0A@@@@YAXXZ" +// MSABI: define {{.*}} @"??$f@$2UD@@PERDerived@@H8A@@a@@H0A@@@@YAXXZ" template void f(); // CHECK: define weak_odr void @_Z1fIXtl1DmcM7DerivedKiadL_ZN1A1bEEEEEEvv -// MSABI-FIXME: define {{.*}} @"??$f@$2UD@@PERDerived@@H03H0A@@@@YAXXZ" +// MSABI: define {{.*}} @"??$f@$2UD@@PERDerived@@H8A@@b@@H0A@@@@YAXXZ" template void f(); // FIXME: Is the Ut_1 mangling here correct? // CHECK: define weak_odr void @_Z1fIXtl1DmcM7DerivedKiadL_ZN6NestedUt_1kEE8ELi2EEEEvv -// FIXME: This mangles the same as &A::a (bug in the MS ABI). -// MSABI-FIXME: define {{.*}} @"??$f@$2UD@@PERDerived@@H0A@H01@@@YAXXZ" +// MSABI: define {{.*}} @"??$f@$2UD@@PERDerived@@H8@Nested@@k@@H01@@@YAXXZ" template void f(); struct MoreDerived : A, Derived { int z; }; // CHECK: define weak_odr void @_Z1fIXtl1DmcM7DerivedKiadL_ZN11MoreDerived1zEEn8EEEEvv -// MSABI-FIXME: define {{.*}} @"??$f@$2UD@@PERDerived@@H0BI@H0A@@@@YAXXZ" +// MSABI: define {{.*}} @"??$f@$2UD@@PERDerived@@H8MoreDerived@@z@@H0A@@@@YAXXZ" template void f(); -#endif -// FIXME: Pointers to member functions. +struct DerivedVirtually : virtual A, Nested { int z; }; +struct D2 { const int DerivedVirtually::*p; int k; }; +template void f() {} +// CHECK: define weak_odr void @_Z1fIXtl2D2LM16DerivedVirtuallyKi0ELi1EEEEvv +// MSABI: define {{.*}} @"??$f@$2UD2@@PERDerivedVirtually@@HFA@?0H00@@@YAXXZ" +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl2D2EEEvv +// MSABI: define {{.*}} @"??$f@$2UD2@@PERDerivedVirtually@@HFA@?0H0A@@@@YAXXZ" +template void f(); +// CHECK: define weak_odr void @_Z1fIXtl2D2adL_ZN16DerivedVirtually1zEEEEEvv +// MSABI: define {{.*}} @"??$f@$2UD2@@PERDerivedVirtually@@HFBA@A@H0A@@@@YAXXZ" +template void f(); + +// Forward-decl without MS inheritance keyword means unspecified inheritance +// which is different from e. g. single inheritance. +struct UnspecInherStruct; +struct D3 { const int UnspecInherStruct::*p; }; +template void f() {} +struct UnspecInherStruct { int i; }; +// CHECK: define weak_odr void @_Z1fIXtl2D3adL_ZN17UnspecInherStruct1iEEEEEvv +// MSABI: define {{.*}} @"??$f@$2UD3@@PERUnspecInherStruct@@HGA@A@A@@@@YAXXZ" +template void f(); + +// Pointers to member functions. +// Test struct templates instead of function templates so as to cover +// the separate code which handles nullptr in their pointer-to-member arguments. +struct Derived2 : A, Nested { void f(); virtual void g(); }; +struct D4 { void (Derived2::*p)(); }; +template struct S1 { static void fn() {} }; +// CHECK: define weak_odr void @_ZN2S1IXtl2D4adL_ZN8Derived21fEvEEEE2fnEv +// MSABI: define {{.*}} @"?fn@?$S1@$2UD4@@P8Derived2@@EAAXXZE?f@2@QEAAXXZ@@@SAXXZ" +template void S1::fn(); +// CHECK: define weak_odr void @_ZN2S1IXtl2D4adL_ZN8Derived21gEvEEEE2fnEv +// MSABI: define {{.*}} @"?fn@?$S1@$2UD4@@P8Derived2@@EAAXXZE??_92@$BA@AA@@@SAXXZ" +template void S1::fn(); +// CHECK: define weak_odr void @_ZN2S1IXtl2D4EEE2fnEv +// MSABI: define {{.*}} @"?fn@?$S1@$2UD4@@P8Derived2@@EAAXXZHA@@@@SAXXZ" +template void S1::fn(); + +struct NoInheritance { void f(); }; +struct D5 { void (NoInheritance::*p)(); }; +template struct S2 { static void fn() {} }; +// CHECK: define weak_odr void @_ZN2S2IXtl2D5adL_ZN13NoInheritance1fEvEEEE2fnEv +// MSABI: define {{.*}} @"?fn@?$S2@$2UD5@@P8NoInheritance@@EAAXXZE?f@2@QEAAXXZ@@@SAXXZ" +template void S2::fn(); +// CHECK: define weak_odr void @_ZN2S2IXtl2D5EEE2fnEv +// MSABI: define {{.*}} @"?fn@?$S2@$2UD5@@P8NoInheritance@@EAAXXZN@@@SAXXZ" +template void S2::fn(); + +struct NoInheritanceButUnspecified; +struct D6 { void (NoInheritanceButUnspecified::*p)(); }; +template struct S3 { static void fn() {} }; +// CHECK: define weak_odr void @_ZN2S3IXtl2D6EEE2fnEv +// MSABI: define {{.*}} @"?fn@?$S3@$2UD6@@P8NoInheritanceButUnspecified@@EAAXXZJA@A@?0@@@SAXXZ" +template void S3::fn(); + union E { int n; @@ -204,8 +261,6 @@ template void f(); template void f(); // Empty and nearly-empty unions. -// Some of the MSVC manglings here are our invention, because MSVC rejects, but -// seem likely to be right. union H1 {}; union H2 { int : 1, : 2, : 3; }; union H3 { int : 1, a, : 2, b, : 3; }; diff --git a/clang/test/CodeGenCXX/mangle-ms-templates.cpp b/clang/test/CodeGenCXX/mangle-ms-templates.cpp index 7402d367ae3e9..cefe1e0cb5a55 100644 --- a/clang/test/CodeGenCXX/mangle-ms-templates.cpp +++ b/clang/test/CodeGenCXX/mangle-ms-templates.cpp @@ -272,7 +272,7 @@ struct type1 { }; extern const record inst; void recref(type1) {} -// CHECK: "?recref@@YAXU?$type1@$E?inst@@3Urecord@@B@@@Z" +// CHECK: "?recref@@YAXU?$type1@$1?inst@@3Urecord@@B@@@Z" struct _GUID {}; struct __declspec(uuid("{12345678-1234-1234-1234-1234567890aB}")) uuid; @@ -286,7 +286,7 @@ struct UUIDType2 {}; void fun(UUIDType1 a) {} // CHECK: "?fun@@YAXU?$UUIDType1@Uuuid@@$1?_GUID_12345678_1234_1234_1234_1234567890ab@@3U__s_GUID@@B@@@Z" void fun(UUIDType2 b) {} -// CHECK: "?fun@@YAXU?$UUIDType2@Uuuid@@$E?_GUID_12345678_1234_1234_1234_1234567890ab@@3U__s_GUID@@B@@@Z" +// CHECK: "?fun@@YAXU?$UUIDType2@Uuuid@@$1?_GUID_12345678_1234_1234_1234_1234567890ab@@3U__s_GUID@@B@@@Z" template struct TypeWithFriendDefinition { friend void FunctionDefinedWithInjectedName(TypeWithFriendDefinition) {}