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

Reply via email to