Author: Timm Baeder Date: 2025-04-20T20:12:47+02:00 New Revision: ea3eb8d6258a018f118b5d41057ca333d1c8d4a0
URL: https://github.com/llvm/llvm-project/commit/ea3eb8d6258a018f118b5d41057ca333d1c8d4a0 DIFF: https://github.com/llvm/llvm-project/commit/ea3eb8d6258a018f118b5d41057ca333d1c8d4a0.diff LOG: [clang][bytecode] Fix bos/bdos with non-zero offset applied (#136482) Compute the offset from the record layout. Unfortunately, not all the test cases from the current interpreter work. Added: Modified: clang/lib/AST/ByteCode/InterpBuiltin.cpp clang/test/AST/ByteCode/builtin-object-size.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index aaf0f3f019b94..523e471d3c82c 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -2196,6 +2196,53 @@ static unsigned computeFullDescSize(const ASTContext &ASTCtx, return 0; } +static unsigned computePointerOffset(const ASTContext &ASTCtx, + const Pointer &Ptr) { + unsigned Result = 0; + + Pointer P = Ptr; + while (P.isArrayElement() || P.isField()) { + P = P.expand(); + const Descriptor *D = P.getFieldDesc(); + + if (P.isArrayElement()) { + unsigned ElemSize = + ASTCtx.getTypeSizeInChars(D->getElemQualType()).getQuantity(); + if (P.isOnePastEnd()) + Result += ElemSize * P.getNumElems(); + else + Result += ElemSize * P.getIndex(); + P = P.expand().getArray(); + } else if (P.isBaseClass()) { + + const auto *RD = cast<CXXRecordDecl>(D->asDecl()); + bool IsVirtual = Ptr.isVirtualBaseClass(); + P = P.getBase(); + const Record *BaseRecord = P.getRecord(); + + const ASTRecordLayout &Layout = + ASTCtx.getASTRecordLayout(cast<CXXRecordDecl>(BaseRecord->getDecl())); + if (IsVirtual) + Result += Layout.getVBaseClassOffset(RD).getQuantity(); + else + Result += Layout.getBaseClassOffset(RD).getQuantity(); + } else if (P.isField()) { + const FieldDecl *FD = P.getField(); + const ASTRecordLayout &Layout = + ASTCtx.getASTRecordLayout(FD->getParent()); + unsigned FieldIndex = FD->getFieldIndex(); + uint64_t FieldOffset = + ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex)) + .getQuantity(); + Result += FieldOffset; + P = P.getBase(); + } else + llvm_unreachable("Unhandled descriptor type"); + } + + return Result; +} + static bool interp__builtin_object_size(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *Func, @@ -2217,7 +2264,7 @@ static bool interp__builtin_object_size(InterpState &S, CodePtr OpPC, const ASTContext &ASTCtx = S.getASTContext(); - unsigned ByteOffset = 0; + unsigned ByteOffset = computePointerOffset(ASTCtx, Ptr); unsigned FullSize = computeFullDescSize(ASTCtx, DeclDesc); pushInteger(S, FullSize - ByteOffset, Call->getType()); diff --git a/clang/test/AST/ByteCode/builtin-object-size.cpp b/clang/test/AST/ByteCode/builtin-object-size.cpp index 62bb1642c5301..6f4ef54bcbafa 100644 --- a/clang/test/AST/ByteCode/builtin-object-size.cpp +++ b/clang/test/AST/ByteCode/builtin-object-size.cpp @@ -1,7 +1,9 @@ // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=both,expected %s // RUN: %clang_cc1 -verify=both,ref %s -// both-no-diagnostics +// ref-no-diagnostics + +typedef __SIZE_TYPE__ size_t; int a; static_assert(__builtin_object_size(&a, 0) == sizeof(int), ""); @@ -12,3 +14,43 @@ static_assert(__builtin_object_size(&arr, 0) == (sizeof(int)*2), ""); float arrf[2]; static_assert(__builtin_object_size(&arrf, 0) == (sizeof(float)*2), ""); +static_assert(__builtin_object_size(&arrf[1], 0) == sizeof(float), ""); +static_assert(__builtin_object_size(&arrf[2], 0) == 0, ""); + + + +struct S { + int a; + char c; +}; + +S s; +static_assert(__builtin_object_size(&s, 0) == sizeof(s), ""); + +S ss[2]; +static_assert(__builtin_object_size(&ss[1], 0) == sizeof(s), ""); +static_assert(__builtin_object_size(&ss[1].c, 0) == sizeof(int), ""); + +struct A { char buf[16]; }; +struct B : A {}; +struct C { int i; B bs[1]; } c; +static_assert(__builtin_object_size(&c.bs[0], 3) == 16); +static_assert(__builtin_object_size(&c.bs[1], 3) == 0); + +/// These are from test/SemaCXX/builtin-object-size-cxx14. +/// They all don't work since they are rejected when evaluating the first +/// parameter of the __builtin_object_size call. +/// +/// GCC rejects them as well. +namespace InvalidBase { + // Ensure this doesn't crash. + struct S { const char *name; }; + S invalid_base(); // expected-note {{declared here}} + constexpr size_t bos_name = __builtin_object_size(invalid_base().name, 1); // expected-error {{must be initialized by a constant expression}} \ + // expected-note {{non-constexpr function 'invalid_base'}} + + struct T { ~T(); }; + T invalid_base_2(); + constexpr size_t bos_dtor = __builtin_object_size(&(T&)(T&&)invalid_base_2(), 0); // expected-error {{must be initialized by a constant expression}} \ + // expected-note {{non-literal type 'T'}} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits