1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++11 -verify -analyzer-config eagerly-assume=false %s
2 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++17 -verify -analyzer-config eagerly-assume=false %s
3 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++11 -analyzer-config elide-constructors=false -DNO_ELIDE_FLAG -verify -analyzer-config eagerly-assume=false %s
4 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++17 -analyzer-config elide-constructors=false -DNO_ELIDE_FLAG -verify -analyzer-config eagerly-assume=false %s
5 
6 // Copy elision always occurs in C++17, otherwise it's under
7 // an on-by-default flag.
8 #if __cplusplus >= 201703L
9   #define ELIDE 1
10 #else
11   #ifndef NO_ELIDE_FLAG
12     #define ELIDE 1
13   #endif
14 #endif
15 
16 void clang_analyzer_eval(bool);
17 
18 namespace variable_functional_cast_crash {
19 
20 struct A {
Avariable_functional_cast_crash::A21   A(int) {}
22 };
23 
foo()24 void foo() {
25   A a = A(0);
26 }
27 
28 struct B {
29   A a;
Bvariable_functional_cast_crash::B30   B(): a(A(0)) {}
31 };
32 
33 } // namespace variable_functional_cast_crash
34 
35 
36 namespace ctor_initializer {
37 
38 struct S {
39   int x, y, z;
40 };
41 
42 struct T {
43   S s;
44   int w;
Tctor_initializer::T45   T(int w): s(), w(w) {}
46 };
47 
48 class C {
49   T t;
50 public:
C()51   C() : t(T(4)) {
52     S s = {1, 2, 3};
53     t.s = s;
54     // FIXME: Should be TRUE regardless of copy elision.
55     clang_analyzer_eval(t.w == 4);
56 #ifdef ELIDE
57     // expected-warning@-2{{TRUE}}
58 #else
59     // expected-warning@-4{{UNKNOWN}}
60 #endif
61   }
62 };
63 
64 
65 struct A {
66   int x;
Actor_initializer::A67   A(): x(0) {}
~Actor_initializer::A68   ~A() {}
69 };
70 
71 struct B {
72   A a;
Bctor_initializer::B73   B() : a(A()) {}
74 };
75 
foo()76 void foo() {
77   B b;
78   clang_analyzer_eval(b.a.x == 0); // expected-warning{{TRUE}}
79 }
80 
81 } // namespace ctor_initializer
82 
83 
84 namespace elision_on_ternary_op_branches {
85 class C1 {
86   int x;
87 public:
C1(int x)88   C1(int x): x(x) {}
getX() const89   int getX() const { return x; }
90   ~C1();
91 };
92 
93 class C2 {
94   int x;
95   int y;
96 public:
C2(int x,int y)97   C2(int x, int y): x(x), y(y) {}
getX() const98   int getX() const { return x; }
getY() const99   int getY() const { return y; }
100   ~C2();
101 };
102 
foo(int coin)103 void foo(int coin) {
104   C1 c1 = coin ? C1(1) : C1(2);
105   if (coin) {
106     clang_analyzer_eval(c1.getX() == 1); // expected-warning{{TRUE}}
107   } else {
108     clang_analyzer_eval(c1.getX() == 2); // expected-warning{{TRUE}}
109   }
110   C2 c2 = coin ? C2(3, 4) : C2(5, 6);
111   if (coin) {
112     clang_analyzer_eval(c2.getX() == 3); // expected-warning{{TRUE}}
113     clang_analyzer_eval(c2.getY() == 4); // expected-warning{{TRUE}}
114   } else {
115     clang_analyzer_eval(c2.getX() == 5); // expected-warning{{TRUE}}
116     clang_analyzer_eval(c2.getY() == 6); // expected-warning{{TRUE}}
117   }
118 }
119 } // namespace elision_on_ternary_op_branches
120 
121 
122 namespace address_vector_tests {
123 
124 template <typename T> struct AddressVector {
125   T *buf[20];
126   int len;
127 
AddressVectoraddress_vector_tests::AddressVector128   AddressVector() : len(0) {}
129 
pushaddress_vector_tests::AddressVector130   void push(T *t) {
131     buf[len] = t;
132     ++len;
133   }
134 };
135 
136 class ClassWithoutDestructor {
137   AddressVector<ClassWithoutDestructor> &v;
138 
139 public:
ClassWithoutDestructor(AddressVector<ClassWithoutDestructor> & v)140   ClassWithoutDestructor(AddressVector<ClassWithoutDestructor> &v) : v(v) {
141     push();
142   }
143 
ClassWithoutDestructor(ClassWithoutDestructor && c)144   ClassWithoutDestructor(ClassWithoutDestructor &&c) : v(c.v) { push(); }
ClassWithoutDestructor(const ClassWithoutDestructor & c)145   ClassWithoutDestructor(const ClassWithoutDestructor &c) : v(c.v) { push(); }
146 
push()147   void push() { v.push(this); }
148 };
149 
make1(AddressVector<ClassWithoutDestructor> & v)150 ClassWithoutDestructor make1(AddressVector<ClassWithoutDestructor> &v) {
151   return ClassWithoutDestructor(v);
152 }
make2(AddressVector<ClassWithoutDestructor> & v)153 ClassWithoutDestructor make2(AddressVector<ClassWithoutDestructor> &v) {
154   return make1(v);
155 }
make3(AddressVector<ClassWithoutDestructor> & v)156 ClassWithoutDestructor make3(AddressVector<ClassWithoutDestructor> &v) {
157   return make2(v);
158 }
159 
testMultipleReturns()160 void testMultipleReturns() {
161   AddressVector<ClassWithoutDestructor> v;
162   ClassWithoutDestructor c = make3(v);
163 
164 #if ELIDE
165   clang_analyzer_eval(v.len == 1); // expected-warning{{TRUE}}
166   clang_analyzer_eval(v.buf[0] == &c); // expected-warning{{TRUE}}
167 #else
168   clang_analyzer_eval(v.len == 5); // expected-warning{{TRUE}}
169   clang_analyzer_eval(v.buf[0] != v.buf[1]); // expected-warning{{TRUE}}
170   clang_analyzer_eval(v.buf[1] != v.buf[2]); // expected-warning{{TRUE}}
171   clang_analyzer_eval(v.buf[2] != v.buf[3]); // expected-warning{{TRUE}}
172   clang_analyzer_eval(v.buf[3] != v.buf[4]); // expected-warning{{TRUE}}
173   clang_analyzer_eval(v.buf[4] == &c); // expected-warning{{TRUE}}
174 #endif
175 }
176 
consume(ClassWithoutDestructor c)177 void consume(ClassWithoutDestructor c) {
178   c.push();
179 }
180 
testArgumentConstructorWithoutDestructor()181 void testArgumentConstructorWithoutDestructor() {
182   AddressVector<ClassWithoutDestructor> v;
183 
184   consume(make3(v));
185 
186 #if ELIDE
187   clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}}
188   clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}}
189 #else
190   clang_analyzer_eval(v.len == 6); // expected-warning{{TRUE}}
191   clang_analyzer_eval(v.buf[0] != v.buf[1]); // expected-warning{{TRUE}}
192   clang_analyzer_eval(v.buf[1] != v.buf[2]); // expected-warning{{TRUE}}
193   clang_analyzer_eval(v.buf[2] != v.buf[3]); // expected-warning{{TRUE}}
194   clang_analyzer_eval(v.buf[3] != v.buf[4]); // expected-warning{{TRUE}}
195   // We forced a push() in consume(), let's see if the address here matches
196   // the address during construction.
197   clang_analyzer_eval(v.buf[4] == v.buf[5]); // expected-warning{{TRUE}}
198 #endif
199 }
200 
201 class ClassWithDestructor {
202   AddressVector<ClassWithDestructor> &v;
203 
204 public:
ClassWithDestructor(AddressVector<ClassWithDestructor> & v)205   ClassWithDestructor(AddressVector<ClassWithDestructor> &v) : v(v) {
206     push();
207   }
208 
ClassWithDestructor(ClassWithDestructor && c)209   ClassWithDestructor(ClassWithDestructor &&c) : v(c.v) { push(); }
ClassWithDestructor(const ClassWithDestructor & c)210   ClassWithDestructor(const ClassWithDestructor &c) : v(c.v) { push(); }
211 
~ClassWithDestructor()212   ~ClassWithDestructor() { push(); }
213 
push()214   void push() { v.push(this); }
215 };
216 
testVariable()217 void testVariable() {
218   AddressVector<ClassWithDestructor> v;
219   {
220     ClassWithDestructor c = ClassWithDestructor(v);
221     // Check if the last destructor is an automatic destructor.
222     // A temporary destructor would have fired by now.
223 #if ELIDE
224     clang_analyzer_eval(v.len == 1); // expected-warning{{TRUE}}
225 #else
226     clang_analyzer_eval(v.len == 3); // expected-warning{{TRUE}}
227 #endif
228   }
229 #if ELIDE
230   // 0. Construct the variable.
231   // 1. Destroy the variable.
232   clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}}
233   clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}}
234 #else
235   // 0. Construct the temporary.
236   // 1. Construct the variable.
237   // 2. Destroy the temporary.
238   // 3. Destroy the variable.
239   clang_analyzer_eval(v.len == 4); // expected-warning{{TRUE}}
240   clang_analyzer_eval(v.buf[0] == v.buf[2]); // expected-warning{{TRUE}}
241   clang_analyzer_eval(v.buf[1] == v.buf[3]); // expected-warning{{TRUE}}
242 #endif
243 }
244 
245 struct TestCtorInitializer {
246   ClassWithDestructor c;
TestCtorInitializeraddress_vector_tests::TestCtorInitializer247   TestCtorInitializer(AddressVector<ClassWithDestructor> &v)
248     : c(ClassWithDestructor(v)) {}
249 };
250 
testCtorInitializer()251 void testCtorInitializer() {
252   AddressVector<ClassWithDestructor> v;
253   {
254     TestCtorInitializer t(v);
255     // Check if the last destructor is an automatic destructor.
256     // A temporary destructor would have fired by now.
257 #if ELIDE
258     clang_analyzer_eval(v.len == 1); // expected-warning{{TRUE}}
259 #else
260     clang_analyzer_eval(v.len == 3); // expected-warning{{TRUE}}
261 #endif
262   }
263 #if ELIDE
264   // 0. Construct the member variable.
265   // 1. Destroy the member variable.
266   clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}}
267   clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}}
268 #else
269   // 0. Construct the temporary.
270   // 1. Construct the member variable.
271   // 2. Destroy the temporary.
272   // 3. Destroy the member variable.
273   clang_analyzer_eval(v.len == 4); // expected-warning{{TRUE}}
274   clang_analyzer_eval(v.buf[0] == v.buf[2]); // expected-warning{{TRUE}}
275   clang_analyzer_eval(v.buf[1] == v.buf[3]); // expected-warning{{TRUE}}
276 #endif
277 }
278 
279 
make1(AddressVector<ClassWithDestructor> & v)280 ClassWithDestructor make1(AddressVector<ClassWithDestructor> &v) {
281   return ClassWithDestructor(v);
282 }
make2(AddressVector<ClassWithDestructor> & v)283 ClassWithDestructor make2(AddressVector<ClassWithDestructor> &v) {
284   return make1(v);
285 }
make3(AddressVector<ClassWithDestructor> & v)286 ClassWithDestructor make3(AddressVector<ClassWithDestructor> &v) {
287   return make2(v);
288 }
289 
testMultipleReturnsWithDestructors()290 void testMultipleReturnsWithDestructors() {
291   AddressVector<ClassWithDestructor> v;
292   {
293     ClassWithDestructor c = make3(v);
294     // Check if the last destructor is an automatic destructor.
295     // A temporary destructor would have fired by now.
296 #if ELIDE
297     clang_analyzer_eval(v.len == 1); // expected-warning{{TRUE}}
298 #else
299     clang_analyzer_eval(v.len == 9); // expected-warning{{TRUE}}
300 #endif
301   }
302 
303 #if ELIDE
304   // 0. Construct the variable. Yes, constructor in make1() constructs
305   //    the variable 'c'.
306   // 1. Destroy the variable.
307   clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}}
308   clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}}
309 #else
310   // 0. Construct the temporary in make1().
311   // 1. Construct the temporary in make2().
312   // 2. Destroy the temporary in make1().
313   // 3. Construct the temporary in make3().
314   // 4. Destroy the temporary in make2().
315   // 5. Construct the temporary here.
316   // 6. Destroy the temporary in make3().
317   // 7. Construct the variable.
318   // 8. Destroy the temporary here.
319   // 9. Destroy the variable.
320   clang_analyzer_eval(v.len == 10); // expected-warning{{TRUE}}
321   clang_analyzer_eval(v.buf[0] == v.buf[2]); // expected-warning{{TRUE}}
322   clang_analyzer_eval(v.buf[1] == v.buf[4]); // expected-warning{{TRUE}}
323   clang_analyzer_eval(v.buf[3] == v.buf[6]); // expected-warning{{TRUE}}
324   clang_analyzer_eval(v.buf[5] == v.buf[8]); // expected-warning{{TRUE}}
325   clang_analyzer_eval(v.buf[7] == v.buf[9]); // expected-warning{{TRUE}}
326 #endif
327 }
328 
consume(ClassWithDestructor c)329 void consume(ClassWithDestructor c) {
330   c.push();
331 }
332 
testArgumentConstructorWithDestructor()333 void testArgumentConstructorWithDestructor() {
334   AddressVector<ClassWithDestructor> v;
335 
336   consume(make3(v));
337 
338 #if ELIDE
339   // 0. Construct the argument.
340   // 1. Forced push() in consume().
341   // 2. Destroy the argument.
342   clang_analyzer_eval(v.len == 3); // expected-warning{{TRUE}}
343   clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}}
344   clang_analyzer_eval(v.buf[1] == v.buf[2]); // expected-warning{{TRUE}}
345 #else
346   // 0. Construct the temporary in make1().
347   // 1. Construct the temporary in make2().
348   // 2. Destroy the temporary in make1().
349   // 3. Construct the temporary in make3().
350   // 4. Destroy the temporary in make2().
351   // 5. Construct the temporary here.
352   // 6. Destroy the temporary in make3().
353   // 7. Construct the argument.
354   // 8. Forced push() in consume().
355   // 9. Destroy the argument. Notice the reverse order!
356   // 10. Destroy the temporary here.
357   clang_analyzer_eval(v.len == 11); // expected-warning{{TRUE}}
358   clang_analyzer_eval(v.buf[0] == v.buf[2]); // expected-warning{{TRUE}}
359   clang_analyzer_eval(v.buf[1] == v.buf[4]); // expected-warning{{TRUE}}
360   clang_analyzer_eval(v.buf[3] == v.buf[6]); // expected-warning{{TRUE}}
361   clang_analyzer_eval(v.buf[5] == v.buf[10]); // expected-warning{{TRUE}}
362   clang_analyzer_eval(v.buf[7] == v.buf[8]); // expected-warning{{TRUE}}
363   clang_analyzer_eval(v.buf[8] == v.buf[9]); // expected-warning{{TRUE}}
364 #endif
365 }
366 
367 } // namespace address_vector_tests
368