Skip to content

Commit

Permalink
[analyzer] Handle C++11 member initializer expressions.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
jrose-apple committed Jul 17, 2013
1 parent 5fded08 commit 5f6c173
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 8 deletions.
22 changes: 14 additions & 8 deletions clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -737,17 +736,22 @@ 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);

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 =
Expand All @@ -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);
}

Expand Down
34 changes: 34 additions & 0 deletions clang/test/Analysis/initializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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}}
}
}

0 comments on commit 5f6c173

Please sign in to comment.