forked from OSchip/llvm-project
[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:
parent
5fded08403
commit
5f6c173e7c
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue