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

via cfe-commits cfe-commits at lists.llvm.org
Mon Aug 19 03:20:12 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Timm Baeder (tbaederr)

<details>
<summary>Changes</summary>



---
Full diff: https://github.com/llvm/llvm-project/pull/104756.diff


2 Files Affected:

- (modified) clang/lib/AST/ByteCode/MemberPointer.cpp (+29-14) 
- (modified) clang/test/AST/ByteCode/memberpointers.cpp (+17) 


``````````diff
diff --git a/clang/lib/AST/ByteCode/MemberPointer.cpp b/clang/lib/AST/ByteCode/MemberPointer.cpp
index 0c1b6edc5f7e10..1cc4800e5195d5 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,40 @@ 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);
-
+  const RecordDecl *FieldParent = nullptr;
   unsigned Offset = 0;
-  Offset += FieldRecord->getField(FD)->Offset;
   Offset += CastedBase.block()->getDescriptor()->getMetadataSize();
 
+  if (const auto *FD = dyn_cast<FieldDecl>(Dcl)) {
+    if (FD->getParent() == BaseRecord->getDecl())
+      return CastedBase.atField(BaseRecord->getField(FD)->Offset);
+
+    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);
+      FieldParent = F->getParent();
+      const Record *FieldRecord = Ctx.getRecord(FieldParent);
+      Offset += FieldRecord->getField(F)->Offset;
+    }
+  }
+
+  assert(FieldParent);
+  assert(BaseRecord);
   if (Offset > CastedBase.block()->getSize())
     return std::nullopt;
 
-  if (const RecordDecl *BaseDecl = Base.getDeclPtr().getRecord()->getDecl();
-      BaseDecl != FieldParent)
-    Offset += Ctx.collectBaseOffset(FieldParent, BaseDecl);
-
   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..f73d09a6cf9e0a 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>
+  int ReadField(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);
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/104756


More information about the cfe-commits mailing list