Index: lib/StaticAnalyzer/Core/ExprEngineCXX.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -216,12 +216,6 @@ const CXXBindTemporaryExpr *BTE = TCC->getCXXBindTemporaryExpr(); const MaterializeTemporaryExpr *MTE = TCC->getMaterializedTemporaryExpr(); - if (!BTE) { - // FIXME: Lifetime extension for temporaries without destructors - // is not implemented yet. - MTE = nullptr; - } - if (MTE) { if (const ValueDecl *VD = MTE->getExtendingDecl()) { assert(MTE->getStorageDuration() != SD_FullExpression); @@ -236,16 +230,22 @@ } } - if (MTE && MTE->getStorageDuration() != SD_FullExpression) { - // If the temporary is lifetime-extended, don't save the BTE, - // because we don't need a temporary destructor, but an automatic - // destructor. - BTE = nullptr; + SVal V = UnknownVal(); + if (MTE) { + if (MTE->getStorageDuration() != SD_FullExpression) { + // If the temporary is lifetime-extended, don't save the BTE, + // because we don't need a temporary destructor, but an automatic + // destructor. + BTE = nullptr; + + if (MTE->getStorageDuration() == SD_Static || + MTE->getStorageDuration() == SD_Thread) + V = loc::MemRegionVal(MRMgr.getCXXStaticTempObjectRegion(E)); + } } - // FIXME: Support temporaries lifetime-extended via static references. - // They'd need a getCXXStaticTempObjectRegion(). - SVal V = loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(E, LCtx)); + if (V.isUnknown()) + V = loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(E, LCtx)); if (BTE) State = addObjectUnderConstruction(State, BTE, LCtx, V); Index: test/Analysis/lifetime-extension.cpp =================================================================== --- test/Analysis/lifetime-extension.cpp +++ test/Analysis/lifetime-extension.cpp @@ -234,25 +234,24 @@ } // end namespace maintain_original_object_address_on_move namespace maintain_address_of_copies { -class C; -struct AddressVector { - C *buf[10]; +template struct AddressVector { + const T *buf[10]; int len; AddressVector() : len(0) {} - void push(C *c) { - buf[len] = c; + void push(const T *t) { + buf[len] = t; ++len; } }; class C { - AddressVector &v; + AddressVector &v; public: - C(AddressVector &v) : v(v) { v.push(this); } + C(AddressVector &v) : v(v) { v.push(this); } ~C() { v.push(this); } #ifdef MOVES @@ -268,11 +267,11 @@ #endif } // no-warning - static C make(AddressVector &v) { return C(v); } + static C make(AddressVector &v) { return C(v); } }; void f1() { - AddressVector v; + AddressVector v; { C c = C(v); } @@ -296,7 +295,7 @@ } void f2() { - AddressVector v; + AddressVector v; { const C &c = C::make(v); } @@ -320,7 +319,7 @@ } void f3() { - AddressVector v; + AddressVector v; { C &&c = C::make(v); } @@ -343,12 +342,12 @@ #endif } -C doubleMake(AddressVector &v) { +C doubleMake(AddressVector &v) { return C::make(v); } void f4() { - AddressVector v; + AddressVector v; { C c = doubleMake(v); } @@ -382,4 +381,18 @@ // expected-warning@-12{{UNKNOWN}} #endif } + +class NoDtor { + AddressVector &v; + +public: + NoDtor(AddressVector &v) : v(v) { v.push(this); } +}; + +void f5() { + AddressVector v; + const NoDtor &N = NoDtor(v); + clang_analyzer_eval(v.buf[0] == &N); // expected-warning{{TRUE}} +} + } // end namespace maintain_address_of_copies Index: test/Analysis/temporaries-callback-order.cpp =================================================================== --- test/Analysis/temporaries-callback-order.cpp +++ test/Analysis/temporaries-callback-order.cpp @@ -8,11 +8,7 @@ }; void testTemporaries() { - // This triggers RegionChanges twice: - // - Once for zero-initialization of the structure. - // - Once for creating a temporary region and copying the structure there. - // FIXME: This code shouldn't really produce the extra temporary, however - // that's how we behave for now. + // This triggers RegionChanges once for zero-initialization of the structure. Sub().m(); } @@ -29,7 +25,6 @@ // testTemporaries(): // CHECK-NEXT: RegionChanges -// CHECK-NEXT: RegionChanges // Make sure there's no further output. // CHECK-NOT: Bind