diff options
author | Jordan Rose <jordan_rose@apple.com> | 2012-09-28 17:15:21 +0000 |
---|---|---|
committer | Jordan Rose <jordan_rose@apple.com> | 2012-09-28 17:15:21 +0000 |
commit | 0006ba445962621ed82ec84400a6b978205a3fbc (patch) | |
tree | 7ed95c9d505ee8e11846e304ca16e3e3d7882946 /lib/StaticAnalyzer/Core/ExprEngine.cpp | |
parent | 6f61df3e7256413dcb99afb9673f4206e3c4992c (diff) |
[analyzer] Create a temp region when a method is called on a struct rvalue.
An rvalue has no address, but calling a C++ member function requires a
'this' pointer. This commit makes the analyzer create a temporary region
in which to store the struct rvalue and use as a 'this' pointer whenever
a member function is called on an rvalue, which is essentially what
CodeGen does.
More of <rdar://problem/12137950>. The last part is tracking down the
C++ FIXME in array-struct-region.cpp.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@164829 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer/Core/ExprEngine.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngine.cpp | 53 |
1 files changed, 31 insertions, 22 deletions
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 06216f83ea..3965f04842 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1470,6 +1470,23 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A, } } +/// If the value of the given expression is a NonLoc, copy it into a new +/// temporary region, and replace the value of the expression with that. +static ProgramStateRef createTemporaryRegionIfNeeded(ProgramStateRef State, + const LocationContext *LC, + const Expr *E) { + SVal V = State->getSVal(E, LC); + + if (isa<NonLoc>(V)) { + MemRegionManager &MRMgr = State->getStateManager().getRegionManager(); + const MemRegion *R = MRMgr.getCXXTempObjectRegion(E, LC); + State = State->bindLoc(loc::MemRegionVal(R), V); + State = State->BindExpr(E, LC, loc::MemRegionVal(R)); + } + + return State; +} + /// VisitMemberExpr - Transfer function for member expressions. void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, ExplodedNodeSet &TopDst) { @@ -1478,6 +1495,7 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, ExplodedNodeSet Dst; Decl *member = M->getMemberDecl(); + // Handle static member variables accessed via member syntax. if (VarDecl *VD = dyn_cast<VarDecl>(member)) { assert(M->isGLValue()); Bldr.takeNodes(Pred); @@ -1486,36 +1504,27 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, return; } + ProgramStateRef state = Pred->getState(); + const LocationContext *LCtx = Pred->getLocationContext(); + Expr *BaseExpr = M->getBase()->IgnoreParens(); + // Handle C++ method calls. if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(member)) { - Bldr.takeNodes(Pred); + if (MD->isInstance()) + state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr); + SVal MDVal = svalBuilder.getFunctionPointer(MD); - ProgramStateRef state = - Pred->getState()->BindExpr(M, Pred->getLocationContext(), MDVal); + state = state->BindExpr(M, LCtx, MDVal); + Bldr.generateNode(M, Pred, state); return; } + // Handle regular struct fields / member variables. + state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr); + SVal baseExprVal = state->getSVal(BaseExpr, LCtx); - FieldDecl *field = dyn_cast<FieldDecl>(member); - if (!field) // FIXME: skipping member expressions for non-fields - return; - - Expr *baseExpr = M->getBase()->IgnoreParens(); - ProgramStateRef state = Pred->getState(); - const LocationContext *LCtx = Pred->getLocationContext(); - SVal baseExprVal = state->getSVal(baseExpr, Pred->getLocationContext()); - - // If we're accessing a field of an rvalue, we need to treat it like a - // temporary object. - if (isa<NonLoc>(baseExprVal)) { - const MemRegion *R = - svalBuilder.getRegionManager().getCXXTempObjectRegion(baseExpr, LCtx); - SVal L = loc::MemRegionVal(R); - state = state->bindLoc(L, baseExprVal); - baseExprVal = L; - } - + FieldDecl *field = cast<FieldDecl>(member); SVal L = state->getLValue(field, baseExprVal); if (M->isGLValue()) { ExplodedNodeSet Tmp; |