Index: lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngine.cpp +++ lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -184,17 +184,17 @@ const LocationContext *LC, const Expr *Ex, const Expr *Result) { - SVal V = State->getSVal(Ex, LC); + SVal ExV = State->getSVal(Ex, LC); if (!Result) { // If we don't have an explicit result expression, we're in "if needed" // mode. Only create a region if the current value is a NonLoc. - if (!V.getAs()) + if (!ExV.getAs()) return State; Result = Ex; } else { // We need to create a region no matter what. For sanity, make sure we don't // try to stuff a Loc into a non-pointer temporary region. - assert(!V.getAs() || Loc::isLocType(Result->getType()) || + assert(!ExV.getAs() || Loc::isLocType(Result->getType()) || Result->getType()->isMemberPointerType()); } @@ -259,14 +259,32 @@ } } - // Try to recover some path sensitivity in case we couldn't compute the value. - if (V.isUnknown()) - V = getSValBuilder().conjureSymbolVal(Result, LC, TR->getValueType(), - currBldrCtx->blockCount()); - // Bind the value of the expression to the sub-object region, and then bind - // the sub-object region to our expression. - State = State->bindLoc(Reg, V, LC); + // The result expression would now point to the correct sub-region of the + // newly created temporary region. State = State->BindExpr(Result, LC, Reg); + + // What remains is to copy the value of the object to the new region. + // FIXME: In other words, what we should always do is copy value of the + // Init expression (which corresponds to the bigger object) to the whole + // temporary region TR. However, this value is often no longer present + // in the Environment. If it has disappeared, we instead invalidate TR. + // Still, what we can do is assign the value of expression Ex (which + // corresponds to the sub-object) to the TR's sub-region Reg. At least, + // values inside Reg would be correct. + SVal InitV = State->getSVal(Init, LC); + if (InitV.isUnknown()) + InitV = getSValBuilder().conjureSymbolVal(Result, LC, Init->getType(), + currBldrCtx->blockCount()); + State = State->bindLoc(loc::MemRegionVal(TR), InitV, LC); + + // Try to recover some path sensitivity in case we couldn't compute the value. + if (ExV.isUnknown()) + ExV = getSValBuilder().conjureSymbolVal(Result, LC, Ex->getType(), + currBldrCtx->blockCount()); + + // FIXME: Why do we need to do that if WipeV was known to begin with? + State = State->bindLoc(Reg, ExV, LC); + return State; } Index: test/Analysis/temporaries.cpp =================================================================== --- test/Analysis/temporaries.cpp +++ test/Analysis/temporaries.cpp @@ -503,3 +503,30 @@ }); } } + +namespace CopyToTemporaryCorrectly { +class Super { +public: + void m() { + mImpl(); + } + virtual void mImpl() = 0; +}; +class Sub : public Super { +public: + Sub(const int &p) : j(p) {} + virtual void mImpl() override { + // Used to be undefined pointer dereference because we didn't copy + // the subclass data (j) to the temporary object properly. + (void)(j + 1); // no-warning + if (j != 22) { + clang_analyzer_warnIfReached(); // no-warning + } + } + const int &j; +}; +void run() { + int i = 22; + Sub(i).m(); +} +}