// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\ // RUN: -analyzer-checker=debug.ExprInspection\ // RUN: -Wno-dangling -Wno-c++1z-extensions\ // RUN: -verify=expected,cpp14\ // RUN: -x c++ -std=c++14 %s // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\ // RUN: -analyzer-checker=debug.ExprInspection\ // RUN: -analyzer-config elide-constructors=false\ // RUN: -Wno-dangling -Wno-c++1z-extensions\ // RUN: -verify=expected,cpp14\ // RUN: -x c++ -std=c++14 %s // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core\ // RUN: -analyzer-checker=debug.ExprInspection\ // RUN: -Wno-dangling -verify=expected,cpp17\ // RUN: -x c++ -std=c++17 %s template void clang_analyzer_dump(T&&) {} template T create() { return T{}; } template T const& select(bool cond, T const& t, T const& u) { return cond ? t : u; } struct Composite { int x; int y; }; struct Derived : Composite { int z; }; template struct Array { T array[20]; T&& front() && { return static_cast(array[0]); } }; void whole_object() { int const& i = 10; // extends `int` clang_analyzer_dump(i); // expected-warning-re {{&lifetime_extended_object{int, i, S{{[0-9]+}}} }} Composite&& c = Composite{}; // extends `Composite` clang_analyzer_dump(c); // expected-warning-re {{&lifetime_extended_object{Composite, c, S{{[0-9]+}}} }} auto&& a = Array{}; // extends `Array` clang_analyzer_dump(a); // expected-warning-re {{&lifetime_extended_object{Array, a, S{{[0-9]+}}} }} Composite&& d = Derived{}; // extends `Derived` clang_analyzer_dump(d); // expected-warning-re {{&Base{lifetime_extended_object{Derived, d, S{{[0-9]+}}},Composite} }} } void member_access() { int&& x = Composite{}.x; // extends `Composite` clang_analyzer_dump(x); // expected-warning-re {{&lifetime_extended_object{Composite, x, S{{[0-9]+}}}.x }} int&& y = create().y; // extends `Composite` clang_analyzer_dump(y); // expected-warning-re {{&lifetime_extended_object{struct Composite, y, S{{[0-9]+}}}.y }} int&& d = Array{}.front(); // dangles `Array` clang_analyzer_dump(d); // expected-warning-re {{&Element{temp_object{Array, S{{[0-9]+}}}.array,0 S64b,int} }} } void array_subscript() { int&& i = Array{}.array[0]; // extends `Array` clang_analyzer_dump(i); // expected-warning-re {{&Element{lifetime_extended_object{Array, i, S{{[0-9]+}}}.array,0 S64b,int} }} auto&& c = Array{}.array[0]; // extends `Array` clang_analyzer_dump(c); // expected-warning-re {{&Element{lifetime_extended_object{Array, c, S{{[0-9]+}}}.array,0 S64b,struct Composite} }} auto&& x = Array{}.array[0].x; // extends `Array` clang_analyzer_dump(x); // expected-warning-re {{&Element{lifetime_extended_object{Array, x, S{{[0-9]+}}}.array,0 S64b,struct Composite}.x }} } void ternary(bool cond) { Composite cc; // Value category mismatch of the operands (lvalue and xvalue), ternary produces prvalue auto&& ternaryProducesPRvalue = cond ? Composite{}.x : cc.x; // extends prvalue of 'int', `Composite` in true branch is destroyed clang_analyzer_dump(ternaryProducesPRvalue); // expected-warning-re {{&lifetime_extended_object{int, ternaryProducesPRvalue, S{{[0-9]+}}} }} // Value category agrees (xvalues), lifetime extension is triggered auto&& branchesExtended = cond ? Composite{}.x : static_cast(cc).x; // extends `Composite` in true branch clang_analyzer_dump(branchesExtended); // expected-warning-re@-1 {{&lifetime_extended_object{Composite, branchesExtended, S{{[0-9]+}}}.x }} // expected-warning@-2 {{&cc.x }} // Object of different types in branches are lifetime extended auto&& extendingDifferentTypes = cond ? Composite{}.x : Array{}.array[0]; // extends `Composite` or `Array` clang_analyzer_dump(extendingDifferentTypes); // expected-warning-re@-1 {{&lifetime_extended_object{Composite, extendingDifferentTypes, S{{[0-9]+}}}.x }} // expected-warning-re@-2 {{&Element{lifetime_extended_object{Array, extendingDifferentTypes, S{{[0-9]+}}}.array,0 S64b,int} }} Composite const& variableAndExtended = cond ? static_cast(cc) : Array{}.array[0]; // extends `Array` in false branch clang_analyzer_dump(variableAndExtended); // expected-warning@-1 {{&cc }} // expected-warning-re@-2 {{&Element{lifetime_extended_object{Array, variableAndExtended, S{{[0-9]+}}}.array,0 S64b,struct Composite} }} int const& extendAndDangling = cond ? Array{}.array[0] : Array{}.front(); // extends `Array` only in true branch, false branch dangles clang_analyzer_dump(extendAndDangling); // expected-warning-re@-1 {{&Element{lifetime_extended_object{Array, extendAndDangling, S{{[0-9]+}}}.array,0 S64b,int} }} // expected-warning-re@-2 {{&Element{temp_object{Array, S{{[0-9]+}}}.array,0 S64b,int} }} } struct RefAggregate { int const& rx; Composite&& ry = Composite{}; }; void aggregateWithReferences() { RefAggregate multipleExtensions = {10, Composite{}}; // extends `int` and `Composite` clang_analyzer_dump(multipleExtensions.rx); // expected-warning-re {{&lifetime_extended_object{int, multipleExtensions, S{{[0-9]+}}} }} clang_analyzer_dump(multipleExtensions.ry); // expected-warning-re {{&lifetime_extended_object{Composite, multipleExtensions, S{{[0-9]+}}} }} RefAggregate danglingAndExtended{Array{}.front(), Composite{}}; // extends only `Composite`, `Array` dangles clang_analyzer_dump(danglingAndExtended.rx); // expected-warning-re {{&Element{temp_object{Array, S{{[0-9]+}}}.array,0 S64b,int} }} clang_analyzer_dump(danglingAndExtended.ry); // expected-warning-re {{&lifetime_extended_object{Composite, danglingAndExtended, S{{[0-9]+}}} }} int i = 10; RefAggregate varAndExtended{i, Composite{}}; // extends `Composite` clang_analyzer_dump(varAndExtended.rx); // expected-warning {{&i }} clang_analyzer_dump(varAndExtended.ry); // expected-warning-re {{&lifetime_extended_object{Composite, varAndExtended, S{{[0-9]+}}} }} auto const& viaReference = RefAggregate{10, Composite{}}; // extends `int`, `Composite`, and `RefAggregate` clang_analyzer_dump(viaReference); // expected-warning-re {{&lifetime_extended_object{RefAggregate, viaReference, S{{[0-9]+}}} }} clang_analyzer_dump(viaReference.rx); // expected-warning-re {{&lifetime_extended_object{int, viaReference, S{{[0-9]+}}} }} clang_analyzer_dump(viaReference.ry); // expected-warning-re {{&lifetime_extended_object{Composite, viaReference, S{{[0-9]+}}} }} // clang does not currently implement extending lifetime of object bound to reference members of aggregates, // that are created from default member initializer (see `warn_unsupported_lifetime_extension` from `-Wdangling`) RefAggregate defaultInitExtended{i}; // clang-bug does not extend `Composite` clang_analyzer_dump(defaultInitExtended.ry); // expected-warning {{Unknown }} } void lambda() { auto const& lambdaRef = [capture = create()] {}; clang_analyzer_dump(lambdaRef); // expected-warning-re {{lifetime_extended_object{class (lambda at {{[^)]+}}), lambdaRef, S{{[0-9]+}}} }} // The capture [&refCapture = create()] { ... } per [expr.prim.lambda.capture] p6 equivalent to: // auto& refCapture = create(); // Well-formed, deduces auto = Composite const, and performs lifetime extension // [&refCapture] { ... } // Where 'refCapture' has the same lifetime as the lambda itself. // However, compilers differ: Clang lifetime-extends from C++17, GCC rejects the code, and MSVC dangles // See also CWG2737 (https://cplusplus.github.io/CWG/issues/2737.html) auto const refExtendingCapture = [&refCapture = create()] { clang_analyzer_dump(refCapture); // cpp14-warning-re@-1 {{&temp_object{const struct Composite, S{{[0-9]+}}} }} // cpp17-warning-re@-2 {{&lifetime_extended_object{const struct Composite, refExtendingCapture, S{{[0-9]+}}} }} }; refExtendingCapture(); } void viaStructuredBinding() { auto&& [x, y] = Composite{}; // extends `Composite` and binds it to unnamed decomposed object clang_analyzer_dump(x); // expected-warning-re {{&lifetime_extended_object{Composite, D{{[0-9]+}}, S{{[0-9]+}}}.x }} clang_analyzer_dump(y); // expected-warning-re {{&lifetime_extended_object{Composite, D{{[0-9]+}}, S{{[0-9]+}}}.y }} auto&& [rx, ry] = RefAggregate{10, Composite{}}; // extends `int`, `Composite`, and `RefAggregate`, and binds them to unnamed decomposed object clang_analyzer_dump(rx); // expected-warning-re {{&lifetime_extended_object{int, D{{[0-9]+}}, S{{[0-9]+}}} }} clang_analyzer_dump(ry); // expected-warning-re {{&lifetime_extended_object{Composite, D{{[0-9]+}}, S{{[0-9]+}}} }} } void propagation(bool cond) { int const& le = Composite{}.x; // May return lifetime-extended region or dangling temporary auto&& oneDangling = select(cond, le, 10); // does not extend lifetime of arguments clang_analyzer_dump(oneDangling); // expected-warning-re@-1 {{&lifetime_extended_object{Composite, le, S{{[0-9]+}}}.x }} // expected-warning-re@-2 {{&temp_object{int, S{{[0-9]+}}} }} // Always dangles auto&& bothDangling = select(cond, 10, 20); // does not extend lifetime of arguments clang_analyzer_dump(bothDangling); // expected-warning-re@-1 {{&temp_object{int, S{{[0-9]+}}} }} // expected-warning-re@-2 {{&temp_object{int, S{{[0-9]+}}} }} }