void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) { const CXXRecordDecl *RD = Base.getBase(); for (const auto &I : RD->bases()) { // Don't layout virtual bases. if (I.isVirtual()) continue; const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl()); const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); CharUnits BaseOffset = Base.getBaseOffset() + Layout.getBaseClassOffset(BaseDecl); // Layout the VTT for this base. LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/false); } }
void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) { const CXXRecordDecl *RD = Base.getBase(); for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { // Don't layout virtual bases. if (I->isVirtual()) continue; const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); CharUnits BaseOffset = Base.getBaseOffset() + Layout.getBaseClassOffset(BaseDecl); // Layout the VTT for this base. LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/false); } }
void VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base, bool BaseIsMorallyVirtual, uint64_t VTableIndex, const CXXRecordDecl *VTableClass, VisitedVirtualBasesSetTy &VBases) { const CXXRecordDecl *RD = Base.getBase(); // We're not interested in bases that don't have virtual bases, and not // morally virtual bases. if (!RD->getNumVBases() && !BaseIsMorallyVirtual) return; for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); // Itanium C++ ABI 2.6.2: // Secondary virtual pointers are present for all bases with either // virtual bases or virtual function declarations overridden along a // virtual path. // // If the base class is not dynamic, we don't want to add it, nor any // of its base classes. if (!BaseDecl->isDynamicClass()) continue; bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual; bool BaseDeclIsNonVirtualPrimaryBase = false; CharUnits BaseOffset; if (I->isVirtual()) { // Ignore virtual bases that we've already visited. if (!VBases.insert(BaseDecl)) continue; BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); BaseDeclIsMorallyVirtual = true; } else { const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); BaseOffset = Base.getBaseOffset() + Layout.getBaseClassOffset(BaseDecl); if (!Layout.isPrimaryBaseVirtual() && Layout.getPrimaryBase() == BaseDecl) BaseDeclIsNonVirtualPrimaryBase = true; } // Itanium C++ ABI 2.6.2: // Secondary virtual pointers: for each base class X which (a) has virtual // bases or is reachable along a virtual path from D, and (b) is not a // non-virtual primary base, the address of the virtual table for X-in-D // or an appropriate construction virtual table. if (!BaseDeclIsNonVirtualPrimaryBase && (BaseDecl->getNumVBases() || BaseDeclIsMorallyVirtual)) { // Add the vtable pointer. AddVTablePointer(BaseSubobject(BaseDecl, BaseOffset), VTableIndex, VTableClass); } // And lay out the secondary virtual pointers for the base class. LayoutSecondaryVirtualPointers(BaseSubobject(BaseDecl, BaseOffset), BaseDeclIsMorallyVirtual, VTableIndex, VTableClass, VBases); } }
void VBTableBuilder::findUnambiguousPaths(const CXXRecordDecl *ReusingBase, BaseSubobject CurSubobject, VBTablePathVector &Paths) { size_t PathsStart = Paths.size(); bool ReuseVBPtrFromBase = true; const CXXRecordDecl *CurBase = CurSubobject.getBase(); // If this base has a vbptr, then we've found a path. These are not full // paths, so we don't use CXXBasePath. if (hasVBPtr(CurBase)) { ReuseVBPtrFromBase = false; VBTablePath *Info = new VBTablePath( VBTableInfo(ReusingBase, CurSubobject, /*GV=*/0)); Paths.push_back(Info); } // Recurse onto any bases which themselves have virtual bases. const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(CurBase); for (CXXRecordDecl::base_class_const_iterator I = CurBase->bases_begin(), E = CurBase->bases_end(); I != E; ++I) { const CXXRecordDecl *Base = I->getType()->getAsCXXRecordDecl(); if (!Base->getNumVBases()) continue; // Bases without virtual bases have no vbptrs. CharUnits NextOffset; const CXXRecordDecl *NextReusingBase = Base; if (I->isVirtual()) { if (!VBasesSeen.insert(Base)) continue; // Don't visit virtual bases twice. NextOffset = DerivedLayout.getVBaseClassOffset(Base); } else { NextOffset = (CurSubobject.getBaseOffset() + Layout.getBaseClassOffset(Base)); // If CurBase didn't have a vbptr, then ReusingBase will reuse the vbptr // from the first non-virtual base with vbases for its vbptr. if (ReuseVBPtrFromBase) { NextReusingBase = ReusingBase; ReuseVBPtrFromBase = false; } } size_t NumPaths = Paths.size(); findUnambiguousPaths(NextReusingBase, BaseSubobject(Base, NextOffset), Paths); // Tag paths through this base with the base itself. We might use it to // disambiguate. for (size_t I = NumPaths, E = Paths.size(); I != E; ++I) Paths[I]->NextBase = Base; } bool AmbiguousPaths = rebucketPaths(Paths, PathsStart); if (AmbiguousPaths) rebucketPaths(Paths, PathsStart, /*SecondPass=*/true); #ifndef NDEBUG // Check that the paths are in fact unique. for (size_t I = PathsStart + 1, E = Paths.size(); I != E; ++I) { assert(Paths[I]->Path != Paths[I - 1]->Path && "vbtable paths are not unique"); } #endif }