16
16
#include " MemberPointer.h"
17
17
#include " PrimType.h"
18
18
#include " Record.h"
19
+ #include " clang/AST/RecordLayout.h"
19
20
20
21
using namespace clang ;
21
22
using namespace clang ::interp;
@@ -141,25 +142,38 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
141
142
else
142
143
llvm_unreachable (" Invalid allocation type" );
143
144
144
- if (isDummy () || isUnknownSizeArray () || Desc->asExpr ())
145
+ if (isUnknownSizeArray () || Desc->asExpr ())
145
146
return APValue (Base, CharUnits::Zero (), Path,
146
147
/* IsOnePastEnd=*/ isOnePastEnd (), /* IsNullPtr=*/ false );
147
148
148
- // TODO: compute the offset into the object.
149
149
CharUnits Offset = CharUnits::Zero ();
150
150
151
+ auto getFieldOffset = [&](const FieldDecl *FD) -> CharUnits {
152
+ const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout (FD->getParent ());
153
+ unsigned FieldIndex = FD->getFieldIndex ();
154
+ return ASTCtx.toCharUnitsFromBits (Layout.getFieldOffset (FieldIndex));
155
+ };
156
+
151
157
// Build the path into the object.
152
158
Pointer Ptr = *this ;
153
159
while (Ptr .isField () || Ptr .isArrayElement ()) {
154
160
if (Ptr .isArrayRoot ()) {
155
161
Path.push_back (APValue::LValuePathEntry (
156
162
{Ptr .getFieldDesc ()->asDecl (), /* IsVirtual=*/ false }));
163
+
164
+ if (const auto *FD = dyn_cast<FieldDecl>(Ptr .getFieldDesc ()->asDecl ()))
165
+ Offset += getFieldOffset (FD);
166
+
157
167
Ptr = Ptr .getBase ();
158
168
} else if (Ptr .isArrayElement ()) {
169
+ unsigned Index;
159
170
if (Ptr .isOnePastEnd ())
160
- Path. push_back ( APValue::LValuePathEntry::ArrayIndex ( Ptr .getArray ().getNumElems ()) );
171
+ Index = Ptr .getArray ().getNumElems ();
161
172
else
162
- Path.push_back (APValue::LValuePathEntry::ArrayIndex (Ptr .getIndex ()));
173
+ Index = Ptr .getIndex ();
174
+
175
+ Offset += (Index * ASTCtx.getTypeSizeInChars (Ptr .getType ()));
176
+ Path.push_back (APValue::LValuePathEntry::ArrayIndex (Index));
163
177
Ptr = Ptr .getArray ();
164
178
} else {
165
179
// TODO: figure out if base is virtual
@@ -170,12 +184,21 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
170
184
if (const auto *BaseOrMember = Desc->asDecl ()) {
171
185
Path.push_back (APValue::LValuePathEntry ({BaseOrMember, IsVirtual}));
172
186
Ptr = Ptr .getBase ();
187
+
188
+ if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember))
189
+ Offset += getFieldOffset (FD);
190
+
173
191
continue ;
174
192
}
175
193
llvm_unreachable (" Invalid field type" );
176
194
}
177
195
}
178
196
197
+ // FIXME(perf): We compute the lvalue path above, but we can't supply it
198
+ // for dummy pointers (that causes crashes later in CheckConstantExpression).
199
+ if (isDummy ())
200
+ Path.clear ();
201
+
179
202
// We assemble the LValuePath starting from the innermost pointer to the
180
203
// outermost one. SO in a.b.c, the first element in Path will refer to
181
204
// the field 'c', while later code expects it to refer to 'a'.
0 commit comments