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