Index: include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h =================================================================== --- include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -106,11 +106,6 @@ bool IsTemporaryCtorOrDtor = false; /// This call is a constructor for a temporary that is lifetime-extended - /// by binding a smaller object within it to a reference, for example - /// 'const int &x = C().x;'. - bool IsTemporaryLifetimeExtendedViaSubobject = false; - - /// This call is a constructor for a temporary that is lifetime-extended /// by binding it to a reference-type field within an aggregate, /// for example 'A { const C &c; }; A a = { C() };' bool IsTemporaryLifetimeExtendedViaAggregate = false; Index: lib/StaticAnalyzer/Core/ExprEngineCXX.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -181,22 +181,13 @@ const auto *TOCC = cast(CC); if (const auto *MTE = TOCC->getMaterializedTemporaryExpr()) { if (const ValueDecl *VD = MTE->getExtendingDecl()) { - // Pattern-match various forms of lifetime extension that aren't - // currently supported by the CFG. - // FIXME: Is there a better way to retrieve this information from - // the MaterializeTemporaryExpr? assert(MTE->getStorageDuration() != SD_FullExpression); - if (VD->getType()->isReferenceType()) { - assert(VD->getType()->isReferenceType()); - if (VD->getType()->getPointeeType().getCanonicalType() != - MTE->GetTemporaryExpr()->getType().getCanonicalType()) { - // We're lifetime-extended via our field. Automatic destructors - // aren't quite working in this case. - CallOpts.IsTemporaryLifetimeExtendedViaSubobject = true; - } - } else { + if (!VD->getType()->isReferenceType()) { // We're lifetime-extended by a surrounding aggregate. - // Automatic destructors aren't quite working in this case. + // Automatic destructors aren't quite working in this case + // on the CFG side. We should warn the caller about that. + // FIXME: Is there a better way to retrieve this information from + // the MaterializeTemporaryExpr? CallOpts.IsTemporaryLifetimeExtendedViaAggregate = true; } } Index: lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -696,12 +696,7 @@ if (CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion) return CIP_DisallowedOnce; - // If the temporary is lifetime-extended by binding a smaller object - // within it to a reference, automatic destructors don't work properly. - if (CallOpts.IsTemporaryLifetimeExtendedViaSubobject) - return CIP_DisallowedOnce; - - // If the temporary is lifetime-extended by binding it to a reference-typ + // If the temporary is lifetime-extended by binding it to a reference-type // field within an aggregate, automatic destructors don't work properly. if (CallOpts.IsTemporaryLifetimeExtendedViaAggregate) return CIP_DisallowedOnce; Index: test/Analysis/lifetime-extension.cpp =================================================================== --- test/Analysis/lifetime-extension.cpp +++ test/Analysis/lifetime-extension.cpp @@ -46,10 +46,18 @@ const int &y = A().j[1]; // no-crash const int &z = (A().j[1], A().j[0]); // no-crash - // FIXME: All of these should be TRUE, but constructors aren't inlined. - clang_analyzer_eval(x == 1); // expected-warning{{UNKNOWN}} - clang_analyzer_eval(y == 3); // expected-warning{{UNKNOWN}} - clang_analyzer_eval(z == 2); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(x == 1); + clang_analyzer_eval(y == 3); + clang_analyzer_eval(z == 2); +#ifdef TEMPORARIES + // expected-warning@-4{{TRUE}} + // expected-warning@-4{{TRUE}} + // expected-warning@-4{{TRUE}} +#else + // expected-warning@-8{{UNKNOWN}} + // expected-warning@-8{{UNKNOWN}} + // expected-warning@-8{{UNKNOWN}} +#endif } } // end namespace pr19539_crash_on_destroying_an_integer @@ -144,8 +152,12 @@ { const bool &x = C(true, &after, &before).x; // no-crash } - // FIXME: Should be TRUE. Should not warn about garbage value. - clang_analyzer_eval(after == before); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(after == before); +#ifdef TEMPORARIES + // expected-warning@-2{{TRUE}} +#else + // expected-warning@-4{{UNKNOWN}} +#endif } struct A { // A is an aggregate.