1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\
2 // RUN: -analyzer-checker=debug.ExprInspection\
3 // RUN: -Wno-dangling -Wno-c++1z-extensions\
4 // RUN: -verify=expected,cpp14\
5 // RUN: -x c++ -std=c++14 %s
6 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\
7 // RUN: -analyzer-checker=debug.ExprInspection\
8 // RUN: -analyzer-config elide-constructors=false\
9 // RUN: -Wno-dangling -Wno-c++1z-extensions\
10 // RUN: -verify=expected,cpp14\
11 // RUN: -x c++ -std=c++14 %s
12 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\
13 // RUN: -analyzer-checker=debug.ExprInspection\
14 // RUN: -Wno-dangling -verify=expected,cpp17\
15 // RUN: -x c++ -std=c++17 %s
18 void clang_analyzer_dump(T
&&) {}
21 T
create() { return T
{}; }
24 T
const& select(bool cond
, T
const& t
, T
const& u
) { return cond
? t
: u
; }
31 struct Derived
: Composite
{
39 T
&& front() && { return static_cast<T
&&>(array
[0]); }
43 int const& i
= 10; // extends `int`
44 clang_analyzer_dump(i
); // expected-warning-re {{&lifetime_extended_object{int, i, S{{[0-9]+}}} }}
45 Composite
&& c
= Composite
{}; // extends `Composite`
46 clang_analyzer_dump(c
); // expected-warning-re {{&lifetime_extended_object{Composite, c, S{{[0-9]+}}} }}
47 auto&& a
= Array
<int>{}; // extends `Array<int>`
48 clang_analyzer_dump(a
); // expected-warning-re {{&lifetime_extended_object{Array<int>, a, S{{[0-9]+}}} }}
49 Composite
&& d
= Derived
{}; // extends `Derived`
50 clang_analyzer_dump(d
); // expected-warning-re {{&Base{lifetime_extended_object{Derived, d, S{{[0-9]+}}},Composite} }}
53 void member_access() {
54 int&& x
= Composite
{}.x
; // extends `Composite`
55 clang_analyzer_dump(x
); // expected-warning-re {{&lifetime_extended_object{Composite, x, S{{[0-9]+}}}.x }}
56 int&& y
= create
<Composite
>().y
; // extends `Composite`
57 clang_analyzer_dump(y
); // expected-warning-re {{&lifetime_extended_object{struct Composite, y, S{{[0-9]+}}}.y }}
58 int&& d
= Array
<int>{}.front(); // dangles `Array<int>`
59 clang_analyzer_dump(d
); // expected-warning-re {{&Element{temp_object{Array<int>, S{{[0-9]+}}}.array,0 S64b,int} }}
62 void array_subscript() {
63 int&& i
= Array
<int>{}.array
[0]; // extends `Array<int>`
64 clang_analyzer_dump(i
); // expected-warning-re {{&Element{lifetime_extended_object{Array<int>, i, S{{[0-9]+}}}.array,0 S64b,int} }}
65 auto&& c
= Array
<Composite
>{}.array
[0]; // extends `Array<int>`
66 clang_analyzer_dump(c
); // expected-warning-re {{&Element{lifetime_extended_object{Array<Composite>, c, S{{[0-9]+}}}.array,0 S64b,struct Composite} }}
67 auto&& x
= Array
<Composite
>{}.array
[0].x
; // extends `Array<Composite>`
68 clang_analyzer_dump(x
); // expected-warning-re {{&Element{lifetime_extended_object{Array<Composite>, x, S{{[0-9]+}}}.array,0 S64b,struct Composite}.x }}
71 void ternary(bool cond
) {
73 // Value category mismatch of the operands (lvalue and xvalue), ternary produces prvalue
74 auto&& ternaryProducesPRvalue
= cond
? Composite
{}.x
: cc
.x
; // extends prvalue of 'int', `Composite` in true branch is destroyed
75 clang_analyzer_dump(ternaryProducesPRvalue
); // expected-warning-re {{&lifetime_extended_object{int, ternaryProducesPRvalue, S{{[0-9]+}}} }}
77 // Value category agrees (xvalues), lifetime extension is triggered
78 auto&& branchesExtended
= cond
? Composite
{}.x
: static_cast<Composite
&&>(cc
).x
; // extends `Composite` in true branch
79 clang_analyzer_dump(branchesExtended
);
80 // expected-warning-re@-1 {{&lifetime_extended_object{Composite, branchesExtended, S{{[0-9]+}}}.x }}
81 // expected-warning@-2 {{&cc.x }}
83 // Object of different types in branches are lifetime extended
84 auto&& extendingDifferentTypes
= cond
? Composite
{}.x
: Array
<int>{}.array
[0]; // extends `Composite` or `Array<int>`
85 clang_analyzer_dump(extendingDifferentTypes
);
86 // expected-warning-re@-1 {{&lifetime_extended_object{Composite, extendingDifferentTypes, S{{[0-9]+}}}.x }}
87 // expected-warning-re@-2 {{&Element{lifetime_extended_object{Array<int>, extendingDifferentTypes, S{{[0-9]+}}}.array,0 S64b,int} }}
89 Composite
const& variableAndExtended
= cond
? static_cast<Composite
&&>(cc
) : Array
<Composite
>{}.array
[0]; // extends `Array<Composite>` in false branch
90 clang_analyzer_dump(variableAndExtended
);
91 // expected-warning@-1 {{&cc }}
92 // expected-warning-re@-2 {{&Element{lifetime_extended_object{Array<Composite>, variableAndExtended, S{{[0-9]+}}}.array,0 S64b,struct Composite} }}
94 int const& extendAndDangling
= cond
? Array
<int>{}.array
[0] : Array
<int>{}.front(); // extends `Array<int>` only in true branch, false branch dangles
95 clang_analyzer_dump(extendAndDangling
);
96 // expected-warning-re@-1 {{&Element{lifetime_extended_object{Array<int>, extendAndDangling, S{{[0-9]+}}}.array,0 S64b,int} }}
97 // expected-warning-re@-2 {{&Element{temp_object{Array<int>, S{{[0-9]+}}}.array,0 S64b,int} }}
100 struct RefAggregate
{
102 Composite
&& ry
= Composite
{};
105 void aggregateWithReferences() {
106 RefAggregate multipleExtensions
= {10, Composite
{}}; // extends `int` and `Composite`
107 clang_analyzer_dump(multipleExtensions
.rx
); // expected-warning-re {{&lifetime_extended_object{int, multipleExtensions, S{{[0-9]+}}} }}
108 clang_analyzer_dump(multipleExtensions
.ry
); // expected-warning-re {{&lifetime_extended_object{Composite, multipleExtensions, S{{[0-9]+}}} }}
110 RefAggregate danglingAndExtended
{Array
<int>{}.front(), Composite
{}}; // extends only `Composite`, `Array<int>` dangles
111 clang_analyzer_dump(danglingAndExtended
.rx
); // expected-warning-re {{&Element{temp_object{Array<int>, S{{[0-9]+}}}.array,0 S64b,int} }}
112 clang_analyzer_dump(danglingAndExtended
.ry
); // expected-warning-re {{&lifetime_extended_object{Composite, danglingAndExtended, S{{[0-9]+}}} }}
115 RefAggregate varAndExtended
{i
, Composite
{}}; // extends `Composite`
116 clang_analyzer_dump(varAndExtended
.rx
); // expected-warning {{&i }}
117 clang_analyzer_dump(varAndExtended
.ry
); // expected-warning-re {{&lifetime_extended_object{Composite, varAndExtended, S{{[0-9]+}}} }}
119 auto const& viaReference
= RefAggregate
{10, Composite
{}}; // extends `int`, `Composite`, and `RefAggregate`
120 clang_analyzer_dump(viaReference
); // expected-warning-re {{&lifetime_extended_object{RefAggregate, viaReference, S{{[0-9]+}}} }}
121 clang_analyzer_dump(viaReference
.rx
); // expected-warning-re {{&lifetime_extended_object{int, viaReference, S{{[0-9]+}}} }}
122 clang_analyzer_dump(viaReference
.ry
); // expected-warning-re {{&lifetime_extended_object{Composite, viaReference, S{{[0-9]+}}} }}
124 // FIXME: clang currently support extending lifetime of object bound to reference members of aggregates,
125 // that are created from default member initializer. But CFG and ExprEngine need to be updated to address this change.
126 // The following expect warning: {{&lifetime_extended_object{Composite, defaultInitExtended, S{{[0-9]+}}} }}
127 RefAggregate defaultInitExtended
{i
};
128 clang_analyzer_dump(defaultInitExtended
.ry
); // expected-warning {{Unknown }}
132 auto const& lambdaRef
= [capture
= create
<Composite
>()] {};
133 clang_analyzer_dump(lambdaRef
); // expected-warning-re {{lifetime_extended_object{class (lambda at {{[^)]+}}), lambdaRef, S{{[0-9]+}}} }}
135 // The capture [&refCapture = create<Composite const>()] { ... } per [expr.prim.lambda.capture] p6 equivalent to:
136 // auto& refCapture = create<Composite const>(); // Well-formed, deduces auto = Composite const, and performs lifetime extension
137 // [&refCapture] { ... }
138 // Where 'refCapture' has the same lifetime as the lambda itself.
139 // However, compilers differ: Clang lifetime-extends from C++17, GCC rejects the code, and MSVC dangles
140 // See also CWG2737 (https://cplusplus.github.io/CWG/issues/2737.html)
141 auto const refExtendingCapture
= [&refCapture
= create
<Composite
const>()] {
142 clang_analyzer_dump(refCapture
);
143 // cpp14-warning-re@-1 {{&temp_object{const struct Composite, S{{[0-9]+}}} }}
144 // cpp17-warning-re@-2 {{&lifetime_extended_object{const struct Composite, refExtendingCapture, S{{[0-9]+}}} }}
146 refExtendingCapture();
149 void viaStructuredBinding() {
150 auto&& [x
, y
] = Composite
{}; // extends `Composite` and binds it to unnamed decomposed object
151 clang_analyzer_dump(x
); // expected-warning-re {{&lifetime_extended_object{Composite, D{{[0-9]+}}, S{{[0-9]+}}}.x }}
152 clang_analyzer_dump(y
); // expected-warning-re {{&lifetime_extended_object{Composite, D{{[0-9]+}}, S{{[0-9]+}}}.y }}
154 auto&& [rx
, ry
] = RefAggregate
{10, Composite
{}}; // extends `int`, `Composite`, and `RefAggregate`, and binds them to unnamed decomposed object
155 clang_analyzer_dump(rx
); // expected-warning-re {{&lifetime_extended_object{int, D{{[0-9]+}}, S{{[0-9]+}}} }}
156 clang_analyzer_dump(ry
); // expected-warning-re {{&lifetime_extended_object{Composite, D{{[0-9]+}}, S{{[0-9]+}}} }}
159 void propagation(bool cond
) {
160 int const& le
= Composite
{}.x
;
161 // May return lifetime-extended region or dangling temporary
162 auto&& oneDangling
= select(cond
, le
, 10); // does not extend lifetime of arguments
163 clang_analyzer_dump(oneDangling
);
164 // expected-warning-re@-1 {{&lifetime_extended_object{Composite, le, S{{[0-9]+}}}.x }}
165 // expected-warning-re@-2 {{&temp_object{int, S{{[0-9]+}}} }}
168 auto&& bothDangling
= select(cond
, 10, 20); // does not extend lifetime of arguments
169 clang_analyzer_dump(bothDangling
);
170 // expected-warning-re@-1 {{&temp_object{int, S{{[0-9]+}}} }}
171 // expected-warning-re@-2 {{&temp_object{int, S{{[0-9]+}}} }}