================ @@ -827,6 +827,165 @@ CodeGenFunction::evaluateOrEmitBuiltinObjectSize(const Expr *E, unsigned Type, return ConstantInt::get(ResType, ObjectSize, /*isSigned=*/true); } +llvm::Value * +CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type, + llvm::IntegerType *ResType) { + // 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)) + // + ASTContext &Ctx = getContext(); + const Expr *Base = E->IgnoreParenImpCasts(); + const Expr *Idx = nullptr; + + if (const auto *UO = dyn_cast<UnaryOperator>(Base); + UO && UO->getOpcode() == UO_AddrOf) { + Expr *SubExpr = UO->getSubExpr()->IgnoreParenImpCasts(); + if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(SubExpr)) { + Base = ASE->getBase()->IgnoreParenImpCasts(); + Idx = ASE->getIdx()->IgnoreParenImpCasts(); + + if (const auto *IL = dyn_cast<IntegerLiteral>(Idx)) { + int64_t Val = IL->getValue().getSExtValue(); + if (Val < 0) + // __bdos returns 0 for negative indexes into an array in a struct. + return getDefaultBuiltinObjectSizeResult(Type, ResType); + + if (Val == 0) + // The index is 0, so we don't need to take it into account. + Idx = nullptr; + } + } else { + // Potential pointer to another element in the struct. + Base = SubExpr; + } + } + + // Get the flexible array member Decl. + const ValueDecl *FAMDecl = nullptr; + if (const auto *ME = dyn_cast<MemberExpr>(Base)) { + // Check if \p Base is referencing the FAM itself. + if (const ValueDecl *MD = ME->getMemberDecl()) { + const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel = + getLangOpts().getStrictFlexArraysLevel(); + if (!Decl::isFlexibleArrayMemberLike( + Ctx, MD, MD->getType(), StrictFlexArraysLevel, + /*IgnoreTemplateOrMacroSubstitution=*/true)) + return nullptr; + + FAMDecl = MD; + } + } else if (const auto *DRE = dyn_cast<DeclRefExpr>(Base)) { + // Check if we're pointing to the whole struct. + QualType Ty = DRE->getDecl()->getType(); + if (Ty->isPointerType()) + Ty = Ty->getPointeeType(); + + if (const auto *RD = Ty->getAsRecordDecl()) + // Don't use the outer lexical record because the FAM might be in a + // different RecordDecl. + FAMDecl = FindFlexibleArrayMemberField(Ctx, RD); + } + + if (!FAMDecl || !FAMDecl->hasAttr<CountedByAttr>()) + // No flexible array member found or it doesn't have the "counted_by" ---------------- bwendling wrote:
There are already tests for `alloc_size` and `__bos()` and `__bdos()`. (https://github.com/llvm/llvm-project/blob/c2a2fd209e2da4c80e55d11b114d47b8d1eaaa16/clang/test/CodeGen/alloc-size.c) https://github.com/llvm/llvm-project/pull/71877 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits