Skip to content

Conversation

@tbaederr
Copy link
Contributor

Compute the offset from the record layout.
Unfortunately, not all the test cases from the current interpreter work.

Compute the offset from the record layout.
Unfortunately, not all the test cases from the current interpreter work.
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:bytecode Issues for the clang bytecode constexpr interpreter labels Apr 20, 2025
@llvmbot
Copy link
Member

llvmbot commented Apr 20, 2025

@llvm/pr-subscribers-clang

Author: Timm Baeder (tbaederr)

Changes

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 --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'}}
+}

@tbaederr tbaederr merged commit ea3eb8d into llvm:main Apr 20, 2025
15 checks passed
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
)

Compute the offset from the record layout.
Unfortunately, not all the test cases from the current interpreter work.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:bytecode Issues for the clang bytecode constexpr interpreter clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants