================ @@ -1060,238 +1061,348 @@ CodeGenFunction::evaluateOrEmitBuiltinObjectSize(const Expr *E, unsigned Type, return ConstantInt::get(ResType, ObjectSize, /*isSigned=*/true); } -const FieldDecl *CodeGenFunction::FindFlexibleArrayMemberFieldAndOffset( - ASTContext &Ctx, const RecordDecl *RD, const FieldDecl *FAMDecl, - uint64_t &Offset) { +namespace { + +/// StructFieldAccess is a simple visitor class to grab the first MemberExpr +/// from an Expr. It records any ArraySubscriptExpr we meet along the way. +struct StructFieldAccess + : public ConstStmtVisitor<StructFieldAccess, const MemberExpr *> { + const ArraySubscriptExpr *ASE = nullptr; + bool AddrOfSeen = false; + + const MemberExpr *VisitMemberExpr(const MemberExpr *E) { + if (AddrOfSeen && E->getType()->isArrayType()) + // Avoid forms like '&ptr->array'. + return nullptr; + return E; + } + + const MemberExpr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { + AddrOfSeen = false; // '&ptr->array[idx]' is okay. + ASE = E; + return Visit(E->getBase()); + } + const MemberExpr *VisitCastExpr(const CastExpr *E) { + return Visit(E->getSubExpr()); + } + const MemberExpr *VisitParenExpr(const ParenExpr *E) { + return Visit(E->getSubExpr()); + } + const MemberExpr *VisitUnaryAddrOf(const clang::UnaryOperator *E) { + AddrOfSeen = true; + return Visit(E->getSubExpr()); + } + const MemberExpr *VisitUnaryDeref(const clang::UnaryOperator *E) { + AddrOfSeen = false; + return Visit(E->getSubExpr()); + } +}; + +} // end anonymous namespace + +/// Find a struct's flexible array member. It may be embedded inside multiple +/// sub-structs, but must still be the last field. +static const FieldDecl *FindFlexibleArrayMemberField(CodeGenFunction &CGF, + ASTContext &Ctx, + const RecordDecl *RD) { const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel = - getLangOpts().getStrictFlexArraysLevel(); - uint32_t FieldNo = 0; + CGF.getLangOpts().getStrictFlexArraysLevel(); if (RD->isImplicit()) return nullptr; for (const FieldDecl *FD : RD->fields()) { - if ((!FAMDecl || FD == FAMDecl) && - Decl::isFlexibleArrayMemberLike( + if (Decl::isFlexibleArrayMemberLike( Ctx, FD, FD->getType(), StrictFlexArraysLevel, - /*IgnoreTemplateOrMacroSubstitution=*/true)) { - const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); - Offset += Layout.getFieldOffset(FieldNo); + /*IgnoreTemplateOrMacroSubstitution=*/true)) return FD; + + if (auto RT = FD->getType()->getAs<RecordType>()) + if (const FieldDecl *FD = + FindFlexibleArrayMemberField(CGF, Ctx, RT->getAsRecordDecl())) + return FD; + } + + return nullptr; +} + +/// Calculate the offset of a struct field. It may be embedded inside multiple +/// sub-structs. +static bool GetFieldOffset(ASTContext &Ctx, const RecordDecl *RD, + const FieldDecl *FD, int64_t &Offset) { + if (RD->isImplicit()) + return false; + + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); + uint32_t FieldNo = 0; + + for (const FieldDecl *Field : RD->fields()) { + if (Field == FD) { + Offset += Layout.getFieldOffset(FieldNo); + return true; } - QualType Ty = FD->getType(); - if (Ty->isRecordType()) { - if (const FieldDecl *Field = FindFlexibleArrayMemberFieldAndOffset( - Ctx, Ty->getAsRecordDecl(), FAMDecl, Offset)) { - const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); + if (auto RT = Field->getType()->getAs<RecordType>()) { + if (GetFieldOffset(Ctx, RT->getAsRecordDecl(), FD, Offset)) { Offset += Layout.getFieldOffset(FieldNo); - return Field; + return true; } } if (!RD->isUnion()) ++FieldNo; } - return nullptr; + return false; } -static unsigned CountCountedByAttrs(const RecordDecl *RD) { - unsigned Num = 0; +llvm::Value * +CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE, + unsigned Type, + llvm::IntegerType *ResType) { + ASTContext &Ctx = getContext(); - for (const FieldDecl *FD : RD->fields()) { - if (FD->getType()->isCountAttributedType()) - return ++Num; + // Note: If the whole struct is specificed in the __bdos (i.e. Visitor + // returns a DeclRefExpr). The calculation of the whole size of the structure + // with a flexible array member can be done in two ways: + // + // 1) sizeof(struct S) + count * sizeof(typeof(fam)) + // 2) offsetof(struct S, fam) + count * sizeof(typeof(fam)) + // + // The first will add additional padding after the end of the array + // allocation while the second method is more precise, but not quite expected + // from programmers. See + // https://lore.kernel.org/lkml/ZvV6X5FPBBW7CO1f@archlinux/ for a discussion + // of the topic. + // + // GCC isn't (currently) able to calculate __bdos on a pointer to the whole + // structure. Therefore, because of the above issue, we choose to match what + // GCC does for consistency's sake. ---------------- nickdesaulniers wrote:
This seems to imply a bug in gcc. What if that changes in the future? Is there a bug on file in their issue tracker you could link to from here? If not, does it make sense to file one, then link to it from here? https://github.com/llvm/llvm-project/pull/122198 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits