xref: /freebsd-src/contrib/llvm-project/clang/lib/AST/VTTBuilder.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===- VTTBuilder.cpp - C++ VTT layout builder ----------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This contains code dealing with generation of the layout of virtual table
100b57cec5SDimitry Andric // tables (VTT).
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "clang/AST/VTTBuilder.h"
150b57cec5SDimitry Andric #include "clang/AST/ASTContext.h"
160b57cec5SDimitry Andric #include "clang/AST/BaseSubobject.h"
170b57cec5SDimitry Andric #include "clang/AST/CharUnits.h"
180b57cec5SDimitry Andric #include "clang/AST/Decl.h"
190b57cec5SDimitry Andric #include "clang/AST/DeclCXX.h"
200b57cec5SDimitry Andric #include "clang/AST/RecordLayout.h"
210b57cec5SDimitry Andric #include "clang/AST/Type.h"
220b57cec5SDimitry Andric #include "clang/Basic/LLVM.h"
230b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
240b57cec5SDimitry Andric #include <cassert>
250b57cec5SDimitry Andric #include <cstdint>
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric using namespace clang;
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric #define DUMP_OVERRIDERS 0
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric VTTBuilder::VTTBuilder(ASTContext &Ctx,
320b57cec5SDimitry Andric                        const CXXRecordDecl *MostDerivedClass,
330b57cec5SDimitry Andric                        bool GenerateDefinition)
340b57cec5SDimitry Andric     : Ctx(Ctx), MostDerivedClass(MostDerivedClass),
350b57cec5SDimitry Andric       MostDerivedClassLayout(Ctx.getASTRecordLayout(MostDerivedClass)),
360b57cec5SDimitry Andric       GenerateDefinition(GenerateDefinition) {
370b57cec5SDimitry Andric   // Lay out this VTT.
380b57cec5SDimitry Andric   LayoutVTT(BaseSubobject(MostDerivedClass, CharUnits::Zero()),
390b57cec5SDimitry Andric             /*BaseIsVirtual=*/false);
400b57cec5SDimitry Andric }
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric void VTTBuilder::AddVTablePointer(BaseSubobject Base, uint64_t VTableIndex,
430b57cec5SDimitry Andric                                   const CXXRecordDecl *VTableClass) {
440b57cec5SDimitry Andric   // Store the vtable pointer index if we're generating the primary VTT.
450b57cec5SDimitry Andric   if (VTableClass == MostDerivedClass) {
460b57cec5SDimitry Andric     assert(!SecondaryVirtualPointerIndices.count(Base) &&
470b57cec5SDimitry Andric            "A virtual pointer index already exists for this base subobject!");
480b57cec5SDimitry Andric     SecondaryVirtualPointerIndices[Base] = VTTComponents.size();
490b57cec5SDimitry Andric   }
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric   if (!GenerateDefinition) {
520b57cec5SDimitry Andric     VTTComponents.push_back(VTTComponent());
530b57cec5SDimitry Andric     return;
540b57cec5SDimitry Andric   }
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric   VTTComponents.push_back(VTTComponent(VTableIndex, Base));
570b57cec5SDimitry Andric }
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) {
600b57cec5SDimitry Andric   const CXXRecordDecl *RD = Base.getBase();
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric   for (const auto &I : RD->bases()) {
630b57cec5SDimitry Andric     // Don't layout virtual bases.
640b57cec5SDimitry Andric     if (I.isVirtual())
650b57cec5SDimitry Andric         continue;
660b57cec5SDimitry Andric 
67a7dea167SDimitry Andric     const auto *BaseDecl =
68a7dea167SDimitry Andric         cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric     const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
710b57cec5SDimitry Andric     CharUnits BaseOffset = Base.getBaseOffset() +
720b57cec5SDimitry Andric       Layout.getBaseClassOffset(BaseDecl);
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric     // Layout the VTT for this base.
750b57cec5SDimitry Andric     LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/false);
760b57cec5SDimitry Andric   }
770b57cec5SDimitry Andric }
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric void
800b57cec5SDimitry Andric VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
810b57cec5SDimitry Andric                                            bool BaseIsMorallyVirtual,
820b57cec5SDimitry Andric                                            uint64_t VTableIndex,
830b57cec5SDimitry Andric                                            const CXXRecordDecl *VTableClass,
840b57cec5SDimitry Andric                                            VisitedVirtualBasesSetTy &VBases) {
850b57cec5SDimitry Andric   const CXXRecordDecl *RD = Base.getBase();
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric   // We're not interested in bases that don't have virtual bases, and not
880b57cec5SDimitry Andric   // morally virtual bases.
890b57cec5SDimitry Andric   if (!RD->getNumVBases() && !BaseIsMorallyVirtual)
900b57cec5SDimitry Andric     return;
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric   for (const auto &I : RD->bases()) {
93a7dea167SDimitry Andric     const auto *BaseDecl =
94a7dea167SDimitry Andric         cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric     // Itanium C++ ABI 2.6.2:
970b57cec5SDimitry Andric     //   Secondary virtual pointers are present for all bases with either
980b57cec5SDimitry Andric     //   virtual bases or virtual function declarations overridden along a
990b57cec5SDimitry Andric     //   virtual path.
1000b57cec5SDimitry Andric     //
1010b57cec5SDimitry Andric     // If the base class is not dynamic, we don't want to add it, nor any
1020b57cec5SDimitry Andric     // of its base classes.
1030b57cec5SDimitry Andric     if (!BaseDecl->isDynamicClass())
1040b57cec5SDimitry Andric       continue;
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric     bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual;
1070b57cec5SDimitry Andric     bool BaseDeclIsNonVirtualPrimaryBase = false;
1080b57cec5SDimitry Andric     CharUnits BaseOffset;
1090b57cec5SDimitry Andric     if (I.isVirtual()) {
1100b57cec5SDimitry Andric       // Ignore virtual bases that we've already visited.
1110b57cec5SDimitry Andric       if (!VBases.insert(BaseDecl).second)
1120b57cec5SDimitry Andric         continue;
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric       BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
1150b57cec5SDimitry Andric       BaseDeclIsMorallyVirtual = true;
1160b57cec5SDimitry Andric     } else {
1170b57cec5SDimitry Andric       const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric       BaseOffset = Base.getBaseOffset() +
1200b57cec5SDimitry Andric         Layout.getBaseClassOffset(BaseDecl);
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric       if (!Layout.isPrimaryBaseVirtual() &&
1230b57cec5SDimitry Andric           Layout.getPrimaryBase() == BaseDecl)
1240b57cec5SDimitry Andric         BaseDeclIsNonVirtualPrimaryBase = true;
1250b57cec5SDimitry Andric     }
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric     // Itanium C++ ABI 2.6.2:
1280b57cec5SDimitry Andric     //   Secondary virtual pointers: for each base class X which (a) has virtual
1290b57cec5SDimitry Andric     //   bases or is reachable along a virtual path from D, and (b) is not a
1300b57cec5SDimitry Andric     //   non-virtual primary base, the address of the virtual table for X-in-D
1310b57cec5SDimitry Andric     //   or an appropriate construction virtual table.
1320b57cec5SDimitry Andric     if (!BaseDeclIsNonVirtualPrimaryBase &&
1330b57cec5SDimitry Andric         (BaseDecl->getNumVBases() || BaseDeclIsMorallyVirtual)) {
1340b57cec5SDimitry Andric       // Add the vtable pointer.
1350b57cec5SDimitry Andric       AddVTablePointer(BaseSubobject(BaseDecl, BaseOffset), VTableIndex,
1360b57cec5SDimitry Andric                        VTableClass);
1370b57cec5SDimitry Andric     }
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric     // And lay out the secondary virtual pointers for the base class.
1400b57cec5SDimitry Andric     LayoutSecondaryVirtualPointers(BaseSubobject(BaseDecl, BaseOffset),
1410b57cec5SDimitry Andric                                    BaseDeclIsMorallyVirtual, VTableIndex,
1420b57cec5SDimitry Andric                                    VTableClass, VBases);
1430b57cec5SDimitry Andric   }
1440b57cec5SDimitry Andric }
1450b57cec5SDimitry Andric 
1460b57cec5SDimitry Andric void
1470b57cec5SDimitry Andric VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
1480b57cec5SDimitry Andric                                            uint64_t VTableIndex) {
1490b57cec5SDimitry Andric   VisitedVirtualBasesSetTy VBases;
1500b57cec5SDimitry Andric   LayoutSecondaryVirtualPointers(Base, /*BaseIsMorallyVirtual=*/false,
1510b57cec5SDimitry Andric                                  VTableIndex, Base.getBase(), VBases);
1520b57cec5SDimitry Andric }
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD,
1550b57cec5SDimitry Andric                                    VisitedVirtualBasesSetTy &VBases) {
1560b57cec5SDimitry Andric   for (const auto &I : RD->bases()) {
157a7dea167SDimitry Andric     const auto *BaseDecl =
158a7dea167SDimitry Andric         cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric     // Check if this is a virtual base.
1610b57cec5SDimitry Andric     if (I.isVirtual()) {
1620b57cec5SDimitry Andric       // Check if we've seen this base before.
1630b57cec5SDimitry Andric       if (!VBases.insert(BaseDecl).second)
1640b57cec5SDimitry Andric         continue;
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric       CharUnits BaseOffset =
1670b57cec5SDimitry Andric         MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
1680b57cec5SDimitry Andric 
1690b57cec5SDimitry Andric       LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/true);
1700b57cec5SDimitry Andric     }
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric     // We only need to layout virtual VTTs for this base if it actually has
1730b57cec5SDimitry Andric     // virtual bases.
1740b57cec5SDimitry Andric     if (BaseDecl->getNumVBases())
1750b57cec5SDimitry Andric       LayoutVirtualVTTs(BaseDecl, VBases);
1760b57cec5SDimitry Andric   }
1770b57cec5SDimitry Andric }
1780b57cec5SDimitry Andric 
1790b57cec5SDimitry Andric void VTTBuilder::LayoutVTT(BaseSubobject Base, bool BaseIsVirtual) {
1800b57cec5SDimitry Andric   const CXXRecordDecl *RD = Base.getBase();
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric   // Itanium C++ ABI 2.6.2:
1830b57cec5SDimitry Andric   //   An array of virtual table addresses, called the VTT, is declared for
1840b57cec5SDimitry Andric   //   each class type that has indirect or direct virtual base classes.
1850b57cec5SDimitry Andric   if (RD->getNumVBases() == 0)
1860b57cec5SDimitry Andric     return;
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric   bool IsPrimaryVTT = Base.getBase() == MostDerivedClass;
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric   if (!IsPrimaryVTT) {
1910b57cec5SDimitry Andric     // Remember the sub-VTT index.
192*0fca6ea1SDimitry Andric     SubVTTIndices[Base] = VTTComponents.size();
1930b57cec5SDimitry Andric   }
1940b57cec5SDimitry Andric 
1950b57cec5SDimitry Andric   uint64_t VTableIndex = VTTVTables.size();
1960b57cec5SDimitry Andric   VTTVTables.push_back(VTTVTable(Base, BaseIsVirtual));
1970b57cec5SDimitry Andric 
1980b57cec5SDimitry Andric   // Add the primary vtable pointer.
1990b57cec5SDimitry Andric   AddVTablePointer(Base, VTableIndex, RD);
2000b57cec5SDimitry Andric 
2010b57cec5SDimitry Andric   // Add the secondary VTTs.
2020b57cec5SDimitry Andric   LayoutSecondaryVTTs(Base);
2030b57cec5SDimitry Andric 
2040b57cec5SDimitry Andric   // Add the secondary virtual pointers.
2050b57cec5SDimitry Andric   LayoutSecondaryVirtualPointers(Base, VTableIndex);
2060b57cec5SDimitry Andric 
2070b57cec5SDimitry Andric   // If this is the primary VTT, we want to lay out virtual VTTs as well.
2080b57cec5SDimitry Andric   if (IsPrimaryVTT) {
2090b57cec5SDimitry Andric     VisitedVirtualBasesSetTy VBases;
2100b57cec5SDimitry Andric     LayoutVirtualVTTs(Base.getBase(), VBases);
2110b57cec5SDimitry Andric   }
2120b57cec5SDimitry Andric }
213