Skip to content

Commit c6605a0

Browse files
authored
[clang][bytecode] Fix member pointers to IndirectFieldDecls (#104756)
1 parent 13865b0 commit c6605a0

File tree

2 files changed

+43
-15
lines changed

2 files changed

+43
-15
lines changed

clang/lib/AST/ByteCode/MemberPointer.cpp

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ namespace interp {
1818
std::optional<Pointer> MemberPointer::toPointer(const Context &Ctx) const {
1919
if (!Dcl || isa<FunctionDecl>(Dcl))
2020
return Base;
21-
const FieldDecl *FD = cast<FieldDecl>(Dcl);
22-
assert(FD);
21+
assert((isa<FieldDecl, IndirectFieldDecl>(Dcl)));
2322

2423
if (!Base.isBlockPointer())
2524
return std::nullopt;
@@ -31,24 +30,36 @@ std::optional<Pointer> MemberPointer::toPointer(const Context &Ctx) const {
3130
if (!BaseRecord)
3231
return std::nullopt;
3332

34-
assert(BaseRecord);
35-
if (FD->getParent() == BaseRecord->getDecl())
36-
return CastedBase.atField(BaseRecord->getField(FD)->Offset);
37-
38-
const RecordDecl *FieldParent = FD->getParent();
39-
const Record *FieldRecord = Ctx.getRecord(FieldParent);
40-
4133
unsigned Offset = 0;
42-
Offset += FieldRecord->getField(FD)->Offset;
4334
Offset += CastedBase.block()->getDescriptor()->getMetadataSize();
4435

45-
if (Offset > CastedBase.block()->getSize())
46-
return std::nullopt;
36+
if (const auto *FD = dyn_cast<FieldDecl>(Dcl)) {
37+
if (FD->getParent() == BaseRecord->getDecl())
38+
return CastedBase.atField(BaseRecord->getField(FD)->Offset);
4739

48-
if (const RecordDecl *BaseDecl = Base.getDeclPtr().getRecord()->getDecl();
49-
BaseDecl != FieldParent)
50-
Offset += Ctx.collectBaseOffset(FieldParent, BaseDecl);
40+
const RecordDecl *FieldParent = FD->getParent();
41+
const Record *FieldRecord = Ctx.getRecord(FieldParent);
5142

43+
Offset += FieldRecord->getField(FD)->Offset;
44+
if (Offset > CastedBase.block()->getSize())
45+
return std::nullopt;
46+
47+
if (const RecordDecl *BaseDecl = Base.getDeclPtr().getRecord()->getDecl();
48+
BaseDecl != FieldParent)
49+
Offset += Ctx.collectBaseOffset(FieldParent, BaseDecl);
50+
51+
} else {
52+
const auto *IFD = cast<IndirectFieldDecl>(Dcl);
53+
54+
for (const NamedDecl *ND : IFD->chain()) {
55+
const FieldDecl *F = cast<FieldDecl>(ND);
56+
const RecordDecl *FieldParent = F->getParent();
57+
const Record *FieldRecord = Ctx.getRecord(FieldParent);
58+
Offset += FieldRecord->getField(F)->Offset;
59+
}
60+
}
61+
62+
assert(BaseRecord);
5263
if (Offset > CastedBase.block()->getSize())
5364
return std::nullopt;
5465

clang/test/AST/ByteCode/memberpointers.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,3 +209,20 @@ namespace MemPtrTemporary {
209209

210210
static_assert(apply(A(), &A::f) == 5, "");
211211
}
212+
213+
namespace IndirectFields {
214+
struct I { union { struct { int a, b; }; }; };
215+
216+
template <typename T, int T::*F>
217+
constexpr int ReadField(const T &o) {
218+
return F ? o.*F : 0;
219+
}
220+
void ReadFields() {
221+
I i;
222+
ReadField<I, &I::a>(i);
223+
ReadField<I, &I::b>(i);
224+
}
225+
226+
constexpr I i{12};
227+
static_assert(ReadField<I, &I::a>(i) == 12, "");
228+
}

0 commit comments

Comments
 (0)