aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Core/ExprEngine.cpp
diff options
context:
space:
mode:
authorJordan Rose <jordan_rose@apple.com>2012-09-28 17:15:21 +0000
committerJordan Rose <jordan_rose@apple.com>2012-09-28 17:15:21 +0000
commit0006ba445962621ed82ec84400a6b978205a3fbc (patch)
tree7ed95c9d505ee8e11846e304ca16e3e3d7882946 /lib/StaticAnalyzer/Core/ExprEngine.cpp
parent6f61df3e7256413dcb99afb9673f4206e3c4992c (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.cpp53
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;