================ @@ -956,42 +958,112 @@ static llvm::Value *getArrayIndexingBound(CodeGenFunction &CGF, return nullptr; } -const Expr * -CodeGenFunction::BuildCountedByFieldExpr(const Expr *Base, - const ValueDecl *CountedByVD) { +namespace { + +/// \p MemberExprBaseVisitor returns the base \p DeclRefExpr of a field access. +class MemberExprBaseVisitor + : public StmtVisitor<MemberExprBaseVisitor, Expr *> { + const RecordDecl *ExpectedRD; + + bool IsExpectedRecordDecl(const Expr *E) const { + QualType Ty = E->getType(); + if (Ty->isPointerType()) + Ty = Ty->getPointeeType(); + return ExpectedRD == Ty->getAsRecordDecl(); + } + +public: + MemberExprBaseVisitor(const RecordDecl *ExpectedRD) + : ExpectedRD(ExpectedRD) { } + + //===--------------------------------------------------------------------===// + // Visitor Methods + //===--------------------------------------------------------------------===// + + // Note: if we build C++ support for counted_by, then we'll have to handle + // horrors like this: + // + // struct S { + // int x, y; + // int blah[] __attribute__((counted_by(x))); + // } s; + // + // int foo(int index, int val) { + // int (S::*IHatePMDs)[] = &S::blah; + // (s.*IHatePMDs)[index] = val; + // } + + Expr *Visit(Expr *E) { + return StmtVisitor<MemberExprBaseVisitor, Expr *>::Visit(E); + } + + Expr *VisitCastExpr(CastExpr *E) { + return IsExpectedRecordDecl(E) ? E : Visit(E->getSubExpr()); + } + Expr *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { + return IsExpectedRecordDecl(E) ? E : nullptr; + } + Expr *VisitDeclRefExpr(DeclRefExpr *E) { + return IsExpectedRecordDecl(E) ? E : nullptr; + } + Expr *VisitMemberExpr(MemberExpr *E) { + Expr *Res = Visit(E->getBase()); + return !Res && IsExpectedRecordDecl(E) ? E : Res; + } + Expr *VisitParenExpr(ParenExpr *E) { + return IsExpectedRecordDecl(E) ? E : Visit(E->getSubExpr()); + } + + Expr *VisitArraySubscriptExpr(ArraySubscriptExpr *E) { + return Visit(E->getBase()); + } + Expr *VisitImplicitCastExpr(CastExpr *E) { return Visit(E->getSubExpr()); } + Expr *VisitUnaryOperator(UnaryOperator *E) { return Visit(E->getSubExpr()); } +}; + +} // end anonymous namespace + +llvm::Value * +CodeGenFunction::EmitCountedByFieldExpr(const Expr *Base, + const ValueDecl *CountedByVD) { + const DeclContext *DC = CountedByVD->getLexicalDeclContext(); + const auto *CountedByRD = cast<RecordDecl>(DC); + // Find the outer struct expr (i.e. p in p->a.b.c.d). - Expr *CountedByExpr = const_cast<Expr *>(Base)->IgnoreParenImpCasts(); - - // Work our way up the expression until we reach the DeclRefExpr. - while (!isa<DeclRefExpr>(CountedByExpr)) - if (const auto *ME = dyn_cast<MemberExpr>(CountedByExpr)) - CountedByExpr = ME->getBase()->IgnoreParenImpCasts(); - - // Add back an implicit cast to create the required pr-value. - CountedByExpr = ImplicitCastExpr::Create( - getContext(), CountedByExpr->getType(), CK_LValueToRValue, CountedByExpr, - nullptr, VK_PRValue, FPOptionsOverride()); - - if (const auto *IFD = dyn_cast<IndirectFieldDecl>(CountedByVD)) { - // The counted_by field is inside an anonymous struct / union. The - // IndirectFieldDecl has the correct order of FieldDecls to build this - // easily. (Yay!) - for (NamedDecl *ND : IFD->chain()) { - auto *VD = cast<ValueDecl>(ND); - CountedByExpr = - MemberExpr::CreateImplicit(getContext(), CountedByExpr, - CountedByExpr->getType()->isPointerType(), - VD, VD->getType(), VK_LValue, OK_Ordinary); - } - } else { - CountedByExpr = MemberExpr::CreateImplicit( - getContext(), const_cast<Expr *>(CountedByExpr), - CountedByExpr->getType()->isPointerType(), - const_cast<ValueDecl *>(CountedByVD), CountedByVD->getType(), VK_LValue, - OK_Ordinary); + Expr *CountedByExpr = + MemberExprBaseVisitor(CountedByRD).Visit(const_cast<Expr *>(Base)); + if (!CountedByExpr) + return nullptr; + + llvm::Value *Res = nullptr; + if (CountedByExpr->getType()->isPointerType()) + Res = EmitPointerWithAlignment(CountedByExpr).getPointer(); ---------------- efriedma-quic wrote:
Oo, I should have spotted this earlier. EmitPointerWithAlignment/EmitLValue is going to repeat any side-effects of the expression in question. You can't emit an expression twice, in general. So for the array bounds sanitizer case, I think this needs to be integrated a bit more tightly with the expression emission. (Not sure about the object_size case.) https://github.com/llvm/llvm-project/pull/73730 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits