blob: cf77912ea6c4fe5a5d13b9182085c2798cbc9661 [file] [log] [blame]
Artem Dergachev9d3a7d82018-03-30 19:21:18 +00001// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++11 -verify %s
2// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++17 -verify %s
Artem Dergachev9a209ad2018-06-28 00:30:18 +00003// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++11 -analyzer-config elide-constructors=false -DNO_ELIDE_FLAG -verify %s
4// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++17 -analyzer-config elide-constructors=false -DNO_ELIDE_FLAG -verify %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
Artem Dergachev9d3a7d82018-03-30 19:21:18 +000015
16void clang_analyzer_eval(bool);
17
Artem Dergachev1fe52472018-06-14 01:32:46 +000018namespace variable_functional_cast_crash {
19
20struct A {
21 A(int) {}
22};
23
24void foo() {
25 A a = A(0);
26}
27
28struct B {
29 A a;
30 B(): a(A(0)) {}
31};
32
33} // namespace variable_functional_cast_crash
34
35
Artem Dergacheva84374d2018-06-14 01:40:49 +000036namespace ctor_initializer {
37
38struct S {
39 int x, y, z;
40};
41
42struct T {
43 S s;
44 int w;
45 T(int w): s(), w(w) {}
46};
47
48class C {
49 T t;
50public:
51 C() : t(T(4)) {
52 S s = {1, 2, 3};
53 t.s = s;
Artem Dergachev9a209ad2018-06-28 00:30:18 +000054 // FIXME: Should be TRUE regardless of copy elision.
Artem Dergacheva84374d2018-06-14 01:40:49 +000055 clang_analyzer_eval(t.w == 4);
Artem Dergachev9a209ad2018-06-28 00:30:18 +000056#ifdef ELIDE
Artem Dergacheva84374d2018-06-14 01:40:49 +000057 // expected-warning@-2{{TRUE}}
58#else
59 // expected-warning@-4{{UNKNOWN}}
60#endif
61 }
62};
63
Artem Dergachev53b8ce02018-06-14 01:54:21 +000064
65struct A {
66 int x;
67 A(): x(0) {}
68 ~A() {}
69};
70
71struct B {
72 A a;
73 B() : a(A()) {}
74};
75
76void foo() {
77 B b;
78 clang_analyzer_eval(b.a.x == 0); // expected-warning{{TRUE}}
79}
80
Artem Dergacheva84374d2018-06-14 01:40:49 +000081} // namespace ctor_initializer
82
83
Artem Dergachev53b8ce02018-06-14 01:54:21 +000084namespace elision_on_ternary_op_branches {
85class C1 {
86 int x;
87public:
88 C1(int x): x(x) {}
89 int getX() const { return x; }
90 ~C1();
91};
92
93class C2 {
94 int x;
95 int y;
96public:
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
103void 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
Artem Dergachev1fe52472018-06-14 01:32:46 +0000122namespace address_vector_tests {
123
Artem Dergachev9d3a7d82018-03-30 19:21:18 +0000124template <typename T> struct AddressVector {
125 T *buf[10];
126 int len;
127
128 AddressVector() : len(0) {}
129
130 void push(T *t) {
131 buf[len] = t;
132 ++len;
133 }
134};
135
136class ClassWithoutDestructor {
137 AddressVector<ClassWithoutDestructor> &v;
138
139public:
140 ClassWithoutDestructor(AddressVector<ClassWithoutDestructor> &v) : v(v) {
141 v.push(this);
142 }
143
144 ClassWithoutDestructor(ClassWithoutDestructor &&c) : v(c.v) { v.push(this); }
145 ClassWithoutDestructor(const ClassWithoutDestructor &c) : v(c.v) {
146 v.push(this);
147 }
148};
149
150ClassWithoutDestructor make1(AddressVector<ClassWithoutDestructor> &v) {
151 return ClassWithoutDestructor(v);
152}
153ClassWithoutDestructor make2(AddressVector<ClassWithoutDestructor> &v) {
154 return make1(v);
155}
156ClassWithoutDestructor make3(AddressVector<ClassWithoutDestructor> &v) {
157 return make2(v);
158}
159
160void testMultipleReturns() {
161 AddressVector<ClassWithoutDestructor> v;
162 ClassWithoutDestructor c = make3(v);
163
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000164#if ELIDE
Artem Dergachev9d3a7d82018-03-30 19:21:18 +0000165 clang_analyzer_eval(v.len == 1); // expected-warning{{TRUE}}
Artem Dergachevf28d7f172018-06-14 01:59:35 +0000166 clang_analyzer_eval(v.buf[0] == &c); // expected-warning{{TRUE}}
Artem Dergachev9d3a7d82018-03-30 19:21:18 +0000167#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}
Artem Dergachev1fe52472018-06-14 01:32:46 +0000176
Artem Dergachev53b8ce02018-06-14 01:54:21 +0000177class ClassWithDestructor {
178 AddressVector<ClassWithDestructor> &v;
179
180public:
181 ClassWithDestructor(AddressVector<ClassWithDestructor> &v) : v(v) {
182 v.push(this);
183 }
184
185 ClassWithDestructor(ClassWithDestructor &&c) : v(c.v) { v.push(this); }
186 ClassWithDestructor(const ClassWithDestructor &c) : v(c.v) {
187 v.push(this);
188 }
189
190 ~ClassWithDestructor() { v.push(this); }
191};
192
193void testVariable() {
194 AddressVector<ClassWithDestructor> v;
195 {
196 ClassWithDestructor c = ClassWithDestructor(v);
Artem Dergachevf28d7f172018-06-14 01:59:35 +0000197 // Check if the last destructor is an automatic destructor.
198 // A temporary destructor would have fired by now.
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000199#if ELIDE
Artem Dergachevf28d7f172018-06-14 01:59:35 +0000200 clang_analyzer_eval(v.len == 1); // expected-warning{{TRUE}}
201#else
202 clang_analyzer_eval(v.len == 3); // expected-warning{{TRUE}}
203#endif
Artem Dergachev53b8ce02018-06-14 01:54:21 +0000204 }
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000205#if ELIDE
Artem Dergachev53b8ce02018-06-14 01:54:21 +0000206 // 0. Construct the variable.
207 // 1. Destroy the variable.
208 clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}}
209 clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}}
210#else
211 // 0. Construct the temporary.
212 // 1. Construct the variable.
213 // 2. Destroy the temporary.
214 // 3. Destroy the variable.
215 clang_analyzer_eval(v.len == 4); // expected-warning{{TRUE}}
216 clang_analyzer_eval(v.buf[0] == v.buf[2]); // expected-warning{{TRUE}}
217 clang_analyzer_eval(v.buf[1] == v.buf[3]); // expected-warning{{TRUE}}
218#endif
219}
220
221struct TestCtorInitializer {
222 ClassWithDestructor c;
223 TestCtorInitializer(AddressVector<ClassWithDestructor> &v)
224 : c(ClassWithDestructor(v)) {}
225};
226
227void testCtorInitializer() {
228 AddressVector<ClassWithDestructor> v;
229 {
230 TestCtorInitializer t(v);
Artem Dergachevf28d7f172018-06-14 01:59:35 +0000231 // Check if the last destructor is an automatic destructor.
232 // A temporary destructor would have fired by now.
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000233#if ELIDE
Artem Dergachevf28d7f172018-06-14 01:59:35 +0000234 clang_analyzer_eval(v.len == 1); // expected-warning{{TRUE}}
235#else
236 clang_analyzer_eval(v.len == 3); // expected-warning{{TRUE}}
237#endif
Artem Dergachev53b8ce02018-06-14 01:54:21 +0000238 }
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000239#if ELIDE
Artem Dergachev53b8ce02018-06-14 01:54:21 +0000240 // 0. Construct the member variable.
241 // 1. Destroy the member variable.
242 clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}}
243 clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}}
244#else
245 // 0. Construct the temporary.
246 // 1. Construct the member variable.
247 // 2. Destroy the temporary.
248 // 3. Destroy the member variable.
249 clang_analyzer_eval(v.len == 4); // expected-warning{{TRUE}}
250 clang_analyzer_eval(v.buf[0] == v.buf[2]); // expected-warning{{TRUE}}
251 clang_analyzer_eval(v.buf[1] == v.buf[3]); // expected-warning{{TRUE}}
252#endif
253}
254
Artem Dergachevf28d7f172018-06-14 01:59:35 +0000255
256ClassWithDestructor make1(AddressVector<ClassWithDestructor> &v) {
257 return ClassWithDestructor(v);
258}
259ClassWithDestructor make2(AddressVector<ClassWithDestructor> &v) {
260 return make1(v);
261}
262ClassWithDestructor make3(AddressVector<ClassWithDestructor> &v) {
263 return make2(v);
264}
265
266void testMultipleReturnsWithDestructors() {
267 AddressVector<ClassWithDestructor> v;
268 {
269 ClassWithDestructor c = make3(v);
270 // Check if the last destructor is an automatic destructor.
271 // A temporary destructor would have fired by now.
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000272#if ELIDE
Artem Dergachevf28d7f172018-06-14 01:59:35 +0000273 clang_analyzer_eval(v.len == 1); // expected-warning{{TRUE}}
274#else
275 clang_analyzer_eval(v.len == 9); // expected-warning{{TRUE}}
276#endif
277 }
278
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000279#if ELIDE
Artem Dergachevf28d7f172018-06-14 01:59:35 +0000280 // 0. Construct the variable. Yes, constructor in make1() constructs
281 // the variable 'c'.
282 // 1. Destroy the variable.
283 clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}}
284 clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}}
285#else
286 // 0. Construct the temporary in make1().
287 // 1. Construct the temporary in make2().
288 // 2. Destroy the temporary in make1().
289 // 3. Construct the temporary in make3().
290 // 4. Destroy the temporary in make2().
291 // 5. Construct the temporary here.
292 // 6. Destroy the temporary in make3().
293 // 7. Construct the variable.
294 // 8. Destroy the temporary here.
295 // 9. Destroy the variable.
296 clang_analyzer_eval(v.len == 10); // expected-warning{{TRUE}}
297 clang_analyzer_eval(v.buf[0] == v.buf[2]); // expected-warning{{TRUE}}
298 clang_analyzer_eval(v.buf[1] == v.buf[4]); // expected-warning{{TRUE}}
299 clang_analyzer_eval(v.buf[3] == v.buf[6]); // expected-warning{{TRUE}}
300 clang_analyzer_eval(v.buf[5] == v.buf[8]); // expected-warning{{TRUE}}
301 clang_analyzer_eval(v.buf[7] == v.buf[9]); // expected-warning{{TRUE}}
302#endif
303}
Artem Dergachev1fe52472018-06-14 01:32:46 +0000304} // namespace address_vector_tests