Index: include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h =================================================================== --- include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -105,11 +105,6 @@ /// This call is a constructor or a destructor of a temporary value. 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; - EvalCallOptions() {} }; Index: lib/StaticAnalyzer/Core/ExprEngineCXX.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -179,18 +179,6 @@ break; } case ConstructionContext::TemporaryObjectKind: { - const auto *TOCC = cast(CC); - // See if we're lifetime-extended via our field. If so, take a note. - // Because automatic destructors aren't quite working in this case. - if (const auto *MTE = TOCC->getMaterializedTemporaryExpr()) { - if (const ValueDecl *VD = MTE->getExtendingDecl()) { - assert(VD->getType()->isReferenceType()); - if (VD->getType()->getPointeeType().getCanonicalType() != - MTE->GetTemporaryExpr()->getType().getCanonicalType()) { - CallOpts.IsTemporaryLifetimeExtendedViaSubobject = true; - } - } - } // TODO: Support temporaries lifetime-extended via static references. // They'd need a getCXXStaticTempObjectRegion(). CallOpts.IsTemporaryCtorOrDtor = true; Index: lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -694,11 +694,6 @@ // the fake temporary target. 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; } break; Index: test/Analysis/lifetime-extension.cpp =================================================================== --- test/Analysis/lifetime-extension.cpp +++ test/Analysis/lifetime-extension.cpp @@ -42,10 +42,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 @@ -140,8 +148,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 } } // end namespace maintain_original_object_address_on_lifetime_extension