[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
bwendling wrote: I'll look into it. 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
nathanchance wrote: This breaks `ARCH=arm64 allmodconfig` for me. ``` $ echo CONFIG_WERROR=n >kernel/configs/no-werror.config $ make -skj"$(nproc)" ARCH=arm64 LLVM=1 mrproper {allmod,no-werror.}config drivers/net/ethernet/sfc/falcon/falcon.o PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script. Stack dump: 0. Program arguments: /mnt/nvme/tmp/build/llvm-project-testing/final/bin/clang ... 1. parser at end of file 2. Per-file LLVM IR generation 3. drivers/net/ethernet/sfc/falcon/falcon.c:1099:13: Generating code for declaration 'falcon_reconfigure_xmac_core' 4. drivers/net/ethernet/sfc/falcon/falcon.c:1149:2 : LLVM IR generation of compound statement ('{}') #0 0x55636ce677c8 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/mnt/nvme/tmp/build/llvm-project-testing/final/bin/clang+0x436f7c8) #1 0x55636ce652ee llvm::sys::RunSignalHandlers() (/mnt/nvme/tmp/build/llvm-project-testing/final/bin/clang+0x436d2ee) #2 0x55636cdea976 CrashRecoverySignalHandler(int) CrashRecoveryContext.cpp:0:0 #3 0x7fe53564c1d0 (/usr/lib/libc.so.6+0x3d1d0) #4 0x55636d415238 clang::CodeGen::CodeGenFunction::emitCountedByMemberSize(clang::Expr const*, llvm::Value*, unsigned int, llvm::IntegerType*) (/mnt/nvme/tmp/build/llvm-project-testing/final/bin/clang+0x491d238) #5 0x55636d41489f clang::CodeGen::CodeGenFunction::emitBuiltinObjectSize(clang::Expr const*, unsigned int, llvm::IntegerType*, llvm::Value*, bool) (/mnt/nvme/tmp/build/llvm-project-testing/final/bin/clang+0x491c89f) #6 0x55636d41de14 clang::CodeGen::CodeGenFunction::EmitBuiltinExpr(clang::GlobalDecl, unsigned int, clang::CallExpr const*, clang::CodeGen::ReturnValueSlot) (/mnt/nvme/tmp/build/llvm-project-testing/final/bin/clang+0x4925e14) #8 0x55636d27dd2a (anonymous namespace)::ScalarExprEmitter::VisitCallExpr(clang::CallExpr const*) CGExprScalar.cpp:0:0 #9 0x55636d26a64b (anonymous namespace)::ScalarExprEmitter::Visit(clang::Expr*) CGExprScalar.cpp:0:0 #10 0x55636d26a53d clang::CodeGen::CodeGenFunction::EmitScalarExpr(clang::Expr const*, bool) (/mnt/nvme/tmp/build/llvm-project-testing/final/bin/clang+0x477253d) #11 0x55636d2b42d0 clang::CodeGen::CodeGenFunction::EmitScalarInit(clang::Expr const*, clang::ValueDecl const*, clang::CodeGen::LValue, bool) (/mnt/nvme/tmp/build/llvm-project-testing/final/bin/clang+0x47bc2d0) #12 0x55636d2b78dc clang::CodeGen::CodeGenFunction::EmitAutoVarInit(clang::CodeGen::CodeGenFunction::AutoVarEmission const&) (/mnt/nvme/tmp/build/llvm-project-testing/final/bin/clang+0x47bf8dc) #13 0x55636d2b1c69 clang::CodeGen::CodeGenFunction::EmitVarDecl(clang::VarDecl const&) (/mnt/nvme/tmp/build/llvm-project-testing/final/bin/clang+0x47b9c69) #14 0x55636d2b14ef clang::CodeGen::CodeGenFunction::EmitDecl(clang::Decl const&) (/mnt/nvme/tmp/build/llvm-project-testing/final/bin/clang+0x47b94ef) #15 0x55636d1e146b clang::CodeGen::CodeGenFunction::EmitDeclStmt(clang::DeclStmt const&) (/mnt/nvme/tmp/build/llvm-project-testing/final/bin/clang+0x46e946b) #16 0x55636d1d4d53 clang::CodeGen::CodeGenFunction::EmitSimpleStmt(clang::Stmt const*, llvm::ArrayRef) (/mnt/nvme/tmp/build/llvm-project-testing/final/bin/clang+0x46dcd53) #17 0x55636d1d42f4 clang::CodeGen::CodeGenFunction::EmitStmt(clang::Stmt const*, llvm::ArrayRef) (/mnt/nvme/tmp/build/llvm-project-testing/final/bin/clang+0x46dc2f4) #18 0x55636d1e2652 clang::CodeGen::CodeGenFunction::EmitCompoundStmtWithoutScope(clang::CompoundStmt const&, bool, clang::CodeGen::AggValueSlot) (/mnt/nvme/tmp/build/llvm-project-testing/final/bin/clang+0x46ea652) #19 0x55636d1e1399 clang::CodeGen::CodeGenFunction::EmitCompoundStmt(clang::CompoundStmt const&, bool, clang::CodeGen::AggValueSlot) (/mnt/nvme/tmp/build/llvm-project-testing/final/bin/clang+0x46e9399) #20 0x55636d2797e7 (anonymous namespace)::ScalarExprEmitter::VisitStmtExpr(clang::StmtExpr const*) CGExprScalar.cpp:0:0 #21 0x55636d26a53d clang::CodeGen::CodeGenFunction::EmitScalarExpr(clang::Expr const*, bool) (/mnt/nvme/tmp/build/llvm-project-testing/final/bin/clang+0x477253d) #22 0x55636d23cb84 clang::CodeGen::CodeGenFunction::EmitIgnoredExpr(clang::Expr const*) (/mnt/nvme/tmp/build/llvm-project-testing/final/bin/clang+0x4744b84) #23 0x55636d1d43e7 clang::CodeGen::CodeGenFunction::EmitStmt(clang::Stmt const*, llvm::ArrayRef) (/mnt/nvme/tmp/build/llvm-project-testing/final/bin/clang+0x46dc3e7) #24 0x55636d1e2830 clang::CodeGen::CodeGenFunction::EmitCompoundStmtWithoutScope(clang::CompoundStmt const&, bool, clang::CodeGen::AggValueSlot) (/mnt/nvme/tmp/build/llvm-project-testing/final/bin/clang+0x46ea830) #25 0x55636d1c0676 clang::CodeGen::CodeGenFunction::GenerateCode(clang::GlobalDecl, llvm::Function*, clang::CodeGen::CGFunctionInfo const&) (/mnt/nvme/tmp/build/llvm-project-t
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
https://github.com/bwendling closed 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
bwendling wrote: Friendly ping for any further comments. 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
bwendling wrote: > I still think we may need to triple check how this extension behaves with > count fields that do not get extended AND are negative at runtime (if we > don't already have tests for that), but perhaps is orthogonal to this initial > refactoring. I'll look into test cases with negative values. Thanks! 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
https://github.com/nickdesaulniers approved this pull request. Thanks, I appreciate the comments about common usage patterns; they help make it easier to understand (subjectively) the 4 cases you handle in code. I still think we may need to triple check how this extension behaves with count fields that do not get extended AND are negative at runtime (if we don't already have tests for that), but perhaps is orthogonal to this initial refactoring. You may want to get another +1 before landing (perhaps @efriedma-quic or @rjmccall ). 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
bwendling wrote: @nickdesaulniers I understand what you're saying, and it was addressed in the original patch. I do my best to carry the signed-ness of the variables through to the end so that the checks work out (i.e. the checks for negatives aren't removed after optimizations, which they would be if the results were unsigned). 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1049,236 +1050,362 @@ 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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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) { +if (ASE) + // We don't support multiple subscripts. + return nullptr; + +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()) + 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; + + // Keep track of the field number ourselves, because the other methods + // (CGRecordLayout::getLLVMFieldNo) aren't always equivalent to how the AST + // is laid out. + uint32_t FieldNo = 0; + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); + + 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()) { + 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; +static std::optional +GetFieldOffset(ASTContext &Ctx, const RecordDecl *RD, const FieldDecl *FD) { + int64_t Offset = 0; - for (const FieldDecl *FD : RD->fields()) { -if (FD->getType()->isCountAttributedType()) - return ++Num; - -QualType Ty = FD->getType(); -if (Ty->isRecordType()) - Num += CountCountedByAttrs(Ty->getAsRecordDecl()); - } + if (GetFieldOffset(Ctx, RD, FD, Offset)) +return std::optional(Offset); - return Num; + return std::nullopt; } llvm::Value * -CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type, - llvm::IntegerType *ResType) { - // The code generat
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
https://github.com/nickdesaulniers edited 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
https://github.com/bwendling edited 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,236 +1061,362 @@ 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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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) { +if (ASE) + // We don't support multiple subscripts. + return nullptr; + +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()) + 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; + + // Keep track of the field number ourselves, because the other methods + // (CGRecordLayout::getLLVMFieldNo) aren't always equivalent to how the AST + // is laid out. + uint32_t FieldNo = 0; + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); + + 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()) { + 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; +static std::optional +GetFieldOffset(ASTContext &Ctx, const RecordDecl *RD, const FieldDecl *FD) { + int64_t Offset = 0; - for (const FieldDecl *FD : RD->fields()) { -if (FD->getType()->isCountAttributedType()) - return ++Num; - -QualType Ty = FD->getType(); -if (Ty->isRecordType()) - Num += CountCountedByAttrs(Ty->getAsRecordDecl()); - } + if (GetFieldOffset(Ctx, RD, FD, Offset)) +return std::optional(Offset); - return Num; + return std::nullopt; } llvm::Value * -CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type, - llvm::IntegerType *ResType) { - // The code generat
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
https://github.com/bwendling edited 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1049,236 +1050,362 @@ 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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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) { +if (ASE) + // We don't support multiple subscripts. + return nullptr; + +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()) + 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; + + // Keep track of the field number ourselves, because the other methods + // (CGRecordLayout::getLLVMFieldNo) aren't always equivalent to how the AST + // is laid out. + uint32_t FieldNo = 0; + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); + + 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()) { + 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; +static std::optional +GetFieldOffset(ASTContext &Ctx, const RecordDecl *RD, const FieldDecl *FD) { + int64_t Offset = 0; - for (const FieldDecl *FD : RD->fields()) { -if (FD->getType()->isCountAttributedType()) - return ++Num; - -QualType Ty = FD->getType(); -if (Ty->isRecordType()) - Num += CountCountedByAttrs(Ty->getAsRecordDecl()); - } + if (GetFieldOffset(Ctx, RD, FD, Offset)) +return std::optional(Offset); - return Num; + return std::nullopt; } llvm::Value * -CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type, - llvm::IntegerType *ResType) { - // The code generat
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,236 +1061,362 @@ 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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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) { +if (ASE) + // We don't support multiple subscripts. + return nullptr; + +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()) + 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; + + // Keep track of the field number ourselves, because the other methods + // (CGRecordLayout::getLLVMFieldNo) aren't always equivalent to how the AST + // is laid out. + uint32_t FieldNo = 0; + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); + + 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()) { + 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; +static std::optional +GetFieldOffset(ASTContext &Ctx, const RecordDecl *RD, const FieldDecl *FD) { + int64_t Offset = 0; - for (const FieldDecl *FD : RD->fields()) { -if (FD->getType()->isCountAttributedType()) - return ++Num; - -QualType Ty = FD->getType(); -if (Ty->isRecordType()) - Num += CountCountedByAttrs(Ty->getAsRecordDecl()); - } + if (GetFieldOffset(Ctx, RD, FD, Offset)) +return std::optional(Offset); - return Num; + return std::nullopt; } llvm::Value * -CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type, - llvm::IntegerType *ResType) { - // The code generat
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,236 +1061,362 @@ 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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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) { +if (ASE) + // We don't support multiple subscripts. + return nullptr; + +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()) + 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; + + // Keep track of the field number ourselves, because the other methods + // (CGRecordLayout::getLLVMFieldNo) aren't always equivalent to how the AST + // is laid out. + uint32_t FieldNo = 0; + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); + + 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()) { + 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; +static std::optional +GetFieldOffset(ASTContext &Ctx, const RecordDecl *RD, const FieldDecl *FD) { + int64_t Offset = 0; - for (const FieldDecl *FD : RD->fields()) { -if (FD->getType()->isCountAttributedType()) - return ++Num; - -QualType Ty = FD->getType(); -if (Ty->isRecordType()) - Num += CountCountedByAttrs(Ty->getAsRecordDecl()); - } + if (GetFieldOffset(Ctx, RD, FD, Offset)) +return std::optional(Offset); - return Num; + return std::nullopt; } llvm::Value * -CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type, - llvm::IntegerType *ResType) { - // The code generat
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
bwendling wrote: Friendly Ping. 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
bwendling wrote: Are there anymore comments? 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
https://github.com/bwendling edited 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -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 { + 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()) + 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()) { + 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/ZvV6X5
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,236 +1061,358 @@ 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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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()); bwendling wrote: Okay, so what do I do with an lvalue-to-rvalue cast when I encounter it? As I explained in the comment, I'm using the already emitted `Expr` to calculate the offset to the 'count' object. To get that, all I need is the `MemberExpr` of the flexible array member. 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,236 +1061,358 @@ 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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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; bwendling wrote: It looks like GCC returns -1 in this situation. I'll have us do the same. 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -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 { + 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()) + 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()) { + 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/ZvV6X5
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,236 +1061,358 @@ 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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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()); efriedma-quic wrote: Like I've mentioned before, I generally prefer explicitly classifying casts by CastKind, instead of ignoring the casts, then trying to infer what casts happened later. In particular, you do not want to look through lvalue-to-rvalue conversions in this context. 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,236 +1061,358 @@ 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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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; efriedma-quic wrote: What happens if you have `&ptr->array2d[idx1][idx2]`? 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,236 +1061,355 @@ 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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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()) + 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()) { + 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; - - for (const FieldDecl *FD : RD->fields()) { -if (FD->getType()->isCountAttributedType()) - return ++Num; +static std::optional +GetFieldOffset(ASTContext &Ctx, const RecordDecl *RD, const FieldDecl *FD) { + int64_t Offset = 0; -QualType Ty = FD->getType(); -if (Ty->isRecordType()) - Num += CountCountedByAttrs(Ty->getAsRecordDecl()); - } + if (GetFieldOffset(Ctx, RD, FD, Offset)) +return std::optional(Offset); - return Num; + return std::optional(); } 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; - // i
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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()) + 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; bwendling wrote: Okay. 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,236 +1061,355 @@ 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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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()) + 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()) { + 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; - - for (const FieldDecl *FD : RD->fields()) { -if (FD->getType()->isCountAttributedType()) - return ++Num; +static std::optional +GetFieldOffset(ASTContext &Ctx, const RecordDecl *RD, const FieldDecl *FD) { + int64_t Offset = 0; -QualType Ty = FD->getType(); -if (Ty->isRecordType()) - Num += CountCountedByAttrs(Ty->getAsRecordDecl()); - } + if (GetFieldOffset(Ctx, RD, FD, Offset)) +return std::optional(Offset); - return Num; + return std::optional(); } 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; - // i
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,236 +1061,355 @@ 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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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()) + 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()) { + 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; - - for (const FieldDecl *FD : RD->fields()) { -if (FD->getType()->isCountAttributedType()) - return ++Num; +static std::optional +GetFieldOffset(ASTContext &Ctx, const RecordDecl *RD, const FieldDecl *FD) { + int64_t Offset = 0; -QualType Ty = FD->getType(); -if (Ty->isRecordType()) - Num += CountCountedByAttrs(Ty->getAsRecordDecl()); - } + if (GetFieldOffset(Ctx, RD, FD, Offset)) +return std::optional(Offset); - return Num; + return std::optional(); } 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; - // i
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,236 +1061,355 @@ 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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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()) + 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()) { + 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; - - for (const FieldDecl *FD : RD->fields()) { -if (FD->getType()->isCountAttributedType()) - return ++Num; +static std::optional +GetFieldOffset(ASTContext &Ctx, const RecordDecl *RD, const FieldDecl *FD) { + int64_t Offset = 0; -QualType Ty = FD->getType(); -if (Ty->isRecordType()) - Num += CountCountedByAttrs(Ty->getAsRecordDecl()); - } + if (GetFieldOffset(Ctx, RD, FD, Offset)) +return std::optional(Offset); - return Num; + return std::optional(); bwendling wrote: Done. 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,236 +1061,355 @@ 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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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()) + 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()) { + 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; - - for (const FieldDecl *FD : RD->fields()) { -if (FD->getType()->isCountAttributedType()) - return ++Num; +static std::optional +GetFieldOffset(ASTContext &Ctx, const RecordDecl *RD, const FieldDecl *FD) { + int64_t Offset = 0; -QualType Ty = FD->getType(); -if (Ty->isRecordType()) - Num += CountCountedByAttrs(Ty->getAsRecordDecl()); - } + if (GetFieldOffset(Ctx, RD, FD, Offset)) +return std::optional(Offset); bwendling wrote: Let's keep the original way. It's clearer, at least to me. :-) 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,236 +1061,355 @@ 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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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()) + 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()) { + 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; - - for (const FieldDecl *FD : RD->fields()) { -if (FD->getType()->isCountAttributedType()) - return ++Num; +static std::optional +GetFieldOffset(ASTContext &Ctx, const RecordDecl *RD, const FieldDecl *FD) { + int64_t Offset = 0; -QualType Ty = FD->getType(); -if (Ty->isRecordType()) - Num += CountCountedByAttrs(Ty->getAsRecordDecl()); - } + if (GetFieldOffset(Ctx, RD, FD, Offset)) +return std::optional(Offset); - return Num; + return std::optional(); } 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; - // i
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,236 +1061,355 @@ 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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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()) + 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()) { + 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; - - for (const FieldDecl *FD : RD->fields()) { -if (FD->getType()->isCountAttributedType()) - return ++Num; +static std::optional +GetFieldOffset(ASTContext &Ctx, const RecordDecl *RD, const FieldDecl *FD) { + int64_t Offset = 0; -QualType Ty = FD->getType(); -if (Ty->isRecordType()) - Num += CountCountedByAttrs(Ty->getAsRecordDecl()); - } + if (GetFieldOffset(Ctx, RD, FD, Offset)) +return std::optional(Offset); - return Num; + return std::optional(); } 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; - // i
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
https://github.com/nickdesaulniers edited 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,236 +1061,355 @@ 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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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()) + 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()) { + 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; - - for (const FieldDecl *FD : RD->fields()) { -if (FD->getType()->isCountAttributedType()) - return ++Num; +static std::optional +GetFieldOffset(ASTContext &Ctx, const RecordDecl *RD, const FieldDecl *FD) { + int64_t Offset = 0; -QualType Ty = FD->getType(); -if (Ty->isRecordType()) - Num += CountCountedByAttrs(Ty->getAsRecordDecl()); - } + if (GetFieldOffset(Ctx, RD, FD, Offset)) +return std::optional(Offset); - return Num; + return std::optional(); nickdesaulniers wrote: Ah, no, I'm wrong about the default constructor. But I think `std::nullopt` is still clearer/more cannonical. 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,236 +1061,355 @@ 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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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()) + 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()) { + 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; - - for (const FieldDecl *FD : RD->fields()) { -if (FD->getType()->isCountAttributedType()) - return ++Num; +static std::optional +GetFieldOffset(ASTContext &Ctx, const RecordDecl *RD, const FieldDecl *FD) { + int64_t Offset = 0; -QualType Ty = FD->getType(); -if (Ty->isRecordType()) - Num += CountCountedByAttrs(Ty->getAsRecordDecl()); - } + if (GetFieldOffset(Ctx, RD, FD, Offset)) +return std::optional(Offset); - return Num; + return std::optional(); } 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; - // i
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,236 +1061,355 @@ 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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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()) + 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()) { + 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; - - for (const FieldDecl *FD : RD->fields()) { -if (FD->getType()->isCountAttributedType()) - return ++Num; +static std::optional +GetFieldOffset(ASTContext &Ctx, const RecordDecl *RD, const FieldDecl *FD) { + int64_t Offset = 0; -QualType Ty = FD->getType(); -if (Ty->isRecordType()) - Num += CountCountedByAttrs(Ty->getAsRecordDecl()); - } + if (GetFieldOffset(Ctx, RD, FD, Offset)) +return std::optional(Offset); nickdesaulniers wrote: I think you can do: ```suggestion return {Offset}; ``` 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,236 +1061,355 @@ 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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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()) + 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()) { + 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; - - for (const FieldDecl *FD : RD->fields()) { -if (FD->getType()->isCountAttributedType()) - return ++Num; +static std::optional +GetFieldOffset(ASTContext &Ctx, const RecordDecl *RD, const FieldDecl *FD) { + int64_t Offset = 0; -QualType Ty = FD->getType(); -if (Ty->isRecordType()) - Num += CountCountedByAttrs(Ty->getAsRecordDecl()); - } + if (GetFieldOffset(Ctx, RD, FD, Offset)) +return std::optional(Offset); - return Num; + return std::optional(); } 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; - // i
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,236 +1061,355 @@ 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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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()) + 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()) { + 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; - - for (const FieldDecl *FD : RD->fields()) { -if (FD->getType()->isCountAttributedType()) - return ++Num; +static std::optional +GetFieldOffset(ASTContext &Ctx, const RecordDecl *RD, const FieldDecl *FD) { + int64_t Offset = 0; -QualType Ty = FD->getType(); -if (Ty->isRecordType()) - Num += CountCountedByAttrs(Ty->getAsRecordDecl()); - } + if (GetFieldOffset(Ctx, RD, FD, Offset)) +return std::optional(Offset); - return Num; + return std::optional(); nickdesaulniers wrote: I think what you have will construct a truthy optional with a default initialized `int64_t` of `0`; I suspect what you want is to signal that the value does not exist. ```suggestion return std::nullopt; ``` 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/
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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()) + 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; nickdesaulniers wrote: sure, no problem. Perhaps a comment saying why `FieldDecl::getFieldIndex` is inappropriate to use here might help future travelers. 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
https://github.com/bwendling edited 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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()) + 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; bwendling wrote: No, it doesn't handle the case well. I've tried various different methods of using the layout and context methods and none of them did what I want to use here. They either have assertions that require the FD to be in the record or don't generate the actual offset within the full Let's just leave this as is. :-) 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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()) + 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. bwendling wrote: ?? That's what the comment says... 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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()) + 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()) { + 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/l
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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()) + 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()) { + 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/l
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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()) + 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()) { + 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/l
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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()) + 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()) { + 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/l
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -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 { + 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()) + 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()) { + 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/ZvV6X5
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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()) + 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. nickdesaulniers wrote: Perhaps worth noting in the comment that you're searching for the offset of `FD` in `RD` (IIUC)? 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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()) + 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()) { + 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/l
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -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. +class StructFieldAccess +: public ConstStmtVisitor { + bool AddrOfSeen = false; + +public: + const ArraySubscriptExpr *ASE = nullptr; + + 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()) + 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; nickdesaulniers wrote: Rather than keeping a count, it looks like `FieldDecl` has a method `FieldDecl::getFieldIndex` that can do what you need here (it even has a comment saying it can be used to then pass info to `ASTRecordLayout::getFieldOffset`. It's definitely heavier weight than a simple counter, but can you use it here? I guess one issue is that you skip unions, but maybe `FieldDecl::getFieldIndex` handles that case for you? Or no? The special case for unions is curious; perhaps unit tests for unions with the order of members flipped might expose an edge case. 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -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 { + 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()) + 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()) { + 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/ZvV6X5
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -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 { + 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()) + 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()) { + 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/ZvV6X5
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -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 { + 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()) + 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()) { + 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/ZvV6X5
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -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 { + const ArraySubscriptExpr *ASE = nullptr; + bool AddrOfSeen = false; nickdesaulniers wrote: `AddrOfSeen` is not referenced outside of the methods. Consider making it `private`. 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -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 { + 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()) + 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()) { + 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/ZvV6X5
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
https://github.com/rapidsna commented: Thanks for addressing comments! LGTM. You may still need to wait on Clang code owners review though. 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,238 +1061,331 @@ 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 { + const ArraySubscriptExpr *ASE = nullptr; + + const MemberExpr *VisitMemberExpr(const MemberExpr *E) { return E; } + + const MemberExpr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { +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) { +return Visit(E->getSubExpr()); + } + const MemberExpr *VisitUnaryDeref(const clang::UnaryOperator *E) { +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()) + 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()) { + 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 s
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,238 +1061,331 @@ 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 rapidsna wrote: I see. I'm fine with leaving it this way since this is not a regression introduced by this. Could you please create an issue, though? 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,238 +1061,331 @@ 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 { + const ArraySubscriptExpr *ASE = nullptr; + + const MemberExpr *VisitMemberExpr(const MemberExpr *E) { return E; } + + const MemberExpr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { +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) { +return Visit(E->getSubExpr()); + } + const MemberExpr *VisitUnaryDeref(const clang::UnaryOperator *E) { +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()) + 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()) { + 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 s
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,238 +1061,331 @@ 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 { + const ArraySubscriptExpr *ASE = nullptr; + + const MemberExpr *VisitMemberExpr(const MemberExpr *E) { return E; } + + const MemberExpr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { +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) { +return Visit(E->getSubExpr()); + } + const MemberExpr *VisitUnaryDeref(const clang::UnaryOperator *E) { +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()) + 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()) { + 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 s
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,238 +1061,331 @@ 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 { + const ArraySubscriptExpr *ASE = nullptr; + + const MemberExpr *VisitMemberExpr(const MemberExpr *E) { return E; } + + const MemberExpr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { +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) { +return Visit(E->getSubExpr()); + } + const MemberExpr *VisitUnaryDeref(const clang::UnaryOperator *E) { +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()) + 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()) { + 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 s
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,238 +1061,331 @@ 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 { + const ArraySubscriptExpr *ASE = nullptr; + + const MemberExpr *VisitMemberExpr(const MemberExpr *E) { return E; } + + const MemberExpr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { +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) { +return Visit(E->getSubExpr()); + } + const MemberExpr *VisitUnaryDeref(const clang::UnaryOperator *E) { +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()) + 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()) { + 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 s
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1343,6 +1430,12 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type, assert(Ptr->getType()->isPointerTy() && "Non-pointer passed to __builtin_object_size?"); + if (IsDynamic) bwendling wrote: At this point, we know that `EmittedE` has a value. See line 1429. 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,238 +1061,331 @@ 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 bwendling wrote: Both GCC and Clang return the same value for `__bdos(*ptr->array)` with my new change. For `__bdos(&ptr->array)` GCC returns -1 and Clang returns the calculated value (it does that even without this patch). So it's behavior that existed before the advent of `__counted_by` and is probably wrong, but maybe not? People have different expectations for `__bdos` in various situations it seems... I'm tempted to leave it as is since it isn't a regression, unless you have strong feelings about it. 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,238 +1061,331 @@ 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 rapidsna wrote: I suspect implementing this way will have `__bdos(&ptr->array)` and `__bdos(*ptr->array)` treated as Option (1). Was it intended? 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,238 +1061,331 @@ 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 { + const ArraySubscriptExpr *ASE = nullptr; + + const MemberExpr *VisitMemberExpr(const MemberExpr *E) { return E; } + + const MemberExpr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { +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) { +return Visit(E->getSubExpr()); + } + const MemberExpr *VisitUnaryDeref(const clang::UnaryOperator *E) { +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()) + 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()) { + 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 s
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,238 +1061,331 @@ 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 { + const ArraySubscriptExpr *ASE = nullptr; + + const MemberExpr *VisitMemberExpr(const MemberExpr *E) { return E; } + + const MemberExpr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { +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) { +return Visit(E->getSubExpr()); + } + const MemberExpr *VisitUnaryDeref(const clang::UnaryOperator *E) { +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()) + 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()) { + 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 s
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1343,6 +1430,12 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type, assert(Ptr->getType()->isPointerTy() && "Non-pointer passed to __builtin_object_size?"); + if (IsDynamic) rapidsna wrote: Why did this code block move to here from up there? 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,238 +1061,331 @@ 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 { + const ArraySubscriptExpr *ASE = nullptr; + + const MemberExpr *VisitMemberExpr(const MemberExpr *E) { return E; } + + const MemberExpr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { +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) { +return Visit(E->getSubExpr()); + } + const MemberExpr *VisitUnaryDeref(const clang::UnaryOperator *E) { +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()) + 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()) { + 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 s
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
@@ -1060,238 +1061,331 @@ 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 { + const ArraySubscriptExpr *ASE = nullptr; + + const MemberExpr *VisitMemberExpr(const MemberExpr *E) { return E; } + + const MemberExpr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { +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) { +return Visit(E->getSubExpr()); + } + const MemberExpr *VisitUnaryDeref(const clang::UnaryOperator *E) { +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()) + 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()) { + 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 s
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
bwendling wrote: Howdy! This is essentially a complete rewrite of 00b6d032a22196bc14e4e30e413c040eb1b65da4. The original was overly complex and fragile. The main difference with this PR is basing the calculations off of the already emitted `Expr` instead of doing it within this function. It allows the Visitor to skip past pretty much everything to find the first `MemberExpr`. Note, we don't perform the calculation on the whole struct (i.e. `__bdos(ptr)`) due to issues with GCC compatibility, so the Visitor isn't concerned about any other `Expr` type but a `MemberExpr`. The testcase changes are pretty large, but I visually reviewed the changes and ran the resulting code and it worked produced the expected results. (It even uncovered a bug! :-D) Please take a look and let me know any issues you have. It's mostly an NFC patch, but it's so large and invasive that I can't really mark it as such. 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
[clang] [Clang][counted_by] Refactor __builtin_dynamic_object_size on FAMs (PR #122198)
llvmbot wrote: @llvm/pr-subscribers-clang Author: Bill Wendling (bwendling) Changes Refactoring of how __builtin_dynamic_object_size() is calculated for flexible array members (in preparation for adding support for the 'counted_by' attribute on pointers in structs). The only functionality change is that we use the already emitted Expr code to build our calculations off of rather than re-emitting the Expr. That allows the 'StructFieldAccess' visitor to sift through all casts and ArraySubscriptExprs to find the first MemberExpr. We build our GEPs and calculate offsets based off of relative distances from that MemberExpr. The testcase passes execution tests. There are four categories to support: struct p; struct s { /* ... */ int count; struct p *array[] __attribute__((counted_by(count))); }; 1) Object size of full flexible array member's size 'ptr->array': size_t count = (size_t) ptr->count; size_t flexible_array_member_base_size = sizeof (*ptr->array); size_t flexible_array_member_size = count * flexible_array_member_base_size; return flexible_array_member_size; 2) Object size from partial flexible array member '&ptr->array[idx]': size_t count = (size_t) ptr->count; size_t index = (size_t) idx; size_t flexible_array_member_base_size = sizeof (*ptr->array); size_t flexible_array_member_size = count * flexible_array_member_base_size; size_t index_size = index * flexible_array_member_base_size; return flexible_array_member_size - index_size; 3) Object size from '&ptr->field': size_t count = (size_t) ptr->count; size_t sizeof_struct = sizeof (struct s); size_t flexible_array_member_base_size = sizeof (*ptr->array); size_t flexible_array_member_size = count * flexible_array_member_base_size; size_t field_offset = offsetof (struct s, field); size_t offset_diff = sizeof_struct - field_offset; return flexible_array_member_size + offset_diff; 4) Object size from '&ptr->field[idx]': size_t count = (size_t) ptr->count; size_t index = (size_t) idx; size_t sizeof_struct = sizeof (struct s); size_t field_base_size = sizeof (*ptr->field); size_t flexible_array_member_base_size = sizeof (*ptr->array); size_t flexible_array_member_size = count * flexible_array_member_base_size; size_t field_offset = offsetof (struct s, field) + index * field_base_size; size_t offset_diff = sizeof_struct - field_offset; return offset_diff + flexible_array_member_size; --- Patch is 127.44 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/122198.diff 3 Files Affected: - (modified) clang/lib/CodeGen/CGBuiltin.cpp (+290-197) - (modified) clang/lib/CodeGen/CodeGenFunction.h (+5-13) - (modified) clang/test/CodeGen/attr-counted-by.c (+514-316) ``diff diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index dcea32969fb990..61450bcb5f9af8 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -29,6 +29,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/OSLog.h" #include "clang/AST/OperationKinds.h" +#include "clang/AST/StmtVisitor.h" #include "clang/AST/Type.h" #include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetInfo.h" @@ -1060,33 +1061,82 @@ 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 { + const ArraySubscriptExpr *ASE = nullptr; + + const MemberExpr *VisitMemberExpr(const MemberExpr *E) { return E; } + + const MemberExpr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { +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) { +return Visit(E->getSubExpr()); + } + const MemberExpr *VisitUnaryDeref(const clang::UnaryOperator *E) { +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, + co