Index: lib/StaticAnalyzer/Core/ExprEngineCXX.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -119,8 +119,9 @@ // current construction context. if (CC) { switch (CC->getKind()) { + case ConstructionContext::CXX17ElidedCopyVariableKind: case ConstructionContext::SimpleVariableKind: { - const auto *DSCC = cast(CC); + const auto *DSCC = cast(CC); const auto *DS = DSCC->getDeclStmt(); const auto *Var = cast(DS->getSingleDecl()); SVal LValue = State->getLValue(Var, LCtx); @@ -131,6 +132,7 @@ addObjectUnderConstruction(State, DSCC->getDeclStmt(), LCtx, LValue); return std::make_pair(State, LValue); } + case ConstructionContext::CXX17ElidedCopyConstructorInitializerKind: case ConstructionContext::SimpleConstructorInitializerKind: { const auto *ICC = cast(CC); const auto *Init = ICC->getCXXCtorInitializer(); @@ -259,9 +261,7 @@ CallOpts.IsTemporaryCtorOrDtor = true; return std::make_pair(State, V); } - case ConstructionContext::CXX17ElidedCopyVariableKind: case ConstructionContext::CXX17ElidedCopyReturnedValueKind: - case ConstructionContext::CXX17ElidedCopyConstructorInitializerKind: // Not implemented yet. break; } Index: test/Analysis/cxx17-mandatory-elision.cpp =================================================================== --- test/Analysis/cxx17-mandatory-elision.cpp +++ test/Analysis/cxx17-mandatory-elision.cpp @@ -49,9 +49,64 @@ } }; + +struct A { + int x; + A(): x(0) {} + ~A() {} +}; + +struct B { + A a; + B() : a(A()) {} +}; + +void foo() { + B b; + clang_analyzer_eval(b.a.x == 0); // expected-warning{{TRUE}} +} + } // namespace ctor_initializer +namespace elision_on_ternary_op_branches { +class C1 { + int x; +public: + C1(int x): x(x) {} + int getX() const { return x; } + ~C1(); +}; + +class C2 { + int x; + int y; +public: + C2(int x, int y): x(x), y(y) {} + int getX() const { return x; } + int getY() const { return y; } + ~C2(); +}; + +void foo(int coin) { + C1 c1 = coin ? C1(1) : C1(2); + if (coin) { + clang_analyzer_eval(c1.getX() == 1); // expected-warning{{TRUE}} + } else { + clang_analyzer_eval(c1.getX() == 2); // expected-warning{{TRUE}} + } + C2 c2 = coin ? C2(3, 4) : C2(5, 6); + if (coin) { + clang_analyzer_eval(c2.getX() == 3); // expected-warning{{TRUE}} + clang_analyzer_eval(c2.getY() == 4); // expected-warning{{TRUE}} + } else { + clang_analyzer_eval(c2.getX() == 5); // expected-warning{{TRUE}} + clang_analyzer_eval(c2.getY() == 6); // expected-warning{{TRUE}} + } +} +} // namespace elision_on_ternary_op_branches + + namespace address_vector_tests { template struct AddressVector { @@ -108,4 +163,68 @@ #endif } +class ClassWithDestructor { + AddressVector &v; + +public: + ClassWithDestructor(AddressVector &v) : v(v) { + v.push(this); + } + + ClassWithDestructor(ClassWithDestructor &&c) : v(c.v) { v.push(this); } + ClassWithDestructor(const ClassWithDestructor &c) : v(c.v) { + v.push(this); + } + + ~ClassWithDestructor() { v.push(this); } +}; + +void testVariable() { + AddressVector v; + { + ClassWithDestructor c = ClassWithDestructor(v); + } +#if __cplusplus >= 201703L + // 0. Construct the variable. + // 1. Destroy the variable. + clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}} + clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}} +#else + // 0. Construct the temporary. + // 1. Construct the variable. + // 2. Destroy the temporary. + // 3. Destroy the variable. + clang_analyzer_eval(v.len == 4); // expected-warning{{TRUE}} + clang_analyzer_eval(v.buf[0] == v.buf[2]); // expected-warning{{TRUE}} + clang_analyzer_eval(v.buf[1] == v.buf[3]); // expected-warning{{TRUE}} +#endif +} + +struct TestCtorInitializer { + ClassWithDestructor c; + TestCtorInitializer(AddressVector &v) + : c(ClassWithDestructor(v)) {} +}; + +void testCtorInitializer() { + AddressVector v; + { + TestCtorInitializer t(v); + } +#if __cplusplus >= 201703L + // 0. Construct the member variable. + // 1. Destroy the member variable. + clang_analyzer_eval(v.len == 2); // expected-warning{{TRUE}} + clang_analyzer_eval(v.buf[0] == v.buf[1]); // expected-warning{{TRUE}} +#else + // 0. Construct the temporary. + // 1. Construct the member variable. + // 2. Destroy the temporary. + // 3. Destroy the member variable. + clang_analyzer_eval(v.len == 4); // expected-warning{{TRUE}} + clang_analyzer_eval(v.buf[0] == v.buf[2]); // expected-warning{{TRUE}} + clang_analyzer_eval(v.buf[1] == v.buf[3]); // expected-warning{{TRUE}} +#endif +} + } // namespace address_vector_tests