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