1616#include " MemberPointer.h"
1717#include " PrimType.h"
1818#include " Record.h"
19+ #include " clang/AST/RecordLayout.h"
1920
2021using namespace clang ;
2122using namespace clang ::interp;
@@ -141,25 +142,38 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
141142 else
142143 llvm_unreachable (" Invalid allocation type" );
143144
144- if (isDummy () || isUnknownSizeArray () || Desc->asExpr ())
145+ if (isUnknownSizeArray () || Desc->asExpr ())
145146 return APValue (Base, CharUnits::Zero (), Path,
146147 /* IsOnePastEnd=*/ isOnePastEnd (), /* IsNullPtr=*/ false );
147148
148- // TODO: compute the offset into the object.
149149 CharUnits Offset = CharUnits::Zero ();
150150
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+
151157 // Build the path into the object.
152158 Pointer Ptr = *this ;
153159 while (Ptr.isField () || Ptr.isArrayElement ()) {
154160 if (Ptr.isArrayRoot ()) {
155161 Path.push_back (APValue::LValuePathEntry (
156162 {Ptr.getFieldDesc ()->asDecl (), /* IsVirtual=*/ false }));
163+
164+ if (const auto *FD = dyn_cast<FieldDecl>(Ptr.getFieldDesc ()->asDecl ()))
165+ Offset += getFieldOffset (FD);
166+
157167 Ptr = Ptr.getBase ();
158168 } else if (Ptr.isArrayElement ()) {
169+ unsigned Index;
159170 if (Ptr.isOnePastEnd ())
160- Path. push_back ( APValue::LValuePathEntry::ArrayIndex ( Ptr.getArray ().getNumElems ()) );
171+ Index = Ptr.getArray ().getNumElems ();
161172 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));
163177 Ptr = Ptr.getArray ();
164178 } else {
165179 // TODO: figure out if base is virtual
@@ -170,12 +184,21 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
170184 if (const auto *BaseOrMember = Desc->asDecl ()) {
171185 Path.push_back (APValue::LValuePathEntry ({BaseOrMember, IsVirtual}));
172186 Ptr = Ptr.getBase ();
187+
188+ if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember))
189+ Offset += getFieldOffset (FD);
190+
173191 continue ;
174192 }
175193 llvm_unreachable (" Invalid field type" );
176194 }
177195 }
178196
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+
179202 // We assemble the LValuePath starting from the innermost pointer to the
180203 // outermost one. SO in a.b.c, the first element in Path will refer to
181204 // the field 'c', while later code expects it to refer to 'a'.
0 commit comments