[analyzer] Handle C++11 member initializer expressions.

Previously, we would simply abort the path when we saw a default member
initialization; now, we actually attempt to evaluate it. Like default
arguments, the contents of these expressions are not actually part of the
current function, so we fall back to constant evaluation.

llvm-svn: 186521
This commit is contained in:
Jordan Rose 2013-07-17 17:16:42 +00:00
parent 5fded08403
commit 5f6c173e7c
2 changed files with 48 additions and 8 deletions

View File

@ -612,7 +612,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
switch (S->getStmtClass()) {
// C++ and ARC stuff we don't support yet.
case Expr::ObjCIndirectCopyRestoreExprClass:
case Stmt::CXXDefaultInitExprClass:
case Stmt::CXXDependentScopeMemberExprClass:
case Stmt::CXXPseudoDestructorExprClass:
case Stmt::CXXTryStmtClass:
@ -737,7 +736,8 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
break;
}
case Stmt::CXXDefaultArgExprClass: {
case Stmt::CXXDefaultArgExprClass:
case Stmt::CXXDefaultInitExprClass: {
Bldr.takeNodes(Pred);
ExplodedNodeSet PreVisit;
getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this);
@ -745,9 +745,13 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
ExplodedNodeSet Tmp;
StmtNodeBuilder Bldr2(PreVisit, Tmp, *currBldrCtx);
const LocationContext *LCtx = Pred->getLocationContext();
const CXXDefaultArgExpr *DefaultE = cast<CXXDefaultArgExpr>(S);
const Expr *ArgE = DefaultE->getExpr();
const Expr *ArgE;
if (const CXXDefaultArgExpr *DefE = dyn_cast<CXXDefaultArgExpr>(S))
ArgE = DefE->getExpr();
else if (const CXXDefaultInitExpr *DefE = dyn_cast<CXXDefaultInitExpr>(S))
ArgE = DefE->getExpr();
else
llvm_unreachable("unknown constant wrapper kind");
bool IsTemporary = false;
if (const MaterializeTemporaryExpr *MTE =
@ -760,13 +764,15 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
if (!ConstantVal)
ConstantVal = UnknownVal();
const LocationContext *LCtx = Pred->getLocationContext();
for (ExplodedNodeSet::iterator I = PreVisit.begin(), E = PreVisit.end();
I != E; ++I) {
ProgramStateRef State = (*I)->getState();
State = State->BindExpr(DefaultE, LCtx, *ConstantVal);
State = State->BindExpr(S, LCtx, *ConstantVal);
if (IsTemporary)
State = createTemporaryRegionIfNeeded(State, LCtx, DefaultE,
DefaultE);
State = createTemporaryRegionIfNeeded(State, LCtx,
cast<Expr>(S),
cast<Expr>(S));
Bldr2.generateNode(S, *I, State);
}

View File

@ -109,3 +109,37 @@ namespace DefaultConstructorWithCleanups {
return w.arr[0].value; // no-warning
}
}
namespace DefaultMemberInitializers {
struct Wrapper {
int value = 42;
Wrapper() {}
Wrapper(int x) : value(x) {}
Wrapper(bool) {}
};
void test() {
Wrapper w1;
clang_analyzer_eval(w1.value == 42); // expected-warning{{TRUE}}
Wrapper w2(50);
clang_analyzer_eval(w2.value == 50); // expected-warning{{TRUE}}
Wrapper w3(false);
clang_analyzer_eval(w3.value == 42); // expected-warning{{TRUE}}
}
struct StringWrapper {
const char s[4] = "abc";
const char *p = "xyz";
StringWrapper(bool) {}
};
void testString() {
StringWrapper w(true);
clang_analyzer_eval(w.s[1] == 'b'); // expected-warning{{TRUE}}
clang_analyzer_eval(w.p[1] == 'y'); // expected-warning{{TRUE}}
}
}