Skip to content

Commit 8207ae2

Browse files
tbaederryuxuanchen1997
authored andcommitted
[clang][Interp] Calculate APValue offsets for base classes
Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: Differential Revision: https://phabricator.intern.facebook.com/D60251144
1 parent b1d7985 commit 8207ae2

File tree

5 files changed

+41
-9
lines changed

5 files changed

+41
-9
lines changed

clang/lib/AST/Interp/Descriptor.cpp

+6-4
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,8 @@ static void initField(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
162162
}
163163

164164
static void initBase(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
165-
bool IsActive, const Descriptor *D, unsigned FieldOffset) {
165+
bool IsActive, const Descriptor *D, unsigned FieldOffset,
166+
bool IsVirtualBase) {
166167
assert(D);
167168
assert(D->ElemRecord);
168169

@@ -172,13 +173,14 @@ static void initBase(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
172173
Desc->Desc = D;
173174
Desc->IsInitialized = D->IsArray;
174175
Desc->IsBase = true;
176+
Desc->IsVirtualBase = IsVirtualBase;
175177
Desc->IsActive = IsActive && !IsUnion;
176178
Desc->IsConst = IsConst || D->IsConst;
177179
Desc->IsFieldMutable = IsMutable || D->IsMutable;
178180

179181
for (const auto &V : D->ElemRecord->bases())
180182
initBase(B, Ptr + FieldOffset, IsConst, IsMutable, IsActive, V.Desc,
181-
V.Offset);
183+
V.Offset, false);
182184
for (const auto &F : D->ElemRecord->fields())
183185
initField(B, Ptr + FieldOffset, IsConst, IsMutable, IsActive, IsUnion,
184186
F.Desc, F.Offset);
@@ -187,11 +189,11 @@ static void initBase(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
187189
static void ctorRecord(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,
188190
bool IsActive, const Descriptor *D) {
189191
for (const auto &V : D->ElemRecord->bases())
190-
initBase(B, Ptr, IsConst, IsMutable, IsActive, V.Desc, V.Offset);
192+
initBase(B, Ptr, IsConst, IsMutable, IsActive, V.Desc, V.Offset, false);
191193
for (const auto &F : D->ElemRecord->fields())
192194
initField(B, Ptr, IsConst, IsMutable, IsActive, D->ElemRecord->isUnion(), F.Desc, F.Offset);
193195
for (const auto &V : D->ElemRecord->virtual_bases())
194-
initBase(B, Ptr, IsConst, IsMutable, IsActive, V.Desc, V.Offset);
196+
initBase(B, Ptr, IsConst, IsMutable, IsActive, V.Desc, V.Offset, true);
195197
}
196198

197199
static void destroyField(Block *B, std::byte *Ptr, const Descriptor *D,

clang/lib/AST/Interp/Descriptor.h

+2
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ struct InlineDescriptor {
8383
/// Flag indicating if the field is an embedded base class.
8484
LLVM_PREFERRED_TYPE(bool)
8585
unsigned IsBase : 1;
86+
LLVM_PREFERRED_TYPE(bool)
87+
unsigned IsVirtualBase : 1;
8688
/// Flag indicating if the field is the active member of a union.
8789
LLVM_PREFERRED_TYPE(bool)
8890
unsigned IsActive : 1;

clang/lib/AST/Interp/Pointer.cpp

+17-5
Original file line numberDiff line numberDiff line change
@@ -180,18 +180,30 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
180180
Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index));
181181
Ptr = Ptr.getArray();
182182
} else {
183-
// TODO: figure out if base is virtual
184183
bool IsVirtual = false;
185184

186185
// Create a path entry for the field.
187186
const Descriptor *Desc = Ptr.getFieldDesc();
188187
if (const auto *BaseOrMember = Desc->asDecl()) {
189-
Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
190-
Ptr = Ptr.getBase();
191-
192-
if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember))
188+
if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember)) {
189+
Ptr = Ptr.getBase();
193190
Offset += getFieldOffset(FD);
191+
} else if (const auto *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) {
192+
IsVirtual = Ptr.isVirtualBaseClass();
193+
Ptr = Ptr.getBase();
194+
const Record *BaseRecord = Ptr.getRecord();
195+
196+
const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(
197+
cast<CXXRecordDecl>(BaseRecord->getDecl()));
198+
if (IsVirtual)
199+
Offset += Layout.getVBaseClassOffset(RD);
200+
else
201+
Offset += Layout.getBaseClassOffset(RD);
194202

203+
} else {
204+
Ptr = Ptr.getBase();
205+
}
206+
Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
195207
continue;
196208
}
197209
llvm_unreachable("Invalid field type");

clang/lib/AST/Interp/Pointer.h

+3
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,9 @@ class Pointer {
487487
}
488488
/// Checks if a structure is a base class.
489489
bool isBaseClass() const { return isField() && getInlineDesc()->IsBase; }
490+
bool isVirtualBaseClass() const {
491+
return isField() && getInlineDesc()->IsVirtualBase;
492+
}
490493
/// Checks if the pointer points to a dummy value.
491494
bool isDummy() const {
492495
if (!isBlockPointer())

clang/test/AST/Interp/codegen.cpp

+13
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,16 @@ struct S {
1818
S s;
1919
// CHECK: @sp = constant ptr getelementptr (i8, ptr @s, i64 16), align 8
2020
float &sp = s.c[3];
21+
22+
23+
namespace BaseClassOffsets {
24+
struct A { int a; };
25+
struct B { int b; };
26+
struct C : A, B { int c; };
27+
28+
extern C c;
29+
// CHECK: @_ZN16BaseClassOffsets1aE = global ptr @_ZN16BaseClassOffsets1cE, align 8
30+
A* a = &c;
31+
// CHECK: @_ZN16BaseClassOffsets1bE = global ptr getelementptr (i8, ptr @_ZN16BaseClassOffsets1cE, i64 4), align 8
32+
B* b = &c;
33+
}

0 commit comments

Comments
 (0)