================ @@ -1051,6 +1052,145 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type, return Builder.CreateSelect(Cmp, Res, ConstantInt::get(ResType, 0, IsSigned)); } +namespace { + +/// \p StructBaseExpr returns the base \p Expr with a structure or union type. +struct StructBaseExpr : public ConstStmtVisitor<StructBaseExpr, const Expr *> { + StructBaseExpr() = default; + + //===--------------------------------------------------------------------===// + // Visitor Methods + //===--------------------------------------------------------------------===// + + const Expr *VisitStmt(const Stmt *S) { return nullptr; } + + const Expr *Visit(const Expr *E) { + QualType Ty = E->getType(); + if (Ty->isStructureType() || Ty->isUnionType()) + return E; + + return ConstStmtVisitor<StructBaseExpr, const Expr *>::Visit(E); + } + + const Expr *VisitDeclRefExpr(const DeclRefExpr *E) { return E; } + + const Expr *VisitMemberExpr(const MemberExpr *E) { + return Visit(E->getBase()); + } + const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { + return Visit(E->getBase()); + } + const Expr *VisitCastExpr(const CastExpr *E) { + return Visit(E->getSubExpr()); + } + const Expr *VisitParenExpr(const ParenExpr *E) { + return Visit(E->getSubExpr()); + } + const Expr *VisitUnaryAddrOf(const clang::UnaryOperator *E) { + return Visit(E->getSubExpr()); + } + const Expr *VisitUnaryDeref(const clang::UnaryOperator *E) { + return Visit(E->getSubExpr()); + } +}; + +} // end anonymous namespace + +/// The offset of a field from the beginning of the record. +llvm::Value * +CodeGenFunction::tryEmitObjectSizeCalculation(const Expr *E, unsigned Type, + llvm::IntegerType *ResType) { + if ((Type & 0x01) != 0) + // We handle only the whole object size. + return nullptr; + + E = E->IgnoreParenImpCasts(); + + const Expr *Base = StructBaseExpr().Visit(E); + if (!Base) + return nullptr; + + const RecordDecl *RD = Base->getType()->getAsRecordDecl(); + if (!RD) + return nullptr; + + // Get the full size of the struct. + ASTContext &Ctx = getContext(); + const RecordDecl *OuterRD = RD->getOuterLexicalRecordContext(); + const clang::Type *RT = OuterRD->getTypeForDecl(); + CharUnits RecordSize = Ctx.getTypeSizeInChars(RT); + + Value *Res = nullptr; + + if (const auto *U = dyn_cast<UnaryOperator>(E); + U && (U->getOpcode() == UO_AddrOf || U->getOpcode() == UO_Deref)) + E = U->getSubExpr()->IgnoreParenImpCasts(); + + if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(E)) { + const Expr *Idx = ASE->getIdx(); + Base = ASE->getBase()->IgnoreParenImpCasts(); + + if (const auto *ME = dyn_cast<MemberExpr>(Base); + ME && ME->getType()->isConstantArrayType()) { + // The simple case: + // + // struct s { + // int arr[42]; + // char c; + // /* others */ + // }; + // + // __builtin_dynamic_object_size(&p->arr[idx], 0); + // + // We can translate the __builtin_dynamic_object_call into: + // + // sizeof(struct s) - offsetof(arr) - (idx * sizeof(int)) + // ---------------- zygoloid wrote:
I assume we only need to do this for `Type == 1` (for `0` and `2`, we can just use the LLVM intrinsic, and you're bailing out for `3`). In that case, I don't think we need to care about `sizeof s` here -- for a pointer to an array subscript expression where we know the array bound, we can use `max(sizeof(arr) - sizeof(arr[0]) * idx, 0)`. Type 1 shouldn't permit overwriting the unrelated `c` field in the example above. https://github.com/llvm/llvm-project/pull/80256 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits