[clang] [clang][bytecode] Fix bos/bdos with non-zero offset applied (PR #136482)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Apr 20 04:40:00 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Timm Baeder (tbaederr)
<details>
<summary>Changes</summary>
Compute the offset from the record layout.
Unfortunately, not all the test cases from the current interpreter work.
---
Full diff: https://github.com/llvm/llvm-project/pull/136482.diff
2 Files Affected:
- (modified) clang/lib/AST/ByteCode/InterpBuiltin.cpp (+48-1)
- (modified) clang/test/AST/ByteCode/builtin-object-size.cpp (+43-1)
``````````diff
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'}}
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/136482
More information about the cfe-commits
mailing list