Index: lib/Analysis/LiveVariables.cpp =================================================================== --- lib/Analysis/LiveVariables.cpp +++ lib/Analysis/LiveVariables.cpp @@ -409,6 +409,13 @@ val.liveDecls = DSetFact.add(val.liveDecls, Dtor->getVarDecl()); continue; } + if (Optional Dtor = + elem.getAs()) { + // Temporary objects need to survive until the destructor is called. + val.liveStmts = SSetFact.add(val.liveStmts, + Dtor->getBindTemporaryExpr()->getSubExpr()); + continue; + } if (!elem.getAs()) continue; Index: lib/StaticAnalyzer/Core/CallEvent.cpp =================================================================== --- lib/StaticAnalyzer/Core/CallEvent.cpp +++ lib/StaticAnalyzer/Core/CallEvent.cpp @@ -959,7 +959,6 @@ CFGElement E = (*B)[CalleeCtx->getIndex()]; assert(E.getAs() && "All other CFG elements should have exprs"); - assert(!E.getAs() && "We don't handle temporaries yet"); SValBuilder &SVB = State->getStateManager().getSValBuilder(); const CXXDestructorDecl *Dtor = cast(CalleeCtx->getDecl()); Index: lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngine.cpp +++ lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -662,9 +662,18 @@ QualType varType = D.getBindTemporaryExpr()->getSubExpr()->getType(); - // FIXME: Inlining of temporary destructors is not supported yet anyway, so we - // just put a NULL region for now. This will need to be changed later. - VisitCXXDestructor(varType, nullptr, D.getBindTemporaryExpr(), + const LocationContext *LCtx = Pred->getLocationContext(); + SVal Val = Pred->getState()->getSVal( + D.getBindTemporaryExpr()->getSubExpr(), LCtx->getCurrentStackFrame()); + const MemRegion *Region = nullptr; + // If the class does not have any members, there will not be a region + // for it bound in the environment. + if (Optional LCV = + Val.getAs()) { + Region = LCV->getRegion(); + } + + VisitCXXDestructor(varType, Region, D.getBindTemporaryExpr(), /*IsBase=*/ false, Pred, Dst); } Index: lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -637,12 +637,6 @@ if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors)) return CIP_DisallowedAlways; - // FIXME: This is a hack. We don't handle temporary destructors - // right now, so we shouldn't inline their constructors. - if (CtorExpr->getConstructionKind() == CXXConstructExpr::CK_Complete) - if (!Target || !isa(Target)) - return CIP_DisallowedOnce; - break; } case CE_CXXDestructor: { @@ -807,14 +801,6 @@ AnalysisDeclContextManager &ADCMgr = AMgr.getAnalysisDeclContextManager(); AnalysisDeclContext *CalleeADC = ADCMgr.getContext(D); - // Temporary object destructor processing is currently broken, so we never - // inline them. - // FIXME: Remove this once temp destructors are working. - if (isa(Call)) { - if ((*currBldrCtx->getBlock())[currStmtIdx].getAs()) - return false; - } - // The auto-synthesized bodies are essential to inline as they are // usually small and commonly used. Note: we should do this check early on to // ensure we always inline these calls. Index: lib/StaticAnalyzer/Core/ProgramState.cpp =================================================================== --- lib/StaticAnalyzer/Core/ProgramState.cpp +++ lib/StaticAnalyzer/Core/ProgramState.cpp @@ -506,16 +506,7 @@ } bool ScanReachableSymbols::scan(nonloc::LazyCompoundVal val) { - bool wasVisited = !visited.insert(val.getCVData()).second; - if (wasVisited) - return true; - - StoreManager &StoreMgr = state->getStateManager().getStoreManager(); - // FIXME: We don't really want to use getBaseRegion() here because pointer - // arithmetic doesn't apply, but scanReachableSymbols only accepts base - // regions right now. - const MemRegion *R = val.getRegion()->getBaseRegion(); - return StoreMgr.scanReachableSymbols(val.getStore(), R, *this); + return scan(val.getRegion()); } bool ScanReachableSymbols::scan(nonloc::CompoundVal val) { Index: test/Analysis/temporaries.cpp =================================================================== --- test/Analysis/temporaries.cpp +++ test/Analysis/temporaries.cpp @@ -105,7 +105,7 @@ // FIXME: should be TRUE, but we don't inline the constructors of // temporaries because we can't model their destructors yet. - clang_analyzer_eval(((HasCtorDtor){1, 42}).y == 42); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(((HasCtorDtor){1, 42}).y == 42); // expected-warning{{TRUE}} #endif } } @@ -234,6 +234,17 @@ } } + struct WriteInDestructor { + WriteInDestructor(int *p) : p(p) {} + ~WriteInDestructor() { *p = 23; } // no warning + int *p; + }; + void testDtorInlining() { + int x; + (WriteInDestructor(&x)); + clang_analyzer_eval(x == 23); // expected-warning{{TRUE}} + } + #endif // TEMPORARY_DTORS }