xref: /freebsd/contrib/llvm-project/clang/lib/AST/VTTBuilder.cpp (revision 723da5d92f40a413585107f8455280ea575fe410)
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"
16  #include "clang/AST/BaseSubobject.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  
31  VTTBuilder::VTTBuilder(ASTContext &Ctx,
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  }
213