This revision was landed with ongoing or failed builds. This revision was automatically updated to reflect the committed changes. Closed by commit rGcd93532dfc45: [MS ABI] Fix C++ mangling references to declarations. (authored by bolshakov-a, committed by efriedma).
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D146386/new/ https://reviews.llvm.org/D146386 Files: clang/lib/AST/MicrosoftMangle.cpp clang/test/CodeGenCXX/mangle-class-nttp.cpp clang/test/CodeGenCXX/mangle-ms-templates.cpp
Index: clang/test/CodeGenCXX/mangle-ms-templates.cpp =================================================================== --- clang/test/CodeGenCXX/mangle-ms-templates.cpp +++ clang/test/CodeGenCXX/mangle-ms-templates.cpp @@ -272,7 +272,7 @@ }; extern const record inst; void recref(type1<inst>) {} -// 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 @@ void fun(UUIDType1<uuid> a) {} // CHECK: "?fun@@YAXU?$UUIDType1@Uuuid@@$1?_GUID_12345678_1234_1234_1234_1234567890ab@@3U__s_GUID@@B@@@Z" void fun(UUIDType2<uuid> 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 <typename T> struct TypeWithFriendDefinition { friend void FunctionDefinedWithInjectedName(TypeWithFriendDefinition<T>) {} Index: clang/test/CodeGenCXX/mangle-class-nttp.cpp =================================================================== --- clang/test/CodeGenCXX/mangle-class-nttp.cpp +++ clang/test/CodeGenCXX/mangle-class-nttp.cpp @@ -15,7 +15,7 @@ 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<B{&n}>(); // CHECK: define weak_odr void @_Z1fIXtl1BLPKi0ELi1EEEEvv( // MSABI: define {{.*}} @"??$f@$2UB@@PEBH0A@H00@@@YAXXZ" @@ -36,15 +36,19 @@ // 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<B{&derived.z}>(); -// 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<B{&derived.a_field.a}>(); // CHECK: define weak_odr void @_Z1fIXtl1BadsoKiL_Z6nestedE_EEEEvv +// MSABI: define {{.*}} void @"??$f@$2UB@@PEBH56CE?nested@@3PAUNested@@A0A@@k@@@H0A@@@@YAXXZ" template void f<B{&nested[0].k}>(); +// 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<B{&nested[1].arr[2]}>(); // CHECK: define weak_odr void @_Z1fIXtl1BadsoKiL_Z7derivedE8pEEEEvv @@ -59,14 +63,16 @@ // CHECK: define weak_odr void @_Z1fIXtl2BRsoKiL_Z7derivedE16EEEEvv // MSABI: define {{.*}} void @"??$f@$2UBR@@AEBH6E?derived@@3UDerived@@Az@@@@@YAXXZ" template void f<BR{derived.z}>(); -// 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<BR{nested[0].k}>(); // CHECK: define weak_odr void @_Z1fIXtl2BRsoKiL_Z6nestedE12_0EEEEvv +// MSABI: define {{.*}} void @"??$f@$2UBR@@AEBHC6CE?nested@@3PAUNested@@A00@arr@@00@@@@YAXXZ" template void f<BR{nested[1].arr[1]}>(); // CHECK: define weak_odr void @_Z1fIXtl2BRsoKiL_Z7derivedE4EEEEvv +// MSABI: define {{.*}} void @"??$f@$2UBR@@AEBH66E?derived@@3UDerived@@AA@@b@@@@@YAXXZ" template void f<BR{derived.b}>(); +#ifndef _WIN32 // CHECK: define weak_odr void @_Z1fIXtl2BRdecvPKiplcvPcadL_Z7derivedELl16EEEEvv template void f<BR{fold(*(&derived.b + 3))}>(); #endif @@ -77,42 +83,93 @@ // CHECK: define weak_odr void @_Z1fIXtl1CadsoKiL_Z7derivedE16EEEEvv // MSABI: define {{.*}} void @"??$f@$2UC@@PEBH56E?derived@@3UDerived@@Az@@@@@@YAXXZ" template void f<C{&derived.z}>(); -#ifndef _WIN32 // CHECK: define weak_odr void @_Z1fIXtl1CadsoKiL_Z7derivedE4EEEEvv +// MSABI: define {{.*}} void @"??$f@$2UC@@PEBH566E?derived@@3UDerived@@AA@@b@@@@@@YAXXZ" template void f<C{&derived.b}>(); -#endif // Pointers to members. struct D { const int Derived::*p; int k; }; template<D> 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<D{nullptr, 1}>(); // CHECK: define weak_odr void @_Z1fIXtl1DEEEvv -// MSABI: define {{.*}} @"??$f@$2UD@@PERDerived@@H0?0H0A@@@@YAXXZ" +// MSABI: define {{.*}} @"??$f@$2UD@@PERDerived@@HNH0A@@@@YAXXZ" template void f<D{nullptr}>(); // 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<D{&Derived::z}>(); -#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<D{&A::a}>(); // 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<D{&A::b}>(); // 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<unnamed-tag>@Nested@@k@@H01@@@YAXXZ" template void f<D{&Nested::k, 2}>(); 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<D{(int Derived::*)&MoreDerived::z}>(); -#endif -// FIXME: Pointers to member functions. +struct DerivedVirtually : virtual A, Nested { int z; }; +struct D2 { const int DerivedVirtually::*p; int k; }; +template<D2> void f() {} +// CHECK: define weak_odr void @_Z1fIXtl2D2LM16DerivedVirtuallyKi0ELi1EEEEvv +// MSABI: define {{.*}} @"??$f@$2UD2@@PERDerivedVirtually@@HFA@?0H00@@@YAXXZ" +template void f<D2{nullptr, 1}>(); +// CHECK: define weak_odr void @_Z1fIXtl2D2EEEvv +// MSABI: define {{.*}} @"??$f@$2UD2@@PERDerivedVirtually@@HFA@?0H0A@@@@YAXXZ" +template void f<D2{nullptr}>(); +// CHECK: define weak_odr void @_Z1fIXtl2D2adL_ZN16DerivedVirtually1zEEEEEvv +// MSABI: define {{.*}} @"??$f@$2UD2@@PERDerivedVirtually@@HFBA@A@H0A@@@@YAXXZ" +template void f<D2{&DerivedVirtually::z}>(); + +// 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<D3> 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<D3{&UnspecInherStruct::i}>(); + +// 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 <D4> 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<D4{&Derived2::f}>::fn(); +// CHECK: define weak_odr void @_ZN2S1IXtl2D4adL_ZN8Derived21gEvEEEE2fnEv +// MSABI: define {{.*}} @"?fn@?$S1@$2UD4@@P8Derived2@@EAAXXZE??_92@$BA@AA@@@SAXXZ" +template void S1<D4{&Derived2::g}>::fn(); +// CHECK: define weak_odr void @_ZN2S1IXtl2D4EEE2fnEv +// MSABI: define {{.*}} @"?fn@?$S1@$2UD4@@P8Derived2@@EAAXXZHA@@@@SAXXZ" +template void S1<D4{nullptr}>::fn(); + +struct NoInheritance { void f(); }; +struct D5 { void (NoInheritance::*p)(); }; +template <D5> 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<D5{&NoInheritance::f}>::fn(); +// CHECK: define weak_odr void @_ZN2S2IXtl2D5EEE2fnEv +// MSABI: define {{.*}} @"?fn@?$S2@$2UD5@@P8NoInheritance@@EAAXXZN@@@SAXXZ" +template void S2<D5{nullptr}>::fn(); + +struct NoInheritanceButUnspecified; +struct D6 { void (NoInheritanceButUnspecified::*p)(); }; +template <D6> struct S3 { static void fn() {} }; +// CHECK: define weak_odr void @_ZN2S3IXtl2D6EEE2fnEv +// MSABI: define {{.*}} @"?fn@?$S3@$2UD6@@P8NoInheritanceButUnspecified@@EAAXXZJA@A@?0@@@SAXXZ" +template void S3<D6{nullptr}>::fn(); + union E { int n; @@ -204,8 +261,6 @@ template void f<G{-8, -32}>(); // 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; }; Index: clang/lib/AST/MicrosoftMangle.cpp =================================================================== --- clang/lib/AST/MicrosoftMangle.cpp +++ 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 <functional> #include <optional> using namespace clang; @@ -368,9 +370,13 @@ 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 @@ mangleNumber(VBTableOffset); } +void MicrosoftCXXNameMangler::mangleMemberDataPointerInClassNTTP( + const CXXRecordDecl *RD, const ValueDecl *VD) { + MSInheritanceModel IM = RD->getMSInheritanceModel(); + // <nttp-class-member-data-pointer> ::= <member-data-pointer> + // ::= N + // ::= 8 <postfix> @ <unqualified-name> @ + + 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 @@ mangleNumber(VBTableOffset); } +void MicrosoftCXXNameMangler::mangleMemberFunctionPointerInClassNTTP( + const CXXRecordDecl *RD, const CXXMethodDecl *MD) { + // <nttp-class-member-function-pointer> ::= <member-function-pointer> + // ::= N + // ::= E? <virtual-mem-ptr-thunk> + // ::= E? <mangled-name> <type-encoding> + + if (!MD) { + if (RD->getMSInheritanceModel() != MSInheritanceModel::Single) + return mangleMemberFunctionPointer(RD, MD, ""); + + Out << 'N'; + return; + } + + Out << "E?"; + if (MD->isVirtual()) { + MicrosoftVTableContext *VTContext = + cast<MicrosoftVTableContext>(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 @@ // ::= <substitution> [<postfix>] void MicrosoftCXXNameMangler::mangleNestedName(GlobalDecl GD) { const NamedDecl *ND = cast<NamedDecl>(GD.getDecl()); + + if (const auto *ID = dyn_cast<IndirectFieldDecl>(ND)) + for (unsigned I = 1, IE = ID->getChainingSize(); I < IE; ++I) + mangleSourceName("<unnamed-tag>"); + const DeclContext *DC = getEffectiveDeclContext(ND); while (!DC->isTranslationUnit()) { if (isa<TagDecl>(ND) || isa<VarDecl>(ND)) { @@ -1570,7 +1631,6 @@ // ::= 8 <class> <unqualified-name> @ // ::= A <type> <non-negative integer> # float // ::= B <type> <non-negative integer> # double - // ::= E <mangled-name> # reference to D // # pointer to member, by component value // ::= F <number> <number> // ::= G <number> <number> <number> @@ -1615,7 +1675,7 @@ mangleTemplateArgValue(TPO->getType().getUnqualifiedType(), TPO->getValue()); } else { - mangle(ND, TA.getParamTypeForDecl()->isReferenceType() ? "$E?" : "$1?"); + mangle(ND, "$1?"); } break; } @@ -1744,46 +1804,62 @@ // FIXME: This can only happen as an extension. Invent a mangling. break; } else if (auto *VD = Base.dyn_cast<const ValueDecl*>()) { - 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<char, 2> EntryTypes; + SmallVector<std::function<void()>, 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<FieldDecl>(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<FieldDecl>(D)) { + ET = FD->getType(); + if (const auto *RD = ET->getAsRecordDecl()) + if (RD->isAnonymousStructOrUnion()) + continue; + } else { + ET = getASTContext().getRecordType(cast<CXXRecordDecl>(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<NamedDecl>(D)); + Out << '@'; + }); } + for (auto I = EntryTypes.rbegin(), E = EntryTypes.rend(); I != E; ++I) + Out << *I; + auto *VD = Base.dyn_cast<const ValueDecl*>(); if (!VD) break; Out << "E"; mangle(VD); - for (APValue::LValuePathEntry E : V.getLValuePath()) { - const Decl *D = E.getAsBaseOrMember().getPointer(); - mangleUnqualifiedName(cast<FieldDecl>(D)); - } - for (unsigned I = 0; I != NumAts; ++I) + for (const std::function<void()> &Mangler : EntryManglers) + Mangler(); + if (T->isPointerType()) Out << '@'; } @@ -1794,20 +1870,14 @@ 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<MemberPointerType>()->getMostRecentCXXRecordDecl(); const ValueDecl *D = V.getMemberPointerDecl(); if (T->isMemberDataPointerType()) - mangleMemberDataPointer(RD, D, ""); + mangleMemberDataPointerInClassNTTP(RD, D); else - mangleMemberFunctionPointer(RD, cast_or_null<CXXMethodDecl>(D), ""); + mangleMemberFunctionPointerInClassNTTP(RD, + cast_or_null<CXXMethodDecl>(D)); return; } @@ -1895,7 +1965,6 @@ break; } -mangling_unknown: DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID( DiagnosticsEngine::Error, "cannot mangle this template argument yet");
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits