void VBTableInfo::EmitVBTableDefinition( CodeGenModule &CGM, const CXXRecordDecl *RD, llvm::GlobalVariable::LinkageTypes Linkage) const { assert(RD->getNumVBases() && ReusingBase->getNumVBases() && "should only emit vbtables for classes with vbtables"); const ASTRecordLayout &BaseLayout = CGM.getContext().getASTRecordLayout(VBPtrSubobject.getBase()); const ASTRecordLayout &DerivedLayout = CGM.getContext().getASTRecordLayout(RD); SmallVector<llvm::Constant *, 4> Offsets; // The offset from ReusingBase's vbptr to itself always leads. CharUnits VBPtrOffset = BaseLayout.getVBPtrOffset(); Offsets.push_back( llvm::ConstantInt::get(CGM.IntTy, -VBPtrOffset.getQuantity())); // These are laid out in the same order as in Itanium, which is the same as // the order of the vbase iterator. for (CXXRecordDecl::base_class_const_iterator I = ReusingBase->vbases_begin(), E = ReusingBase->vbases_end(); I != E; ++I) { const CXXRecordDecl *VBase = I->getType()->getAsCXXRecordDecl(); CharUnits Offset = DerivedLayout.getVBaseClassOffset(VBase); assert(!Offset.isNegative()); // Make it relative to the subobject vbptr. Offset -= VBPtrSubobject.getBaseOffset() + VBPtrOffset; Offsets.push_back(llvm::ConstantInt::get(CGM.IntTy, Offset.getQuantity())); } assert(Offsets.size() == cast<llvm::ArrayType>(cast<llvm::PointerType>(GV->getType()) ->getElementType())->getNumElements()); llvm::ArrayType *VBTableType = llvm::ArrayType::get(CGM.IntTy, Offsets.size()); llvm::Constant *Init = llvm::ConstantArray::get(VBTableType, Offsets); GV->setInitializer(Init); // Set the correct linkage. GV->setLinkage(Linkage); // Set the right visibility. CGM.setTypeVisibility(GV, RD, CodeGenModule::TVK_ForVTable); }
/// Check if we are casting to a struct with a flexible array at the end. /// \code /// struct foo { /// size_t len; /// struct bar data[]; /// }; /// \endcode /// or /// \code /// struct foo { /// size_t len; /// struct bar data[0]; /// } /// \endcode /// In these cases it is also valid to allocate size of struct foo + a multiple /// of struct bar. static bool evenFlexibleArraySize(ASTContext &Ctx, CharUnits RegionSize, CharUnits TypeSize, QualType ToPointeeTy) { const RecordType *RT = ToPointeeTy->getAs<RecordType>(); if (!RT) return false; const RecordDecl *RD = RT->getDecl(); RecordDecl::field_iterator Iter(RD->field_begin()); RecordDecl::field_iterator End(RD->field_end()); const FieldDecl *Last = 0; for (; Iter != End; ++Iter) Last = *Iter; assert(Last && "empty structs should already be handled"); const Type *ElemType = Last->getType()->getArrayElementTypeNoTypeQual(); CharUnits FlexSize; if (const ConstantArrayType *ArrayTy = Ctx.getAsConstantArrayType(Last->getType())) { FlexSize = Ctx.getTypeSizeInChars(ElemType); if (ArrayTy->getSize() == 1 && TypeSize > FlexSize) TypeSize -= FlexSize; else if (ArrayTy->getSize() != 0) return false; } else if (RD->hasFlexibleArrayMember()) { FlexSize = Ctx.getTypeSizeInChars(ElemType); } else { return false; } if (FlexSize.isZero()) return false; CharUnits Left = RegionSize - TypeSize; if (Left.isNegative()) return false; if (Left % FlexSize == 0) return true; return false; }