blob: 8ce2000787a7074a35b05faf69cab42b3c473d34 [file] [log] [blame]
George Karpenkova393e682018-08-29 20:29:17 +00001// RUN: %clang_analyze_cc1 -Wno-unused -std=c++11 -analyzer-checker=core,debug.ExprInspection -analyzer-config cfg-temporary-dtors=false -verify -analyzer-config eagerly-assume=false %s
2// RUN: %clang_analyze_cc1 -Wno-unused -std=c++11 -analyzer-checker=core,debug.ExprInspection -analyzer-config cfg-temporary-dtors=true,c++-temp-dtor-inlining=true -DTEMPORARIES -verify -analyzer-config eagerly-assume=false %s
3// RUN: %clang_analyze_cc1 -Wno-unused -std=c++17 -analyzer-checker=core,debug.ExprInspection -analyzer-config cfg-temporary-dtors=true,c++-temp-dtor-inlining=true -DTEMPORARIES -analyzer-config eagerly-assume=false %s
4// RUN: %clang_analyze_cc1 -Wno-unused -std=c++11 -analyzer-checker=core,debug.ExprInspection -analyzer-config cfg-temporary-dtors=false -DMOVES -verify -analyzer-config eagerly-assume=false %s
5// RUN: %clang_analyze_cc1 -Wno-unused -std=c++11 -analyzer-checker=core,debug.ExprInspection -analyzer-config cfg-temporary-dtors=true,c++-temp-dtor-inlining=true -DTEMPORARIES -DMOVES -verify -analyzer-config eagerly-assume=false %s
6// RUN: %clang_analyze_cc1 -Wno-unused -std=c++17 -analyzer-checker=core,debug.ExprInspection -analyzer-config cfg-temporary-dtors=true,c++-temp-dtor-inlining=true -DTEMPORARIES -DMOVES -analyzer-config eagerly-assume=false %s
Artem Dergachevb9d3d302018-03-22 21:54:48 +00007
8// Note: The C++17 run-lines don't -verify yet - it is a no-crash test.
Artem Dergachev28ee2d12016-11-30 19:02:44 +00009
10void clang_analyzer_eval(bool);
Artem Dergacheve07896782018-03-12 23:22:35 +000011void clang_analyzer_checkInlined(bool);
Artem Dergachev28ee2d12016-11-30 19:02:44 +000012
13namespace pr17001_call_wrong_destructor {
14bool x;
15struct A {
16 int *a;
17 A() {}
18 ~A() {}
19};
20struct B : public A {
21 B() {}
22 ~B() { x = true; }
23};
24
25void f() {
26 {
27 const A &a = B();
28 }
29 clang_analyzer_eval(x); // expected-warning{{TRUE}}
30}
31} // end namespace pr17001_call_wrong_destructor
32
33namespace pr19539_crash_on_destroying_an_integer {
34struct A {
35 int i;
36 int j[2];
37 A() : i(1) {
38 j[0] = 2;
39 j[1] = 3;
40 }
41 ~A() {}
42};
43
44void f() {
45 const int &x = A().i; // no-crash
46 const int &y = A().j[1]; // no-crash
47 const int &z = (A().j[1], A().j[0]); // no-crash
48
Artem Dergachev643102d2018-06-04 20:18:37 +000049 clang_analyzer_eval(x == 1);
50 clang_analyzer_eval(y == 3);
51 clang_analyzer_eval(z == 2);
52#ifdef TEMPORARIES
53 // expected-warning@-4{{TRUE}}
54 // expected-warning@-4{{TRUE}}
55 // expected-warning@-4{{TRUE}}
56#else
57 // expected-warning@-8{{UNKNOWN}}
58 // expected-warning@-8{{UNKNOWN}}
59 // expected-warning@-8{{UNKNOWN}}
60#endif
Artem Dergachev28ee2d12016-11-30 19:02:44 +000061}
62} // end namespace pr19539_crash_on_destroying_an_integer
Artem Dergachev308e27e2018-02-27 19:47:49 +000063
64namespace maintain_original_object_address_on_lifetime_extension {
65class C {
66 C **after, **before;
67
68public:
69 bool x;
70
71 C(bool x, C **after, C **before) : x(x), after(after), before(before) {
72 *before = this;
73 }
74
75 // Don't track copies in our tests.
76 C(const C &c) : x(c.x), after(nullptr), before(nullptr) {}
77
78 ~C() { if (after) *after = this; }
79
80 operator bool() const { return x; }
Artem Dergacheve07896782018-03-12 23:22:35 +000081
82 static C make(C **after, C **before) { return C(false, after, before); }
Artem Dergachev308e27e2018-02-27 19:47:49 +000083};
84
85void f1() {
86 C *after, *before;
87 {
88 const C &c = C(true, &after, &before);
89 }
90 clang_analyzer_eval(after == before);
91#ifdef TEMPORARIES
92 // expected-warning@-2{{TRUE}}
93#else
94 // expected-warning@-4{{UNKNOWN}}
95#endif
96}
97
98void f2() {
99 C *after, *before;
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000100 {
101 C c = C(1, &after, &before);
102 }
103 clang_analyzer_eval(after == before); // expected-warning{{TRUE}}
Artem Dergachev308e27e2018-02-27 19:47:49 +0000104}
105
106void f3(bool coin) {
107 C *after, *before;
108 {
109 const C &c = coin ? C(true, &after, &before) : C(false, &after, &before);
110 }
111 clang_analyzer_eval(after == before);
112#ifdef TEMPORARIES
113 // expected-warning@-2{{TRUE}}
114#else
115 // expected-warning@-4{{UNKNOWN}}
116#endif
117}
118
119void f4(bool coin) {
120 C *after, *before;
121 {
122 // no-crash
123 const C &c = C(coin, &after, &before) ?: C(false, &after, &before);
124 }
125 // FIXME: Add support for lifetime extension through binary conditional
126 // operator. Ideally also add support for the binary conditional operator in
127 // C++. Because for now it calls the constructor for the condition twice.
128 if (coin) {
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000129 // FIXME: Should not warn.
Artem Dergachev308e27e2018-02-27 19:47:49 +0000130 clang_analyzer_eval(after == before);
131#ifdef TEMPORARIES
132 // expected-warning@-2{{The left operand of '==' is a garbage value}}
133#else
134 // expected-warning@-4{{UNKNOWN}}
135#endif
136 } else {
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000137 // FIXME: Should be TRUE.
Artem Dergachev308e27e2018-02-27 19:47:49 +0000138 clang_analyzer_eval(after == before);
139#ifdef TEMPORARIES
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000140 // expected-warning@-2{{FALSE}}
Artem Dergachev308e27e2018-02-27 19:47:49 +0000141#else
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000142 // expected-warning@-4{{UNKNOWN}}
Artem Dergachev308e27e2018-02-27 19:47:49 +0000143#endif
144 }
145}
146
147void f5() {
148 C *after, *before;
149 {
150 const bool &x = C(true, &after, &before).x; // no-crash
151 }
Artem Dergachev643102d2018-06-04 20:18:37 +0000152 clang_analyzer_eval(after == before);
153#ifdef TEMPORARIES
154 // expected-warning@-2{{TRUE}}
155#else
156 // expected-warning@-4{{UNKNOWN}}
157#endif
Artem Dergachev308e27e2018-02-27 19:47:49 +0000158}
Artem Dergachev310bca02018-04-25 23:02:06 +0000159
160struct A { // A is an aggregate.
161 const C &c;
162};
163
164void f6() {
165 C *after, *before;
166 {
167 A a{C(true, &after, &before)};
168 }
169 // FIXME: Should be TRUE. Should not warn about garbage value.
170 clang_analyzer_eval(after == before); // expected-warning{{UNKNOWN}}
171}
172
173void f7() {
174 C *after, *before;
175 {
176 A a = {C(true, &after, &before)};
177 }
178 // FIXME: Should be TRUE. Should not warn about garbage value.
179 clang_analyzer_eval(after == before); // expected-warning{{UNKNOWN}}
180}
181
182void f8() {
183 C *after, *before;
184 {
185 A a[2] = {C(false, nullptr, nullptr), C(true, &after, &before)};
186 }
187 // FIXME: Should be TRUE. Should not warn about garbage value.
188 clang_analyzer_eval(after == before); // expected-warning{{UNKNOWN}}
189}
Artem Dergachev308e27e2018-02-27 19:47:49 +0000190} // end namespace maintain_original_object_address_on_lifetime_extension
191
192namespace maintain_original_object_address_on_move {
193class C {
194 int *x;
195
196public:
197 C() : x(nullptr) {}
198 C(int *x) : x(x) {}
199 C(const C &c) = delete;
200 C(C &&c) : x(c.x) { c.x = nullptr; }
201 C &operator=(C &&c) {
202 x = c.x;
203 c.x = nullptr;
204 return *this;
205 }
206 ~C() {
207 // This was triggering the division by zero warning in f1() and f2():
208 // Because move-elision materialization was incorrectly causing the object
209 // to be relocated from one address to another before move, but destructor
210 // was operating on the old address, it was still thinking that 'x' is set.
211 if (x)
212 *x = 0;
213 }
214};
215
216void f1() {
217 int x = 1;
218 // &x is replaced with nullptr in move-constructor before the temporary dies.
219 C c = C(&x);
220 // Hence x was not set to 0 yet.
221 1 / x; // no-warning
222}
223void f2() {
224 int x = 1;
225 C c;
226 // &x is replaced with nullptr in move-assignment before the temporary dies.
227 c = C(&x);
228 // Hence x was not set to 0 yet.
229 1 / x; // no-warning
230}
231} // end namespace maintain_original_object_address_on_move
Artem Dergacheve07896782018-03-12 23:22:35 +0000232
233namespace maintain_address_of_copies {
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000234class C;
Artem Dergacheve07896782018-03-12 23:22:35 +0000235
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000236struct AddressVector {
237 C *buf[10];
Artem Dergacheve07896782018-03-12 23:22:35 +0000238 int len;
239
240 AddressVector() : len(0) {}
241
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000242 void push(C *c) {
243 buf[len] = c;
Artem Dergacheve07896782018-03-12 23:22:35 +0000244 ++len;
245 }
246};
247
248class C {
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000249 AddressVector &v;
Artem Dergacheve07896782018-03-12 23:22:35 +0000250
251public:
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000252 C(AddressVector &v) : v(v) { v.push(this); }
Artem Dergacheve07896782018-03-12 23:22:35 +0000253 ~C() { v.push(this); }
254
255#ifdef MOVES
256 C(C &&c) : v(c.v) { v.push(this); }
257#endif
258
259 // Note how return-statements prefer move-constructors when available.
260 C(const C &c) : v(c.v) {
261#ifdef MOVES
262 clang_analyzer_checkInlined(false); // no-warning
263#else
264 v.push(this);
265#endif
266 } // no-warning
267
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000268 static C make(AddressVector &v) { return C(v); }
Artem Dergacheve07896782018-03-12 23:22:35 +0000269};
270
271void f1() {
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000272 AddressVector v;
Artem Dergacheve07896782018-03-12 23:22:35 +0000273 {
274 C c = C(v);
275 }
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000276 // 0. Construct variable 'c' (copy/move elided).
277 // 1. Destroy variable 'c'.
278 clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}}
279 clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}}
Artem Dergacheve07896782018-03-12 23:22:35 +0000280}
281
282void f2() {
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000283 AddressVector v;
Artem Dergacheve07896782018-03-12 23:22:35 +0000284 {
285 const C &c = C::make(v);
286 }
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000287 // 0. Construct the return value of make() (copy/move elided) and
288 // lifetime-extend it directly via reference 'c',
289 // 1. Destroy the temporary lifetime-extended by 'c'.
290 clang_analyzer_eval(v.len == 2);
291 clang_analyzer_eval(v.buf[0] == v.buf[1]);
Artem Dergacheve07896782018-03-12 23:22:35 +0000292#ifdef TEMPORARIES
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000293 // expected-warning@-3{{TRUE}}
294 // expected-warning@-3{{TRUE}}
Artem Dergacheve07896782018-03-12 23:22:35 +0000295#else
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000296 // expected-warning@-6{{UNKNOWN}}
297 // expected-warning@-6{{UNKNOWN}}
Artem Dergacheve07896782018-03-12 23:22:35 +0000298#endif
299}
300
301void f3() {
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000302 AddressVector v;
Artem Dergacheve07896782018-03-12 23:22:35 +0000303 {
304 C &&c = C::make(v);
305 }
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000306 // 0. Construct the return value of make() (copy/move elided) and
307 // lifetime-extend it directly via reference 'c',
308 // 1. Destroy the temporary lifetime-extended by 'c'.
309 clang_analyzer_eval(v.len == 2);
310 clang_analyzer_eval(v.buf[0] == v.buf[1]);
Artem Dergacheve07896782018-03-12 23:22:35 +0000311#ifdef TEMPORARIES
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000312 // expected-warning@-3{{TRUE}}
313 // expected-warning@-3{{TRUE}}
Artem Dergacheve07896782018-03-12 23:22:35 +0000314#else
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000315 // expected-warning@-6{{UNKNOWN}}
316 // expected-warning@-6{{UNKNOWN}}
Artem Dergacheve07896782018-03-12 23:22:35 +0000317#endif
318}
319
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000320C doubleMake(AddressVector &v) {
Artem Dergacheve07896782018-03-12 23:22:35 +0000321 return C::make(v);
322}
323
324void f4() {
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000325 AddressVector v;
Artem Dergacheve07896782018-03-12 23:22:35 +0000326 {
327 C c = doubleMake(v);
328 }
Artem Dergachev9a209ad2018-06-28 00:30:18 +0000329 // 0. Construct variable 'c' (all copies/moves elided),
330 // 1. Destroy variable 'c'.
331 clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}}
332 clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}}
Artem Dergacheve07896782018-03-12 23:22:35 +0000333}
334} // end namespace maintain_address_of_copies