1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++11 \
2 // RUN: -analyzer-config eagerly-assume=false -verify %s
3 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++17 \
4 // RUN: -analyzer-config eagerly-assume=false -verify %s
5 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++11 \
6 // RUN: -analyzer-config elide-constructors=false -DNO_ELIDE_FLAG \
7 // RUN: -analyzer-config eagerly-assume=false -verify=expected,no-elide %s
8 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++17 \
9 // RUN: -analyzer-config elide-constructors=false \
10 // RUN: -analyzer-config eagerly-assume=false -verify %s
12 // Copy elision always occurs in C++17, otherwise it's under
13 // an on-by-default flag.
14 #if __cplusplus >= 201703L
22 void clang_analyzer_eval(bool);
23 void clang_analyzer_dump(int);
25 namespace variable_functional_cast_crash
{
40 } // namespace variable_functional_cast_crash
43 namespace ctor_initializer
{
52 T(int w
): s(), w(w
) {}
61 // FIXME: Should be TRUE regardless of copy elision.
62 clang_analyzer_eval(t
.w
== 4);
64 // expected-warning@-2{{TRUE}}
66 // expected-warning@-4{{UNKNOWN}}
85 clang_analyzer_eval(b
.a
.x
== 0); // expected-warning{{TRUE}}
88 } // namespace ctor_initializer
91 namespace elision_on_ternary_op_branches
{
96 int getX() const { return x
; }
104 C2(int x
, int y
): x(x
), y(y
) {}
105 int getX() const { return x
; }
106 int getY() const { return y
; }
111 C1 c1
= coin
? C1(1) : C1(2);
113 clang_analyzer_eval(c1
.getX() == 1); // expected-warning{{TRUE}}
115 clang_analyzer_eval(c1
.getX() == 2); // expected-warning{{TRUE}}
117 C2 c2
= coin
? C2(3, 4) : C2(5, 6);
119 clang_analyzer_eval(c2
.getX() == 3); // expected-warning{{TRUE}}
120 clang_analyzer_eval(c2
.getY() == 4); // expected-warning{{TRUE}}
122 clang_analyzer_eval(c2
.getX() == 5); // expected-warning{{TRUE}}
123 clang_analyzer_eval(c2
.getY() == 6); // expected-warning{{TRUE}}
126 } // namespace elision_on_ternary_op_branches
129 namespace address_vector_tests
{
131 template <typename T
> struct AddressVector
{
135 AddressVector() : len(0) {}
143 class ClassWithoutDestructor
{
144 AddressVector
<ClassWithoutDestructor
> &v
;
147 ClassWithoutDestructor(AddressVector
<ClassWithoutDestructor
> &v
) : v(v
) {
151 ClassWithoutDestructor(ClassWithoutDestructor
&&c
) : v(c
.v
) { push(); }
152 ClassWithoutDestructor(const ClassWithoutDestructor
&c
) : v(c
.v
) { push(); }
154 void push() { v
.push(this); }
157 ClassWithoutDestructor
make1(AddressVector
<ClassWithoutDestructor
> &v
) {
158 return ClassWithoutDestructor(v
);
159 // no-elide-warning@-1 {{Address of stack memory associated with temporary \
160 object of type
'ClassWithoutDestructor' is still \
161 referred to by the stack variable
'v' upon returning to the caller
}}
163 ClassWithoutDestructor
make2(AddressVector
<ClassWithoutDestructor
> &v
) {
165 // no-elide-warning@-1 {{Address of stack memory associated with temporary \
166 object of type
'ClassWithoutDestructor' is still \
167 referred to by the stack variable
'v' upon returning to the caller
}}
169 ClassWithoutDestructor
make3(AddressVector
<ClassWithoutDestructor
> &v
) {
171 // no-elide-warning@-1 {{Address of stack memory associated with temporary \
172 object of type
'ClassWithoutDestructor' is still \
173 referred to by the stack variable
'v' upon returning to the caller
}}
176 void testMultipleReturns() {
177 AddressVector
<ClassWithoutDestructor
> v
;
178 ClassWithoutDestructor c
= make3(v
);
181 clang_analyzer_eval(v
.len
== 1); // expected-warning{{TRUE}}
182 clang_analyzer_eval(v
.buf
[0] == &c
); // expected-warning{{TRUE}}
184 clang_analyzer_eval(v
.len
== 5); // expected-warning{{TRUE}}
185 clang_analyzer_eval(v
.buf
[0] != v
.buf
[1]); // expected-warning{{TRUE}}
186 clang_analyzer_eval(v
.buf
[1] != v
.buf
[2]); // expected-warning{{TRUE}}
187 clang_analyzer_eval(v
.buf
[2] != v
.buf
[3]); // expected-warning{{TRUE}}
188 clang_analyzer_eval(v
.buf
[3] != v
.buf
[4]); // expected-warning{{TRUE}}
189 clang_analyzer_eval(v
.buf
[4] == &c
); // expected-warning{{TRUE}}
193 void consume(ClassWithoutDestructor c
) {
195 // expected-warning@-1 {{Address of stack memory associated with local \
196 variable
'c' is still referred to by the stack variable
'v' upon returning \
200 void testArgumentConstructorWithoutDestructor() {
201 AddressVector
<ClassWithoutDestructor
> v
;
206 clang_analyzer_eval(v
.len
== 2); // expected-warning{{TRUE}}
207 clang_analyzer_eval(v
.buf
[0] == v
.buf
[1]); // expected-warning{{TRUE}}
209 clang_analyzer_eval(v
.len
== 6); // expected-warning{{TRUE}}
210 clang_analyzer_eval(v
.buf
[0] != v
.buf
[1]); // expected-warning{{TRUE}}
211 clang_analyzer_eval(v
.buf
[1] != v
.buf
[2]); // expected-warning{{TRUE}}
212 clang_analyzer_eval(v
.buf
[2] != v
.buf
[3]); // expected-warning{{TRUE}}
213 clang_analyzer_eval(v
.buf
[3] != v
.buf
[4]); // expected-warning{{TRUE}}
214 // We forced a push() in consume(), let's see if the address here matches
215 // the address during construction.
216 clang_analyzer_eval(v
.buf
[4] == v
.buf
[5]); // expected-warning{{TRUE}}
220 class ClassWithDestructor
{
221 AddressVector
<ClassWithDestructor
> &v
;
224 ClassWithDestructor(AddressVector
<ClassWithDestructor
> &v
) : v(v
) {
228 ClassWithDestructor(ClassWithDestructor
&&c
) : v(c
.v
) { push(); }
229 ClassWithDestructor(const ClassWithDestructor
&c
) : v(c
.v
) { push(); }
231 ~ClassWithDestructor() { push(); }
233 void push() { v
.push(this); }
236 void testVariable() {
237 AddressVector
<ClassWithDestructor
> v
;
239 ClassWithDestructor c
= ClassWithDestructor(v
);
240 // Check if the last destructor is an automatic destructor.
241 // A temporary destructor would have fired by now.
243 clang_analyzer_eval(v
.len
== 1); // expected-warning{{TRUE}}
245 clang_analyzer_eval(v
.len
== 3); // expected-warning{{TRUE}}
249 // 0. Construct the variable.
250 // 1. Destroy the variable.
251 clang_analyzer_eval(v
.len
== 2); // expected-warning{{TRUE}}
252 clang_analyzer_eval(v
.buf
[0] == v
.buf
[1]); // expected-warning{{TRUE}}
254 // 0. Construct the temporary.
255 // 1. Construct the variable.
256 // 2. Destroy the temporary.
257 // 3. Destroy the variable.
258 clang_analyzer_eval(v
.len
== 4); // expected-warning{{TRUE}}
259 clang_analyzer_eval(v
.buf
[0] == v
.buf
[2]); // expected-warning{{TRUE}}
260 clang_analyzer_eval(v
.buf
[1] == v
.buf
[3]); // expected-warning{{TRUE}}
264 struct TestCtorInitializer
{
265 ClassWithDestructor c
;
266 TestCtorInitializer(AddressVector
<ClassWithDestructor
> &v
)
267 : c(ClassWithDestructor(v
)) {}
268 // no-elide-warning@-1 {{Address of stack memory associated with temporary \
269 object of type
'ClassWithDestructor' is still referred \
270 to by the stack variable
'v' upon returning to the caller
}}
273 void testCtorInitializer() {
274 AddressVector
<ClassWithDestructor
> v
;
276 TestCtorInitializer
t(v
);
277 // Check if the last destructor is an automatic destructor.
278 // A temporary destructor would have fired by now.
280 clang_analyzer_eval(v
.len
== 1); // expected-warning{{TRUE}}
282 clang_analyzer_eval(v
.len
== 3); // expected-warning{{TRUE}}
286 // 0. Construct the member variable.
287 // 1. Destroy the member variable.
288 clang_analyzer_eval(v
.len
== 2); // expected-warning{{TRUE}}
289 clang_analyzer_eval(v
.buf
[0] == v
.buf
[1]); // expected-warning{{TRUE}}
291 // 0. Construct the temporary.
292 // 1. Construct the member variable.
293 // 2. Destroy the temporary.
294 // 3. Destroy the member variable.
295 clang_analyzer_eval(v
.len
== 4); // expected-warning{{TRUE}}
296 clang_analyzer_eval(v
.buf
[0] == v
.buf
[2]); // expected-warning{{TRUE}}
297 clang_analyzer_eval(v
.buf
[1] == v
.buf
[3]); // expected-warning{{TRUE}}
302 ClassWithDestructor
make1(AddressVector
<ClassWithDestructor
> &v
) {
303 return ClassWithDestructor(v
);
304 // no-elide-warning@-1 {{Address of stack memory associated with temporary \
305 object of type
'ClassWithDestructor' is still referred \
306 to by the stack variable
'v' upon returning to the caller
}}
308 ClassWithDestructor
make2(AddressVector
<ClassWithDestructor
> &v
) {
310 // no-elide-warning@-1 {{Address of stack memory associated with temporary \
311 object of type
'ClassWithDestructor' is still referred \
312 to by the stack variable
'v' upon returning to the caller
}}
314 ClassWithDestructor
make3(AddressVector
<ClassWithDestructor
> &v
) {
316 // no-elide-warning@-1 {{Address of stack memory associated with temporary \
317 object of type
'ClassWithDestructor' is still referred \
318 to by the stack variable
'v' upon returning to the caller
}}
321 void testMultipleReturnsWithDestructors() {
322 AddressVector
<ClassWithDestructor
> v
;
324 ClassWithDestructor c
= make3(v
);
325 // Check if the last destructor is an automatic destructor.
326 // A temporary destructor would have fired by now.
328 clang_analyzer_eval(v
.len
== 1); // expected-warning{{TRUE}}
330 clang_analyzer_eval(v
.len
== 9); // expected-warning{{TRUE}}
335 // 0. Construct the variable. Yes, constructor in make1() constructs
337 // 1. Destroy the variable.
338 clang_analyzer_eval(v
.len
== 2); // expected-warning{{TRUE}}
339 clang_analyzer_eval(v
.buf
[0] == v
.buf
[1]); // expected-warning{{TRUE}}
341 // 0. Construct the temporary in make1().
342 // 1. Construct the temporary in make2().
343 // 2. Destroy the temporary in make1().
344 // 3. Construct the temporary in make3().
345 // 4. Destroy the temporary in make2().
346 // 5. Construct the temporary here.
347 // 6. Destroy the temporary in make3().
348 // 7. Construct the variable.
349 // 8. Destroy the temporary here.
350 // 9. Destroy the variable.
351 clang_analyzer_eval(v
.len
== 10); // expected-warning{{TRUE}}
352 clang_analyzer_eval(v
.buf
[0] == v
.buf
[2]); // expected-warning{{TRUE}}
353 clang_analyzer_eval(v
.buf
[1] == v
.buf
[4]); // expected-warning{{TRUE}}
354 clang_analyzer_eval(v
.buf
[3] == v
.buf
[6]); // expected-warning{{TRUE}}
355 clang_analyzer_eval(v
.buf
[5] == v
.buf
[8]); // expected-warning{{TRUE}}
356 clang_analyzer_eval(v
.buf
[7] == v
.buf
[9]); // expected-warning{{TRUE}}
360 void consume(ClassWithDestructor c
) {
362 // expected-warning@-1 {{Address of stack memory associated with local \
363 variable
'c' is still referred to by the stack variable
'v' upon returning \
367 void testArgumentConstructorWithDestructor() {
368 AddressVector
<ClassWithDestructor
> v
;
373 // 0. Construct the argument.
374 // 1. Forced push() in consume().
375 // 2. Destroy the argument.
376 clang_analyzer_eval(v
.len
== 3); // expected-warning{{TRUE}}
377 clang_analyzer_eval(v
.buf
[0] == v
.buf
[1]); // expected-warning{{TRUE}}
378 clang_analyzer_eval(v
.buf
[1] == v
.buf
[2]); // expected-warning{{TRUE}}
380 // 0. Construct the temporary in make1().
381 // 1. Construct the temporary in make2().
382 // 2. Destroy the temporary in make1().
383 // 3. Construct the temporary in make3().
384 // 4. Destroy the temporary in make2().
385 // 5. Construct the temporary here.
386 // 6. Destroy the temporary in make3().
387 // 7. Construct the argument.
388 // 8. Forced push() in consume().
389 // 9. Destroy the argument. Notice the reverse order!
390 // 10. Destroy the temporary here.
391 clang_analyzer_eval(v
.len
== 11); // expected-warning{{TRUE}}
392 clang_analyzer_eval(v
.buf
[0] == v
.buf
[2]); // expected-warning{{TRUE}}
393 clang_analyzer_eval(v
.buf
[1] == v
.buf
[4]); // expected-warning{{TRUE}}
394 clang_analyzer_eval(v
.buf
[3] == v
.buf
[6]); // expected-warning{{TRUE}}
395 clang_analyzer_eval(v
.buf
[5] == v
.buf
[10]); // expected-warning{{TRUE}}
396 clang_analyzer_eval(v
.buf
[7] == v
.buf
[8]); // expected-warning{{TRUE}}
397 clang_analyzer_eval(v
.buf
[8] == v
.buf
[9]); // expected-warning{{TRUE}}
409 // no-elide-warning@-1 {{Address of stack memory associated with temporary \
410 object of type
'Foo' is still referred to by the stack \
411 variable
'z' upon returning to the caller
}}
414 void test_copy_elision() {
416 // If the copy elided, 'z' points to 'tmp', otherwise it's a dangling pointer.
421 } // namespace address_vector_tests
423 namespace arg_directly_from_return_in_loop
{
433 int accessValue(Result r
) {
438 for (int i
= 0; i
< 3; ++i
) {
439 int v
= accessValue(create());
441 clang_analyzer_dump(v
); // expected-warning {{10 S32b}}
443 clang_analyzer_dump(v
); // expected-warning {{10 S32b}}
444 // was {{reg_${{[0-9]+}}<int r.value> }} for C++11
449 } // namespace arg_directly_from_return_in_loop