[clang] 59e1366 - [clang][Interp] Fix getField() for integral pointers (#102120)

via cfe-commits cfe-commits at lists.llvm.org
Tue Aug 6 04:37:16 PDT 2024


Author: Timm Baeder
Date: 2024-08-06T13:37:11+02:00
New Revision: 59e13666dd2e81e58253488a29635fb2992ed741

URL: https://github.com/llvm/llvm-project/commit/59e13666dd2e81e58253488a29635fb2992ed741
DIFF: https://github.com/llvm/llvm-project/commit/59e13666dd2e81e58253488a29635fb2992ed741.diff

LOG: [clang][Interp] Fix getField() for integral pointers (#102120)

Instead of just adding the Record::Field offset, instead get the
FieldDecl offset in the RecordLayout.

Unfortunately, the offset we pass to the ops here is not made to easily
go back to a FieldDecl, so we have to iterate over the parent Record.

Added: 
    

Modified: 
    clang/lib/AST/Interp/Compiler.cpp
    clang/lib/AST/Interp/Interp.h
    clang/lib/AST/Interp/Pointer.cpp
    clang/lib/AST/Interp/Pointer.h
    clang/test/AST/Interp/c.c

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp
index e5280491dfd73..02cbe38f5fb1f 100644
--- a/clang/lib/AST/Interp/Compiler.cpp
+++ b/clang/lib/AST/Interp/Compiler.cpp
@@ -335,6 +335,10 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
     if (!PointeeType.isNull()) {
       if (std::optional<PrimType> T = classify(PointeeType))
         Desc = P.createDescriptor(SubExpr, *T);
+      else
+        Desc = P.createDescriptor(SubExpr, PointeeType.getTypePtr(),
+                                  std::nullopt, true, false,
+                                  /*IsMutable=*/false, nullptr);
     }
     return this->emitNull(classifyPrim(CE->getType()), Desc, CE);
   }

diff  --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index 04f88efdc0acf..2eed0d3d1f16b 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -1504,6 +1504,12 @@ inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
 
   if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize())
     return false;
+
+  if (Ptr.isIntegralPointer()) {
+    S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getCtx(), Off));
+    return true;
+  }
+
   S.Stk.push<Pointer>(Ptr.atField(Off));
   return true;
 }
@@ -1527,6 +1533,11 @@ inline bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
   if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize())
     return false;
 
+  if (Ptr.isIntegralPointer()) {
+    S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getCtx(), Off));
+    return true;
+  }
+
   S.Stk.push<Pointer>(Ptr.atField(Off));
   return true;
 }

diff  --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp
index 2b1f8b460510c..ba9683a059e18 100644
--- a/clang/lib/AST/Interp/Pointer.cpp
+++ b/clang/lib/AST/Interp/Pointer.cpp
@@ -597,3 +597,30 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
     return std::nullopt;
   return Result;
 }
+
+IntPointer IntPointer::atOffset(const ASTContext &ASTCtx,
+                                unsigned Offset) const {
+  if (!this->Desc)
+    return *this;
+  const Record *R = this->Desc->ElemRecord;
+  if (!R)
+    return *this;
+
+  const Record::Field *F = nullptr;
+  for (auto &It : R->fields()) {
+    if (It.Offset == Offset) {
+      F = &It;
+      break;
+    }
+  }
+  if (!F)
+    return *this;
+
+  const FieldDecl *FD = F->Decl;
+  const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());
+  unsigned FieldIndex = FD->getFieldIndex();
+  uint64_t FieldOffset =
+      ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex))
+          .getQuantity();
+  return IntPointer{this->Desc, FieldOffset};
+}

diff  --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h
index 6f6983458ab60..b7b4f82f16f66 100644
--- a/clang/lib/AST/Interp/Pointer.h
+++ b/clang/lib/AST/Interp/Pointer.h
@@ -44,6 +44,8 @@ struct BlockPointer {
 struct IntPointer {
   const Descriptor *Desc;
   uint64_t Value;
+
+  IntPointer atOffset(const ASTContext &ASTCtx, unsigned Offset) const;
 };
 
 enum class Storage { Block, Int, Fn };
@@ -88,6 +90,9 @@ class Pointer {
     PointeeStorage.Int.Value = 0;
     PointeeStorage.Int.Desc = nullptr;
   }
+  Pointer(IntPointer &&IntPtr) : StorageKind(Storage::Int) {
+    PointeeStorage.Int = std::move(IntPtr);
+  }
   Pointer(Block *B);
   Pointer(Block *B, uint64_t BaseAndOffset);
   Pointer(const Pointer &P);
@@ -161,9 +166,8 @@ class Pointer {
 
   /// Creates a pointer to a field.
   [[nodiscard]] Pointer atField(unsigned Off) const {
+    assert(isBlockPointer());
     unsigned Field = Offset + Off;
-    if (isIntegralPointer())
-      return Pointer(asIntPointer().Value + Field, asIntPointer().Desc);
     return Pointer(asBlockPointer().Pointee, Field, Field);
   }
 

diff  --git a/clang/test/AST/Interp/c.c b/clang/test/AST/Interp/c.c
index 9ec305d59c68c..13a5e082a125f 100644
--- a/clang/test/AST/Interp/c.c
+++ b/clang/test/AST/Interp/c.c
@@ -101,8 +101,6 @@ int somefunc(int i) {
                              // all-warning {{overflow in expression; result is 131'073 with type 'int'}}
 }
 
-/// FIXME: The following test is incorrect in the new interpreter.
-/// The null pointer returns 16 from its getIntegerRepresentation().
 #pragma clang diagnostic ignored "-Wpointer-to-int-cast"
 struct ArrayStruct {
   char n[1];
@@ -111,10 +109,7 @@ char name2[(int)&((struct ArrayStruct*)0)->n]; // expected-warning {{folded to c
                                                // pedantic-expected-warning {{folded to constant array}} \
                                                // ref-warning {{folded to constant array}} \
                                                // pedantic-ref-warning {{folded to constant array}}
-_Static_assert(sizeof(name2) == 0, ""); // expected-error {{failed}} \
-                                        // expected-note {{evaluates to}} \
-                                        // pedantic-expected-error {{failed}} \
-                                        // pedantic-expected-note {{evaluates to}}
+_Static_assert(sizeof(name2) == 0, "");
 
 #ifdef __SIZEOF_INT128__
 void *PR28739d = &(&PR28739d)[(__int128)(unsigned long)-1]; // all-warning {{refers past the last possible element}}


        


More information about the cfe-commits mailing list