150
|
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 {
|
|
21 A(int) {}
|
|
22 };
|
|
23
|
|
24 void foo() {
|
|
25 A a = A(0);
|
|
26 }
|
|
27
|
|
28 struct B {
|
|
29 A a;
|
|
30 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;
|
|
45 T(int w): s(), w(w) {}
|
|
46 };
|
|
47
|
|
48 class C {
|
|
49 T t;
|
|
50 public:
|
|
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;
|
|
67 A(): x(0) {}
|
|
68 ~A() {}
|
|
69 };
|
|
70
|
|
71 struct B {
|
|
72 A a;
|
|
73 B() : a(A()) {}
|
|
74 };
|
|
75
|
|
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:
|
|
88 C1(int x): x(x) {}
|
|
89 int getX() const { return x; }
|
|
90 ~C1();
|
|
91 };
|
|
92
|
|
93 class C2 {
|
|
94 int x;
|
|
95 int y;
|
|
96 public:
|
|
97 C2(int x, int y): x(x), y(y) {}
|
|
98 int getX() const { return x; }
|
|
99 int getY() const { return y; }
|
|
100 ~C2();
|
|
101 };
|
|
102
|
|
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
|
|
128 AddressVector() : len(0) {}
|
|
129
|
|
130 void push(T *t) {
|
|
131 buf[len] = t;
|
|
132 ++len;
|
|
133 }
|
|
134 };
|
|
135
|
|
136 class ClassWithoutDestructor {
|
|
137 AddressVector<ClassWithoutDestructor> &v;
|
|
138
|
|
139 public:
|
|
140 ClassWithoutDestructor(AddressVector<ClassWithoutDestructor> &v) : v(v) {
|
|
141 push();
|
|
142 }
|
|
143
|
|
144 ClassWithoutDestructor(ClassWithoutDestructor &&c) : v(c.v) { push(); }
|
|
145 ClassWithoutDestructor(const ClassWithoutDestructor &c) : v(c.v) { push(); }
|
|
146
|
|
147 void push() { v.push(this); }
|
|
148 };
|
|
149
|
|
150 ClassWithoutDestructor make1(AddressVector<ClassWithoutDestructor> &v) {
|
|
151 return ClassWithoutDestructor(v);
|
|
152 }
|
|
153 ClassWithoutDestructor make2(AddressVector<ClassWithoutDestructor> &v) {
|
|
154 return make1(v);
|
|
155 }
|
|
156 ClassWithoutDestructor make3(AddressVector<ClassWithoutDestructor> &v) {
|
|
157 return make2(v);
|
|
158 }
|
|
159
|
|
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
|
|
177 void consume(ClassWithoutDestructor c) {
|
|
178 c.push();
|
|
179 }
|
|
180
|
|
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:
|
|
205 ClassWithDestructor(AddressVector<ClassWithDestructor> &v) : v(v) {
|
|
206 push();
|
|
207 }
|
|
208
|
|
209 ClassWithDestructor(ClassWithDestructor &&c) : v(c.v) { push(); }
|
|
210 ClassWithDestructor(const ClassWithDestructor &c) : v(c.v) { push(); }
|
|
211
|
|
212 ~ClassWithDestructor() { push(); }
|
|
213
|
|
214 void push() { v.push(this); }
|
|
215 };
|
|
216
|
|
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;
|
|
247 TestCtorInitializer(AddressVector<ClassWithDestructor> &v)
|
|
248 : c(ClassWithDestructor(v)) {}
|
|
249 };
|
|
250
|
|
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
|
|
280 ClassWithDestructor make1(AddressVector<ClassWithDestructor> &v) {
|
|
281 return ClassWithDestructor(v);
|
|
282 }
|
|
283 ClassWithDestructor make2(AddressVector<ClassWithDestructor> &v) {
|
|
284 return make1(v);
|
|
285 }
|
|
286 ClassWithDestructor make3(AddressVector<ClassWithDestructor> &v) {
|
|
287 return make2(v);
|
|
288 }
|
|
289
|
|
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
|
|
329 void consume(ClassWithDestructor c) {
|
|
330 c.push();
|
|
331 }
|
|
332
|
|
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
|