1 // 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
8 // Note: The C++17 run-lines don't -verify yet - it is a no-crash test.
10 void clang_analyzer_eval(bool);
11 void clang_analyzer_checkInlined(bool);
13 namespace pr17001_call_wrong_destructor
{
29 clang_analyzer_eval(x
); // expected-warning{{TRUE}}
31 } // end namespace pr17001_call_wrong_destructor
33 namespace pr19539_crash_on_destroying_an_integer
{
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
49 clang_analyzer_eval(x
== 1);
50 clang_analyzer_eval(y
== 3);
51 clang_analyzer_eval(z
== 2);
53 // expected-warning@-4{{TRUE}}
54 // expected-warning@-4{{TRUE}}
55 // expected-warning@-4{{TRUE}}
57 // expected-warning@-8{{UNKNOWN}}
58 // expected-warning@-8{{UNKNOWN}}
59 // expected-warning@-8{{UNKNOWN}}
62 } // end namespace pr19539_crash_on_destroying_an_integer
64 namespace maintain_original_object_address_on_lifetime_extension
{
71 C(bool x
, C
**after
, C
**before
) : x(x
), after(after
), before(before
) {
75 // Don't track copies in our tests.
76 C(const C
&c
) : x(c
.x
), after(nullptr), before(nullptr) {}
78 ~C() { if (after
) *after
= this; }
80 operator bool() const { return x
; }
82 static C
make(C
**after
, C
**before
) { return C(false, after
, before
); }
88 const C
&c
= C(true, &after
, &before
);
90 clang_analyzer_eval(after
== before
);
92 // expected-warning@-2{{TRUE}}
94 // expected-warning@-4{{UNKNOWN}}
101 C c
= C(1, &after
, &before
);
103 clang_analyzer_eval(after
== before
); // expected-warning{{TRUE}}
109 const C
&c
= coin
? C(true, &after
, &before
) : C(false, &after
, &before
);
111 clang_analyzer_eval(after
== before
);
113 // expected-warning@-2{{TRUE}}
115 // expected-warning@-4{{UNKNOWN}}
123 const C
&c
= C(coin
, &after
, &before
) ?: C(false, &after
, &before
);
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.
129 // FIXME: Should not warn.
130 clang_analyzer_eval(after
== before
);
132 // expected-warning@-2{{The left operand of '==' is a garbage value}}
134 // expected-warning@-4{{UNKNOWN}}
137 // FIXME: Should be TRUE.
138 clang_analyzer_eval(after
== before
);
140 // expected-warning@-2{{FALSE}}
142 // expected-warning@-4{{UNKNOWN}}
150 const bool &x
= C(true, &after
, &before
).x
; // no-crash
152 clang_analyzer_eval(after
== before
);
154 // expected-warning@-2{{TRUE}}
156 // expected-warning@-4{{UNKNOWN}}
160 struct A
{ // A is an aggregate.
167 A a
{C(true, &after
, &before
)};
169 // FIXME: Should be TRUE. Should not warn about garbage value.
170 clang_analyzer_eval(after
== before
); // expected-warning{{UNKNOWN}}
176 A a
= {C(true, &after
, &before
)};
178 // FIXME: Should be TRUE. Should not warn about garbage value.
179 clang_analyzer_eval(after
== before
); // expected-warning{{UNKNOWN}}
185 A a
[2] = {C(false, nullptr, nullptr), C(true, &after
, &before
)};
187 // FIXME: Should be TRUE. Should not warn about garbage value.
188 clang_analyzer_eval(after
== before
); // expected-warning{{UNKNOWN}}
190 } // end namespace maintain_original_object_address_on_lifetime_extension
192 namespace maintain_original_object_address_on_move
{
199 C(const C
&c
) = delete;
200 C(C
&&c
) : x(c
.x
) { c
.x
= nullptr; }
201 C
&operator=(C
&&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.
218 // &x is replaced with nullptr in move-constructor before the temporary dies.
220 // Hence x was not set to 0 yet.
226 // &x is replaced with nullptr in move-assignment before the temporary dies.
228 // Hence x was not set to 0 yet.
231 } // end namespace maintain_original_object_address_on_move
233 namespace maintain_address_of_copies
{
236 struct AddressVector
{
240 AddressVector() : len(0) {}
252 C(AddressVector
&v
) : v(v
) { v
.push(this); }
253 ~C() { v
.push(this); }
256 C(C
&&c
) : v(c
.v
) { v
.push(this); }
259 // Note how return-statements prefer move-constructors when available.
260 C(const C
&c
) : v(c
.v
) {
262 clang_analyzer_checkInlined(false); // no-warning
268 static C
make(AddressVector
&v
) { return C(v
); }
276 // 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}}
285 const C
&c
= C::make(v
);
287 // 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]);
293 // expected-warning@-3{{TRUE}}
294 // expected-warning@-3{{TRUE}}
296 // expected-warning@-6{{UNKNOWN}}
297 // expected-warning@-6{{UNKNOWN}}
306 // 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]);
312 // expected-warning@-3{{TRUE}}
313 // expected-warning@-3{{TRUE}}
315 // expected-warning@-6{{UNKNOWN}}
316 // expected-warning@-6{{UNKNOWN}}
320 C
doubleMake(AddressVector
&v
) {
329 // 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}}
334 } // end namespace maintain_address_of_copies