-
Notifications
You must be signed in to change notification settings - Fork 14.3k
Fix MSVC 1920+ auto NTTP mangling for pointers to members #97007
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix MSVC 1920+ auto NTTP mangling for pointers to members #97007
Conversation
@llvm/pr-subscribers-clang Author: Max Winkler (MaxEW707) ChangesFixes #70899. This is a continuation of #92477 for pointers to member data and pointers to member functions. The mangled name must be prefixed with Full diff: https://github.com/llvm/llvm-project/pull/97007.diff 5 Files Affected:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 7ebfc87144269..834d8f27c3c4d 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -111,6 +111,12 @@ ABI Changes in This Version
earlier versions of Clang unless such code is built with the compiler option
`-fms-compatibility-version=19.14` to imitate the MSVC 1914 mangling behavior.
+- Fixed Microsoft name mangling for auto non-type template arguments of pointer
+ to member type for MSVC 1920+. This change resolves incompatibilities with code
+ compiled by MSVC 1920+ but will introduce incompatibilities with code compiled by
+ earlier versions of Clang unless such code is built with the compiler option
+ `-fms-compatibility-version=19.14` to imitate the MSVC 1914 mangling behavior.
+
AST Dumping Potentially Breaking Changes
----------------------------------------
diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index 7f1e9ab02ec26..fac14ce1dce8c 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -368,11 +368,15 @@ class MicrosoftCXXNameMangler {
void mangleFunctionEncoding(GlobalDecl GD, bool ShouldMangle);
void mangleVariableEncoding(const VarDecl *VD);
void mangleMemberDataPointer(const CXXRecordDecl *RD, const ValueDecl *VD,
+ const NonTypeTemplateParmDecl *PD,
+ QualType TemplateArgType,
StringRef Prefix = "$");
void mangleMemberDataPointerInClassNTTP(const CXXRecordDecl *,
const ValueDecl *);
void mangleMemberFunctionPointer(const CXXRecordDecl *RD,
const CXXMethodDecl *MD,
+ const NonTypeTemplateParmDecl *PD,
+ QualType TemplateArgType,
StringRef Prefix = "$");
void mangleFunctionPointer(const FunctionDecl *FD,
const NonTypeTemplateParmDecl *PD,
@@ -673,12 +677,17 @@ void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) {
}
}
-void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD,
- const ValueDecl *VD,
- StringRef Prefix) {
+void MicrosoftCXXNameMangler::mangleMemberDataPointer(
+ const CXXRecordDecl *RD, const ValueDecl *VD,
+ const NonTypeTemplateParmDecl *PD, QualType TemplateArgType,
+ StringRef Prefix) {
// <member-data-pointer> ::= <integer-literal>
// ::= $F <number> <number>
// ::= $G <number> <number> <number>
+ //
+ // <auto-nttp> ::= $ M <type> <integer-literal>
+ // <auto-nttp> ::= $ M <type> F <name> <number>
+ // <auto-nttp> ::= $ M <type> G <name> <number> <number>
int64_t FieldOffset;
int64_t VBTableOffset;
@@ -707,7 +716,18 @@ void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD,
case MSInheritanceModel::Unspecified: Code = 'G'; break;
}
- Out << Prefix << Code;
+ Out << Prefix;
+
+ if (VD &&
+ getASTContext().getLangOpts().isCompatibleWithMSVC(
+ LangOptions::MSVC2019) &&
+ PD && PD->getType()->getTypeClass() == Type::Auto &&
+ !TemplateArgType.isNull()) {
+ Out << "M";
+ mangleType(TemplateArgType, SourceRange(), QMM_Drop);
+ }
+
+ Out << Code;
mangleNumber(FieldOffset);
@@ -728,7 +748,7 @@ void MicrosoftCXXNameMangler::mangleMemberDataPointerInClassNTTP(
// ::= 8 <postfix> @ <unqualified-name> @
if (IM != MSInheritanceModel::Single && IM != MSInheritanceModel::Multiple)
- return mangleMemberDataPointer(RD, VD, "");
+ return mangleMemberDataPointer(RD, VD, nullptr, QualType(), "");
if (!VD) {
Out << 'N';
@@ -742,14 +762,19 @@ void MicrosoftCXXNameMangler::mangleMemberDataPointerInClassNTTP(
Out << '@';
}
-void
-MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD,
- const CXXMethodDecl *MD,
- StringRef Prefix) {
+void MicrosoftCXXNameMangler::mangleMemberFunctionPointer(
+ const CXXRecordDecl *RD, const CXXMethodDecl *MD,
+ const NonTypeTemplateParmDecl *PD, QualType TemplateArgType,
+ StringRef Prefix) {
// <member-function-pointer> ::= $1? <name>
// ::= $H? <name> <number>
// ::= $I? <name> <number> <number>
// ::= $J? <name> <number> <number> <number>
+ //
+ // <auto-nttp> ::= $ M <type> 1? <name>
+ // <auto-nttp> ::= $ M <type> H? <name> <number>
+ // <auto-nttp> ::= $ M <type> I? <name> <number> <number>
+ // <auto-nttp> ::= $ M <type> J? <name> <number> <number> <number>
MSInheritanceModel IM = RD->getMSInheritanceModel();
@@ -767,7 +792,17 @@ MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD,
uint64_t VBTableOffset = 0;
uint64_t VBPtrOffset = 0;
if (MD) {
- Out << Prefix << Code << '?';
+ Out << Prefix;
+
+ if (getASTContext().getLangOpts().isCompatibleWithMSVC(
+ LangOptions::MSVC2019) &&
+ PD && PD->getType()->getTypeClass() == Type::Auto &&
+ !TemplateArgType.isNull()) {
+ Out << "M";
+ mangleType(TemplateArgType, SourceRange(), QMM_Drop);
+ }
+
+ Out << Code << '?';
if (MD->isVirtual()) {
MicrosoftVTableContext *VTContext =
cast<MicrosoftVTableContext>(getASTContext().getVTableContext());
@@ -859,7 +894,7 @@ void MicrosoftCXXNameMangler::mangleMemberFunctionPointerInClassNTTP(
if (!MD) {
if (RD->getMSInheritanceModel() != MSInheritanceModel::Single)
- return mangleMemberFunctionPointer(RD, MD, "");
+ return mangleMemberFunctionPointer(RD, MD, nullptr, QualType(), "");
Out << 'N';
return;
@@ -1732,12 +1767,15 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD,
if (isa<FieldDecl>(ND) || isa<IndirectFieldDecl>(ND)) {
mangleMemberDataPointer(cast<CXXRecordDecl>(ND->getDeclContext())
->getMostRecentNonInjectedDecl(),
- cast<ValueDecl>(ND));
+ cast<ValueDecl>(ND),
+ cast<NonTypeTemplateParmDecl>(Parm),
+ TA.getParamTypeForDecl());
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
if (MD && MD->isInstance()) {
mangleMemberFunctionPointer(
- MD->getParent()->getMostRecentNonInjectedDecl(), MD);
+ MD->getParent()->getMostRecentNonInjectedDecl(), MD,
+ cast<NonTypeTemplateParmDecl>(Parm), TA.getParamTypeForDecl());
} else {
mangleFunctionPointer(FD, cast<NonTypeTemplateParmDecl>(Parm),
TA.getParamTypeForDecl());
@@ -1767,12 +1805,12 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD,
const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
if (MPT->isMemberFunctionPointerType() &&
!isa<FunctionTemplateDecl>(TD)) {
- mangleMemberFunctionPointer(RD, nullptr);
+ mangleMemberFunctionPointer(RD, nullptr, nullptr, QualType());
return;
}
if (MPT->isMemberDataPointer()) {
if (!isa<FunctionTemplateDecl>(TD)) {
- mangleMemberDataPointer(RD, nullptr);
+ mangleMemberDataPointer(RD, nullptr, nullptr, QualType());
return;
}
// nullptr data pointers are always represented with a single field
@@ -1979,9 +2017,10 @@ void MicrosoftCXXNameMangler::mangleTemplateArgValue(QualType T,
cast_or_null<CXXMethodDecl>(D));
} else {
if (T->isMemberDataPointerType())
- mangleMemberDataPointer(RD, D, "");
+ mangleMemberDataPointer(RD, D, nullptr, QualType(), "");
else
- mangleMemberFunctionPointer(RD, cast_or_null<CXXMethodDecl>(D), "");
+ mangleMemberFunctionPointer(RD, cast_or_null<CXXMethodDecl>(D), nullptr,
+ QualType(), "");
}
return;
}
diff --git a/clang/test/CodeGenCXX/mangle-ms-auto-templates-memptrs.cpp b/clang/test/CodeGenCXX/mangle-ms-auto-templates-memptrs.cpp
new file mode 100644
index 0000000000000..360ebdecc5562
--- /dev/null
+++ b/clang/test/CodeGenCXX/mangle-ms-auto-templates-memptrs.cpp
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 -std=c++17 -fms-compatibility-version=19.20 -emit-llvm %s -o - -fms-extensions -fdelayed-template-parsing -triple=x86_64-pc-windows-msvc | FileCheck --check-prefix=AFTER %s
+// RUN: %clang_cc1 -std=c++17 -fms-compatibility-version=19.14 -emit-llvm %s -o - -fms-extensions -fdelayed-template-parsing -triple=x86_64-pc-windows-msvc | FileCheck --check-prefix=BEFORE %s
+
+template <auto a>
+class AutoParmTemplate {
+public:
+ AutoParmTemplate() {}
+};
+
+template <auto a>
+auto AutoFunc() {
+ return a;
+}
+
+struct A {};
+struct B {};
+
+struct S { int a; void f(); virtual void g(); };
+struct M : A, B { int a; void f(); virtual void g(); };
+struct V : virtual A { int a; void f(); virtual void g(); };
+
+void template_mangling() {
+
+ AutoParmTemplate<&S::f> auto_method_single_inheritance;
+ // AFTER: call {{.*}} @"??0?$AutoParmTemplate@$MP8S@@EAAXXZ1?f@1@QEAAXXZ@@QEAA@XZ"
+ // BEFORE: call {{.*}} @"??0?$AutoParmTemplate@$1?f@S@@QEAAXXZ@@QEAA@XZ"
+
+ AutoParmTemplate<&M::f> auto_method_multiple_inheritance;
+ // AFTER: call {{.*}} @"??0?$AutoParmTemplate@$MP8M@@EAAXXZH?f@1@QEAAXXZA@@@QEAA@XZ"
+ // BEFORE: call {{.*}} @"??0?$AutoParmTemplate@$H?f@M@@QEAAXXZA@@@QEAA@XZ"
+
+ AutoParmTemplate<&V::f> auto_method_virtual_inheritance;
+ // AFTER: call {{.*}} @"??0?$AutoParmTemplate@$MP8V@@EAAXXZI?f@1@QEAAXXZA@A@@@QEAA@XZ"
+ // BEFORE: call {{.*}} @"??0?$AutoParmTemplate@$I?f@V@@QEAAXXZA@A@@@QEAA@XZ"
+
+ AutoFunc<&S::f>();
+ // AFTER: call {{.*}} @"??$AutoFunc@$MP8S@@EAAXXZ1?f@1@QEAAXXZ@@YA?A?<auto>@@XZ"
+ // BEFORE: call {{.*}} @"??$AutoFunc@$1?f@S@@QEAAXXZ@@YA?A?<auto>@@XZ"
+
+ AutoFunc<&M::f>();
+ // AFTER: call {{.*}} @"??$AutoFunc@$MP8M@@EAAXXZH?f@1@QEAAXXZA@@@YA?A?<auto>@@XZ"
+ // BEFORE: call {{.*}} @"??$AutoFunc@$H?f@M@@QEAAXXZA@@@YA?A?<auto>@@XZ"
+
+ AutoFunc<&V::f>();
+ // AFTER: call {{.*}} @"??$AutoFunc@$MP8V@@EAAXXZI?f@1@QEAAXXZA@A@@@YA?A?<auto>@@XZ"
+ // BEFORE: call {{.*}} @"??$AutoFunc@$I?f@V@@QEAAXXZA@A@@@YA?A?<auto>@@XZ"
+
+ AutoParmTemplate<&S::a> auto_data_single_inheritance;
+ // AFTER: call {{.*}} @"??0?$AutoParmTemplate@$MPEQS@@H07@@QEAA@XZ"
+ // BEFORE: call {{.*}} @"??0?$AutoParmTemplate@$07@@QEAA@XZ"
+
+ AutoParmTemplate<&M::a> auto_data_multiple_inheritance;
+ // AFTER: call {{.*}} @"??0?$AutoParmTemplate@$MPEQM@@H0M@@@QEAA@XZ"
+ // BEFORE: call {{.*}} @"??0?$AutoParmTemplate@$0M@@@QEAA@XZ"
+
+ AutoParmTemplate<&V::a> auto_data_virtual_inheritance;
+ // AFTER: call {{.*}} @"??0?$AutoParmTemplate@$MPEQV@@HFBA@A@@@QEAA@XZ"
+ // BEFORE: call {{.*}} @"??0?$AutoParmTemplate@$FBA@A@@@QEAA@XZ"
+
+ AutoFunc<&S::a>();
+ // AFTER: call {{.*}} @"??$AutoFunc@$MPEQS@@H07@@YA?A?<auto>@@XZ"
+ // BEFORE: call {{.*}} @"??$AutoFunc@$07@@YA?A?<auto>@@XZ"
+
+ AutoFunc<&M::a>();
+ // AFTER: call {{.*}} @"??$AutoFunc@$MPEQM@@H0M@@@YA?A?<auto>@@XZ"
+ // BEFORE: call {{.*}} @"??$AutoFunc@$0M@@@YA?A?<auto>@@XZ"
+
+ AutoFunc<&V::a>();
+ // AFTER: call {{.*}} @"??$AutoFunc@$MPEQV@@HFBA@A@@@YA?A?<auto>@@XZ"
+ // BEFORE: call {{.*}} @"??$AutoFunc@$FBA@A@@@YA?A?<auto>@@XZ"
+}
diff --git a/clang/test/CodeGenCXX/mangle-ms-auto-templates-nullptr.cpp b/clang/test/CodeGenCXX/mangle-ms-auto-templates-nullptr.cpp
new file mode 100644
index 0000000000000..8f98c1e59f73d
--- /dev/null
+++ b/clang/test/CodeGenCXX/mangle-ms-auto-templates-nullptr.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -std=c++17 -fms-compatibility-version=19.20 -emit-llvm %s -o - -fms-extensions -fdelayed-template-parsing -triple=x86_64-pc-windows-msvc | FileCheck --check-prefix=AFTER %s
+// RUN: %clang_cc1 -std=c++17 -fms-compatibility-version=19.14 -emit-llvm %s -o - -fms-extensions -fdelayed-template-parsing -triple=x86_64-pc-windows-msvc | FileCheck --check-prefix=BEFORE %s
+
+template <auto a>
+class AutoParmTemplate {
+public:
+ AutoParmTemplate() {}
+};
+
+template <auto a>
+auto AutoFunc() {
+ return a;
+}
+
+void template_mangling() {
+
+ AutoParmTemplate<nullptr> auto_nullptr;
+ // AFTER: call {{.*}} @"??0?$AutoParmTemplate@$M$$T0A@@@QEAA@XZ"
+ // BEFORE: call {{.*}} @"??0?$AutoParmTemplate@$0A@@@QEAA@XZ"
+
+ AutoFunc<nullptr>();
+ // AFTER: call {{.*}} @"??$AutoFunc@$M$$T0A@@@YA?A?<auto>@@XZ"
+ // BEFORE: call {{.*}} @"??$AutoFunc@$0A@@@YA?A?<auto>@@XZ"
+}
diff --git a/llvm/test/Demangle/ms-auto-templates.test b/llvm/test/Demangle/ms-auto-templates.test
index a90ffb69df558..3d928cad77075 100644
--- a/llvm/test/Demangle/ms-auto-templates.test
+++ b/llvm/test/Demangle/ms-auto-templates.test
@@ -55,3 +55,45 @@
??0?$AutoNTTPClass@$MH0A@$M_N0A@$MD0GB@@@QEAA@XZ
; CHECK: public: __cdecl AutoNTTPClass<0, 0, 97>::AutoNTTPClass<0, 0, 97>(void)
+
+??0?$AutoNTTPClass@$M$$T0A@@@QEAA@XZ
+; CHECK: public: __cdecl AutoNTTPClass<0>::AutoNTTPClass<0>(void)
+
+??0?$AutoNTTPClass@$0A@@@QEAA@XZ
+; CHECK: public: __cdecl AutoNTTPClass<0>::AutoNTTPClass<0>(void)
+
+??0?$AutoNTTPClass@$MP8S@@EAAXXZ1?f@1@QEAAXXZ@@QEAA@XZ
+; CHECK: public: __cdecl AutoNTTPClass<&public: void __cdecl S::f(void)>::AutoNTTPClass<&public: void __cdecl S::f(void)>(void)
+
+??0?$AutoNTTPClass@$1?f@S@@QEAAXXZ@@QEAA@XZ
+; CHECK: public: __cdecl AutoNTTPClass<&public: void __cdecl S::f(void)>::AutoNTTPClass<&public: void __cdecl S::f(void)>(void)
+
+??0?$AutoNTTPClass@$MP8M@@EAAXXZH?f@1@QEAAXXZA@@@QEAA@XZ
+; CHECK: public: __cdecl AutoNTTPClass<{public: void __cdecl M::f(void),0}>::AutoNTTPClass<{public: void __cdecl M::f(void),0}>(void)
+
+??0?$AutoNTTPClass@$H?f@M@@QEAAXXZA@@@QEAA@XZ
+; CHECK: public: __cdecl AutoNTTPClass<{public: void __cdecl M::f(void),0}>::AutoNTTPClass<{public: void __cdecl M::f(void),0}>(void)
+
+??0?$AutoNTTPClass@$MP8V@@EAAXXZI?f@1@QEAAXXZA@A@@@QEAA@XZ
+; CHECK: public: __cdecl AutoNTTPClass<{public: void __cdecl V::f(void),0,0}>::AutoNTTPClass<{public: void __cdecl V::f(void),0,0}>(void)
+
+??0?$AutoNTTPClass@$I?f@V@@QEAAXXZA@A@@@QEAA@XZ
+; CHECK: public: __cdecl AutoNTTPClass<{public: void __cdecl V::f(void),0,0}>::AutoNTTPClass<{public: void __cdecl V::f(void),0,0}>(void)
+
+??0?$AutoNTTPClass@$MPEQS@@H07@@QEAA@XZ
+; CHECK: public: __cdecl AutoNTTPClass<8>::AutoNTTPClass<8>(void)
+
+??0?$AutoNTTPClass@$07@@QEAA@XZ
+; CHECK: public: __cdecl AutoNTTPClass<8>::AutoNTTPClass<8>(void)
+
+??0?$AutoNTTPClass@$MPEQM@@H0M@@@QEAA@XZ
+; CHECK: public: __cdecl AutoNTTPClass<12>::AutoNTTPClass<12>(void)
+
+??0?$AutoNTTPClass@$0M@@@QEAA@XZ
+; CHECK: public: __cdecl AutoNTTPClass<12>::AutoNTTPClass<12>(void)
+
+??0?$AutoNTTPClass@$MPEQV@@HFBA@A@@@QEAA@XZ
+; CHECK: public: __cdecl AutoNTTPClass<{16,0}>::AutoNTTPClass<{16,0}>(void)
+
+??0?$AutoNTTPClass@$FBA@A@@@QEAA@XZ
+; CHECK: public: __cdecl AutoNTTPClass<{16,0}>::AutoNTTPClass<{16,0}>(void)
|
|
||
void template_mangling() { | ||
|
||
AutoParmTemplate<nullptr> auto_nullptr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a separate file since nullptr
gets mangled the same as an integer literal.
In VS2017 this gets mangled without the $M <type>
so clang emits an error for emitting the same mangled name definition for two different objects if these tests are inside mangle-ms-auto-templates.cpp
which has tests for mangling integer literals.
VS2017 gets around this by erroneously putting all the definitions into COMDAT sections which clang does not do at the moment when trying to be VS2017 compatible.
return; | ||
} | ||
if (MPT->isMemberDataPointer()) { | ||
if (!isa<FunctionTemplateDecl>(TD)) { | ||
mangleMemberDataPointer(RD, nullptr); | ||
mangleMemberDataPointer(RD, nullptr, nullptr, QualType()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These use cases appear to be added from, 5518a9d, with support for C++20 nttp changes.
From looking at the code we only hit this path when compiling for C++20 and it also already properly mangles according to VS2019+ by doing $M <type>
elsewhere.
I intend to take a look at C++20 NTTP after this PR and then take a more holistic look to see if we can better merge the C++11-17 and C++20 mangling paths in MicrosoftMangle.cpp
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
Fixes llvm#70899. This is a continuation of llvm#92477 for pointers to member data and pointers to member functions. The mangled name must be prefixed with `$M <mangled-type>` for the deduced type of the nttp parameter.
Fixes #70899.
This is a continuation of #92477 for pointers to member data and pointers to member functions.
The mangled name must be prefixed with
$M <mangled-type>
for the deduced type of the nttp parameter.