diff options
author | Ted Kremenek <kremenek@apple.com> | 2012-07-14 05:04:10 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2012-07-14 05:04:10 +0000 |
commit | 3f635c08b2d0b2d5bafb38da09589cb238407faa (patch) | |
tree | 04c1df56543f84916e9385ca2dcaadf8f47097b9 /lib/StaticAnalyzer/Core/ExprEngine.cpp | |
parent | 5c3ea5c57971317c35b120ef0a2a2c79bd171008 (diff) |
Refine CFG so that '&&' and '||' don't lead to extra confluence points when used in a branch, but
instead push the terminator for the branch down into the basic blocks of the subexpressions of '&&' and '||'
respectively. This eliminates some artifical control-flow from the CFG and results in a more
compact CFG.
Note that this patch only alters the branches 'while', 'if' and 'for'. This was complex enough for
one patch. The remaining branches (e.g., do...while) can be handled in a separate patch, but they
weren't immediately tackled because they were less important.
It is possible that this patch introduces some subtle bugs, particularly w.r.t. to destructor placement.
I've tried to audit these changes, but it is also known that the destructor logic needs some refinement
in the area of '||' and '&&' regardless (i.e., their are known bugs).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@160218 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer/Core/ExprEngine.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngine.cpp | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index d78234890b..904fcf1ca0 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1208,6 +1208,45 @@ static SVal RecoverCastedSymbol(ProgramStateManager& StateMgr, return state->getSVal(Ex, LCtx); } +static const Stmt *ResolveCondition(const Stmt *Condition, + const CFGBlock *B) { + if (const Expr *Ex = dyn_cast<Expr>(Condition)) + Condition = Ex->IgnoreParens(); + + const BinaryOperator *BO = dyn_cast<BinaryOperator>(Condition); + if (!BO || !BO->isLogicalOp()) + return Condition; + + // For logical operations, we still have the case where some branches + // use the traditional "merge" approach and others sink the branch + // directly into the basic blocks representing the logical operation. + // We need to distinguish between those two cases here. + + // The invariants are still shifting, but it is possible that the + // last element in a CFGBlock is not a CFGStmt. Look for the last + // CFGStmt as the value of the condition. + CFGBlock::const_reverse_iterator I = B->rbegin(), E = B->rend(); + for (; I != E; ++I) { + CFGElement Elem = *I; + CFGStmt *CS = dyn_cast<CFGStmt>(&Elem); + if (!CS) + continue; + if (CS->getStmt() != Condition) + break; + return Condition; + } + + assert(I != E); + + while (Condition) { + BO = dyn_cast<BinaryOperator>(Condition); + if (!BO || !BO->isLogicalOp()) + return Condition; + Condition = BO->getRHS()->IgnoreParens(); + } + llvm_unreachable("could not resolve condition"); +} + void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term, NodeBuilderContext& BldCtx, ExplodedNode *Pred, @@ -1224,6 +1263,12 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term, return; } + + // Resolve the condition in the precense of nested '||' and '&&'. + if (const Expr *Ex = dyn_cast<Expr>(Condition)) + Condition = Ex->IgnoreParens(); + + Condition = ResolveCondition(Condition, BldCtx.getBlock()); PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), Condition->getLocStart(), "Error evaluating branch"); |