clang 22.0.0git
VTTBuilder.cpp
Go to the documentation of this file.
1//===- VTTBuilder.cpp - C++ VTT layout builder ----------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This contains code dealing with generation of the layout of virtual table
10// tables (VTT).
11//
12//===----------------------------------------------------------------------===//
13
17#include "clang/AST/CharUnits.h"
18#include "clang/AST/Decl.h"
19#include "clang/AST/DeclCXX.h"
21#include "clang/AST/Type.h"
22#include "clang/Basic/LLVM.h"
23#include <cassert>
24#include <cstdint>
25
26using namespace clang;
27
28#define DUMP_OVERRIDERS 0
29
31 const CXXRecordDecl *MostDerivedClass,
32 bool GenerateDefinition)
33 : Ctx(Ctx), MostDerivedClass(MostDerivedClass),
34 MostDerivedClassLayout(Ctx.getASTRecordLayout(MostDerivedClass)),
35 GenerateDefinition(GenerateDefinition) {
36 // Lay out this VTT.
37 LayoutVTT(BaseSubobject(MostDerivedClass, CharUnits::Zero()),
38 /*BaseIsVirtual=*/false);
39}
40
41void VTTBuilder::AddVTablePointer(BaseSubobject Base, uint64_t VTableIndex,
42 const CXXRecordDecl *VTableClass) {
43 // Store the vtable pointer index if we're generating the primary VTT.
44 if (VTableClass == MostDerivedClass) {
45 assert(!SecondaryVirtualPointerIndices.count(Base) &&
46 "A virtual pointer index already exists for this base subobject!");
47 SecondaryVirtualPointerIndices[Base] = VTTComponents.size();
48 }
49
50 if (!GenerateDefinition) {
51 VTTComponents.push_back(VTTComponent());
52 return;
53 }
54
55 VTTComponents.push_back(VTTComponent(VTableIndex, Base));
56}
57
58void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) {
59 const CXXRecordDecl *RD = Base.getBase();
60
61 for (const auto &I : RD->bases()) {
62 // Don't layout virtual bases.
63 if (I.isVirtual())
64 continue;
65
66 const auto *BaseDecl = I.getType()->castAsCXXRecordDecl();
67 const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
68 CharUnits BaseOffset = Base.getBaseOffset() +
69 Layout.getBaseClassOffset(BaseDecl);
70
71 // Layout the VTT for this base.
72 LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/false);
73 }
74}
75
76void
77VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
78 bool BaseIsMorallyVirtual,
79 uint64_t VTableIndex,
80 const CXXRecordDecl *VTableClass,
81 VisitedVirtualBasesSetTy &VBases) {
82 const CXXRecordDecl *RD = Base.getBase();
83
84 // We're not interested in bases that don't have virtual bases, and not
85 // morally virtual bases.
86 if (!RD->getNumVBases() && !BaseIsMorallyVirtual)
87 return;
88
89 for (const auto &I : RD->bases()) {
90 const auto *BaseDecl = I.getType()->castAsCXXRecordDecl();
91
92 // Itanium C++ ABI 2.6.2:
93 // Secondary virtual pointers are present for all bases with either
94 // virtual bases or virtual function declarations overridden along a
95 // virtual path.
96 //
97 // If the base class is not dynamic, we don't want to add it, nor any
98 // of its base classes.
99 if (!BaseDecl->isDynamicClass())
100 continue;
101
102 bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual;
103 bool BaseDeclIsNonVirtualPrimaryBase = false;
104 CharUnits BaseOffset;
105 if (I.isVirtual()) {
106 // Ignore virtual bases that we've already visited.
107 if (!VBases.insert(BaseDecl).second)
108 continue;
109
110 BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
111 BaseDeclIsMorallyVirtual = true;
112 } else {
113 const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
114
115 BaseOffset = Base.getBaseOffset() +
116 Layout.getBaseClassOffset(BaseDecl);
117
118 if (!Layout.isPrimaryBaseVirtual() &&
119 Layout.getPrimaryBase() == BaseDecl)
120 BaseDeclIsNonVirtualPrimaryBase = true;
121 }
122
123 // Itanium C++ ABI 2.6.2:
124 // Secondary virtual pointers: for each base class X which (a) has virtual
125 // bases or is reachable along a virtual path from D, and (b) is not a
126 // non-virtual primary base, the address of the virtual table for X-in-D
127 // or an appropriate construction virtual table.
128 if (!BaseDeclIsNonVirtualPrimaryBase &&
129 (BaseDecl->getNumVBases() || BaseDeclIsMorallyVirtual)) {
130 // Add the vtable pointer.
131 AddVTablePointer(BaseSubobject(BaseDecl, BaseOffset), VTableIndex,
132 VTableClass);
133 }
134
135 // And lay out the secondary virtual pointers for the base class.
136 LayoutSecondaryVirtualPointers(BaseSubobject(BaseDecl, BaseOffset),
137 BaseDeclIsMorallyVirtual, VTableIndex,
138 VTableClass, VBases);
139 }
140}
141
142void
143VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
144 uint64_t VTableIndex) {
145 VisitedVirtualBasesSetTy VBases;
146 LayoutSecondaryVirtualPointers(Base, /*BaseIsMorallyVirtual=*/false,
147 VTableIndex, Base.getBase(), VBases);
148}
149
150void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD,
151 VisitedVirtualBasesSetTy &VBases) {
152 for (const auto &I : RD->bases()) {
153 const auto *BaseDecl = I.getType()->castAsCXXRecordDecl();
154
155 // Check if this is a virtual base.
156 if (I.isVirtual()) {
157 // Check if we've seen this base before.
158 if (!VBases.insert(BaseDecl).second)
159 continue;
160
161 CharUnits BaseOffset =
162 MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
163
164 LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/true);
165 }
166
167 // We only need to layout virtual VTTs for this base if it actually has
168 // virtual bases.
169 if (BaseDecl->getNumVBases())
170 LayoutVirtualVTTs(BaseDecl, VBases);
171 }
172}
173
174void VTTBuilder::LayoutVTT(BaseSubobject Base, bool BaseIsVirtual) {
175 const CXXRecordDecl *RD = Base.getBase();
176
177 // Itanium C++ ABI 2.6.2:
178 // An array of virtual table addresses, called the VTT, is declared for
179 // each class type that has indirect or direct virtual base classes.
180 if (RD->getNumVBases() == 0)
181 return;
182
183 bool IsPrimaryVTT = Base.getBase() == MostDerivedClass;
184
185 if (!IsPrimaryVTT) {
186 // Remember the sub-VTT index.
187 SubVTTIndices[Base] = VTTComponents.size();
188 }
189
190 uint64_t VTableIndex = VTTVTables.size();
191 VTTVTables.push_back(VTTVTable(Base, BaseIsVirtual));
192
193 // Add the primary vtable pointer.
194 AddVTablePointer(Base, VTableIndex, RD);
195
196 // Add the secondary VTTs.
197 LayoutSecondaryVTTs(Base);
198
199 // Add the secondary virtual pointers.
200 LayoutSecondaryVirtualPointers(Base, VTableIndex);
201
202 // If this is the primary VTT, we want to lay out virtual VTTs as well.
203 if (IsPrimaryVTT) {
204 VisitedVirtualBasesSetTy VBases;
205 LayoutVirtualVTTs(Base.getBase(), VBases);
206 }
207}
Defines the clang::ASTContext interface.
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
C Language Family Type Representation.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:188
CharUnits getBaseClassOffset(const CXXRecordDecl *Base) const
getBaseClassOffset - Get the offset, in chars, for the given base class.
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.
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
base_class_range bases()
Definition DeclCXX.h:608
unsigned getNumVBases() const
Retrieves the number of virtual base classes of this class.
Definition DeclCXX.h:623
static CharUnits Zero()
Zero - Construct a CharUnits quantity of zero.
Definition CharUnits.h:53
VTTBuilder(ASTContext &Ctx, const CXXRecordDecl *MostDerivedClass, bool GenerateDefinition)
The JSON file list parser is used to communicate input to InstallAPI.
unsigned long uint64_t