19#include "llvm/ADT/SetOperations.h"
20#include "llvm/ADT/SetVector.h"
21#include "llvm/ADT/SmallPtrSet.h"
22#include "llvm/Support/Format.h"
23#include "llvm/Support/raw_ostream.h"
29#define DUMP_OVERRIDERS 0
50 BaseOffset() : DerivedClass(
nullptr),
VirtualBase(
nullptr),
55 NonVirtualOffset(NonVirtualOffset) { }
62class FinalOverriders {
65 struct OverriderInfo {
76 OverriderInfo() : Method(
nullptr),
VirtualBase(
nullptr),
102 typedef std::pair<const CXXMethodDecl *, CharUnits> MethodBaseOffsetPairTy;
104 typedef llvm::DenseMap<MethodBaseOffsetPairTy,
105 OverriderInfo> OverridersMapTy;
109 OverridersMapTy OverridersMap;
114 typedef llvm::DenseMap<std::pair<const CXXRecordDecl *, unsigned>,
117 typedef llvm::DenseMap<const CXXRecordDecl *, unsigned> SubobjectCountMapTy;
123 SubobjectOffsetMapTy &SubobjectOffsets,
124 SubobjectOffsetMapTy &SubobjectLayoutClassOffsets,
125 SubobjectCountMapTy &SubobjectCounts);
132 VisitedVirtualBasesSetTy& VisitedVirtualBases);
143 assert(OverridersMap.count(std::make_pair(MD, BaseOffset)) &&
144 "Did not find overrider!");
146 return OverridersMap.lookup(std::make_pair(MD, BaseOffset));
151 VisitedVirtualBasesSetTy VisitedVirtualBases;
153 VisitedVirtualBases);
158FinalOverriders::FinalOverriders(
const CXXRecordDecl *MostDerivedClass,
161 : MostDerivedClass(MostDerivedClass),
162 MostDerivedClassOffset(MostDerivedClassOffset), LayoutClass(LayoutClass),
167 SubobjectOffsetMapTy SubobjectOffsets;
168 SubobjectOffsetMapTy SubobjectLayoutClassOffsets;
169 SubobjectCountMapTy SubobjectCounts;
172 MostDerivedClassOffset,
173 SubobjectOffsets, SubobjectLayoutClassOffsets,
180 for (
const auto &Overrider : FinalOverriders) {
184 for (
const auto &M : Methods) {
185 unsigned SubobjectNumber = M.first;
186 assert(SubobjectOffsets.count(std::make_pair(MD->
getParent(),
188 "Did not find subobject offset!");
193 assert(M.second.size() == 1 &&
"Final overrider is not unique!");
197 assert(SubobjectLayoutClassOffsets.count(
198 std::make_pair(OverriderRD, Method.
Subobject))
199 &&
"Did not find subobject offset!");
201 SubobjectLayoutClassOffsets[std::make_pair(OverriderRD,
204 OverriderInfo& Overrider = OverridersMap[std::make_pair(MD, BaseOffset)];
205 assert(!Overrider.Method &&
"Overrider should not exist yet!");
207 Overrider.Offset = OverriderOffset;
208 Overrider.Method = Method.
Method;
219static BaseOffset ComputeBaseOffset(
const ASTContext &Context,
224 unsigned NonVirtualStart = 0;
228 for (
int I = Path.size(), E = 0; I != E; --I) {
231 if (Element.Base->isVirtual()) {
233 QualType VBaseType = Element.Base->getType();
240 for (
unsigned I = NonVirtualStart, E = Path.size(); I != E; ++I) {
254 return BaseOffset(DerivedRD,
VirtualBase, NonVirtualOffset);
258static BaseOffset ComputeBaseOffset(
const ASTContext &Context,
265 llvm_unreachable(
"Class must be derived from the passed in base class!");
267 return ComputeBaseOffset(Context, DerivedRD, Paths.front());
271ComputeReturnAdjustmentBaseOffset(
ASTContext &Context,
283 assert(CanDerivedReturnType->getTypeClass() ==
284 CanBaseReturnType->getTypeClass() &&
285 "Types must have same type class!");
287 if (CanDerivedReturnType == CanBaseReturnType) {
292 if (isa<ReferenceType>(CanDerivedReturnType)) {
293 CanDerivedReturnType =
294 CanDerivedReturnType->getAs<
ReferenceType>()->getPointeeType();
297 }
else if (isa<PointerType>(CanDerivedReturnType)) {
298 CanDerivedReturnType =
299 CanDerivedReturnType->getAs<
PointerType>()->getPointeeType();
303 llvm_unreachable(
"Unexpected return type!");
309 if (CanDerivedReturnType.getUnqualifiedType() ==
316 cast<CXXRecordDecl>(cast<RecordType>(CanDerivedReturnType)->getDecl());
319 cast<CXXRecordDecl>(cast<RecordType>(CanBaseReturnType)->getDecl());
321 return ComputeBaseOffset(Context, BaseRD, DerivedRD);
327 SubobjectOffsetMapTy &SubobjectOffsets,
328 SubobjectOffsetMapTy &SubobjectLayoutClassOffsets,
329 SubobjectCountMapTy &SubobjectCounts) {
332 unsigned SubobjectNumber = 0;
334 SubobjectNumber = ++SubobjectCounts[RD];
337 assert(!SubobjectOffsets.count(std::make_pair(RD, SubobjectNumber))
338 &&
"Subobject offset already exists!");
339 assert(!SubobjectLayoutClassOffsets.count(std::make_pair(RD, SubobjectNumber))
340 &&
"Subobject offset already exists!");
342 SubobjectOffsets[std::make_pair(RD, SubobjectNumber)] =
Base.getBaseOffset();
343 SubobjectLayoutClassOffsets[std::make_pair(RD, SubobjectNumber)] =
347 for (
const auto &B : RD->
bases()) {
348 const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
354 if (SubobjectOffsets.count(std::make_pair(BaseDecl, 0)))
360 BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
361 BaseOffsetInLayoutClass =
367 BaseOffset =
Base.getBaseOffset() + Offset;
368 BaseOffsetInLayoutClass = OffsetInLayoutClass + Offset;
372 B.isVirtual(), BaseOffsetInLayoutClass,
373 SubobjectOffsets, SubobjectLayoutClassOffsets,
379 VisitedVirtualBasesSetTy &VisitedVirtualBases) {
383 for (
const auto &B : RD->
bases()) {
384 const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
392 if (!VisitedVirtualBases.insert(BaseDecl).second) {
397 BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
405 Out <<
"Final overriders for (";
408 Out <<
Base.getBaseOffset().getQuantity() <<
")\n";
411 for (
const auto *MD : RD->
methods()) {
414 MD = MD->getCanonicalDecl();
416 OverriderInfo Overrider = getOverrider(MD,
Base.getBaseOffset());
419 MD->printQualifiedName(Out);
421 Overrider.Method->printQualifiedName(Out);
422 Out <<
", " << Overrider.Offset.getQuantity() <<
')';
425 if (!Overrider.Method->isPure())
426 Offset = ComputeReturnAdjustmentBaseOffset(Context, Overrider.Method, MD);
428 if (!Offset.isEmpty()) {
429 Out <<
" [ret-adj: ";
430 if (Offset.VirtualBase) {
431 Offset.VirtualBase->printQualifiedName(Out);
435 Out << Offset.NonVirtualOffset.getQuantity() <<
" nv]";
443struct VCallOffsetMap {
445 typedef std::pair<const CXXMethodDecl *, CharUnits> MethodAndOffsetPairTy;
453 static bool MethodsCanShareVCallOffset(
const CXXMethodDecl *LHS,
467 bool empty()
const {
return Offsets.empty(); }
478 if (
LT == RT)
return true;
488bool VCallOffsetMap::MethodsCanShareVCallOffset(
const CXXMethodDecl *LHS,
494 if (isa<CXXDestructorDecl>(LHS))
495 return isa<CXXDestructorDecl>(RHS);
502 if (LHSName != RHSName)
506 return HasSameVirtualSignature(LHS, RHS);
512 for (
const auto &OffsetPair : Offsets) {
513 if (MethodsCanShareVCallOffset(OffsetPair.first, MD))
518 Offsets.push_back(MethodAndOffsetPairTy(MD, OffsetOffset));
524 for (
const auto &OffsetPair : Offsets) {
525 if (MethodsCanShareVCallOffset(OffsetPair.first, MD))
526 return OffsetPair.second;
529 llvm_unreachable(
"Should always find a vcall offset offset!");
533class VCallAndVBaseOffsetBuilder {
535 typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits>
536 VBaseOffsetOffsetsMapTy;
555 VTableComponentVectorTy Components;
561 VCallOffsetMap VCallOffsets;
566 VBaseOffsetOffsetsMapTy VBaseOffsetOffsets;
570 const FinalOverriders *Overriders;
586 CharUnits getCurrentOffsetOffset()
const;
592 const FinalOverriders *Overriders,
595 : VTables(VTables), MostDerivedClass(MostDerivedClass),
596 LayoutClass(LayoutClass), Context(MostDerivedClass->
getASTContext()),
597 Overriders(Overriders) {
600 AddVCallAndVBaseOffsets(
Base, BaseIsVirtual, OffsetInLayoutClass);
604 typedef VTableComponentVectorTy::const_reverse_iterator const_iterator;
605 const_iterator components_begin()
const {
return Components.rbegin(); }
606 const_iterator components_end()
const {
return Components.rend(); }
608 const VCallOffsetMap &getVCallOffsets()
const {
return VCallOffsets; }
609 const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets()
const {
610 return VBaseOffsetOffsets;
635 if (PrimaryBaseIsVirtual) {
637 "Primary vbase should have a zero offset!");
646 "Primary base should have a zero offset!");
648 PrimaryBaseOffset =
Base.getBaseOffset();
651 AddVCallAndVBaseOffsets(
653 PrimaryBaseIsVirtual, RealBaseOffset);
656 AddVBaseOffsets(
Base.getBase(), RealBaseOffset);
660 AddVCallOffsets(
Base, RealBaseOffset);
663CharUnits VCallAndVBaseOffsetBuilder::getCurrentOffsetOffset()
const {
668 size_t NumComponentsAboveAddrPoint = 3;
670 NumComponentsAboveAddrPoint--;
671 int64_t OffsetIndex =
672 -(int64_t)(NumComponentsAboveAddrPoint + Components.size());
677 VTables.isRelativeLayout()
680 CharUnits OffsetOffset = OffsetWidth * OffsetIndex;
698 "Primary base should have a zero offset!");
705 for (
const auto *MD : RD->
methods()) {
710 CharUnits OffsetOffset = getCurrentOffsetOffset();
714 if (!VCallOffsets.AddVCallOffset(MD, OffsetOffset))
721 FinalOverriders::OverriderInfo Overrider =
722 Overriders->getOverrider(MD,
Base.getBaseOffset());
726 Offset = Overrider.Offset - VBaseOffset;
729 Components.push_back(
734 for (
const auto &B : RD->
bases()) {
738 const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
739 if (BaseDecl == PrimaryBase)
752VCallAndVBaseOffsetBuilder::AddVBaseOffsets(
const CXXRecordDecl *RD,
758 for (
const auto &B : RD->
bases()) {
759 const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
762 if (B.isVirtual() && VisitedVirtualBases.insert(BaseDecl).second) {
767 assert(!VBaseOffsetOffsets.count(BaseDecl) &&
768 "vbase offset offset already exists!");
770 CharUnits VBaseOffsetOffset = getCurrentOffsetOffset();
771 VBaseOffsetOffsets.insert(
772 std::make_pair(BaseDecl, VBaseOffsetOffset));
774 Components.push_back(
779 AddVBaseOffsets(BaseDecl, OffsetInLayoutClass);
784class ItaniumVTableBuilder {
789 PrimaryBasesSetVectorTy;
791 typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits>
792 VBaseOffsetOffsetsMapTy;
796 typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVTableIndicesTy;
812 bool MostDerivedClassIsVirtual;
823 const FinalOverriders Overriders;
827 llvm::DenseMap<const CXXRecordDecl *, VCallOffsetMap> VCallOffsetsForVBases;
831 VBaseOffsetOffsetsMapTy VBaseOffsetOffsets;
837 AddressPointsMapTy AddressPoints;
851 const uint64_t VTableIndex;
854 uint64_t VTableIndex)
855 : BaseOffset(BaseOffset),
856 BaseOffsetInLayoutClass(BaseOffsetInLayoutClass),
857 VTableIndex(VTableIndex) { }
864 MethodInfo(MethodInfo
const&) =
default;
867 typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy;
871 MethodInfoMapTy MethodInfoMap;
875 MethodVTableIndicesTy MethodVTableIndices;
877 typedef llvm::DenseMap<uint64_t, ThunkInfo> VTableThunksMapTy;
881 VTableThunksMapTy VTableThunks;
884 typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
895 void ComputeThisAdjustments();
901 VisitedVirtualBasesSetTy PrimaryVirtualBases;
918 FinalOverriders::OverriderInfo Overrider);
946 CharUnits FirstBaseOffsetInLayoutClass)
const;
954 PrimaryBasesSetVectorTy &PrimaryBases);
969 bool BaseIsMorallyVirtual,
970 bool BaseIsVirtualInLayoutClass,
985 VisitedVirtualBasesSetTy &VBases);
990 VisitedVirtualBasesSetTy &VBases);
994 bool isBuildingConstructorVTable()
const {
995 return MostDerivedClass != LayoutClass;
1006 bool MostDerivedClassIsVirtual,
1008 : VTables(VTables), MostDerivedClass(MostDerivedClass),
1009 MostDerivedClassOffset(MostDerivedClassOffset),
1010 MostDerivedClassIsVirtual(MostDerivedClassIsVirtual),
1011 LayoutClass(LayoutClass), Context(MostDerivedClass->
getASTContext()),
1012 Overriders(MostDerivedClass, MostDerivedClassOffset, LayoutClass) {
1018 dumpLayout(llvm::outs());
1021 uint64_t getNumThunks()
const {
1022 return Thunks.size();
1025 ThunksMapTy::const_iterator thunks_begin()
const {
1026 return Thunks.begin();
1029 ThunksMapTy::const_iterator thunks_end()
const {
1030 return Thunks.end();
1033 const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets()
const {
1034 return VBaseOffsetOffsets;
1037 const AddressPointsMapTy &getAddressPoints()
const {
1038 return AddressPoints;
1041 MethodVTableIndicesTy::const_iterator vtable_indices_begin()
const {
1042 return MethodVTableIndices.begin();
1045 MethodVTableIndicesTy::const_iterator vtable_indices_end()
const {
1046 return MethodVTableIndices.end();
1051 AddressPointsMapTy::const_iterator address_points_begin()
const {
1052 return AddressPoints.begin();
1055 AddressPointsMapTy::const_iterator address_points_end()
const {
1056 return AddressPoints.end();
1059 VTableThunksMapTy::const_iterator vtable_thunks_begin()
const {
1060 return VTableThunks.begin();
1063 VTableThunksMapTy::const_iterator vtable_thunks_end()
const {
1064 return VTableThunks.end();
1068 void dumpLayout(raw_ostream&);
1073 assert(!isBuildingConstructorVTable() &&
1074 "Can't add thunks for construction vtable");
1079 if (llvm::is_contained(ThunksVector, Thunk))
1082 ThunksVector.push_back(Thunk);
1091template <
class VisitorTy>
1093visitAllOverriddenMethods(
const CXXMethodDecl *MD, VisitorTy &Visitor) {
1097 if (!Visitor(OverriddenMD))
1099 visitAllOverriddenMethods(OverriddenMD, Visitor);
1107 OverriddenMethodsSetTy& OverriddenMethods) {
1108 auto OverriddenMethodsCollector = [&](
const CXXMethodDecl *MD) {
1110 return OverriddenMethods.insert(MD).second;
1112 visitAllOverriddenMethods(MD, OverriddenMethodsCollector);
1115void ItaniumVTableBuilder::ComputeThisAdjustments() {
1118 for (
const auto &MI : MethodInfoMap) {
1120 const MethodInfo &MethodInfo = MI.second;
1123 uint64_t VTableIndex = MethodInfo.VTableIndex;
1124 if (Components[VTableIndex].
getKind() ==
1129 FinalOverriders::OverriderInfo Overrider =
1130 Overriders.getOverrider(MD, MethodInfo.BaseOffset);
1133 if (MethodInfo.BaseOffsetInLayoutClass == Overrider.Offset) {
1139 if (VTableThunks.lookup(VTableIndex).Return.isEmpty())
1144 ComputeThisAdjustment(MD, MethodInfo.BaseOffsetInLayoutClass, Overrider);
1152 if (isa<CXXDestructorDecl>(MD)) {
1159 MethodInfoMap.clear();
1161 if (isBuildingConstructorVTable()) {
1166 for (
const auto &TI : VTableThunks) {
1171 switch (Component.
getKind()) {
1173 llvm_unreachable(
"Unexpected vtable component kind!");
1185 if (MD->
getParent() == MostDerivedClass)
1186 AddThunk(MD, Thunk);
1191ItaniumVTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
1194 if (!Offset.isEmpty()) {
1195 if (Offset.VirtualBase) {
1197 if (Offset.DerivedClass == MostDerivedClass) {
1200 VBaseOffsetOffsets.lookup(Offset.VirtualBase).getQuantity();
1203 VTables.getVirtualBaseOffsetOffset(Offset.DerivedClass,
1204 Offset.VirtualBase).getQuantity();
1208 Adjustment.
NonVirtual = Offset.NonVirtualOffset.getQuantity();
1214BaseOffset ItaniumVTableBuilder::ComputeThisAdjustmentBaseOffset(
1223 llvm_unreachable(
"Class must be derived from the passed in base class!");
1228 BaseOffset Offset = ComputeBaseOffset(Context, DerivedRD, Path);
1230 CharUnits OffsetToBaseSubobject = Offset.NonVirtualOffset;
1232 if (Offset.VirtualBase) {
1240 OffsetToBaseSubobject +=
1249 if (OffsetToBaseSubobject ==
Base.getBaseOffset()) {
1252 Offset.NonVirtualOffset = -Offset.NonVirtualOffset;
1257 return BaseOffset();
1262 FinalOverriders::OverriderInfo Overrider) {
1264 if (Overrider.Method->isPure())
1268 BaseOffsetInLayoutClass);
1270 BaseSubobject OverriderBaseSubobject(Overrider.Method->getParent(),
1274 BaseOffset Offset = ComputeThisAdjustmentBaseOffset(OverriddenBaseSubobject,
1275 OverriderBaseSubobject);
1276 if (Offset.isEmpty())
1281 if (Offset.VirtualBase) {
1283 VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Offset.VirtualBase];
1285 if (VCallOffsets.empty()) {
1288 VCallAndVBaseOffsetBuilder Builder(
1289 VTables, MostDerivedClass, MostDerivedClass,
1296 VCallOffsets = Builder.getVCallOffsets();
1300 VCallOffsets.getVCallOffsetOffset(MD).getQuantity();
1304 Adjustment.
NonVirtual = Offset.NonVirtualOffset.getQuantity();
1309void ItaniumVTableBuilder::AddMethod(
const CXXMethodDecl *MD,
1313 "Destructor can't have return adjustment!");
1339static bool OverridesIndirectMethodInBases(
1347 if (OverridesIndirectMethodInBases(OverriddenMD, Bases))
1354bool ItaniumVTableBuilder::IsOverriderUsed(
1357 CharUnits FirstBaseOffsetInLayoutClass)
const {
1360 if (BaseOffsetInLayoutClass == FirstBaseOffsetInLayoutClass)
1369 if (Overrider->getParent() == FirstBaseInPrimaryBaseChain)
1375 PrimaryBases.insert(RD);
1388 "Primary base should always be at offset 0!");
1396 FirstBaseOffsetInLayoutClass) {
1402 "Primary base should always be at offset 0!");
1405 if (!PrimaryBases.insert(PrimaryBase))
1406 llvm_unreachable(
"Found a duplicate primary base!");
1413 return OverridesIndirectMethodInBases(Overrider, PrimaryBases);
1423 BasesSetVectorTy &Bases) {
1424 OverriddenMethodsSetTy OverriddenMethods;
1425 ComputeAllOverriddenMethods(MD, OverriddenMethods);
1427 for (
const CXXRecordDecl *PrimaryBase : llvm::reverse(Bases)) {
1429 for (
const CXXMethodDecl *OverriddenMD : OverriddenMethods) {
1431 if (OverriddenMD->getParent() == PrimaryBase)
1432 return OverriddenMD;
1439void ItaniumVTableBuilder::AddMethods(
1443 PrimaryBasesSetVectorTy &PrimaryBases) {
1458 CharUnits PrimaryBaseOffsetInLayoutClass;
1461 "Primary vbase should have a zero offset!");
1472 PrimaryBaseOffsetInLayoutClass =
1476 "Primary base should have a zero offset!");
1478 PrimaryBaseOffset =
Base.getBaseOffset();
1479 PrimaryBaseOffsetInLayoutClass = BaseOffsetInLayoutClass;
1483 PrimaryBaseOffsetInLayoutClass, FirstBaseInPrimaryBaseChain,
1484 FirstBaseOffsetInLayoutClass, PrimaryBases);
1486 if (!PrimaryBases.insert(PrimaryBase))
1487 llvm_unreachable(
"Found a duplicate primary base!");
1491 NewVirtualFunctionsTy NewVirtualFunctions;
1496 for (
const auto *MD : RD->
methods()) {
1497 if (!ItaniumVTableContext::hasVtableSlot(MD))
1502 FinalOverriders::OverriderInfo Overrider =
1503 Overriders.getOverrider(MD,
Base.getBaseOffset());
1509 FindNearestOverriddenMethod(MD, PrimaryBases)) {
1510 if (ComputeReturnAdjustmentBaseOffset(Context, MD,
1511 OverriddenMD).isEmpty()) {
1514 assert(MethodInfoMap.count(OverriddenMD) &&
1515 "Did not find the overridden method!");
1516 MethodInfo &OverriddenMethodInfo = MethodInfoMap[OverriddenMD];
1518 MethodInfo MethodInfo(
Base.getBaseOffset(), BaseOffsetInLayoutClass,
1519 OverriddenMethodInfo.VTableIndex);
1521 assert(!MethodInfoMap.count(MD) &&
1522 "Should not have method info for this method yet!");
1524 MethodInfoMap.insert(std::make_pair(MD, MethodInfo));
1525 MethodInfoMap.erase(OverriddenMD);
1531 if (!isBuildingConstructorVTable() && OverriddenMD != MD) {
1534 ComputeThisAdjustment(OverriddenMD, BaseOffsetInLayoutClass,
1538 Overrider.Method->getParent() == MostDerivedClass) {
1543 BaseOffset ReturnAdjustmentOffset =
1544 ComputeReturnAdjustmentBaseOffset(Context, Overrider.Method, MD);
1546 ComputeReturnAdjustment(ReturnAdjustmentOffset);
1549 AddThunk(Overrider.Method,
1559 NewImplicitVirtualFunctions.push_back(MD);
1561 NewVirtualFunctions.push_back(MD);
1565 NewImplicitVirtualFunctions.begin(), NewImplicitVirtualFunctions.end(),
1569 if (A->isCopyAssignmentOperator() != B->isCopyAssignmentOperator())
1570 return A->isCopyAssignmentOperator();
1571 if (A->isMoveAssignmentOperator() != B->isMoveAssignmentOperator())
1572 return A->isMoveAssignmentOperator();
1573 if (isa<CXXDestructorDecl>(A) != isa<CXXDestructorDecl>(B))
1574 return isa<CXXDestructorDecl>(A);
1575 assert(A->getOverloadedOperator() == OO_EqualEqual &&
1576 B->getOverloadedOperator() == OO_EqualEqual &&
1577 "unexpected or duplicate implicit virtual function");
1582 NewVirtualFunctions.append(NewImplicitVirtualFunctions.begin(),
1583 NewImplicitVirtualFunctions.end());
1587 FinalOverriders::OverriderInfo Overrider =
1588 Overriders.getOverrider(MD,
Base.getBaseOffset());
1591 MethodInfo MethodInfo(
Base.getBaseOffset(), BaseOffsetInLayoutClass,
1594 assert(!MethodInfoMap.count(MD) &&
1595 "Should not have method info for this method yet!");
1596 MethodInfoMap.insert(std::make_pair(MD, MethodInfo));
1600 if (!IsOverriderUsed(OverriderMD, BaseOffsetInLayoutClass,
1601 FirstBaseInPrimaryBaseChain,
1602 FirstBaseOffsetInLayoutClass)) {
1609 BaseOffset ReturnAdjustmentOffset;
1610 if (!OverriderMD->
isPure()) {
1611 ReturnAdjustmentOffset =
1612 ComputeReturnAdjustmentBaseOffset(Context, OverriderMD, MD);
1616 ComputeReturnAdjustment(ReturnAdjustmentOffset);
1622void ItaniumVTableBuilder::LayoutVTable() {
1623 LayoutPrimaryAndSecondaryVTables(
BaseSubobject(MostDerivedClass,
1626 MostDerivedClassIsVirtual,
1627 MostDerivedClassOffset);
1629 VisitedVirtualBasesSetTy VBases;
1632 DeterminePrimaryVirtualBases(MostDerivedClass, MostDerivedClassOffset,
1636 LayoutVTablesForVirtualBases(MostDerivedClass, VBases);
1639 bool IsAppleKext = Context.
getLangOpts().AppleKext;
1644void ItaniumVTableBuilder::LayoutPrimaryAndSecondaryVTables(
1646 bool BaseIsVirtualInLayoutClass,
CharUnits OffsetInLayoutClass) {
1647 assert(
Base.getBase()->isDynamicClass() &&
"class does not have a vtable!");
1649 unsigned VTableIndex = Components.size();
1650 VTableIndices.push_back(VTableIndex);
1653 VCallAndVBaseOffsetBuilder Builder(
1654 VTables, MostDerivedClass, LayoutClass, &Overriders,
Base,
1655 BaseIsVirtualInLayoutClass, OffsetInLayoutClass);
1656 Components.append(Builder.components_begin(), Builder.components_end());
1659 if (BaseIsVirtualInLayoutClass && !Builder.getVCallOffsets().empty()) {
1660 VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[
Base.getBase()];
1662 if (VCallOffsets.empty())
1663 VCallOffsets = Builder.getVCallOffsets();
1668 if (
Base.getBase() == MostDerivedClass)
1669 VBaseOffsetOffsets = Builder.getVBaseOffsetOffsets();
1672 CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass;
1679 uint64_t AddressPoint = Components.size();
1682 PrimaryBasesSetVectorTy PrimaryBases;
1683 AddMethods(
Base, OffsetInLayoutClass,
1684 Base.getBase(), OffsetInLayoutClass,
1688 if (RD == MostDerivedClass) {
1689 assert(MethodVTableIndices.empty());
1690 for (
const auto &I : MethodInfoMap) {
1692 const MethodInfo &MI = I.second;
1695 = MI.VTableIndex - AddressPoint;
1697 = MI.VTableIndex + 1 - AddressPoint;
1699 MethodVTableIndices[MD] = MI.VTableIndex - AddressPoint;
1705 ComputeThisAdjustments();
1709 AddressPoints.insert(
1712 unsigned(VTableIndices.size() - 1),
1713 unsigned(AddressPoint - VTableIndex)}));
1728 OffsetInLayoutClass) {
1738 LayoutSecondaryVTables(
Base, BaseIsMorallyVirtual, OffsetInLayoutClass);
1743 bool BaseIsMorallyVirtual,
1754 for (
const auto &B : RD->
bases()) {
1759 const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
1765 if (isBuildingConstructorVTable()) {
1771 if (!BaseIsMorallyVirtual && !BaseDecl->
getNumVBases())
1777 CharUnits BaseOffset =
Base.getBaseOffset() + RelativeBaseOffset;
1780 OffsetInLayoutClass + RelativeBaseOffset;
1784 if (BaseDecl == PrimaryBase) {
1786 BaseIsMorallyVirtual, BaseOffsetInLayoutClass);
1791 LayoutPrimaryAndSecondaryVTables(
1793 BaseIsMorallyVirtual,
1795 BaseOffsetInLayoutClass);
1799void ItaniumVTableBuilder::DeterminePrimaryVirtualBases(
1801 VisitedVirtualBasesSetTy &VBases) {
1809 bool IsPrimaryVirtualBase =
true;
1811 if (isBuildingConstructorVTable()) {
1817 CharUnits PrimaryBaseOffsetInLayoutClass =
1822 if (PrimaryBaseOffsetInLayoutClass != OffsetInLayoutClass)
1823 IsPrimaryVirtualBase =
false;
1826 if (IsPrimaryVirtualBase)
1827 PrimaryVirtualBases.insert(PrimaryBase);
1832 for (
const auto &B : RD->
bases()) {
1833 const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
1837 if (B.isVirtual()) {
1838 if (!VBases.insert(BaseDecl).second)
1844 BaseOffsetInLayoutClass =
1847 BaseOffsetInLayoutClass =
1851 DeterminePrimaryVirtualBases(BaseDecl, BaseOffsetInLayoutClass, VBases);
1855void ItaniumVTableBuilder::LayoutVTablesForVirtualBases(
1856 const CXXRecordDecl *RD, VisitedVirtualBasesSetTy &VBases) {
1861 for (
const auto &B : RD->
bases()) {
1862 const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl();
1867 !PrimaryVirtualBases.count(BaseDecl) &&
1868 VBases.insert(BaseDecl).second) {
1879 LayoutPrimaryAndSecondaryVTables(
1883 BaseOffsetInLayoutClass);
1889 LayoutVTablesForVirtualBases(BaseDecl, VBases);
1894void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
1898 if (isBuildingConstructorVTable()) {
1899 Out <<
"Construction vtable for ('";
1902 Out << MostDerivedClassOffset.
getQuantity() <<
") in '";
1905 Out <<
"Vtable for '";
1908 Out <<
"' (" << Components.size() <<
" entries).\n";
1914 std::multimap<uint64_t, BaseSubobject> AddressPointsByIndex;
1915 for (
const auto &AP : AddressPoints) {
1918 VTableIndices[AP.second.VTableIndex] + AP.second.AddressPointIndex;
1920 AddressPointsByIndex.insert(std::make_pair(Index,
Base));
1923 for (
unsigned I = 0, E = Components.size(); I != E; ++I) {
1926 Out << llvm::format(
"%4d | ", I);
1931 switch (Component.
getKind()) {
1934 Out <<
"vcall_offset ("
1940 Out <<
"vbase_offset ("
1946 Out <<
"offset_to_top ("
1960 PredefinedIdentKind::PrettyFunctionNoVirtual, MD);
1966 Out <<
" [deleted]";
1968 ThunkInfo Thunk = VTableThunks.lookup(I);
1972 Out <<
"\n [return adjustment: ";
1977 Out <<
" vbase offset offset";
1985 Out <<
"\n [this adjustment: ";
1990 Out <<
" vcall offset offset";
2009 Out <<
"() [complete]";
2011 Out <<
"() [deleting]";
2016 ThunkInfo Thunk = VTableThunks.lookup(I);
2020 Out <<
"\n [this adjustment: ";
2025 Out <<
" vcall offset offset";
2039 PredefinedIdentKind::PrettyFunctionNoVirtual, MD);
2040 Out <<
"[unused] " << Str;
2050 uint64_t NextIndex = Index + 1;
2051 if (AddressPointsByIndex.count(NextIndex)) {
2052 if (AddressPointsByIndex.count(NextIndex) == 1) {
2054 AddressPointsByIndex.find(NextIndex)->second;
2057 Base.getBase()->printQualifiedName(Out);
2058 Out <<
", " <<
Base.getBaseOffset().getQuantity();
2059 Out <<
") vtable address --\n";
2062 AddressPointsByIndex.lower_bound(NextIndex)->second.getBaseOffset();
2065 std::set<std::string> ClassNames;
2066 for (
const auto &I :
2067 llvm::make_range(AddressPointsByIndex.equal_range(NextIndex))) {
2068 assert(I.second.getBaseOffset() == BaseOffset &&
2069 "Invalid base offset!");
2074 for (
const std::string &Name : ClassNames) {
2075 Out <<
" -- (" << Name;
2076 Out <<
", " << BaseOffset.
getQuantity() <<
") vtable address --\n";
2084 if (isBuildingConstructorVTable())
2091 std::map<std::string, CharUnits> ClassNamesAndOffsets;
2092 for (
const auto &I : VBaseOffsetOffsets) {
2093 std::string ClassName = I.first->getQualifiedNameAsString();
2095 ClassNamesAndOffsets.insert(std::make_pair(ClassName, OffsetOffset));
2098 Out <<
"Virtual base offset offsets for '";
2101 Out << ClassNamesAndOffsets.size();
2102 Out << (ClassNamesAndOffsets.size() == 1 ?
" entry" :
" entries") <<
").\n";
2104 for (
const auto &I : ClassNamesAndOffsets)
2105 Out <<
" " << I.first <<
" | " << I.second.getQuantity() <<
'\n';
2110 if (!Thunks.empty()) {
2112 std::map<std::string, const CXXMethodDecl *> MethodNamesAndDecls;
2114 for (
const auto &I : Thunks) {
2117 PredefinedIdentKind::PrettyFunctionNoVirtual, MD);
2119 MethodNamesAndDecls.insert(std::make_pair(MethodName, MD));
2122 for (
const auto &I : MethodNamesAndDecls) {
2123 const std::string &MethodName = I.first;
2126 ThunkInfoVectorTy ThunksVector = Thunks[MD];
2128 assert(LHS.
Method ==
nullptr && RHS.
Method ==
nullptr);
2132 Out <<
"Thunks for '" << MethodName <<
"' (" << ThunksVector.size();
2133 Out << (ThunksVector.size() == 1 ?
" entry" :
" entries") <<
").\n";
2135 for (
unsigned I = 0, E = ThunksVector.size(); I != E; ++I) {
2136 const ThunkInfo &Thunk = ThunksVector[I];
2138 Out << llvm::format(
"%4d | ", I);
2143 Out <<
" non-virtual";
2146 Out <<
" vbase offset offset";
2155 Out <<
"this adjustment: ";
2160 Out <<
" vcall offset offset";
2173 std::map<uint64_t, std::string> IndicesMap;
2175 for (
const auto *MD : MostDerivedClass->
methods()) {
2177 if (!ItaniumVTableContext::hasVtableSlot(MD))
2182 PredefinedIdentKind::PrettyFunctionNoVirtual, MD);
2186 assert(MethodVTableIndices.count(GD));
2187 uint64_t VTableIndex = MethodVTableIndices[GD];
2188 IndicesMap[VTableIndex] = MethodName +
" [complete]";
2189 IndicesMap[VTableIndex + 1] = MethodName +
" [deleting]";
2191 assert(MethodVTableIndices.count(MD));
2192 IndicesMap[MethodVTableIndices[MD]] = MethodName;
2197 if (!IndicesMap.empty()) {
2198 Out <<
"VTable indices for '";
2200 Out <<
"' (" << IndicesMap.size() <<
" entries).\n";
2202 for (
const auto &I : IndicesMap) {
2203 uint64_t VTableIndex = I.first;
2204 const std::string &MethodName = I.second;
2206 Out << llvm::format(
"%4" PRIu64
" | ", VTableIndex) << MethodName
2217 unsigned numVTables) {
2220 for (
auto it = addressPoints.begin(); it != addressPoints.end(); ++it) {
2221 const auto &addressPointLoc = it->second;
2222 unsigned vtableIndex = addressPointLoc.VTableIndex;
2223 unsigned addressPoint = addressPointLoc.AddressPointIndex;
2224 if (indexMap[vtableIndex]) {
2227 assert(indexMap[vtableIndex] == addressPoint &&
2228 "Every vtable index should have a unique address point. Found a "
2229 "vtable that has two different address points.");
2231 indexMap[vtableIndex] = addressPoint;
2246 : VTableComponents(VTableComponents), VTableThunks(VTableThunks),
2248 AddressPoints, VTableIndices.size())) {
2249 if (VTableIndices.size() <= 1)
2250 assert(VTableIndices.size() == 1 && VTableIndices[0] == 0);
2256 assert((LHS.first != RHS.first || LHS.second == RHS.second) &&
2257 "Different thunks should have unique indices!");
2258 return LHS.first < RHS.first;
2276 MethodVTableIndicesTy::iterator I = MethodVTableIndices.find(GD);
2277 if (I != MethodVTableIndices.end())
2282 computeVTableRelatedInformation(RD);
2284 I = MethodVTableIndices.find(GD);
2285 assert(I != MethodVTableIndices.end() &&
"Did not find index!");
2292 ClassPairTy ClassPair(RD, VBase);
2294 VirtualBaseClassOffsetOffsetsMapTy::iterator I =
2295 VirtualBaseClassOffsetOffsets.find(ClassPair);
2296 if (I != VirtualBaseClassOffsetOffsets.end())
2299 VCallAndVBaseOffsetBuilder Builder(*
this, RD, RD,
nullptr,
2304 for (
const auto &I : Builder.getVBaseOffsetOffsets()) {
2306 ClassPairTy ClassPair(RD, I.first);
2308 VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I.second));
2311 I = VirtualBaseClassOffsetOffsets.find(ClassPair);
2312 assert(I != VirtualBaseClassOffsetOffsets.end() &&
"Did not find index!");
2317static std::unique_ptr<VTableLayout>
2320 VTableThunks(Builder.vtable_thunks_begin(), Builder.vtable_thunks_end());
2322 return std::make_unique<VTableLayout>(
2323 Builder.VTableIndices, Builder.vtable_components(), VTableThunks,
2324 Builder.getAddressPoints());
2328ItaniumVTableContext::computeVTableRelatedInformation(
const CXXRecordDecl *RD) {
2329 std::unique_ptr<const VTableLayout> &Entry = VTableLayouts[RD];
2339 MethodVTableIndices.insert(Builder.vtable_indices_begin(),
2340 Builder.vtable_indices_end());
2343 Thunks.insert(Builder.thunks_begin(), Builder.thunks_end());
2354 if (VirtualBaseClassOffsetOffsets.count(std::make_pair(RD, VBase)))
2357 for (
const auto &I : Builder.getVBaseOffsetOffsets()) {
2359 ClassPairTy ClassPair(RD, I.first);
2361 VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I.second));
2365std::unique_ptr<VTableLayout>
2368 bool MostDerivedClassIsVirtual,
const CXXRecordDecl *LayoutClass) {
2369 ItaniumVTableBuilder Builder(*
this, MostDerivedClass, MostDerivedClassOffset,
2370 MostDerivedClassIsVirtual, LayoutClass);
2418class VFTableBuilder {
2420 typedef llvm::DenseMap<GlobalDecl, MethodVFTableLocation>
2421 MethodVFTableLocationsTy;
2423 typedef llvm::iterator_range<MethodVFTableLocationsTy::const_iterator>
2424 method_locations_range;
2442 const FinalOverriders Overriders;
2447 MethodVFTableLocationsTy MethodVFTableLocations;
2450 bool HasRTTIComponent =
false;
2457 const uint64_t VBTableIndex;
2460 const uint64_t VFTableIndex;
2471 MethodInfo(uint64_t VBTableIndex, uint64_t VFTableIndex,
2472 bool UsesExtraSlot =
false)
2473 : VBTableIndex(VBTableIndex), VFTableIndex(VFTableIndex),
2474 Shadowed(
false), UsesExtraSlot(UsesExtraSlot) {}
2477 : VBTableIndex(0), VFTableIndex(0), Shadowed(
false),
2478 UsesExtraSlot(
false) {}
2481 typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy;
2485 MethodInfoMapTy MethodInfoMap;
2487 typedef llvm::DenseMap<uint64_t, ThunkInfo> VTableThunksMapTy;
2491 VTableThunksMapTy VTableThunks;
2494 typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
2505 if (llvm::is_contained(ThunksVector, Thunk))
2508 ThunksVector.push_back(Thunk);
2513 CharUnits ComputeThisOffset(FinalOverriders::OverriderInfo Overrider);
2515 void CalculateVtordispAdjustment(FinalOverriders::OverriderInfo Overrider,
2522 VTableThunks[Components.size()] = TI;
2527 "Destructor can't have return adjustment!");
2538 BasesSetVectorTy &VisitedBases);
2540 void LayoutVFTable() {
2542 if (HasRTTIComponent)
2545 BasesSetVectorTy VisitedBases;
2550 assert(!Components.empty() &&
"vftable can't be empty");
2552 assert(MethodVFTableLocations.empty());
2553 for (
const auto &I : MethodInfoMap) {
2555 const MethodInfo &MI = I.second;
2560 if (MD->
getParent() != MostDerivedClass || MI.Shadowed)
2567 MethodVFTableLocations[MD] = Loc;
2576 Context(MostDerivedClass->getASTContext()),
2577 MostDerivedClass(MostDerivedClass),
2578 MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)),
2580 Overriders(MostDerivedClass,
CharUnits(), MostDerivedClass) {
2587 HasRTTIComponent =
true;
2592 dumpLayout(llvm::outs());
2595 uint64_t getNumThunks()
const {
return Thunks.size(); }
2597 ThunksMapTy::const_iterator thunks_begin()
const {
return Thunks.begin(); }
2599 ThunksMapTy::const_iterator thunks_end()
const {
return Thunks.end(); }
2601 method_locations_range vtable_locations()
const {
2602 return method_locations_range(MethodVFTableLocations.begin(),
2603 MethodVFTableLocations.end());
2608 VTableThunksMapTy::const_iterator vtable_thunks_begin()
const {
2609 return VTableThunks.begin();
2612 VTableThunksMapTy::const_iterator vtable_thunks_end()
const {
2613 return VTableThunks.end();
2616 void dumpLayout(raw_ostream &);
2676VFTableBuilder::ComputeThisOffset(FinalOverriders::OverriderInfo Overrider) {
2677 BasesSetVectorTy Bases;
2681 OverriddenMethodsSetTy VisitedOverriddenMethods;
2682 auto InitialOverriddenDefinitionCollector = [&](
2684 if (OverriddenMD->size_overridden_methods() == 0)
2685 Bases.insert(OverriddenMD->getParent());
2687 return VisitedOverriddenMethods.insert(OverriddenMD).second;
2689 visitAllOverriddenMethods(Overrider.Method,
2690 InitialOverriddenDefinitionCollector);
2695 if (Bases.size() == 0)
2696 return Overrider.Offset;
2699 Overrider.Method->getParent()->lookupInBases(
2701 return Bases.count(
Specifier->getType()->getAsCXXRecordDecl());
2715 CharUnits ThisOffset = Overrider.Offset;
2722 QualType CurTy = Element.Base->getType();
2727 if (Element.Base->isVirtual()) {
2738 LastVBaseOffset = ThisOffset =
2745 if (isa<CXXDestructorDecl>(Overrider.Method)) {
2746 if (LastVBaseOffset.
isZero()) {
2750 ThisOffset = Overrider.Offset;
2754 ThisOffset = LastVBaseOffset;
2758 if (Ret > ThisOffset ||
First) {
2764 assert(!
First &&
"Method not found in the given subobject?");
2866void VFTableBuilder::CalculateVtordispAdjustment(
2867 FinalOverriders::OverriderInfo Overrider,
CharUnits ThisOffset,
2871 const ASTRecordLayout::VBaseOffsetsMapTy::const_iterator &VBaseMapEntry =
2873 assert(VBaseMapEntry != VBaseMap.end());
2877 if (!VBaseMapEntry->second.hasVtorDisp() ||
2883 CharUnits OffsetOfVBaseWithVFPtr = VBaseMapEntry->second.VBaseOffset;
2885 (OffsetOfVBaseWithVFPtr - WhichVFPtr.
FullOffsetInMDC).getQuantity() - 4;
2889 if (Overrider.Method->getParent() == MostDerivedClass ||
2890 !Overrider.VirtualBase)
2902 TA.
NonVirtual = (ThisOffset - Overrider.Offset).getQuantity();
2916 typedef llvm::DenseMap<DeclarationName, unsigned> VisitedGroupIndicesTy;
2917 VisitedGroupIndicesTy VisitedGroupIndices;
2918 for (
const auto *D : RD->
decls()) {
2919 const auto *ND = dyn_cast<NamedDecl>(D);
2922 VisitedGroupIndicesTy::iterator J;
2924 std::tie(J, Inserted) = VisitedGroupIndices.insert(
2925 std::make_pair(ND->getDeclName(), Groups.size()));
2927 Groups.push_back(MethodGroup());
2928 if (
const auto *MD = dyn_cast<CXXMethodDecl>(ND))
2933 for (
const MethodGroup &Group : Groups)
2934 VirtualMethods.append(Group.rbegin(), Group.rend());
2938 for (
const auto &B : RD->
bases()) {
2939 if (B.isVirtual() && B.getType()->getAsCXXRecordDecl() ==
Base)
2947 BasesSetVectorTy &VisitedBases) {
2957 const CXXRecordDecl *NextBase =
nullptr, *NextLastVBase = LastVBase;
2962 NextLastVBase = NextBase;
2970 "No primary virtual bases in this ABI");
2971 NextBase = PrimaryBase;
2972 NextBaseOffset =
Base.getBaseOffset();
2976 AddMethods(
BaseSubobject(NextBase, NextBaseOffset), BaseDepth + 1,
2977 NextLastVBase, VisitedBases);
2978 if (!VisitedBases.insert(NextBase))
2979 llvm_unreachable(
"Found a duplicate primary base!");
2995 FinalOverriders::OverriderInfo FinalOverrider =
2996 Overriders.getOverrider(MD,
Base.getBaseOffset());
2997 const CXXMethodDecl *FinalOverriderMD = FinalOverrider.Method;
2999 FindNearestOverriddenMethod(MD, VisitedBases);
3002 bool ReturnAdjustingThunk =
false, ForceReturnAdjustmentMangling =
false;
3003 CharUnits ThisOffset = ComputeThisOffset(FinalOverrider);
3006 if ((OverriddenMD || FinalOverriderMD != MD) &&
3008 CalculateVtordispAdjustment(FinalOverrider, ThisOffset,
3009 ThisAdjustmentOffset);
3017 MethodInfoMapTy::iterator OverriddenMDIterator =
3018 MethodInfoMap.find(OverriddenMD);
3021 if (OverriddenMDIterator == MethodInfoMap.end())
3024 MethodInfo &OverriddenMethodInfo = OverriddenMDIterator->second;
3026 VBIndex = OverriddenMethodInfo.VBTableIndex;
3033 ReturnAdjustingThunk = !ComputeReturnAdjustmentBaseOffset(
3034 Context, MD, OverriddenMD).isEmpty() ||
3035 OverriddenMethodInfo.UsesExtraSlot;
3037 if (!ReturnAdjustingThunk) {
3040 MethodInfo MI(VBIndex, OverriddenMethodInfo.VFTableIndex);
3041 MethodInfoMap.erase(OverriddenMDIterator);
3043 assert(!MethodInfoMap.count(MD) &&
3044 "Should not have method info for this method yet!");
3045 MethodInfoMap.insert(std::make_pair(MD, MI));
3051 OverriddenMethodInfo.Shadowed =
true;
3055 ForceReturnAdjustmentMangling =
3056 !(MD == FinalOverriderMD && ThisAdjustmentOffset.
isEmpty());
3067 MethodInfo MI(VBIndex,
3068 HasRTTIComponent ? Components.size() - 1 : Components.size(),
3069 ReturnAdjustingThunk);
3071 assert(!MethodInfoMap.count(MD) &&
3072 "Should not have method info for this method yet!");
3073 MethodInfoMap.insert(std::make_pair(MD, MI));
3077 BaseOffset ReturnAdjustmentOffset;
3079 if (!FinalOverriderMD->
isPure()) {
3080 ReturnAdjustmentOffset =
3081 ComputeReturnAdjustmentBaseOffset(Context, FinalOverriderMD, MD);
3083 if (!ReturnAdjustmentOffset.isEmpty()) {
3084 ForceReturnAdjustmentMangling =
true;
3086 ReturnAdjustmentOffset.NonVirtualOffset.getQuantity();
3087 if (ReturnAdjustmentOffset.VirtualBase) {
3094 ReturnAdjustmentOffset.VirtualBase);
3098 AddMethod(FinalOverriderMD,
3100 ForceReturnAdjustmentMangling ? MD :
nullptr));
3107 Elem->printQualifiedName(Out);
3113 bool ContinueFirstLine) {
3115 bool Multiline =
false;
3116 const char *LinePrefix =
"\n ";
3118 if (!ContinueFirstLine)
3120 Out <<
"[return adjustment (to type '"
3132 if (Multiline || !ContinueFirstLine)
3134 Out <<
"[this adjustment: ";
3142 Out << LinePrefix <<
" vboffset at "
3150void VFTableBuilder::dumpLayout(raw_ostream &Out) {
3151 Out <<
"VFTable for ";
3155 Out <<
"' (" << Components.size()
3156 << (Components.size() == 1 ?
" entry" :
" entries") <<
").\n";
3158 for (
unsigned I = 0, E = Components.size(); I != E; ++I) {
3159 Out << llvm::format(
"%4d | ", I);
3164 switch (Component.
getKind()) {
3182 Out <<
" [deleted]";
3184 ThunkInfo Thunk = VTableThunks.lookup(I);
3195 Out <<
"() [scalar deleting]";
3200 ThunkInfo Thunk = VTableThunks.lookup(I);
3203 "No return adjustment needed for destructors!");
3214 "Unexpected vftable component type %0 for component number %1");
3224 if (!Thunks.empty()) {
3226 std::map<std::string, const CXXMethodDecl *> MethodNamesAndDecls;
3228 for (
const auto &I : Thunks) {
3233 MethodNamesAndDecls.insert(std::make_pair(MethodName, MD));
3236 for (
const auto &MethodNameAndDecl : MethodNamesAndDecls) {
3237 const std::string &MethodName = MethodNameAndDecl.first;
3240 ThunkInfoVectorTy ThunksVector = Thunks[MD];
3241 llvm::stable_sort(ThunksVector, [](
const ThunkInfo &LHS,
3248 Out <<
"Thunks for '" << MethodName <<
"' (" << ThunksVector.size();
3249 Out << (ThunksVector.size() == 1 ?
" entry" :
" entries") <<
").\n";
3251 for (
unsigned I = 0, E = ThunksVector.size(); I != E; ++I) {
3252 const ThunkInfo &Thunk = ThunksVector[I];
3254 Out << llvm::format(
"%4d | ", I);
3298void MicrosoftVTableContext::computeVTablePaths(
bool ForVBTables,
3301 assert(Paths.empty());
3306 Paths.push_back(std::make_unique<VPtrInfo>(RD));
3311 for (
const auto &B : RD->
bases()) {
3313 if (B.isVirtual() && VBasesSeen.count(
Base))
3316 if (!
Base->isDynamicClass())
3322 for (
const std::unique_ptr<VPtrInfo> &BaseInfo : BasePaths) {
3329 auto P = std::make_unique<VPtrInfo>(*BaseInfo);
3333 if (
P->MangledPath.empty() ||
P->MangledPath.back() !=
Base)
3334 P->NextBaseToMangle =
Base;
3339 if (
P->ObjectWithVPtr ==
Base &&
3342 P->ObjectWithVPtr = RD;
3347 P->ContainingVBases.push_back(
Base);
3348 else if (
P->ContainingVBases.empty())
3352 P->FullOffsetInMDC =
P->NonVirtualOffset;
3356 Paths.push_back(std::move(
P));
3360 VBasesSeen.insert(
Base);
3364 for (
const auto &VB :
Base->vbases())
3365 VBasesSeen.insert(VB.getType()->getAsCXXRecordDecl());
3376 if (
P.NextBaseToMangle) {
3377 P.MangledPath.push_back(
P.NextBaseToMangle);
3378 P.NextBaseToMangle =
nullptr;
3392 llvm::make_pointee_range(Paths));
3396 bool Changed =
false;
3397 for (
size_t I = 0, E = PathsSorted.size(); I != E;) {
3399 size_t BucketStart = I;
3403 PathsSorted[BucketStart].get().MangledPath ==
3404 PathsSorted[I].get().MangledPath);
3407 if (I - BucketStart > 1) {
3408 for (
size_t II = BucketStart; II != I; ++II)
3410 assert(Changed &&
"no paths were extended to fix ambiguity");
3419typedef llvm::SetVector<BaseSubobject, std::vector<BaseSubobject>,
3429 FullPathTy &FullPath,
3430 std::list<FullPathTy> &Paths) {
3432 Paths.push_back(FullPath);
3445 IntroducingObject, FullPath, Paths);
3446 FullPath.pop_back();
3452 FullPaths.remove_if([&](
const FullPathTy &SpecificPath) {
3453 for (
const FullPathTy &OtherPath : FullPaths) {
3454 if (&SpecificPath == &OtherPath)
3456 if (llvm::all_of(SpecificPath, [&](
const BaseSubobject &BSO) {
3457 return OtherPath.contains(BSO);
3468 const FullPathTy &FullPath) {
3476 assert(Offset.getQuantity() == -1);
3480 assert(Offset.getQuantity() != -1);
3486 return BS.getType()->getAsCXXRecordDecl() == Base;
3501 std::list<FullPathTy> &FullPaths) {
3503 if (FullPaths.empty())
3505 if (FullPaths.size() == 1)
3506 return &FullPaths.front();
3508 const FullPathTy *BestPath =
nullptr;
3509 typedef std::set<const CXXMethodDecl *> OverriderSetTy;
3510 OverriderSetTy LastOverrides;
3511 for (
const FullPathTy &SpecificPath : FullPaths) {
3512 assert(!SpecificPath.empty());
3513 OverriderSetTy CurrentOverrides;
3514 const CXXRecordDecl *TopLevelRD = SpecificPath.begin()->getBase();
3519 FinalOverriders Overriders(TopLevelRD,
CharUnits::Zero(), TopLevelRD);
3523 FinalOverriders::OverriderInfo OI =
3528 if (ComputeReturnAdjustmentBaseOffset(Context, OverridingMethod, MD)
3534 if (llvm::none_of(SpecificPath, [&](
const BaseSubobject &BSO) {
3535 return BSO.
getBase() == OverridingParent;
3538 CurrentOverrides.insert(OverridingMethod);
3540 OverriderSetTy NewOverrides =
3541 llvm::set_difference(CurrentOverrides, LastOverrides);
3542 if (NewOverrides.empty())
3544 OverriderSetTy MissingOverrides =
3545 llvm::set_difference(LastOverrides, CurrentOverrides);
3546 if (MissingOverrides.empty()) {
3548 BestPath = &SpecificPath;
3549 std::swap(CurrentOverrides, LastOverrides);
3554 const CXXMethodDecl *ConflictMD = *MissingOverrides.begin();
3565 return BestPath ? BestPath : &FullPaths.front();
3572 FullPathTy FullPath;
3573 std::list<FullPathTy> FullPaths;
3574 for (
const std::unique_ptr<VPtrInfo>& Info : Paths) {
3577 BaseSubobject(Info->IntroducingObject, Info->FullOffsetInMDC), FullPath,
3581 Info->PathToIntroducingObject.clear();
3582 if (
const FullPathTy *BestPath =
3585 Info->PathToIntroducingObject.push_back(BSO.getBase());
3602void MicrosoftVTableContext::computeVTableRelatedInformation(
3607 if (VFPtrLocations.count(RD))
3613 auto VFPtrs = std::make_unique<VPtrInfoVector>();
3614 computeVTablePaths(
false, RD, *VFPtrs);
3616 VFPtrLocations[RD] = std::move(VFPtrs);
3619 MethodVFTableLocationsTy NewMethodLocations;
3620 for (
const std::unique_ptr<VPtrInfo> &VFPtr : *VFPtrLocations[RD]) {
3621 VFTableBuilder Builder(*
this, RD, *VFPtr);
3623 VFTableIdTy id(RD, VFPtr->FullOffsetInMDC);
3624 assert(VFTableLayouts.count(
id) == 0);
3626 Builder.vtable_thunks_begin(), Builder.vtable_thunks_end());
3627 VFTableLayouts[id] = std::make_unique<VTableLayout>(
3629 EmptyAddressPointsMap);
3630 Thunks.insert(Builder.thunks_begin(), Builder.thunks_end());
3633 for (
const auto &Loc : Builder.vtable_locations()) {
3634 auto Insert = NewMethodLocations.insert(Loc);
3644 MethodVFTableLocations.insert(NewMethodLocations.begin(),
3645 NewMethodLocations.end());
3647 dumpMethodLocations(RD, NewMethodLocations, llvm::outs());
3650void MicrosoftVTableContext::dumpMethodLocations(
3651 const CXXRecordDecl *RD,
const MethodVFTableLocationsTy &NewMethods,
3655 std::map<MethodVFTableLocation, std::string> IndicesMap;
3656 bool HasNonzeroOffset =
false;
3658 for (
const auto &I : NewMethods) {
3659 const CXXMethodDecl *MD = cast<const CXXMethodDecl>(I.first.getDecl());
3665 if (isa<CXXDestructorDecl>(MD)) {
3666 IndicesMap[I.second] = MethodName +
" [scalar deleting]";
3668 IndicesMap[I.second] = MethodName;
3671 if (!I.second.VFPtrOffset.isZero() || I.second.VBTableIndex != 0)
3672 HasNonzeroOffset =
true;
3676 if (!IndicesMap.empty()) {
3677 Out <<
"VFTable indices for ";
3680 Out <<
"' (" << IndicesMap.size()
3681 << (IndicesMap.size() == 1 ?
" entry" :
" entries") <<
").\n";
3685 for (
const auto &I : IndicesMap) {
3686 CharUnits VFPtrOffset = I.first.VFPtrOffset;
3687 uint64_t VBIndex = I.first.VBTableIndex;
3688 if (HasNonzeroOffset &&
3689 (VFPtrOffset != LastVFPtrOffset || VBIndex != LastVBIndex)) {
3690 assert(VBIndex > LastVBIndex || VFPtrOffset > LastVFPtrOffset);
3691 Out <<
" -- accessible via ";
3693 Out <<
"vbtable index " << VBIndex <<
", ";
3694 Out <<
"vfptr at offset " << VFPtrOffset.
getQuantity() <<
" --\n";
3695 LastVFPtrOffset = VFPtrOffset;
3696 LastVBIndex = VBIndex;
3699 uint64_t VTableIndex = I.first.Index;
3700 const std::string &MethodName = I.second;
3701 Out << llvm::format(
"%4" PRIu64
" | ", VTableIndex) << MethodName <<
'\n';
3709const VirtualBaseInfo &MicrosoftVTableContext::computeVBTableRelatedInformation(
3716 std::unique_ptr<VirtualBaseInfo> &Entry = VBaseInfo[RD];
3719 Entry = std::make_unique<VirtualBaseInfo>();
3723 computeVTablePaths(
true, RD, VBI->
VBPtrPaths);
3731 computeVBTableRelatedInformation(VBPtrBase);
3739 for (
const auto &VB : RD->
vbases()) {
3740 const CXXRecordDecl *CurVBase = VB.getType()->getAsCXXRecordDecl();
3750 const VirtualBaseInfo &VBInfo = computeVBTableRelatedInformation(Derived);
3757 return computeVBTableRelatedInformation(RD).
VBPtrPaths;
3762 computeVTableRelatedInformation(RD);
3764 assert(VFPtrLocations.count(RD) &&
"Couldn't find vfptr locations");
3765 return *VFPtrLocations[RD];
3771 computeVTableRelatedInformation(RD);
3773 VFTableIdTy id(RD, VFPtrOffset);
3774 assert(VFTableLayouts.count(
id) &&
"Couldn't find a VFTable at this offset");
3775 return *VFTableLayouts[id];
3781 "Only use this method for virtual methods or dtors");
3782 if (isa<CXXDestructorDecl>(GD.
getDecl()))
3787 MethodVFTableLocationsTy::iterator I = MethodVFTableLocations.find(GD);
3788 if (I != MethodVFTableLocations.end())
3793 computeVTableRelatedInformation(RD);
3795 I = MethodVFTableLocations.find(GD);
3796 assert(I != MethodVFTableLocations.end() &&
"Did not find index!");
Defines the clang::ASTContext interface.
ASTImporterLookupTable & LT
static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)
static Decl::Kind getKind(const Decl *D)
const NestedNameSpecifier * Specifier
static void findPathsToSubobject(ASTContext &Context, const ASTRecordLayout &MostDerivedLayout, const CXXRecordDecl *RD, CharUnits Offset, BaseSubobject IntroducingObject, FullPathTy &FullPath, std::list< FullPathTy > &Paths)
static const FullPathTy * selectBestPath(ASTContext &Context, const CXXRecordDecl *RD, const VPtrInfo &Info, std::list< FullPathTy > &FullPaths)
static CharUnits getOffsetOfFullPath(ASTContext &Context, const CXXRecordDecl *RD, const FullPathTy &FullPath)
static void removeRedundantPaths(std::list< FullPathTy > &FullPaths)
static std::unique_ptr< VTableLayout > CreateVTableLayout(const ItaniumVTableBuilder &Builder)
static bool vfptrIsEarlierInMDC(const ASTRecordLayout &Layout, const MethodVFTableLocation &LHS, const MethodVFTableLocation &RHS)
static bool isDirectVBase(const CXXRecordDecl *Base, const CXXRecordDecl *RD)
static void PrintBasePath(const VPtrInfo::BasePath &Path, raw_ostream &Out)
static VTableLayout::AddressPointsIndexMapTy MakeAddressPointIndices(const VTableLayout::AddressPointsMapTy &addressPoints, unsigned numVTables)
static bool rebucketPaths(VPtrInfoVector &Paths)
static bool extendPath(VPtrInfo &P)
static void dumpMicrosoftThunkAdjustment(const ThunkInfo &TI, raw_ostream &Out, bool ContinueFirstLine)
static void GroupNewVirtualOverloads(const CXXRecordDecl *RD, SmallVector< const CXXMethodDecl *, 10 > &VirtualMethods)
static void computeFullPathsForVFTables(ASTContext &Context, const CXXRecordDecl *RD, VPtrInfoVector &Paths)
static bool setsIntersect(const llvm::SmallPtrSet< const CXXRecordDecl *, 4 > &A, ArrayRef< const CXXRecordDecl * > B)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
const ASTRecordLayout & getASTRecordLayout(const RecordDecl *D) const
Get or compute information about the layout of the specified record (struct/union/class) D,...
CanQualType getCanonicalType(QualType T) const
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
const LangOptions & getLangOpts() const
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
DiagnosticsEngine & getDiagnostics() const
const TargetInfo & getTargetInfo() const
CharUnits toCharUnitsFromBits(int64_t BitSize) const
Convert a size in bits to a size in characters.
ASTRecordLayout - This class contains layout information for one RecordDecl, which is a struct/union/...
bool hasOwnVFPtr() const
hasOwnVFPtr - Does this class provide its own virtual-function table pointer, rather than inheriting ...
const CXXRecordDecl * getBaseSharingVBPtr() const
bool hasOwnVBPtr() const
hasOwnVBPtr - Does this class provide its own virtual-base table pointer, rather than inheriting one ...
llvm::DenseMap< const CXXRecordDecl *, VBaseInfo > VBaseOffsetsMapTy
CharUnits getVBPtrOffset() const
getVBPtrOffset - Get the offset for virtual base table pointer.
CharUnits getBaseClassOffset(const CXXRecordDecl *Base) const
getBaseClassOffset - Get the offset, in chars, for the given base class.
CharUnits getVBaseClassOffset(const CXXRecordDecl *VBase) const
getVBaseClassOffset - Get the offset, in chars, for the given base class.
const VBaseOffsetsMapTy & getVBaseOffsetsMap() const
const CXXRecordDecl * getPrimaryBase() const
getPrimaryBase - Get the primary base for this record.
bool isPrimaryBaseVirtual() const
isPrimaryBaseVirtual - Get whether the primary base for this record is virtual or not.
const CXXRecordDecl * getBase() const
getBase - Returns the base class declaration.
CharUnits getBaseOffset() const
getBaseOffset - Returns the base class offset.
Represents a path from a specific derived class (which is not represented as part of the path) to a p...
BasePaths - Represents the set of paths from a derived class to one of its (direct or indirect) bases...
Represents a base class of a C++ class.
bool isVirtual() const
Determines whether the base class is a virtual base class (or not).
QualType getType() const
Retrieves the type of the base class.
Represents a C++ destructor within a class.
A mapping from each virtual member function to its set of final overriders.
Represents a static or instance method of a struct/union/class.
overridden_method_range overridden_methods() const
unsigned size_overridden_methods() const
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
CXXMethodDecl * getCanonicalDecl() override
Retrieves the "canonical" declaration of the given declaration.
Represents a C++ struct/union/class.
base_class_iterator bases_end()
method_range methods() const
bool isPolymorphic() const
Whether this class is polymorphic (C++ [class.virtual]), which means that the class contains or inher...
base_class_iterator bases_begin()
base_class_range vbases()
base_class_iterator vbases_begin()
bool isDynamicClass() const
void getFinalOverriders(CXXFinalOverriderMap &FinaOverriders) const
Retrieve the final overriders for each virtual member function in the class hierarchy where this clas...
unsigned getNumVBases() const
Retrieves the number of virtual base classes of this class.
bool isDerivedFrom(const CXXRecordDecl *Base) const
Determine whether this class is derived from the class Base.
CanQual< T > getUnqualifiedType() const
Retrieve the unqualified form of this type.
CanProxy< U > getAs() const
Retrieve a canonical type pointer with a different static type, upcasting or downcasting as needed.
CharUnits - This is an opaque type for sizes expressed in character units.
bool isZero() const
isZero - Test whether the quantity equals zero.
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
static CharUnits Zero()
Zero - Construct a CharUnits quantity of zero.
DeclContext * getParent()
getParent - Returns the containing DeclContext.
decl_range decls() const
decls_begin/decls_end - Iterate over the declarations stored in this context.
Decl - This represents one declaration (or definition), e.g.
ASTContext & getASTContext() const LLVM_READONLY
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
SourceLocation getLocation() const
The name of a declaration.
Concrete class used by the front-end to report problems and issues.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
unsigned getCustomDiagID(Level L, const char(&FormatString)[N])
Return an ID for a diagnostic with the specified format string and level.
bool isPure() const
Whether this virtual function is pure, i.e.
bool isImmediateFunction() const
QualType getReturnType() const
bool isDeleted() const
Whether this function has been deleted.
Represents a prototype with parameter type info, e.g.
Qualifiers getMethodQuals() const
ArrayRef< QualType > getParamTypes() const
FunctionType - C99 6.7.5.3 - Function Declarators.
QualType getReturnType() const
GlobalDecl - represents a global declaration.
GlobalDecl getCanonicalDecl() const
CXXDtorType getDtorType() const
const Decl * getDecl() const
uint64_t getMethodVTableIndex(GlobalDecl GD)
Locate a virtual function in the vtable.
std::unique_ptr< VTableLayout > createConstructionVTableLayout(const CXXRecordDecl *MostDerivedClass, CharUnits MostDerivedClassOffset, bool MostDerivedClassIsVirtual, const CXXRecordDecl *LayoutClass)
~ItaniumVTableContext() override
CharUnits getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, const CXXRecordDecl *VBase)
Return the offset in chars (relative to the vtable address point) where the offset of the virtual bas...
ItaniumVTableContext(ASTContext &Context, VTableComponentLayout ComponentLayout=Pointer)
unsigned getVBTableIndex(const CXXRecordDecl *Derived, const CXXRecordDecl *VBase)
Returns the index of VBase in the vbtable of Derived.
const VPtrInfoVector & enumerateVBTables(const CXXRecordDecl *RD)
MethodVFTableLocation getMethodVFTableLocation(GlobalDecl GD)
const VPtrInfoVector & getVFPtrOffsets(const CXXRecordDecl *RD)
const VTableLayout & getVFTableLayout(const CXXRecordDecl *RD, CharUnits VFPtrOffset)
~MicrosoftVTableContext() override
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
std::string getQualifiedNameAsString() const
void printQualifiedName(raw_ostream &OS) const
Returns a human-readable qualified name for this declaration, like A::B::i, for i being member of nam...
The set of methods that override a given virtual method in each subobject where it occurs.
PointerType - C99 6.7.5.1 - Pointer Declarators.
static std::string ComputeName(PredefinedIdentKind IK, const Decl *CurrentDecl)
A (possibly-)qualified type.
QualType getCanonicalType() const
Base for LValueReferenceType and RValueReferenceType.
bool isMicrosoft() const
Is this ABI an MSVC-compatible ABI?
uint64_t getPointerWidth(LangAS AddrSpace) const
Return the width of pointers on this target, for the specified address space.
TargetCXXABI getCXXABI() const
Get the C++ ABI currently in use.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
const T * castAs() const
Member-template castAs<specific type>.
Represents a single component in a vtable.
static VTableComponent MakeCompleteDtor(const CXXDestructorDecl *DD)
static VTableComponent MakeRTTI(const CXXRecordDecl *RD)
const CXXMethodDecl * getUnusedFunctionDecl() const
static VTableComponent MakeOffsetToTop(CharUnits Offset)
CharUnits getVBaseOffset() const
static VTableComponent MakeUnusedFunction(const CXXMethodDecl *MD)
Kind getKind() const
Get the kind of this vtable component.
static VTableComponent MakeFunction(const CXXMethodDecl *MD)
@ CK_DeletingDtorPointer
A pointer to the deleting destructor.
@ CK_UnusedFunctionPointer
An entry that is never used.
@ CK_CompleteDtorPointer
A pointer to the complete destructor.
static VTableComponent MakeVBaseOffset(CharUnits Offset)
const CXXRecordDecl * getRTTIDecl() const
static VTableComponent MakeDeletingDtor(const CXXDestructorDecl *DD)
CharUnits getOffsetToTop() const
const CXXMethodDecl * getFunctionDecl() const
static VTableComponent MakeVCallOffset(CharUnits Offset)
CharUnits getVCallOffset() const
const CXXDestructorDecl * getDestructorDecl() const
static bool hasVtableSlot(const CXXMethodDecl *MD)
Determine whether this function should be assigned a vtable slot.
ThunksMapTy Thunks
Contains all thunks that a given method decl will need.
VTableLayout(ArrayRef< size_t > VTableIndices, ArrayRef< VTableComponent > VTableComponents, ArrayRef< VTableThunkTy > VTableThunks, const AddressPointsMapTy &AddressPoints)
llvm::DenseMap< BaseSubobject, AddressPointLocation > AddressPointsMapTy
std::pair< uint64_t, ThunkInfo > VTableThunkTy
Defines the clang::TargetInfo interface.
bool Ret(InterpState &S, CodePtr &PC, APValue &Result)
@ Dtor_Complete
Complete object dtor.
@ Dtor_Deleting
Deleting dtor.
@ PrettyFunctionNoVirtual
The same as PrettyFunction, except that the 'virtual' keyword is omitted for virtual member functions...
Represents an element in a path from a derived class to a base class.
const CXXRecordDecl * VBase
If nonnull, holds the last vbase which contains the vfptr that the method definition is adjusted to.
CharUnits VFPtrOffset
This is the offset of the vfptr from the start of the last vbase, or the complete type if there are n...
union clang::ReturnAdjustment::VirtualAdjustment Virtual
int64_t NonVirtual
The non-virtual adjustment from the derived object to its nearest virtual base.
A this pointer adjustment.
union clang::ThisAdjustment::VirtualAdjustment Virtual
int64_t NonVirtual
The non-virtual adjustment from the derived object to its nearest virtual base.
The this pointer adjustment as well as an optional return adjustment for a thunk.
ThisAdjustment This
The this pointer adjustment.
const CXXMethodDecl * Method
Holds a pointer to the overridden method this thunk is for, if needed by the ABI to distinguish diffe...
ReturnAdjustment Return
The return adjustment.
Uniquely identifies a virtual method within a class hierarchy by the method itself and a class subobj...
CXXMethodDecl * Method
The overriding virtual method.
unsigned Subobject
The subobject in which the overriding virtual method resides.
const CXXRecordDecl * InVirtualSubobject
The virtual base class subobject of which this overridden virtual method is a part.
Holds information about the inheritance path to a virtual base or function table pointer.
CharUnits NonVirtualOffset
IntroducingObject is at this offset from its containing complete object or virtual base.
CharUnits FullOffsetInMDC
Static offset from the top of the most derived class to this vfptr, including any virtual base offset...
const CXXRecordDecl * getVBaseWithVPtr() const
The vptr is stored inside the non-virtual component of this virtual base.
const CXXRecordDecl * IntroducingObject
This is the class that introduced the vptr by declaring new virtual methods or virtual bases.
BasePath MangledPath
The bases from the inheritance path that got used to mangle the vbtable name.
BasePath PathToIntroducingObject
This holds the base classes path from the complete type to the first base with the given vfptr offset...
All virtual base related information about a given record decl.
VPtrInfoVector VBPtrPaths
Information on all virtual base tables used when this record is the most derived class.
llvm::DenseMap< const CXXRecordDecl *, unsigned > VBTableIndices
A map from virtual base to vbtable index for doing a conversion from the the derived class to the a b...
struct clang::ReturnAdjustment::VirtualAdjustment::@182 Itanium
struct clang::ReturnAdjustment::VirtualAdjustment::@183 Microsoft
uint32_t VBPtrOffset
The offset (in bytes) of the vbptr, relative to the beginning of the derived class.
int64_t VBaseOffsetOffset
The offset (in bytes), relative to the address point of the virtual base class offset.
uint32_t VBIndex
Index of the virtual base in the vbtable.
int32_t VtordispOffset
The offset of the vtordisp (in bytes), relative to the ECX.
int32_t VBOffsetOffset
The offset (in bytes) of the vbase offset in the vbtable.
int64_t VCallOffsetOffset
The offset (in bytes), relative to the address point, of the virtual call offset.
int32_t VBPtrOffset
The offset of the vbptr of the derived class (in bytes), relative to the ECX after vtordisp adjustmen...
struct clang::ThisAdjustment::VirtualAdjustment::@185 Microsoft
struct clang::ThisAdjustment::VirtualAdjustment::@184 Itanium