Skip to content

Commit cd93532

Browse files
bolshakov-aefriedma-quic
authored andcommitted
[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 e8fdc06, and Microsoft might change mangling algorithm since then. But class type NTTPs are introduced only in C++20, and the test was written in b637148. 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
1 parent e48826e commit cd93532

File tree

3 files changed

+182
-58
lines changed

3 files changed

+182
-58
lines changed

clang/lib/AST/MicrosoftMangle.cpp

Lines changed: 103 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,14 @@
2929
#include "clang/Basic/FileManager.h"
3030
#include "clang/Basic/SourceManager.h"
3131
#include "clang/Basic/TargetInfo.h"
32+
#include "llvm/ADT/SmallVector.h"
3233
#include "llvm/ADT/StringExtras.h"
3334
#include "llvm/Support/CRC.h"
3435
#include "llvm/Support/MD5.h"
3536
#include "llvm/Support/MathExtras.h"
3637
#include "llvm/Support/StringSaver.h"
3738
#include "llvm/Support/xxhash.h"
39+
#include <functional>
3840
#include <optional>
3941

4042
using namespace clang;
@@ -368,9 +370,13 @@ class MicrosoftCXXNameMangler {
368370
void mangleVariableEncoding(const VarDecl *VD);
369371
void mangleMemberDataPointer(const CXXRecordDecl *RD, const ValueDecl *VD,
370372
StringRef Prefix = "$");
373+
void mangleMemberDataPointerInClassNTTP(const CXXRecordDecl *,
374+
const ValueDecl *);
371375
void mangleMemberFunctionPointer(const CXXRecordDecl *RD,
372376
const CXXMethodDecl *MD,
373377
StringRef Prefix = "$");
378+
void mangleMemberFunctionPointerInClassNTTP(const CXXRecordDecl *RD,
379+
const CXXMethodDecl *MD);
374380
void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD,
375381
const MethodVFTableLocation &ML);
376382
void mangleNumber(int64_t Number);
@@ -711,6 +717,28 @@ void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD,
711717
mangleNumber(VBTableOffset);
712718
}
713719

720+
void MicrosoftCXXNameMangler::mangleMemberDataPointerInClassNTTP(
721+
const CXXRecordDecl *RD, const ValueDecl *VD) {
722+
MSInheritanceModel IM = RD->getMSInheritanceModel();
723+
// <nttp-class-member-data-pointer> ::= <member-data-pointer>
724+
// ::= N
725+
// ::= 8 <postfix> @ <unqualified-name> @
726+
727+
if (IM != MSInheritanceModel::Single && IM != MSInheritanceModel::Multiple)
728+
return mangleMemberDataPointer(RD, VD, "");
729+
730+
if (!VD) {
731+
Out << 'N';
732+
return;
733+
}
734+
735+
Out << '8';
736+
mangleNestedName(VD);
737+
Out << '@';
738+
mangleUnqualifiedName(VD);
739+
Out << '@';
740+
}
741+
714742
void
715743
MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD,
716744
const CXXMethodDecl *MD,
@@ -775,6 +803,34 @@ MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD,
775803
mangleNumber(VBTableOffset);
776804
}
777805

806+
void MicrosoftCXXNameMangler::mangleMemberFunctionPointerInClassNTTP(
807+
const CXXRecordDecl *RD, const CXXMethodDecl *MD) {
808+
// <nttp-class-member-function-pointer> ::= <member-function-pointer>
809+
// ::= N
810+
// ::= E? <virtual-mem-ptr-thunk>
811+
// ::= E? <mangled-name> <type-encoding>
812+
813+
if (!MD) {
814+
if (RD->getMSInheritanceModel() != MSInheritanceModel::Single)
815+
return mangleMemberFunctionPointer(RD, MD, "");
816+
817+
Out << 'N';
818+
return;
819+
}
820+
821+
Out << "E?";
822+
if (MD->isVirtual()) {
823+
MicrosoftVTableContext *VTContext =
824+
cast<MicrosoftVTableContext>(getASTContext().getVTableContext());
825+
MethodVFTableLocation ML =
826+
VTContext->getMethodVFTableLocation(GlobalDecl(MD));
827+
mangleVirtualMemPtrThunk(MD, ML);
828+
} else {
829+
mangleName(MD);
830+
mangleFunctionEncoding(MD, /*ShouldMangle=*/true);
831+
}
832+
}
833+
778834
void MicrosoftCXXNameMangler::mangleVirtualMemPtrThunk(
779835
const CXXMethodDecl *MD, const MethodVFTableLocation &ML) {
780836
// Get the vftable offset.
@@ -1188,6 +1244,11 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(GlobalDecl GD,
11881244
// ::= <substitution> [<postfix>]
11891245
void MicrosoftCXXNameMangler::mangleNestedName(GlobalDecl GD) {
11901246
const NamedDecl *ND = cast<NamedDecl>(GD.getDecl());
1247+
1248+
if (const auto *ID = dyn_cast<IndirectFieldDecl>(ND))
1249+
for (unsigned I = 1, IE = ID->getChainingSize(); I < IE; ++I)
1250+
mangleSourceName("<unnamed-tag>");
1251+
11911252
const DeclContext *DC = getEffectiveDeclContext(ND);
11921253
while (!DC->isTranslationUnit()) {
11931254
if (isa<TagDecl>(ND) || isa<VarDecl>(ND)) {
@@ -1570,7 +1631,6 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD,
15701631
// ::= 8 <class> <unqualified-name> @
15711632
// ::= A <type> <non-negative integer> # float
15721633
// ::= B <type> <non-negative integer> # double
1573-
// ::= E <mangled-name> # reference to D
15741634
// # pointer to member, by component value
15751635
// ::= F <number> <number>
15761636
// ::= G <number> <number> <number>
@@ -1615,7 +1675,7 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD,
16151675
mangleTemplateArgValue(TPO->getType().getUnqualifiedType(),
16161676
TPO->getValue());
16171677
} else {
1618-
mangle(ND, TA.getParamTypeForDecl()->isReferenceType() ? "$E?" : "$1?");
1678+
mangle(ND, "$1?");
16191679
}
16201680
break;
16211681
}
@@ -1744,46 +1804,62 @@ void MicrosoftCXXNameMangler::mangleTemplateArgValue(QualType T,
17441804
// FIXME: This can only happen as an extension. Invent a mangling.
17451805
break;
17461806
} else if (auto *VD = Base.dyn_cast<const ValueDecl*>()) {
1747-
Out << (T->isReferenceType() ? "E" : "1");
1807+
Out << "E";
17481808
mangle(VD);
17491809
} else {
17501810
break;
17511811
}
17521812
} else {
1753-
unsigned NumAts = 0;
1754-
if (T->isPointerType()) {
1813+
if (T->isPointerType())
17551814
Out << "5";
1756-
++NumAts;
1757-
}
17581815

1759-
QualType T = Base.getType();
1816+
SmallVector<char, 2> EntryTypes;
1817+
SmallVector<std::function<void()>, 2> EntryManglers;
1818+
QualType ET = Base.getType();
17601819
for (APValue::LValuePathEntry E : V.getLValuePath()) {
1761-
// We don't know how to mangle array subscripting yet.
1762-
if (T->isArrayType())
1763-
goto mangling_unknown;
1820+
if (auto *AT = ET->getAsArrayTypeUnsafe()) {
1821+
EntryTypes.push_back('C');
1822+
EntryManglers.push_back([this, I = E.getAsArrayIndex()] {
1823+
Out << '0';
1824+
mangleNumber(I);
1825+
Out << '@';
1826+
});
1827+
ET = AT->getElementType();
1828+
continue;
1829+
}
17641830

17651831
const Decl *D = E.getAsBaseOrMember().getPointer();
1766-
auto *FD = dyn_cast<FieldDecl>(D);
1767-
// We don't know how to mangle derived-to-base conversions yet.
1768-
if (!FD)
1769-
goto mangling_unknown;
1770-
1771-
Out << "6";
1772-
++NumAts;
1773-
T = FD->getType();
1832+
if (auto *FD = dyn_cast<FieldDecl>(D)) {
1833+
ET = FD->getType();
1834+
if (const auto *RD = ET->getAsRecordDecl())
1835+
if (RD->isAnonymousStructOrUnion())
1836+
continue;
1837+
} else {
1838+
ET = getASTContext().getRecordType(cast<CXXRecordDecl>(D));
1839+
// Bug in MSVC: fully qualified name of base class should be used for
1840+
// mangling to prevent collisions e.g. on base classes with same names
1841+
// in different namespaces.
1842+
}
1843+
1844+
EntryTypes.push_back('6');
1845+
EntryManglers.push_back([this, D] {
1846+
mangleUnqualifiedName(cast<NamedDecl>(D));
1847+
Out << '@';
1848+
});
17741849
}
17751850

1851+
for (auto I = EntryTypes.rbegin(), E = EntryTypes.rend(); I != E; ++I)
1852+
Out << *I;
1853+
17761854
auto *VD = Base.dyn_cast<const ValueDecl*>();
17771855
if (!VD)
17781856
break;
17791857
Out << "E";
17801858
mangle(VD);
17811859

1782-
for (APValue::LValuePathEntry E : V.getLValuePath()) {
1783-
const Decl *D = E.getAsBaseOrMember().getPointer();
1784-
mangleUnqualifiedName(cast<FieldDecl>(D));
1785-
}
1786-
for (unsigned I = 0; I != NumAts; ++I)
1860+
for (const std::function<void()> &Mangler : EntryManglers)
1861+
Mangler();
1862+
if (T->isPointerType())
17871863
Out << '@';
17881864
}
17891865

@@ -1794,20 +1870,14 @@ void MicrosoftCXXNameMangler::mangleTemplateArgValue(QualType T,
17941870
if (WithScalarType)
17951871
mangleType(T, SourceRange(), QMM_Escape);
17961872

1797-
// FIXME: The below manglings don't include a conversion, so bail if there
1798-
// would be one. MSVC mangles the (possibly converted) value of the
1799-
// pointer-to-member object as if it were a struct, leading to collisions
1800-
// in some cases.
1801-
if (!V.getMemberPointerPath().empty())
1802-
break;
1803-
18041873
const CXXRecordDecl *RD =
18051874
T->castAs<MemberPointerType>()->getMostRecentCXXRecordDecl();
18061875
const ValueDecl *D = V.getMemberPointerDecl();
18071876
if (T->isMemberDataPointerType())
1808-
mangleMemberDataPointer(RD, D, "");
1877+
mangleMemberDataPointerInClassNTTP(RD, D);
18091878
else
1810-
mangleMemberFunctionPointer(RD, cast_or_null<CXXMethodDecl>(D), "");
1879+
mangleMemberFunctionPointerInClassNTTP(RD,
1880+
cast_or_null<CXXMethodDecl>(D));
18111881
return;
18121882
}
18131883

@@ -1895,7 +1965,6 @@ void MicrosoftCXXNameMangler::mangleTemplateArgValue(QualType T,
18951965
break;
18961966
}
18971967

1898-
mangling_unknown:
18991968
DiagnosticsEngine &Diags = Context.getDiags();
19001969
unsigned DiagID = Diags.getCustomDiagID(
19011970
DiagnosticsEngine::Error, "cannot mangle this template argument yet");

0 commit comments

Comments
 (0)