[clang] [clang][bytecode] Fix member pointers to IndirectFieldDecls (PR #104756)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Mon Aug 19 03:24:54 PDT 2024
https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/104756
>From f6787843ec316df6505274d3bb312d9d44c0de67 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Mon, 19 Aug 2024 11:31:10 +0200
Subject: [PATCH] [clang][bytecode] Fix member pointers to IndirectFieldDecls
---
clang/lib/AST/ByteCode/MemberPointer.cpp | 41 ++++++++++++++--------
clang/test/AST/ByteCode/memberpointers.cpp | 17 +++++++++
2 files changed, 43 insertions(+), 15 deletions(-)
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..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);
+}
More information about the cfe-commits
mailing list