[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. llvm-svn: 164829
This commit is contained in:
parent
e7126582a4
commit
b559f18584
|
@ -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;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -x c %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -x c++ -analyzer-config c++-inlining=constructors %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -DINLINE -verify -x c %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -DINLINE -verify -x c++ -analyzer-config c++-inlining=constructors %s
|
||||
|
||||
void clang_analyzer_eval(int);
|
||||
|
||||
|
@ -11,7 +13,14 @@ struct S {
|
|||
#endif
|
||||
};
|
||||
|
||||
#ifdef INLINE
|
||||
struct S getS() {
|
||||
struct S s = { 42 };
|
||||
return s;
|
||||
}
|
||||
#else
|
||||
struct S getS();
|
||||
#endif
|
||||
|
||||
|
||||
void testAssignment() {
|
||||
|
|
Loading…
Reference in New Issue