void SwiftAggLowering::addTypedData(const RecordDecl *record, CharUnits begin, const ASTRecordLayout &layout) { // Unions are a special case. if (record->isUnion()) { for (auto field : record->fields()) { if (field->isBitField()) { addBitFieldData(field, begin, 0); } else { addTypedData(field->getType(), begin); } } return; } // Note that correctness does not rely on us adding things in // their actual order of layout; it's just somewhat more efficient // for the builder. // With that in mind, add "early" C++ data. auto cxxRecord = dyn_cast<CXXRecordDecl>(record); if (cxxRecord) { // - a v-table pointer, if the class adds its own if (layout.hasOwnVFPtr()) { addTypedData(CGM.Int8PtrTy, begin); } // - non-virtual bases for (auto &baseSpecifier : cxxRecord->bases()) { if (baseSpecifier.isVirtual()) continue; auto baseRecord = baseSpecifier.getType()->getAsCXXRecordDecl(); addTypedData(baseRecord, begin + layout.getBaseClassOffset(baseRecord)); } // - a vbptr if the class adds its own if (layout.hasOwnVBPtr()) { addTypedData(CGM.Int8PtrTy, begin + layout.getVBPtrOffset()); } } // Add fields. for (auto field : record->fields()) { auto fieldOffsetInBits = layout.getFieldOffset(field->getFieldIndex()); if (field->isBitField()) { addBitFieldData(field, begin, fieldOffsetInBits); } else { addTypedData(field->getType(), begin + CGM.getContext().toCharUnitsFromBits(fieldOffsetInBits)); } } // Add "late" C++ data: if (cxxRecord) { // - virtual bases for (auto &vbaseSpecifier : cxxRecord->vbases()) { auto baseRecord = vbaseSpecifier.getType()->getAsCXXRecordDecl(); addTypedData(baseRecord, begin + layout.getVBaseClassOffset(baseRecord)); } } }
bool CGRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout) { const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); // If we have a primary base, lay it out first. if (PrimaryBase) { if (!Layout.isPrimaryBaseVirtual()) { if (!LayoutNonVirtualBase(PrimaryBase, CharUnits::Zero())) return false; } else { if (!LayoutVirtualBase(PrimaryBase, CharUnits::Zero())) return false; } // Otherwise, add a vtable / vf-table if the layout says to do so. } else if (Layout.hasOwnVFPtr()) { llvm::Type *FunctionType = llvm::FunctionType::get(llvm::Type::getInt32Ty(Types.getLLVMContext()), /*isVarArg=*/true); llvm::Type *VTableTy = FunctionType->getPointerTo(); if (getTypeAlignment(VTableTy) > Alignment) { // FIXME: Should we allow this to happen in Sema? assert(!Packed && "Alignment is wrong even with packed struct!"); return false; } assert(NextFieldOffset.isZero() && "VTable pointer must come first!"); AppendField(CharUnits::Zero(), VTableTy->getPointerTo()); } // Layout the non-virtual bases. for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { if (I->isVirtual()) continue; const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); // We've already laid out the primary base. if (BaseDecl == PrimaryBase && !Layout.isPrimaryBaseVirtual()) continue; if (!LayoutNonVirtualBase(BaseDecl, Layout.getBaseClassOffset(BaseDecl))) return false; } // Add a vb-table pointer if the layout insists. if (Layout.hasOwnVBPtr()) { CharUnits VBPtrOffset = Layout.getVBPtrOffset(); llvm::Type *Vbptr = llvm::Type::getInt32PtrTy(Types.getLLVMContext()); AppendPadding(VBPtrOffset, getTypeAlignment(Vbptr)); AppendField(VBPtrOffset, Vbptr); } return true; }