clang  19.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 
14 #include "clang/AST/VTTBuilder.h"
15 #include "clang/AST/ASTContext.h"
17 #include "clang/AST/CharUnits.h"
18 #include "clang/AST/Decl.h"
19 #include "clang/AST/DeclCXX.h"
20 #include "clang/AST/RecordLayout.h"
21 #include "clang/AST/Type.h"
22 #include "clang/Basic/LLVM.h"
23 #include "llvm/Support/Casting.h"
24 #include <cassert>
25 #include <cstdint>
26 
27 using namespace clang;
28 
29 #define DUMP_OVERRIDERS 0
30 
32  const CXXRecordDecl *MostDerivedClass,
33  bool GenerateDefinition)
34  : Ctx(Ctx), MostDerivedClass(MostDerivedClass),
35  MostDerivedClassLayout(Ctx.getASTRecordLayout(MostDerivedClass)),
36  GenerateDefinition(GenerateDefinition) {
37  // Lay out this VTT.
38  LayoutVTT(BaseSubobject(MostDerivedClass, CharUnits::Zero()),
39  /*BaseIsVirtual=*/false);
40 }
41 
42 void VTTBuilder::AddVTablePointer(BaseSubobject Base, uint64_t VTableIndex,
43  const CXXRecordDecl *VTableClass) {
44  // Store the vtable pointer index if we're generating the primary VTT.
45  if (VTableClass == MostDerivedClass) {
46  assert(!SecondaryVirtualPointerIndices.count(Base) &&
47  "A virtual pointer index already exists for this base subobject!");
48  SecondaryVirtualPointerIndices[Base] = VTTComponents.size();
49  }
50 
51  if (!GenerateDefinition) {
52  VTTComponents.push_back(VTTComponent());
53  return;
54  }
55 
56  VTTComponents.push_back(VTTComponent(VTableIndex, Base));
57 }
58 
59 void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) {
60  const CXXRecordDecl *RD = Base.getBase();
61 
62  for (const auto &I : RD->bases()) {
63  // Don't layout virtual bases.
64  if (I.isVirtual())
65  continue;
66 
67  const auto *BaseDecl =
68  cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
69 
70  const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
71  CharUnits BaseOffset = Base.getBaseOffset() +
72  Layout.getBaseClassOffset(BaseDecl);
73 
74  // Layout the VTT for this base.
75  LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/false);
76  }
77 }
78 
79 void
80 VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
81  bool BaseIsMorallyVirtual,
82  uint64_t VTableIndex,
83  const CXXRecordDecl *VTableClass,
84  VisitedVirtualBasesSetTy &VBases) {
85  const CXXRecordDecl *RD = Base.getBase();
86 
87  // We're not interested in bases that don't have virtual bases, and not
88  // morally virtual bases.
89  if (!RD->getNumVBases() && !BaseIsMorallyVirtual)
90  return;
91 
92  for (const auto &I : RD->bases()) {
93  const auto *BaseDecl =
94  cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
95 
96  // Itanium C++ ABI 2.6.2:
97  // Secondary virtual pointers are present for all bases with either
98  // virtual bases or virtual function declarations overridden along a
99  // virtual path.
100  //
101  // If the base class is not dynamic, we don't want to add it, nor any
102  // of its base classes.
103  if (!BaseDecl->isDynamicClass())
104  continue;
105 
106  bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual;
107  bool BaseDeclIsNonVirtualPrimaryBase = false;
108  CharUnits BaseOffset;
109  if (I.isVirtual()) {
110  // Ignore virtual bases that we've already visited.
111  if (!VBases.insert(BaseDecl).second)
112  continue;
113 
114  BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
115  BaseDeclIsMorallyVirtual = true;
116  } else {
117  const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
118 
119  BaseOffset = Base.getBaseOffset() +
120  Layout.getBaseClassOffset(BaseDecl);
121 
122  if (!Layout.isPrimaryBaseVirtual() &&
123  Layout.getPrimaryBase() == BaseDecl)
124  BaseDeclIsNonVirtualPrimaryBase = true;
125  }
126 
127  // Itanium C++ ABI 2.6.2:
128  // Secondary virtual pointers: for each base class X which (a) has virtual
129  // bases or is reachable along a virtual path from D, and (b) is not a
130  // non-virtual primary base, the address of the virtual table for X-in-D
131  // or an appropriate construction virtual table.
132  if (!BaseDeclIsNonVirtualPrimaryBase &&
133  (BaseDecl->getNumVBases() || BaseDeclIsMorallyVirtual)) {
134  // Add the vtable pointer.
135  AddVTablePointer(BaseSubobject(BaseDecl, BaseOffset), VTableIndex,
136  VTableClass);
137  }
138 
139  // And lay out the secondary virtual pointers for the base class.
140  LayoutSecondaryVirtualPointers(BaseSubobject(BaseDecl, BaseOffset),
141  BaseDeclIsMorallyVirtual, VTableIndex,
142  VTableClass, VBases);
143  }
144 }
145 
146 void
147 VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
148  uint64_t VTableIndex) {
149  VisitedVirtualBasesSetTy VBases;
150  LayoutSecondaryVirtualPointers(Base, /*BaseIsMorallyVirtual=*/false,
151  VTableIndex, Base.getBase(), VBases);
152 }
153 
154 void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD,
155  VisitedVirtualBasesSetTy &VBases) {
156  for (const auto &I : RD->bases()) {
157  const auto *BaseDecl =
158  cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
159 
160  // Check if this is a virtual base.
161  if (I.isVirtual()) {
162  // Check if we've seen this base before.
163  if (!VBases.insert(BaseDecl).second)
164  continue;
165 
166  CharUnits BaseOffset =
167  MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
168 
169  LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/true);
170  }
171 
172  // We only need to layout virtual VTTs for this base if it actually has
173  // virtual bases.
174  if (BaseDecl->getNumVBases())
175  LayoutVirtualVTTs(BaseDecl, VBases);
176  }
177 }
178 
179 void VTTBuilder::LayoutVTT(BaseSubobject Base, bool BaseIsVirtual) {
180  const CXXRecordDecl *RD = Base.getBase();
181 
182  // Itanium C++ ABI 2.6.2:
183  // An array of virtual table addresses, called the VTT, is declared for
184  // each class type that has indirect or direct virtual base classes.
185  if (RD->getNumVBases() == 0)
186  return;
187 
188  bool IsPrimaryVTT = Base.getBase() == MostDerivedClass;
189 
190  if (!IsPrimaryVTT) {
191  // Remember the sub-VTT index.
192  SubVTTIndices[Base] = VTTComponents.size();
193  }
194 
195  uint64_t VTableIndex = VTTVTables.size();
196  VTTVTables.push_back(VTTVTable(Base, BaseIsVirtual));
197 
198  // Add the primary vtable pointer.
199  AddVTablePointer(Base, VTableIndex, RD);
200 
201  // Add the secondary VTTs.
202  LayoutSecondaryVTTs(Base);
203 
204  // Add the secondary virtual pointers.
205  LayoutSecondaryVirtualPointers(Base, VTableIndex);
206 
207  // If this is the primary VTT, we want to lay out virtual VTTs as well.
208  if (IsPrimaryVTT) {
209  VisitedVirtualBasesSetTy VBases;
210  LayoutVirtualVTTs(Base.getBase(), VBases);
211  }
212 }
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:185
const ASTRecordLayout & getASTRecordLayout(const RecordDecl *D) const
Get or compute information about the layout of the specified record (struct/union/class) D,...
ASTRecordLayout - This class contains layout information for one RecordDecl, which is a struct/union/...
Definition: RecordLayout.h:38
const CXXRecordDecl * getPrimaryBase() const
getPrimaryBase - Get the primary base for this record.
Definition: RecordLayout.h:234
CharUnits getBaseClassOffset(const CXXRecordDecl *Base) const
getBaseClassOffset - Get the offset, in chars, for the given base class.
Definition: RecordLayout.h:249
CharUnits getVBaseClassOffset(const CXXRecordDecl *VBase) const
getVBaseClassOffset - Get the offset, in chars, for the given base class.
Definition: RecordLayout.h:259
bool isPrimaryBaseVirtual() const
isPrimaryBaseVirtual - Get whether the primary base for this record is virtual or not.
Definition: RecordLayout.h:242
Represents a C++ struct/union/class.
Definition: DeclCXX.h:258
base_class_range bases()
Definition: DeclCXX.h:619
unsigned getNumVBases() const
Retrieves the number of virtual base classes of this class.
Definition: DeclCXX.h:634
CharUnits - This is an opaque type for sizes expressed in character units.
Definition: CharUnits.h:38
static CharUnits Zero()
Zero - Construct a CharUnits quantity of zero.
Definition: CharUnits.h:53
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
Definition: Type.h:5561
RecordDecl * getDecl() const
Definition: Type.h:5571
VTTBuilder(ASTContext &Ctx, const CXXRecordDecl *MostDerivedClass, bool GenerateDefinition)
Definition: VTTBuilder.cpp:31
The JSON file list parser is used to communicate input to InstallAPI.
unsigned long uint64_t