1 | // RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -triple x86_64-apple-darwin12 -fheinous-gnu-extensions -std=c++11 -analyzer-config cfg-rich-constructors=false %s > %t 2>&1 |
2 | // RUN: FileCheck --input-file=%t -check-prefixes=CHECK,WARNINGS %s |
3 | // RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -triple x86_64-apple-darwin12 -fheinous-gnu-extensions -std=c++11 -analyzer-config cfg-rich-constructors=true %s > %t 2>&1 |
4 | // RUN: FileCheck --input-file=%t -check-prefixes=CHECK,ANALYZER %s |
5 | |
6 | // This file tests how we construct two different flavors of the Clang CFG - |
7 | // the CFG used by the Sema analysis-based warnings and the CFG used by the |
8 | // static analyzer. The difference in the behavior is checked via FileCheck |
9 | // prefixes (WARNINGS and ANALYZER respectively). When introducing new analyzer |
10 | // flags, no new run lines should be added - just these flags would go to the |
11 | // respective line depending on where is it turned on and where is it turned |
12 | // off. Feel free to add tests that test only one of the CFG flavors if you're |
13 | // not sure how the other flavor is supposed to work in your case. |
14 | |
15 | // CHECK-LABEL: void checkWrap(int i) |
16 | // CHECK: ENTRY |
17 | // CHECK-NEXT: Succs (1): B1 |
18 | // CHECK: [B1] |
19 | // CHECK: Succs (21): B2 B3 B4 B5 B6 B7 B8 B9 |
20 | // CHECK: B10 B11 B12 B13 B14 B15 B16 B17 B18 B19 |
21 | // CHECK: B20 B21 B0 |
22 | // CHECK: [B0 (EXIT)] |
23 | // CHECK-NEXT: Preds (21): B2 B3 B4 B5 B6 B7 B8 B9 |
24 | // CHECK-NEXT: B10 B11 B12 B13 B14 B15 B16 B17 B18 B19 |
25 | // CHECK-NEXT: B20 B21 B1 |
26 | void checkWrap(int i) { |
27 | switch(i) { |
28 | case 0: break; |
29 | case 1: break; |
30 | case 2: break; |
31 | case 3: break; |
32 | case 4: break; |
33 | case 5: break; |
34 | case 6: break; |
35 | case 7: break; |
36 | case 8: break; |
37 | case 9: break; |
38 | case 10: break; |
39 | case 11: break; |
40 | case 12: break; |
41 | case 13: break; |
42 | case 14: break; |
43 | case 15: break; |
44 | case 16: break; |
45 | case 17: break; |
46 | case 18: break; |
47 | case 19: break; |
48 | } |
49 | } |
50 | |
51 | // CHECK-LABEL: void checkDeclStmts() |
52 | // CHECK: ENTRY |
53 | // CHECK-NEXT: Succs (1): B1 |
54 | // CHECK: [B1] |
55 | // CHECK-NEXT: 1: int i; |
56 | // CHECK-NEXT: 2: int j; |
57 | // CHECK-NEXT: 3: 1 |
58 | // CHECK-NEXT: 4: int k = 1; |
59 | // CHECK-NEXT: 5: int l; |
60 | // CHECK-NEXT: 6: 2 |
61 | // CHECK-NEXT: 7: int m = 2; |
62 | // WARNINGS-NEXT: (CXXConstructExpr, struct standalone) |
63 | // ANALYZER-NEXT: (CXXConstructExpr, [B1.9], struct standalone) |
64 | // CHECK-NEXT: 9: struct standalone myStandalone; |
65 | // WARNINGS-NEXT: (CXXConstructExpr, struct (anonymous struct at {{.*}})) |
66 | // ANALYZER-NEXT: (CXXConstructExpr, [B1.11], struct (anonymous struct at {{.*}})) |
67 | // CHECK-NEXT: 11: struct (anonymous struct at {{.*}}) myAnon; |
68 | // WARNINGS-NEXT: (CXXConstructExpr, struct named) |
69 | // ANALYZER-NEXT: (CXXConstructExpr, [B1.13], struct named) |
70 | // CHECK-NEXT: 13: struct named myNamed; |
71 | // CHECK-NEXT: Preds (1): B2 |
72 | // CHECK-NEXT: Succs (1): B0 |
73 | void checkDeclStmts() { |
74 | int i, j; |
75 | int k = 1, l, m = 2; |
76 | |
77 | struct standalone { int x, y; }; |
78 | struct standalone myStandalone; |
79 | |
80 | struct { int x, y; } myAnon; |
81 | |
82 | struct named { int x, y; } myNamed; |
83 | |
84 | static_assert(1, "abc"); |
85 | } |
86 | |
87 | |
88 | // CHECK-LABEL: void checkGCCAsmRValueOutput() |
89 | // CHECK: [B2 (ENTRY)] |
90 | // CHECK-NEXT: Succs (1): B1 |
91 | // CHECK: [B1] |
92 | // CHECK-NEXT: 1: int arg |
93 | // CHECK-NEXT: 2: arg |
94 | // CHECK-NEXT: 3: (int)[B1.2] (CStyleCastExpr, NoOp, int) |
95 | // CHECK-NEXT: 4: asm ("" : "=r" ([B1.3])); |
96 | // CHECK-NEXT: 5: arg |
97 | // CHECK-NEXT: 6: asm ("" : "=r" ([B1.5])); |
98 | void checkGCCAsmRValueOutput() { |
99 | int arg; |
100 | __asm__("" : "=r"((int)arg)); // rvalue output operand |
101 | __asm__("" : "=r"(arg)); // lvalue output operand |
102 | } |
103 | |
104 | |
105 | // CHECK-LABEL: void F(EmptyE e) |
106 | // CHECK: ENTRY |
107 | // CHECK-NEXT: Succs (1): B1 |
108 | // CHECK: [B1] |
109 | // CHECK-NEXT: 1: e |
110 | // CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, LValueToRValue, enum EmptyE) |
111 | // CHECK-NEXT: 3: [B1.2] (ImplicitCastExpr, IntegralCast, int) |
112 | // CHECK-NEXT: T: switch [B1.3] |
113 | // CHECK-NEXT: Preds (1): B2 |
114 | // CHECK-NEXT: Succs (1): B0 |
115 | // CHECK: [B0 (EXIT)] |
116 | // CHECK-NEXT: Preds (1): B1 |
117 | enum EmptyE {}; |
118 | void F(EmptyE e) { |
119 | switch (e) {} |
120 | } |
121 | |
122 | // CHECK-LABEL: void testBuiltinSize() |
123 | // CHECK: ENTRY |
124 | // CHECK-NEXT: Succs (1): B1 |
125 | // CHECK: [B1] |
126 | // CHECK-NEXT: 1: __builtin_object_size |
127 | // CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, BuiltinFnToFnPtr, unsigned long (*)(const void *, int) noexcept) |
128 | // CHECK-NEXT: 3: [B1.2](dummy(), 0) |
129 | // CHECK-NEXT: 4: (void)[B1.3] (CStyleCastExpr, ToVoid, void) |
130 | // CHECK-NEXT: Preds (1): B2 |
131 | // CHECK-NEXT: Succs (1): B0 |
132 | // CHECK: [B0 (EXIT)] |
133 | // CHECK-NEXT: Preds (1): B1 |
134 | void testBuiltinSize() { |
135 | extern int *dummy(); |
136 | (void)__builtin_object_size(dummy(), 0); |
137 | } |
138 | |
139 | |
140 | class A { |
141 | public: |
142 | A() {} |
143 | ~A() {} |
144 | }; |
145 | |
146 | // CHECK-LABEL: void test_deletedtor() |
147 | // CHECK: [B2 (ENTRY)] |
148 | // CHECK-NEXT: Succs (1): B1 |
149 | // CHECK: [B1] |
150 | // CHECK-NEXT: 1: CFGNewAllocator(A *) |
151 | // WARNINGS-NEXT: 2: (CXXConstructExpr, class A) |
152 | // ANALYZER-NEXT: 2: (CXXConstructExpr, [B1.3], class A) |
153 | // CHECK-NEXT: 3: new A([B1.2]) |
154 | // CHECK-NEXT: 4: A *a = new A(); |
155 | // CHECK-NEXT: 5: a |
156 | // CHECK-NEXT: 6: [B1.5] (ImplicitCastExpr, LValueToRValue, class A *) |
157 | // CHECK-NEXT: 7: [B1.6]->~A() (Implicit destructor) |
158 | // CHECK-NEXT: 8: delete [B1.6] |
159 | // CHECK-NEXT: Preds (1): B2 |
160 | // CHECK-NEXT: Succs (1): B0 |
161 | // CHECK: [B0 (EXIT)] |
162 | // CHECK-NEXT: Preds (1): B1 |
163 | void test_deletedtor() { |
164 | A *a = new A(); |
165 | delete a; |
166 | } |
167 | |
168 | // CHECK-LABEL: void test_deleteArraydtor() |
169 | // CHECK: [B2 (ENTRY)] |
170 | // CHECK-NEXT: Succs (1): B1 |
171 | // CHECK: [B1] |
172 | // CHECK-NEXT: 1: 5 |
173 | // CHECK-NEXT: 2: CFGNewAllocator(A *) |
174 | // WARNINGS-NEXT: 3: (CXXConstructExpr, class A [5]) |
175 | // ANALYZER-NEXT: 3: (CXXConstructExpr, [B1.4], class A [5]) |
176 | // CHECK-NEXT: 4: new A {{\[\[}}B1.1]] |
177 | // CHECK-NEXT: 5: A *a = new A [5]; |
178 | // CHECK-NEXT: 6: a |
179 | // CHECK-NEXT: 7: [B1.6] (ImplicitCastExpr, LValueToRValue, class A *) |
180 | // CHECK-NEXT: 8: [B1.7]->~A() (Implicit destructor) |
181 | // CHECK-NEXT: 9: delete [] [B1.7] |
182 | // CHECK-NEXT: Preds (1): B2 |
183 | // CHECK-NEXT: Succs (1): B0 |
184 | // CHECK: [B0 (EXIT)] |
185 | // CHECK-NEXT: Preds (1): B1 |
186 | void test_deleteArraydtor() { |
187 | A *a = new A[5]; |
188 | delete[] a; |
189 | } |
190 | |
191 | |
192 | namespace NoReturnSingleSuccessor { |
193 | struct A { |
194 | A(); |
195 | ~A(); |
196 | }; |
197 | |
198 | struct B : public A { |
199 | B(); |
200 | ~B() __attribute__((noreturn)); |
201 | }; |
202 | |
203 | // CHECK-LABEL: int test1(int *x) |
204 | // CHECK: 1: 1 |
205 | // CHECK-NEXT: 2: return |
206 | // CHECK-NEXT: ~B() (Implicit destructor) |
207 | // CHECK-NEXT: Preds (1) |
208 | // CHECK-NEXT: Succs (1): B0 |
209 | int test1(int *x) { |
210 | B b; |
211 | if (x) |
212 | return 1; |
213 | } |
214 | |
215 | // CHECK-LABEL: int test2(int *x) |
216 | // CHECK: 1: 1 |
217 | // CHECK-NEXT: 2: return |
218 | // CHECK-NEXT: destructor |
219 | // CHECK-NEXT: Preds (1) |
220 | // CHECK-NEXT: Succs (1): B0 |
221 | int test2(int *x) { |
222 | const A& a = B(); |
223 | if (x) |
224 | return 1; |
225 | } |
226 | } |
227 | |
228 | // Test CFG support for "extending" an enum. |
229 | // CHECK-LABEL: int test_enum_with_extension(enum MyEnum value) |
230 | // CHECK: [B7 (ENTRY)] |
231 | // CHECK-NEXT: Succs (1): B2 |
232 | // CHECK: [B1] |
233 | // CHECK-NEXT: 1: x |
234 | // CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, LValueToRValue, int) |
235 | // CHECK-NEXT: 3: return [B1.2]; |
236 | // CHECK-NEXT: Preds (5): B3 B4 B5 B6 B2(Unreachable) |
237 | // CHECK-NEXT: Succs (1): B0 |
238 | // CHECK: [B2] |
239 | // CHECK-NEXT: 1: 0 |
240 | // CHECK-NEXT: 2: int x = 0; |
241 | // CHECK-NEXT: 3: value |
242 | // CHECK-NEXT: 4: [B2.3] (ImplicitCastExpr, LValueToRValue, enum MyEnum) |
243 | // CHECK-NEXT: 5: [B2.4] (ImplicitCastExpr, IntegralCast, int) |
244 | // CHECK-NEXT: T: switch [B2.5] |
245 | // CHECK-NEXT: Preds (1): B7 |
246 | // CHECK-NEXT: Succs (5): B3 B4 B5 B6 B1(Unreachable) |
247 | // CHECK: [B3] |
248 | // CHECK-NEXT: case D: |
249 | // CHECK-NEXT: 1: 4 |
250 | // CHECK-NEXT: 2: x |
251 | // CHECK-NEXT: 3: [B3.2] = [B3.1] |
252 | // CHECK-NEXT: T: break; |
253 | // CHECK-NEXT: Preds (1): B2 |
254 | // CHECK-NEXT: Succs (1): B1 |
255 | // CHECK: [B4] |
256 | // CHECK-NEXT: case C: |
257 | // CHECK-NEXT: 1: 3 |
258 | // CHECK-NEXT: 2: x |
259 | // CHECK-NEXT: 3: [B4.2] = [B4.1] |
260 | // CHECK-NEXT: T: break; |
261 | // CHECK-NEXT: Preds (1): B2 |
262 | // CHECK-NEXT: Succs (1): B1 |
263 | // CHECK: [B5] |
264 | // CHECK-NEXT: case B: |
265 | // CHECK-NEXT: 1: 2 |
266 | // CHECK-NEXT: 2: x |
267 | // CHECK-NEXT: 3: [B5.2] = [B5.1] |
268 | // CHECK-NEXT: T: break; |
269 | // CHECK-NEXT: Preds (1): B2 |
270 | // CHECK-NEXT: Succs (1): B1 |
271 | // CHECK: [B6] |
272 | // CHECK-NEXT: case A: |
273 | // CHECK-NEXT: 1: 1 |
274 | // CHECK-NEXT: 2: x |
275 | // CHECK-NEXT: 3: [B6.2] = [B6.1] |
276 | // CHECK-NEXT: T: break; |
277 | // CHECK-NEXT: Preds (1): B2 |
278 | // CHECK-NEXT: Succs (1): B1 |
279 | // CHECK: [B0 (EXIT)] |
280 | // CHECK-NEXT: Preds (1): B1 |
281 | enum MyEnum { A, B, C }; |
282 | static const enum MyEnum D = (enum MyEnum) 32; |
283 | |
284 | int test_enum_with_extension(enum MyEnum value) { |
285 | int x = 0; |
286 | switch (value) { |
287 | case A: x = 1; break; |
288 | case B: x = 2; break; |
289 | case C: x = 3; break; |
290 | case D: x = 4; break; |
291 | } |
292 | return x; |
293 | } |
294 | |
295 | // CHECK-LABEL: int test_enum_with_extension_default(enum MyEnum value) |
296 | // CHECK: [B7 (ENTRY)] |
297 | // CHECK-NEXT: Succs (1): B2 |
298 | // CHECK: [B1] |
299 | // CHECK-NEXT: 1: x |
300 | // CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, LValueToRValue, int) |
301 | // CHECK-NEXT: 3: return [B1.2]; |
302 | // CHECK-NEXT: Preds (4): B3 B4 B5 B6 |
303 | // CHECK-NEXT: Succs (1): B0 |
304 | // CHECK: [B2] |
305 | // CHECK-NEXT: 1: 0 |
306 | // CHECK-NEXT: 2: int x = 0; |
307 | // CHECK-NEXT: 3: value |
308 | // CHECK-NEXT: 4: [B2.3] (ImplicitCastExpr, LValueToRValue, enum MyEnum) |
309 | // CHECK-NEXT: 5: [B2.4] (ImplicitCastExpr, IntegralCast, int) |
310 | // CHECK-NEXT: T: switch [B2.5] |
311 | // CHECK-NEXT: Preds (1): B7 |
312 | // CHECK-NEXT: Succs (4): B4 B5 B6 B3(Unreachable) |
313 | // CHECK: [B3] |
314 | // CHECK-NEXT: default: |
315 | // CHECK-NEXT: 1: 4 |
316 | // CHECK-NEXT: 2: x |
317 | // CHECK-NEXT: 3: [B3.2] = [B3.1] |
318 | // CHECK-NEXT: T: break; |
319 | // CHECK-NEXT: Preds (1): B2(Unreachable) |
320 | // CHECK-NEXT: Succs (1): B1 |
321 | // CHECK: [B4] |
322 | // CHECK-NEXT: case C: |
323 | // CHECK-NEXT: 1: 3 |
324 | // CHECK-NEXT: 2: x |
325 | // CHECK-NEXT: 3: [B4.2] = [B4.1] |
326 | // CHECK-NEXT: T: break; |
327 | // CHECK-NEXT: Preds (1): B2 |
328 | // CHECK-NEXT: Succs (1): B1 |
329 | // CHECK: [B5] |
330 | // CHECK-NEXT: case B: |
331 | // CHECK-NEXT: 1: 2 |
332 | // CHECK-NEXT: 2: x |
333 | // CHECK-NEXT: 3: [B5.2] = [B5.1] |
334 | // CHECK-NEXT: T: break; |
335 | // CHECK-NEXT: Preds (1): B2 |
336 | // CHECK-NEXT: Succs (1): B1 |
337 | // CHECK: [B6] |
338 | // CHECK-NEXT: case A: |
339 | // CHECK-NEXT: 1: 1 |
340 | // CHECK-NEXT: 2: x |
341 | // CHECK-NEXT: 3: [B6.2] = [B6.1] |
342 | // CHECK-NEXT: T: break; |
343 | // CHECK-NEXT: Preds (1): B2 |
344 | // CHECK-NEXT: Succs (1): B1 |
345 | // CHECK: [B0 (EXIT)] |
346 | // CHECK-NEXT: Preds (1): B1 |
347 | int test_enum_with_extension_default(enum MyEnum value) { |
348 | int x = 0; |
349 | switch (value) { |
350 | case A: x = 1; break; |
351 | case B: x = 2; break; |
352 | case C: x = 3; break; |
353 | default: x = 4; break; |
354 | } |
355 | return x; |
356 | } |
357 | |
358 | |
359 | // CHECK-LABEL: void test_placement_new() |
360 | // CHECK: [B2 (ENTRY)] |
361 | // CHECK-NEXT: Succs (1): B1 |
362 | // CHECK: [B1] |
363 | // CHECK-NEXT: 1: int buffer[16]; |
364 | // CHECK-NEXT: 2: buffer |
365 | // CHECK-NEXT: 3: [B1.2] (ImplicitCastExpr, ArrayToPointerDecay, int *) |
366 | // CHECK-NEXT: 4: [B1.3] (ImplicitCastExpr, BitCast, void *) |
367 | // CHECK-NEXT: 5: CFGNewAllocator(MyClass *) |
368 | // WARNINGS-NEXT: 6: (CXXConstructExpr, class MyClass) |
369 | // ANALYZER-NEXT: 6: (CXXConstructExpr, [B1.7], class MyClass) |
370 | // CHECK-NEXT: 7: new ([B1.4]) MyClass([B1.6]) |
371 | // CHECK-NEXT: 8: MyClass *obj = new (buffer) MyClass(); |
372 | // CHECK-NEXT: Preds (1): B2 |
373 | // CHECK-NEXT: Succs (1): B0 |
374 | // CHECK: [B0 (EXIT)] |
375 | // CHECK-NEXT: Preds (1): B1 |
376 | |
377 | extern void* operator new (unsigned long sz, void* v); |
378 | extern void* operator new[] (unsigned long sz, void* ptr); |
379 | |
380 | class MyClass { |
381 | public: |
382 | MyClass() {} |
383 | ~MyClass() {} |
384 | }; |
385 | |
386 | void test_placement_new() { |
387 | int buffer[16]; |
388 | MyClass* obj = new (buffer) MyClass(); |
389 | } |
390 | |
391 | // CHECK-LABEL: void test_placement_new_array() |
392 | // CHECK: [B2 (ENTRY)] |
393 | // CHECK-NEXT: Succs (1): B1 |
394 | // CHECK: [B1] |
395 | // CHECK-NEXT: 1: int buffer[16]; |
396 | // CHECK-NEXT: 2: buffer |
397 | // CHECK-NEXT: 3: [B1.2] (ImplicitCastExpr, ArrayToPointerDecay, int *) |
398 | // CHECK-NEXT: 4: [B1.3] (ImplicitCastExpr, BitCast, void *) |
399 | // CHECK-NEXT: 5: 5 |
400 | // CHECK-NEXT: 6: CFGNewAllocator(MyClass *) |
401 | // WARNINGS-NEXT: 7: (CXXConstructExpr, class MyClass [5]) |
402 | // ANALYZER-NEXT: 7: (CXXConstructExpr, [B1.8], class MyClass [5]) |
403 | // CHECK-NEXT: 8: new ([B1.4]) MyClass {{\[\[}}B1.5]] |
404 | // CHECK-NEXT: 9: MyClass *obj = new (buffer) MyClass [5]; |
405 | // CHECK-NEXT: Preds (1): B2 |
406 | // CHECK-NEXT: Succs (1): B0 |
407 | // CHECK: [B0 (EXIT)] |
408 | // CHECK-NEXT: Preds (1): B1 |
409 | |
410 | void test_placement_new_array() { |
411 | int buffer[16]; |
412 | MyClass* obj = new (buffer) MyClass[5]; |
413 | } |
414 | |
415 | |
416 | // CHECK-LABEL: void test_lifetime_extended_temporaries() |
417 | // CHECK: [B1] |
418 | struct LifetimeExtend { LifetimeExtend(int); ~LifetimeExtend(); }; |
419 | struct Aggregate { const LifetimeExtend a; const LifetimeExtend b; }; |
420 | struct AggregateRef { const LifetimeExtend &a; const LifetimeExtend &b; }; |
421 | void test_lifetime_extended_temporaries() { |
422 | // CHECK: LifetimeExtend(1); |
423 | // CHECK-NEXT: : 1 |
424 | // CHECK-NEXT: ~LifetimeExtend() |
425 | // CHECK-NOT: ~LifetimeExtend() |
426 | { |
427 | const LifetimeExtend &l = LifetimeExtend(1); |
428 | 1; |
429 | } |
430 | // CHECK: LifetimeExtend(2) |
431 | // CHECK-NEXT: ~LifetimeExtend() |
432 | // CHECK-NEXT: : 2 |
433 | // CHECK-NOT: ~LifetimeExtend() |
434 | { |
435 | // No life-time extension. |
436 | const int &l = (LifetimeExtend(2), 2); |
437 | 2; |
438 | } |
439 | // CHECK: LifetimeExtend(3) |
440 | // CHECK-NEXT: : 3 |
441 | // CHECK-NEXT: ~LifetimeExtend() |
442 | // CHECK-NOT: ~LifetimeExtend() |
443 | { |
444 | // The last one is lifetime extended. |
445 | const LifetimeExtend &l = (3, LifetimeExtend(3)); |
446 | 3; |
447 | } |
448 | // CHECK: LifetimeExtend(4) |
449 | // CHECK-NEXT: ~LifetimeExtend() |
450 | // CHECK-NEXT: ~LifetimeExtend() |
451 | // CHECK-NEXT: : 4 |
452 | // CHECK-NOT: ~LifetimeExtend() |
453 | { |
454 | Aggregate a{LifetimeExtend(4), LifetimeExtend(4)}; |
455 | 4; |
456 | } |
457 | // CHECK: LifetimeExtend(5) |
458 | // CHECK-NEXT: : 5 |
459 | // FIXME: We want to emit the destructors of the lifetime |
460 | // extended variables here. |
461 | // CHECK-NOT: ~LifetimeExtend() |
462 | { |
463 | AggregateRef a{LifetimeExtend(5), LifetimeExtend(5)}; |
464 | 5; |
465 | } |
466 | // FIXME: Add tests for lifetime extension via subobject |
467 | // references (LifetimeExtend().some_member). |
468 | } |
469 | |
470 | |
471 | // FIXME: The destructor for 'a' shouldn't be there because it's deleted |
472 | // in the union. |
473 | // CHECK-LABEL: void foo() |
474 | // CHECK: [B2 (ENTRY)] |
475 | // CHECK-NEXT: Succs (1): B1 |
476 | // CHECK: [B1] |
477 | // WARNINGS-NEXT: 1: (CXXConstructExpr, struct pr37688_deleted_union_destructor::A) |
478 | // ANALYZER-NEXT: 1: (CXXConstructExpr, [B1.2], struct pr37688_deleted_union_destructor::A) |
479 | // CHECK-NEXT: 2: pr37688_deleted_union_destructor::A a; |
480 | // CHECK-NEXT: 3: [B1.2].~A() (Implicit destructor) |
481 | // CHECK-NEXT: Preds (1): B2 |
482 | // CHECK-NEXT: Succs (1): B0 |
483 | // CHECK: [B0 (EXIT)] |
484 | // CHECK-NEXT: Preds (1): B1 |
485 | |
486 | namespace pr37688_deleted_union_destructor { |
487 | struct S { ~S(); }; |
488 | struct A { |
489 | ~A() noexcept {} |
490 | union { |
491 | struct { |
492 | S s; |
493 | } ss; |
494 | }; |
495 | }; |
496 | void foo() { |
497 | A a; |
498 | } |
499 | } // end namespace pr37688_deleted_union_destructor |
500 | |
501 | |
502 | // CHECK-LABEL: template<> int *PR18472<int>() |
503 | // CHECK: [B2 (ENTRY)] |
504 | // CHECK-NEXT: Succs (1): B1 |
505 | // CHECK: [B1] |
506 | // CHECK-NEXT: 1: 0 |
507 | // CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, NullToPointer, PR18472_t) |
508 | // CHECK-NEXT: 3: (PR18472_t)[B1.2] (CStyleCastExpr, NoOp, PR18472_t) |
509 | // CHECK-NEXT: 4: CFGNewAllocator(int *) |
510 | // CHECK-NEXT: 5: new (([B1.3])) int |
511 | // CHECK-NEXT: 6: return [B1.5]; |
512 | // CHECK-NEXT: Preds (1): B2 |
513 | // CHECK-NEXT: Succs (1): B0 |
514 | // CHECK: [B0 (EXIT)] |
515 | // CHECK-NEXT: Preds (1): B1 |
516 | |
517 | extern "C" typedef int *PR18472_t; |
518 | void *operator new (unsigned long, PR18472_t); |
519 | template <class T> T *PR18472() { |
520 | return new (((PR18472_t) 0)) T; |
521 | } |
522 | void PR18472_helper() { |
523 | PR18472<int>(); |
524 | } |
525 | |
526 | |