================ @@ -859,53 +860,93 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type, } if (IsDynamic) { - LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel = - getLangOpts().getStrictFlexArraysLevel(); + // The code generated here calculates the size of a struct with a flexible + // array member that uses the counted_by attribute. There are two instances + // we handle: + // + // struct s { + // unsigned long flags; + // int count; + // int array[] __attribute__((counted_by(count))); + // } + // + // 1) bdos of the flexible array itself: + // + // __builtin_dynamic_object_size(p->array, 1) == + // p->count * sizeof(*p->array) + // + // 2) bdos of a pointer into the flexible array: + // + // __builtin_dynamic_object_size(&p->array[42], 1) == + // (p->count - 42) * sizeof(*p->array) + // + // 2) bdos of the whole struct, including the flexible array: + // + // __builtin_dynamic_object_size(p, 1) == + // max(sizeof(struct s), + // offsetof(struct s, array) + p->count * sizeof(*p->array)) + // const Expr *Base = E->IgnoreParenImpCasts(); - - if (FieldDecl *FD = FindCountedByField(Base, StrictFlexArraysLevel)) { - const auto *ME = dyn_cast<MemberExpr>(Base); - llvm::Value *ObjectSize = nullptr; - - if (!ME) { - const auto *DRE = dyn_cast<DeclRefExpr>(Base); - ValueDecl *VD = nullptr; - - ObjectSize = ConstantInt::get( - ResType, - getContext().getTypeSize(DRE->getType()->getPointeeType()) / 8, - true); - - if (auto *RD = DRE->getType()->getPointeeType()->getAsRecordDecl()) - VD = RD->getLastField(); - - Expr *ICE = ImplicitCastExpr::Create( - getContext(), DRE->getType(), CK_LValueToRValue, - const_cast<Expr *>(cast<Expr>(DRE)), nullptr, VK_PRValue, - FPOptionsOverride()); - ME = MemberExpr::CreateImplicit(getContext(), ICE, true, VD, - VD->getType(), VK_LValue, OK_Ordinary); + const Expr *Idx = nullptr; + if (const auto *UO = dyn_cast<UnaryOperator>(Base); + UO && UO->getOpcode() == UO_AddrOf) { + if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(UO->getSubExpr())) { + Base = ASE->getBase(); + Idx = ASE->getIdx()->IgnoreParenImpCasts(); + if (const auto *IL = dyn_cast<IntegerLiteral>(Idx); + IL && !IL->getValue().getZExtValue()) { + Idx = nullptr; + } } + } - // At this point, we know that \p ME is a flexible array member. - const auto *ArrayTy = getContext().getAsArrayType(ME->getType()); - unsigned Size = getContext().getTypeSize(ArrayTy->getElementType()); + if (const ValueDecl *CountedByFD = FindCountedByField(Base)) { + const RecordDecl *OuterRD = + CountedByFD->getDeclContext()->getOuterLexicalRecordContext(); + ASTContext &Ctx = getContext(); - llvm::Value *CountField = - EmitAnyExprToTemp(MemberExpr::CreateImplicit( - getContext(), const_cast<Expr *>(ME->getBase()), - ME->isArrow(), FD, FD->getType(), VK_LValue, - OK_Ordinary)) - .getScalarVal(); + // Load the counted_by field. + const Expr *CountedByExpr = BuildCountedByFieldExpr(Base, CountedByFD); + llvm::Value *CountedByInst = + EmitAnyExprToTemp(CountedByExpr).getScalarVal(); - llvm::Value *Mul = Builder.CreateMul( - CountField, llvm::ConstantInt::get(CountField->getType(), Size / 8)); - Mul = Builder.CreateZExtOrTrunc(Mul, ResType); + if (Idx) { + llvm::Value *IdxInst = EmitAnyExprToTemp(Idx).getScalarVal(); + IdxInst = Builder.CreateZExtOrTrunc(IdxInst, CountedByInst->getType()); + CountedByInst = Builder.CreateSub(CountedByInst, IdxInst); + } - if (ObjectSize) - return Builder.CreateAdd(ObjectSize, Mul); + // Get the size of the flexible array member's base type. + const ValueDecl *FAM = FindFlexibleArrayMemberField(Ctx, OuterRD); + const ArrayType *ArrayTy = Ctx.getAsArrayType(FAM->getType()); ---------------- rapidsna wrote:
I see. So sounds like this relies on the fact that counted_by can currently be added to a flexible array member only? Should we add an assertion here to make it easier to deal with when that assumption breaks in future? https://github.com/llvm/llvm-project/pull/70606 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits