[clang] c6605a0 - [clang][bytecode] Fix member pointers to IndirectFieldDecls (#104756)

via cfe-commits cfe-commits at lists.llvm.org
Mon Aug 19 06:28:16 PDT 2024


Author: Timm Baeder
Date: 2024-08-19T15:28:12+02:00
New Revision: c6605a08681309188fa260a409bf5d37400876a0

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

LOG: [clang][bytecode] Fix member pointers to IndirectFieldDecls (#104756)

Added: 
    

Modified: 
    clang/lib/AST/ByteCode/MemberPointer.cpp
    clang/test/AST/ByteCode/memberpointers.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ByteCode/MemberPointer.cpp b/clang/lib/AST/ByteCode/MemberPointer.cpp
index 0c1b6edc5f7e10..0fe94db97a3c40 100644
--- a/clang/lib/AST/ByteCode/MemberPointer.cpp
+++ b/clang/lib/AST/ByteCode/MemberPointer.cpp
@@ -18,8 +18,7 @@ namespace interp {
 std::optional<Pointer> MemberPointer::toPointer(const Context &Ctx) const {
   if (!Dcl || isa<FunctionDecl>(Dcl))
     return Base;
-  const FieldDecl *FD = cast<FieldDecl>(Dcl);
-  assert(FD);
+  assert((isa<FieldDecl, IndirectFieldDecl>(Dcl)));
 
   if (!Base.isBlockPointer())
     return std::nullopt;
@@ -31,24 +30,36 @@ std::optional<Pointer> MemberPointer::toPointer(const Context &Ctx) const {
   if (!BaseRecord)
     return std::nullopt;
 
-  assert(BaseRecord);
-  if (FD->getParent() == BaseRecord->getDecl())
-    return CastedBase.atField(BaseRecord->getField(FD)->Offset);
-
-  const RecordDecl *FieldParent = FD->getParent();
-  const Record *FieldRecord = Ctx.getRecord(FieldParent);
-
   unsigned Offset = 0;
-  Offset += FieldRecord->getField(FD)->Offset;
   Offset += CastedBase.block()->getDescriptor()->getMetadataSize();
 
-  if (Offset > CastedBase.block()->getSize())
-    return std::nullopt;
+  if (const auto *FD = dyn_cast<FieldDecl>(Dcl)) {
+    if (FD->getParent() == BaseRecord->getDecl())
+      return CastedBase.atField(BaseRecord->getField(FD)->Offset);
 
-  if (const RecordDecl *BaseDecl = Base.getDeclPtr().getRecord()->getDecl();
-      BaseDecl != FieldParent)
-    Offset += Ctx.collectBaseOffset(FieldParent, BaseDecl);
+    const RecordDecl *FieldParent = FD->getParent();
+    const Record *FieldRecord = Ctx.getRecord(FieldParent);
 
+    Offset += FieldRecord->getField(FD)->Offset;
+    if (Offset > CastedBase.block()->getSize())
+      return std::nullopt;
+
+    if (const RecordDecl *BaseDecl = Base.getDeclPtr().getRecord()->getDecl();
+        BaseDecl != FieldParent)
+      Offset += Ctx.collectBaseOffset(FieldParent, BaseDecl);
+
+  } else {
+    const auto *IFD = cast<IndirectFieldDecl>(Dcl);
+
+    for (const NamedDecl *ND : IFD->chain()) {
+      const FieldDecl *F = cast<FieldDecl>(ND);
+      const RecordDecl *FieldParent = F->getParent();
+      const Record *FieldRecord = Ctx.getRecord(FieldParent);
+      Offset += FieldRecord->getField(F)->Offset;
+    }
+  }
+
+  assert(BaseRecord);
   if (Offset > CastedBase.block()->getSize())
     return std::nullopt;
 

diff  --git a/clang/test/AST/ByteCode/memberpointers.cpp b/clang/test/AST/ByteCode/memberpointers.cpp
index f38e9486386315..ea4a725d3fd0df 100644
--- a/clang/test/AST/ByteCode/memberpointers.cpp
+++ b/clang/test/AST/ByteCode/memberpointers.cpp
@@ -209,3 +209,20 @@ namespace MemPtrTemporary {
 
   static_assert(apply(A(), &A::f) == 5, "");
 }
+
+namespace IndirectFields {
+  struct I { union { struct { int a, b; }; }; };
+
+  template <typename T, int T::*F>
+  constexpr int ReadField(const T &o) {
+    return F ? o.*F : 0;
+  }
+  void ReadFields() {
+    I i;
+    ReadField<I, &I::a>(i);
+    ReadField<I, &I::b>(i);
+  }
+
+  constexpr I i{12};
+  static_assert(ReadField<I, &I::a>(i) == 12, "");
+}


        


More information about the cfe-commits mailing list