[clang] cd93532 - [MS ABI] Fix C++ mangling references to declarations.
Eli Friedman via cfe-commits
cfe-commits at lists.llvm.org
Wed May 3 18:20:41 PDT 2023
Author: Bolshakov
Date: 2023-05-03T18:20:16-07:00
New Revision: cd93532dfc455255cb2fa553090d14aaa52b106b
URL: https://github.com/llvm/llvm-project/commit/cd93532dfc455255cb2fa553090d14aaa52b106b
DIFF: https://github.com/llvm/llvm-project/commit/cd93532dfc455255cb2fa553090d14aaa52b106b.diff
LOG: [MS ABI] Fix C++ mangling references to declarations.
Several issues have been discovered and (hopefully) fixed here:
- Reference NTTPs should be mangled in the same manner as pointer
ones.
- Pointer fields of class type NTTPs should be treated in the same
manner as reference ones.
- Pointer-to-member fields of class type NTTPs should be treated
differently compared to pointer-to-member NTTPs. Tests on
pointer-to-member-function NTTP class fields added.
- Correct mangling of pointers to anonymous union members.
- A bug in mangling references to subobjects fixed.
- Mangling array subscripts and base class members in references
to subobjects.
Reference NTTP mangling was done back in 2013
in e8fdc06e0dab2e7b98339425dbe369e27e2092a3, and Microsoft might change
mangling algorithm since then. But class type NTTPs are introduced only
in C++20, and the test was written in
b637148ecb62b900872b34eedd78b923bb43c378.
It is strange if the MS ABI had been realy changed, because Microsoft
claims that they maintain ABI stability since VS 2015. I've tested both
on v142 and v143 MSVC toolsets, and they show the same behavior
on the test cases which are changed in this PR. But
pointer-to-member-function NTTP class field mangling has been actually
changed, because it was erroneous in v142, leading to name collisions.
Moreover, pointer-to-member mangling with conversions across class
hierarchy has been enabled.
Differential Revision: https://reviews.llvm.org/D146386
Added:
Modified:
clang/lib/AST/MicrosoftMangle.cpp
clang/test/CodeGenCXX/mangle-class-nttp.cpp
clang/test/CodeGenCXX/mangle-ms-templates.cpp
Removed:
################################################################################
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 <functional>
#include <optional>
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();
+ // <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 @@ MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD,
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 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(GlobalDecl GD,
// ::= <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 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD,
// ::= 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 @@ 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<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
diff erent 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 @@ 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<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 @@ 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<B> 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<B{&n}>();
// CHECK: define weak_odr void @_Z1fIXtl1BLPKi0ELi1EEEEvv(
// MSABI: define {{.*}} @"??$f@$2UB@@PEBH0A at H00@@@YAXXZ"
@@ -36,15 +36,19 @@ template void f<B{fold(reinterpret_cast<int*>(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<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 @@ template<BR> void f() {}
// 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 at 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 @@ template<C> void f() {}
// 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 at H0A@@@@YAXXZ"
+// MSABI: define {{.*}} @"??$f@$2UD@@PERDerived@@H82 at 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 at 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 at 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 at 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 at A@H0A@@@@YAXXZ"
+template void f<D2{&DerivedVirtually::z}>();
+
+// Forward-decl without MS inheritance keyword means unspecified inheritance
+// which is
diff erent 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 at 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 at 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 at 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 at 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 at A@?0@@@SAXXZ"
+template void S3<D6{nullptr}>::fn();
+
union E {
int n;
@@ -204,8 +261,6 @@ template void f<G{1, 2}>();
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; };
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<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 @@ struct UUIDType2 {};
void fun(UUIDType1<uuid> a) {}
// CHECK: "?fun@@YAXU?$UUIDType1 at Uuuid@@$1?_GUID_12345678_1234_1234_1234_1234567890ab@@3U__s_GUID@@B@@@Z"
void fun(UUIDType2<uuid> b) {}
-// CHECK: "?fun@@YAXU?$UUIDType2 at Uuuid@@$E?_GUID_12345678_1234_1234_1234_1234567890ab@@3U__s_GUID@@B@@@Z"
+// CHECK: "?fun@@YAXU?$UUIDType2 at Uuuid@@$1?_GUID_12345678_1234_1234_1234_1234567890ab@@3U__s_GUID@@B@@@Z"
template <typename T> struct TypeWithFriendDefinition {
friend void FunctionDefinedWithInjectedName(TypeWithFriendDefinition<T>) {}
More information about the cfe-commits
mailing list