xref: /llvm-project/clang/unittests/AST/ByteCode/Descriptor.cpp (revision 800b07396ff54b037fa9b73bb15586456656fb79)
1a07aba5dSTimm Baeder #include "../../../lib/AST/ByteCode/Descriptor.h"
2a07aba5dSTimm Baeder #include "../../../lib/AST/ByteCode/Context.h"
3a07aba5dSTimm Baeder #include "../../../lib/AST/ByteCode/Program.h"
4a07aba5dSTimm Baeder #include "clang/AST/ASTContext.h"
5a07aba5dSTimm Baeder #include "clang/AST/Decl.h"
6a07aba5dSTimm Baeder #include "clang/ASTMatchers/ASTMatchFinder.h"
7a07aba5dSTimm Baeder #include "clang/ASTMatchers/ASTMatchers.h"
8a07aba5dSTimm Baeder #include "clang/Tooling/Tooling.h"
9a07aba5dSTimm Baeder #include "gtest/gtest.h"
10a07aba5dSTimm Baeder 
11a07aba5dSTimm Baeder using namespace clang;
12a07aba5dSTimm Baeder using namespace clang::interp;
13a07aba5dSTimm Baeder using namespace clang::ast_matchers;
14a07aba5dSTimm Baeder 
15a07aba5dSTimm Baeder /// Inspect generated Descriptors as well as the pointers we create.
16a07aba5dSTimm Baeder ///
17a07aba5dSTimm Baeder TEST(Descriptor, Primitives) {
18a07aba5dSTimm Baeder   constexpr char Code[] = "struct A { bool a; bool b; };\n"
19a07aba5dSTimm Baeder                           "struct S {\n"
20a07aba5dSTimm Baeder                           "  float f;\n"
21a07aba5dSTimm Baeder                           "  char s[4];\n"
22a07aba5dSTimm Baeder                           "  A a[3];\n"
23a07aba5dSTimm Baeder                           "  short l[3][3];\n"
24a07aba5dSTimm Baeder                           "  int EmptyA[0];\n"
25a07aba5dSTimm Baeder                           "};\n"
26a07aba5dSTimm Baeder                           "constexpr S d = {0.0, \"foo\", {{true, false}, "
27a07aba5dSTimm Baeder                           "{false, true}, {false, false}},\n"
28a07aba5dSTimm Baeder                           "  {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, {}};\n";
29a07aba5dSTimm Baeder 
30a07aba5dSTimm Baeder   auto AST = tooling::buildASTFromCodeWithArgs(
31a07aba5dSTimm Baeder       Code, {"-fexperimental-new-constant-interpreter"});
32a07aba5dSTimm Baeder 
33a07aba5dSTimm Baeder   const VarDecl *D = selectFirst<VarDecl>(
34a07aba5dSTimm Baeder       "d", match(varDecl().bind("d"), AST->getASTContext()));
35a07aba5dSTimm Baeder   ASSERT_NE(D, nullptr);
36a07aba5dSTimm Baeder 
37a07aba5dSTimm Baeder   const auto &Ctx = AST->getASTContext().getInterpContext();
38a07aba5dSTimm Baeder   Program &Prog = Ctx.getProgram();
39a07aba5dSTimm Baeder   // Global is registered.
40a07aba5dSTimm Baeder   ASSERT_TRUE(Prog.getGlobal(D));
41a07aba5dSTimm Baeder 
42a07aba5dSTimm Baeder   // Get a Pointer to the global.
43a07aba5dSTimm Baeder   const Pointer &GlobalPtr = Prog.getPtrGlobal(*Prog.getGlobal(D));
44a07aba5dSTimm Baeder 
45a07aba5dSTimm Baeder   // Test Descriptor of the struct S.
46a07aba5dSTimm Baeder   const Descriptor *GlobalDesc = GlobalPtr.getFieldDesc();
47a07aba5dSTimm Baeder   ASSERT_TRUE(GlobalDesc == GlobalPtr.getDeclDesc());
48a07aba5dSTimm Baeder 
49a07aba5dSTimm Baeder   ASSERT_TRUE(GlobalDesc->asDecl() == D);
50a07aba5dSTimm Baeder   ASSERT_FALSE(GlobalDesc->asExpr());
51a07aba5dSTimm Baeder   ASSERT_TRUE(GlobalDesc->asValueDecl() == D);
52a07aba5dSTimm Baeder   ASSERT_FALSE(GlobalDesc->asFieldDecl());
53a07aba5dSTimm Baeder   ASSERT_FALSE(GlobalDesc->asRecordDecl());
54a07aba5dSTimm Baeder 
55a07aba5dSTimm Baeder   // Still true because this is a global variable.
56a07aba5dSTimm Baeder   ASSERT_TRUE(GlobalDesc->getMetadataSize() == sizeof(GlobalInlineDescriptor));
57a07aba5dSTimm Baeder   ASSERT_FALSE(GlobalDesc->isPrimitiveArray());
58a07aba5dSTimm Baeder   ASSERT_FALSE(GlobalDesc->isCompositeArray());
59a07aba5dSTimm Baeder   ASSERT_FALSE(GlobalDesc->isZeroSizeArray());
60a07aba5dSTimm Baeder   ASSERT_FALSE(GlobalDesc->isUnknownSizeArray());
61a07aba5dSTimm Baeder   ASSERT_FALSE(GlobalDesc->isPrimitive());
62a07aba5dSTimm Baeder   ASSERT_FALSE(GlobalDesc->isArray());
63a07aba5dSTimm Baeder   ASSERT_TRUE(GlobalDesc->isRecord());
64a07aba5dSTimm Baeder 
65a07aba5dSTimm Baeder   // Test the Record for the struct S.
66a07aba5dSTimm Baeder   const Record *SRecord = GlobalDesc->ElemRecord;
67a07aba5dSTimm Baeder   ASSERT_TRUE(SRecord);
68a07aba5dSTimm Baeder   ASSERT_TRUE(SRecord->getNumFields() == 5);
69a07aba5dSTimm Baeder   ASSERT_TRUE(SRecord->getNumBases() == 0);
70a07aba5dSTimm Baeder   ASSERT_FALSE(SRecord->getDestructor());
71a07aba5dSTimm Baeder 
72a07aba5dSTimm Baeder   // First field.
73a07aba5dSTimm Baeder   const Record::Field *F1 = SRecord->getField(0u);
74a07aba5dSTimm Baeder   ASSERT_TRUE(F1);
75a07aba5dSTimm Baeder   ASSERT_FALSE(F1->isBitField());
76a07aba5dSTimm Baeder   ASSERT_TRUE(F1->Desc->isPrimitive());
77a07aba5dSTimm Baeder 
78a07aba5dSTimm Baeder   // Second field.
79a07aba5dSTimm Baeder   const Record::Field *F2 = SRecord->getField(1u);
80a07aba5dSTimm Baeder   ASSERT_TRUE(F2);
81a07aba5dSTimm Baeder   ASSERT_FALSE(F2->isBitField());
82a07aba5dSTimm Baeder   ASSERT_TRUE(F2->Desc->isArray());
83a07aba5dSTimm Baeder   ASSERT_FALSE(F2->Desc->isCompositeArray());
84a07aba5dSTimm Baeder   ASSERT_TRUE(F2->Desc->isPrimitiveArray());
85a07aba5dSTimm Baeder   ASSERT_FALSE(F2->Desc->isPrimitive());
86a07aba5dSTimm Baeder   ASSERT_FALSE(F2->Desc->ElemDesc);
87a07aba5dSTimm Baeder   ASSERT_EQ(F2->Desc->getNumElems(), 4u);
88a07aba5dSTimm Baeder   ASSERT_TRUE(F2->Desc->getElemSize() > 0);
89a07aba5dSTimm Baeder 
90a07aba5dSTimm Baeder   // Third field.
91a07aba5dSTimm Baeder   const Record::Field *F3 = SRecord->getField(2u);
92a07aba5dSTimm Baeder   ASSERT_TRUE(F3);
93a07aba5dSTimm Baeder   ASSERT_FALSE(F3->isBitField());
94a07aba5dSTimm Baeder   ASSERT_TRUE(F3->Desc->isArray());
95a07aba5dSTimm Baeder   ASSERT_TRUE(F3->Desc->isCompositeArray());
96a07aba5dSTimm Baeder   ASSERT_FALSE(F3->Desc->isPrimitiveArray());
97a07aba5dSTimm Baeder   ASSERT_FALSE(F3->Desc->isPrimitive());
98a07aba5dSTimm Baeder   ASSERT_TRUE(F3->Desc->ElemDesc);
99a07aba5dSTimm Baeder   ASSERT_EQ(F3->Desc->getNumElems(), 3u);
100a07aba5dSTimm Baeder   ASSERT_TRUE(F3->Desc->getElemSize() > 0);
101a07aba5dSTimm Baeder 
102a07aba5dSTimm Baeder   // Fourth field.
103a07aba5dSTimm Baeder   // Multidimensional arrays are treated as composite arrays, even
104a07aba5dSTimm Baeder   // if the value type is primitive.
105a07aba5dSTimm Baeder   const Record::Field *F4 = SRecord->getField(3u);
106a07aba5dSTimm Baeder   ASSERT_TRUE(F4);
107a07aba5dSTimm Baeder   ASSERT_FALSE(F4->isBitField());
108a07aba5dSTimm Baeder   ASSERT_TRUE(F4->Desc->isArray());
109a07aba5dSTimm Baeder   ASSERT_TRUE(F4->Desc->isCompositeArray());
110a07aba5dSTimm Baeder   ASSERT_FALSE(F4->Desc->isPrimitiveArray());
111a07aba5dSTimm Baeder   ASSERT_FALSE(F4->Desc->isPrimitive());
112a07aba5dSTimm Baeder   ASSERT_TRUE(F4->Desc->ElemDesc);
113a07aba5dSTimm Baeder   ASSERT_EQ(F4->Desc->getNumElems(), 3u);
114a07aba5dSTimm Baeder   ASSERT_TRUE(F4->Desc->getElemSize() > 0);
115a07aba5dSTimm Baeder   ASSERT_TRUE(F4->Desc->ElemDesc->isPrimitiveArray());
116a07aba5dSTimm Baeder 
117a07aba5dSTimm Baeder   // Fifth field. Zero-size array.
118a07aba5dSTimm Baeder   const Record::Field *F5 = SRecord->getField(4u);
119a07aba5dSTimm Baeder   ASSERT_TRUE(F5);
120a07aba5dSTimm Baeder   ASSERT_FALSE(F5->isBitField());
121a07aba5dSTimm Baeder   ASSERT_TRUE(F5->Desc->isArray());
122a07aba5dSTimm Baeder   ASSERT_FALSE(F5->Desc->isCompositeArray());
123a07aba5dSTimm Baeder   ASSERT_TRUE(F5->Desc->isPrimitiveArray());
124a07aba5dSTimm Baeder   ASSERT_FALSE(F5->Desc->isPrimitive());
125a07aba5dSTimm Baeder   ASSERT_EQ(F5->Desc->getNumElems(), 0u);
126a07aba5dSTimm Baeder 
127a07aba5dSTimm Baeder   // Check pointer stuff.
128a07aba5dSTimm Baeder   // Global variables have an inline descriptor.
129a07aba5dSTimm Baeder   ASSERT_TRUE(GlobalPtr.isRoot());
130a07aba5dSTimm Baeder   ASSERT_TRUE(GlobalPtr.isLive());
131a07aba5dSTimm Baeder   ASSERT_FALSE(GlobalPtr.isZero());
132a07aba5dSTimm Baeder   ASSERT_FALSE(GlobalPtr.isField());
133a07aba5dSTimm Baeder   ASSERT_TRUE(GlobalPtr.getFieldDesc() == GlobalPtr.getDeclDesc());
134a07aba5dSTimm Baeder   ASSERT_TRUE(GlobalPtr.getOffset() == 0);
135a07aba5dSTimm Baeder   ASSERT_FALSE(GlobalPtr.inArray());
136a07aba5dSTimm Baeder   ASSERT_FALSE(GlobalPtr.isArrayElement());
137a07aba5dSTimm Baeder   ASSERT_FALSE(GlobalPtr.isArrayRoot());
138a07aba5dSTimm Baeder   ASSERT_FALSE(GlobalPtr.inPrimitiveArray());
139a07aba5dSTimm Baeder   ASSERT_TRUE(GlobalPtr.isStatic());
140a07aba5dSTimm Baeder   ASSERT_TRUE(GlobalPtr.isInitialized());
141a07aba5dSTimm Baeder   ASSERT_FALSE(GlobalPtr.isOnePastEnd());
142a07aba5dSTimm Baeder   ASSERT_FALSE(GlobalPtr.isElementPastEnd());
143a07aba5dSTimm Baeder 
144a07aba5dSTimm Baeder   // Pointer to the first field (a primitive).
145a07aba5dSTimm Baeder   const Pointer &PF1 = GlobalPtr.atField(F1->Offset);
146a07aba5dSTimm Baeder   ASSERT_TRUE(PF1.isLive());
147a07aba5dSTimm Baeder   ASSERT_TRUE(PF1.isInitialized());
148a07aba5dSTimm Baeder   ASSERT_TRUE(PF1.isField());
149a07aba5dSTimm Baeder   ASSERT_FALSE(PF1.inArray());
150a07aba5dSTimm Baeder   ASSERT_FALSE(PF1.isArrayElement());
151a07aba5dSTimm Baeder   ASSERT_FALSE(PF1.isArrayRoot());
152a07aba5dSTimm Baeder   ASSERT_FALSE(PF1.isOnePastEnd());
153a07aba5dSTimm Baeder   ASSERT_FALSE(PF1.isRoot());
154a07aba5dSTimm Baeder   ASSERT_TRUE(PF1.getFieldDesc()->isPrimitive());
155a07aba5dSTimm Baeder   ASSERT_TRUE(Pointer::hasSameBase(PF1, GlobalPtr));
156a07aba5dSTimm Baeder   ASSERT_TRUE(PF1.getBase() == GlobalPtr);
157a07aba5dSTimm Baeder 
158a07aba5dSTimm Baeder   // Pointer to the second field (a primitive array).
159a07aba5dSTimm Baeder   const Pointer &PF2 = GlobalPtr.atField(F2->Offset);
160a07aba5dSTimm Baeder   ASSERT_TRUE(PF2.isLive());
161a07aba5dSTimm Baeder   ASSERT_TRUE(PF2.isInitialized());
162a07aba5dSTimm Baeder   ASSERT_TRUE(PF2.isField());
163a07aba5dSTimm Baeder   ASSERT_TRUE(PF2.inArray());
164a07aba5dSTimm Baeder   ASSERT_FALSE(PF2.isArrayElement());
165a07aba5dSTimm Baeder   ASSERT_TRUE(PF2.isArrayRoot());
166a07aba5dSTimm Baeder   ASSERT_TRUE(PF2.getNumElems() == 4);
167a07aba5dSTimm Baeder   ASSERT_FALSE(PF2.isOnePastEnd());
168a07aba5dSTimm Baeder   ASSERT_FALSE(PF2.isRoot());
169a07aba5dSTimm Baeder   ASSERT_FALSE(PF2.getFieldDesc()->isPrimitive());
170a07aba5dSTimm Baeder   ASSERT_TRUE(PF2.getFieldDesc()->isArray());
171a07aba5dSTimm Baeder   ASSERT_TRUE(Pointer::hasSameBase(PF2, GlobalPtr));
172a07aba5dSTimm Baeder   ASSERT_TRUE(PF2.getBase() == GlobalPtr);
173a07aba5dSTimm Baeder 
174a07aba5dSTimm Baeder   // Check contents of field 2 (a primitive array).
175a07aba5dSTimm Baeder   {
176a07aba5dSTimm Baeder     const Pointer &E1 = PF2.atIndex(0);
177a07aba5dSTimm Baeder     ASSERT_TRUE(E1.isLive());
178a07aba5dSTimm Baeder     ASSERT_FALSE(E1.isArrayRoot());
179a07aba5dSTimm Baeder     ASSERT_TRUE(E1.isArrayElement());
180a07aba5dSTimm Baeder     ASSERT_TRUE(E1.inPrimitiveArray());
181a07aba5dSTimm Baeder     ASSERT_TRUE(E1.deref<char>() == 'f');
182a07aba5dSTimm Baeder     ASSERT_EQ(E1.getIndex(), 0u);
183a07aba5dSTimm Baeder     ASSERT_TRUE(E1 == E1.atIndex(0));
184a07aba5dSTimm Baeder     ASSERT_TRUE(Pointer::hasSameBase(E1, GlobalPtr));
185a07aba5dSTimm Baeder 
186a07aba5dSTimm Baeder     const Pointer &E2 = PF2.atIndex(1);
187a07aba5dSTimm Baeder     ASSERT_TRUE(E2.isLive());
188a07aba5dSTimm Baeder     ASSERT_FALSE(E2.isArrayRoot());
189a07aba5dSTimm Baeder     ASSERT_TRUE(E2.isArrayElement());
190a07aba5dSTimm Baeder     ASSERT_EQ(E2.getIndex(), 1u);
191a07aba5dSTimm Baeder     // Narrow() doesn't do anything on primitive array elements, as there is
192a07aba5dSTimm Baeder     // nothing to narrow into.
193a07aba5dSTimm Baeder     ASSERT_EQ(E2.narrow(), E2);
194a07aba5dSTimm Baeder     // ... so this should also hold.
195a07aba5dSTimm Baeder     ASSERT_EQ(E2.expand(), E2);
196a07aba5dSTimm Baeder     ASSERT_EQ(E2.narrow().expand(), E2);
197a07aba5dSTimm Baeder 
198a07aba5dSTimm Baeder     // .atIndex(1).atIndex(1) should be index 1.
199a07aba5dSTimm Baeder     ASSERT_EQ(PF2.atIndex(1).atIndex(1), PF2.atIndex(1));
200a07aba5dSTimm Baeder     ASSERT_EQ(PF2.atIndex(1).narrow().atIndex(1), PF2.atIndex(1));
201a07aba5dSTimm Baeder 
202a07aba5dSTimm Baeder     // getArray() should give us the array field again.
203a07aba5dSTimm Baeder     ASSERT_EQ(E2.getArray(), PF2);
204a07aba5dSTimm Baeder 
205a07aba5dSTimm Baeder     // One-after-the-end pointer.
206a07aba5dSTimm Baeder     const Pointer &O = PF2.atIndex(PF2.getNumElems());
207a07aba5dSTimm Baeder     ASSERT_TRUE(O.isLive());
208a07aba5dSTimm Baeder     ASSERT_TRUE(O.isOnePastEnd());
209a07aba5dSTimm Baeder     ASSERT_TRUE(O.isInitialized());
210a07aba5dSTimm Baeder     ASSERT_TRUE(O.getIndex() == PF2.getNumElems());
211a07aba5dSTimm Baeder   }
212a07aba5dSTimm Baeder 
213a07aba5dSTimm Baeder   // Pointer to the third field (a composite array).
214a07aba5dSTimm Baeder   const Pointer &PF3 = GlobalPtr.atField(F3->Offset);
215a07aba5dSTimm Baeder   ASSERT_TRUE(PF3.isLive());
216a07aba5dSTimm Baeder   ASSERT_TRUE(PF3.isInitialized());
217a07aba5dSTimm Baeder   ASSERT_TRUE(PF3.isField());
218a07aba5dSTimm Baeder   ASSERT_TRUE(PF3.inArray());
219a07aba5dSTimm Baeder   ASSERT_TRUE(PF3.isArrayRoot());
220a07aba5dSTimm Baeder   ASSERT_FALSE(PF3.isArrayElement());
221a07aba5dSTimm Baeder   ASSERT_TRUE(PF3.getNumElems() == 3);
222a07aba5dSTimm Baeder   ASSERT_FALSE(PF3.isOnePastEnd());
223a07aba5dSTimm Baeder   ASSERT_FALSE(PF3.isRoot());
224a07aba5dSTimm Baeder   ASSERT_FALSE(PF3.getFieldDesc()->isPrimitive());
225a07aba5dSTimm Baeder   ASSERT_TRUE(PF3.getFieldDesc()->isArray());
226a07aba5dSTimm Baeder   ASSERT_TRUE(Pointer::hasSameBase(PF3, GlobalPtr));
227a07aba5dSTimm Baeder   ASSERT_TRUE(PF3.getBase() == GlobalPtr);
228a07aba5dSTimm Baeder   ASSERT_EQ(PF3.getRecord(), nullptr);
229a07aba5dSTimm Baeder   ASSERT_TRUE(PF3.getElemRecord());
230a07aba5dSTimm Baeder 
231a07aba5dSTimm Baeder   // Check contents of field 3 (a composite array).
232a07aba5dSTimm Baeder   {
233a07aba5dSTimm Baeder     const Pointer &E1 = PF3.atIndex(0);
234a07aba5dSTimm Baeder     // Note that we didn't call narrow() above, so this points
235a07aba5dSTimm Baeder     // to an array element and not just a field.
236a07aba5dSTimm Baeder     ASSERT_TRUE(E1.isLive());
237a07aba5dSTimm Baeder     ASSERT_EQ(E1.getIndex(), 0);
238a07aba5dSTimm Baeder     ASSERT_TRUE(E1.isInitialized());
239a07aba5dSTimm Baeder     ASSERT_TRUE(E1.isArrayElement());
240a07aba5dSTimm Baeder     ASSERT_TRUE(E1.inArray());
241a07aba5dSTimm Baeder     ASSERT_FALSE(E1.isArrayRoot());
242a07aba5dSTimm Baeder     ASSERT_FALSE(E1.isRoot());
243a07aba5dSTimm Baeder     ASSERT_EQ(E1.getArray(), PF3);
244a07aba5dSTimm Baeder     ASSERT_TRUE(E1.isField());
245a07aba5dSTimm Baeder     ASSERT_TRUE(E1.getElemRecord());
246a07aba5dSTimm Baeder     ASSERT_FALSE(E1.getRecord());
247a07aba5dSTimm Baeder 
248a07aba5dSTimm Baeder     // Now the same with narrow().
249a07aba5dSTimm Baeder     const Pointer &NE1 = PF3.atIndex(0).narrow();
250a07aba5dSTimm Baeder     ASSERT_NE(E1, NE1);
251a07aba5dSTimm Baeder     ASSERT_TRUE(NE1.isLive());
252a07aba5dSTimm Baeder     ASSERT_EQ(NE1.getIndex(), 0);
253a07aba5dSTimm Baeder     ASSERT_TRUE(NE1.isInitialized());
254*800b0739STimm Baeder     ASSERT_TRUE(NE1.isArrayElement());
255a07aba5dSTimm Baeder     ASSERT_TRUE(NE1.isField());
256a07aba5dSTimm Baeder     ASSERT_FALSE(NE1.inArray());
257a07aba5dSTimm Baeder     ASSERT_FALSE(NE1.isArrayRoot());
258a07aba5dSTimm Baeder     ASSERT_FALSE(NE1.isRoot());
259a07aba5dSTimm Baeder     // Not possible, since this is narrow()ed:
260a07aba5dSTimm Baeder     // ASSERT_EQ(NE1.getArray(), PF3);
261a07aba5dSTimm Baeder     ASSERT_EQ(NE1.expand(), E1);
262a07aba5dSTimm Baeder     ASSERT_FALSE(NE1.getElemRecord());
263a07aba5dSTimm Baeder     ASSERT_TRUE(NE1.getRecord());
264a07aba5dSTimm Baeder 
265a07aba5dSTimm Baeder     // Second element, NOT narrowed.
266a07aba5dSTimm Baeder     const Pointer &E2 = PF3.atIndex(1);
267a07aba5dSTimm Baeder     ASSERT_TRUE(E2.isLive());
268a07aba5dSTimm Baeder     ASSERT_EQ(E2.getIndex(), 1);
269a07aba5dSTimm Baeder     ASSERT_TRUE(E2.isInitialized());
270a07aba5dSTimm Baeder     ASSERT_TRUE(E2.isArrayElement());
271a07aba5dSTimm Baeder     ASSERT_TRUE(E2.isField());
272a07aba5dSTimm Baeder     ASSERT_TRUE(E2.inArray());
273a07aba5dSTimm Baeder     ASSERT_FALSE(E2.isArrayRoot());
274a07aba5dSTimm Baeder     ASSERT_FALSE(E2.isRoot());
275a07aba5dSTimm Baeder     ASSERT_EQ(E2.getArray(), PF3);
276a07aba5dSTimm Baeder 
277a07aba5dSTimm Baeder     // Second element, narrowed.
278a07aba5dSTimm Baeder     const Pointer &NE2 = PF3.atIndex(1).narrow();
279a07aba5dSTimm Baeder     ASSERT_TRUE(NE2.isLive());
280a07aba5dSTimm Baeder     ASSERT_EQ(NE2.getIndex(), 0);
281a07aba5dSTimm Baeder     ASSERT_TRUE(NE2.isInitialized());
282*800b0739STimm Baeder     ASSERT_TRUE(NE2.isArrayElement());
283a07aba5dSTimm Baeder     ASSERT_TRUE(NE2.isField());
284a07aba5dSTimm Baeder     ASSERT_FALSE(NE2.inArray());
285a07aba5dSTimm Baeder     ASSERT_FALSE(NE2.isArrayRoot());
286a07aba5dSTimm Baeder     ASSERT_FALSE(NE2.isRoot());
287a07aba5dSTimm Baeder     // Not possible, since this is narrow()ed:
288a07aba5dSTimm Baeder     // ASSERT_EQ(NE2.getArray(), PF3);
289a07aba5dSTimm Baeder     ASSERT_FALSE(NE2.getElemRecord());
290a07aba5dSTimm Baeder     ASSERT_TRUE(NE2.getRecord());
291a07aba5dSTimm Baeder 
292a07aba5dSTimm Baeder     // Chained atIndex() without narrowing in between.
293a07aba5dSTimm Baeder     ASSERT_EQ(PF3.atIndex(1).atIndex(1), PF3.atIndex(1));
294a07aba5dSTimm Baeder 
295a07aba5dSTimm Baeder     // First field of the second element.
296a07aba5dSTimm Baeder     const Pointer &FP1 = NE2.atField(NE2.getRecord()->getField(0u)->Offset);
297a07aba5dSTimm Baeder     ASSERT_TRUE(FP1.isLive());
298a07aba5dSTimm Baeder     ASSERT_TRUE(FP1.isInitialized());
299a07aba5dSTimm Baeder     ASSERT_EQ(FP1.getBase(), NE2);
300a07aba5dSTimm Baeder     ASSERT_FALSE(FP1.isArrayElement());
301a07aba5dSTimm Baeder     ASSERT_FALSE(FP1.inArray());
302a07aba5dSTimm Baeder     ASSERT_FALSE(FP1.inPrimitiveArray());
303a07aba5dSTimm Baeder     ASSERT_TRUE(FP1.isField());
304a07aba5dSTimm Baeder 
305a07aba5dSTimm Baeder     // One-past-the-end of a composite array.
306a07aba5dSTimm Baeder     const Pointer &O = PF3.atIndex(PF3.getNumElems()).narrow();
307a07aba5dSTimm Baeder     ASSERT_TRUE(O.isOnePastEnd());
308a07aba5dSTimm Baeder     ASSERT_TRUE(O.isElementPastEnd());
309a07aba5dSTimm Baeder   }
310a07aba5dSTimm Baeder 
311a07aba5dSTimm Baeder   // Pointer to the fourth field (a multidimensional primitive array).
312a07aba5dSTimm Baeder   const Pointer &PF4 = GlobalPtr.atField(F4->Offset);
313a07aba5dSTimm Baeder   ASSERT_TRUE(PF4.isLive());
314a07aba5dSTimm Baeder   ASSERT_TRUE(PF4.isInitialized());
315a07aba5dSTimm Baeder   ASSERT_TRUE(PF4.isField());
316a07aba5dSTimm Baeder   ASSERT_TRUE(PF4.inArray());
317a07aba5dSTimm Baeder   ASSERT_TRUE(PF4.isArrayRoot());
318a07aba5dSTimm Baeder   ASSERT_FALSE(PF4.isArrayElement());
319a07aba5dSTimm Baeder   ASSERT_TRUE(PF4.getNumElems() == 3);
320a07aba5dSTimm Baeder   ASSERT_FALSE(PF4.isOnePastEnd());
321a07aba5dSTimm Baeder   ASSERT_FALSE(PF4.isRoot());
322a07aba5dSTimm Baeder   ASSERT_FALSE(PF4.getFieldDesc()->isPrimitive());
323a07aba5dSTimm Baeder   ASSERT_TRUE(PF4.getFieldDesc()->isArray());
324a07aba5dSTimm Baeder   ASSERT_TRUE(Pointer::hasSameBase(PF4, GlobalPtr));
325a07aba5dSTimm Baeder   ASSERT_TRUE(PF4.getBase() == GlobalPtr);
326a07aba5dSTimm Baeder   ASSERT_EQ(PF4.getRecord(), nullptr);
327a07aba5dSTimm Baeder   ASSERT_EQ(PF4.getElemRecord(), nullptr);
328a07aba5dSTimm Baeder   ASSERT_NE(PF4.getField(), nullptr);
329a07aba5dSTimm Baeder   ASSERT_TRUE(PF4.getFieldDesc()->ElemDesc->isPrimitiveArray());
330a07aba5dSTimm Baeder   // Check contents of field 4 (a primitive array).
331a07aba5dSTimm Baeder   {
332a07aba5dSTimm Baeder     // Pointer to the first element, is of type short[3].
333a07aba5dSTimm Baeder     const Pointer &E1 = PF4.atIndex(0);
334a07aba5dSTimm Baeder     ASSERT_NE(E1, PF4);
335a07aba5dSTimm Baeder     ASSERT_TRUE(E1.isLive());
336a07aba5dSTimm Baeder     ASSERT_TRUE(E1.isArrayElement());
337a07aba5dSTimm Baeder     ASSERT_TRUE(E1.inArray());
338a07aba5dSTimm Baeder     ASSERT_EQ(E1.getNumElems(), 3u);
339a07aba5dSTimm Baeder     ASSERT_EQ(E1.getIndex(), 0u);
340a07aba5dSTimm Baeder     ASSERT_EQ(E1.getArray(), PF4);
341a07aba5dSTimm Baeder 
342a07aba5dSTimm Baeder     // Now narrow()'ed.
343a07aba5dSTimm Baeder     const Pointer &NE1 = PF4.atIndex(0).narrow();
344a07aba5dSTimm Baeder     ASSERT_NE(NE1, PF4);
345a07aba5dSTimm Baeder     ASSERT_NE(NE1, E1);
346a07aba5dSTimm Baeder     ASSERT_TRUE(NE1.isLive());
347*800b0739STimm Baeder     ASSERT_TRUE(NE1.isArrayElement());
348a07aba5dSTimm Baeder     ASSERT_TRUE(NE1.isArrayRoot());
349a07aba5dSTimm Baeder     ASSERT_FALSE(NE1.getFieldDesc()->isCompositeArray());
350a07aba5dSTimm Baeder     ASSERT_TRUE(NE1.getFieldDesc()->isPrimitiveArray());
351a07aba5dSTimm Baeder     ASSERT_EQ(NE1.getFieldDesc()->getNumElems(), 3u);
352a07aba5dSTimm Baeder     ASSERT_TRUE(NE1.inArray());
353a07aba5dSTimm Baeder     ASSERT_EQ(NE1.getNumElems(), 3u);
354a07aba5dSTimm Baeder     ASSERT_EQ(NE1.getIndex(), 0u);
355a07aba5dSTimm Baeder 
356a07aba5dSTimm Baeder     // Last element of the first dimension.
357a07aba5dSTimm Baeder     const Pointer &PE1 = PF4.atIndex(0).narrow().atIndex(2);
358a07aba5dSTimm Baeder     ASSERT_TRUE(PE1.isLive());
359a07aba5dSTimm Baeder     ASSERT_EQ(PE1.deref<short>(), 3);
360a07aba5dSTimm Baeder     ASSERT_EQ(PE1.getArray(), NE1);
361a07aba5dSTimm Baeder     ASSERT_EQ(PE1.getIndex(), 2u);
362a07aba5dSTimm Baeder 
363a07aba5dSTimm Baeder     // third dimension
364a07aba5dSTimm Baeder     const Pointer &E3 = PF4.atIndex(2);
365a07aba5dSTimm Baeder     ASSERT_NE(E3, PF4);
366a07aba5dSTimm Baeder     ASSERT_TRUE(E3.isLive());
367a07aba5dSTimm Baeder     ASSERT_TRUE(E3.isArrayElement());
368a07aba5dSTimm Baeder     ASSERT_FALSE(E3.isArrayRoot());
369a07aba5dSTimm Baeder     ASSERT_TRUE(E3.inArray());
370a07aba5dSTimm Baeder     ASSERT_EQ(E3.getNumElems(), 3u);
371a07aba5dSTimm Baeder     ASSERT_EQ(E3.getIndex(), 2u);
372a07aba5dSTimm Baeder 
373a07aba5dSTimm Baeder     // Same, but narrow()'ed.
374a07aba5dSTimm Baeder     const Pointer &NE3 = PF4.atIndex(2).narrow();
375a07aba5dSTimm Baeder     ASSERT_NE(NE3, PF4);
376a07aba5dSTimm Baeder     ASSERT_NE(NE3, E1);
377a07aba5dSTimm Baeder     ASSERT_TRUE(NE3.isLive());
378*800b0739STimm Baeder     ASSERT_TRUE(NE3.isArrayElement());
379a07aba5dSTimm Baeder     ASSERT_TRUE(NE3.isArrayRoot());
380a07aba5dSTimm Baeder     ASSERT_FALSE(NE3.getFieldDesc()->isCompositeArray());
381a07aba5dSTimm Baeder     ASSERT_TRUE(NE3.getFieldDesc()->isPrimitiveArray());
382a07aba5dSTimm Baeder     ASSERT_EQ(NE3.getFieldDesc()->getNumElems(), 3u);
383a07aba5dSTimm Baeder     ASSERT_TRUE(NE3.inArray());
384a07aba5dSTimm Baeder     ASSERT_EQ(NE3.getNumElems(), 3u);
385a07aba5dSTimm Baeder     // This is narrow()'ed, so not an "array elemnet"
386a07aba5dSTimm Baeder     ASSERT_EQ(PF4.atIndex(2).getIndex(), 2u);
387a07aba5dSTimm Baeder     ASSERT_EQ(NE3.getIndex(), 0u);
388a07aba5dSTimm Baeder 
389a07aba5dSTimm Baeder     // Last element of the last dimension
390a07aba5dSTimm Baeder     const Pointer &PE3 = PF4.atIndex(2).narrow().atIndex(2);
391a07aba5dSTimm Baeder     ASSERT_TRUE(PE3.isLive());
392a07aba5dSTimm Baeder     ASSERT_EQ(PE3.deref<short>(), 9);
393a07aba5dSTimm Baeder     ASSERT_EQ(PE3.getArray(), NE3);
394a07aba5dSTimm Baeder     ASSERT_EQ(PE3.getIndex(), 2u);
395a07aba5dSTimm Baeder   }
396a07aba5dSTimm Baeder 
397a07aba5dSTimm Baeder   // Zero-size array.
398a07aba5dSTimm Baeder   {
399a07aba5dSTimm Baeder     const Pointer &PF5 = GlobalPtr.atField(F5->Offset);
400a07aba5dSTimm Baeder 
401a07aba5dSTimm Baeder     ASSERT_TRUE(PF5.isZeroSizeArray());
402a07aba5dSTimm Baeder     ASSERT_FALSE(PF5.isOnePastEnd());
403a07aba5dSTimm Baeder     ASSERT_FALSE(PF5.isElementPastEnd());
404a07aba5dSTimm Baeder   }
405a07aba5dSTimm Baeder }
406