aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2011-03-04 01:03:41 +0000
committerTed Kremenek <kremenek@apple.com>2011-03-04 01:03:41 +0000
commit0498247f87ea0d716e0c2931fea812280649e33d (patch)
tree060bbefa6193717fb180978893214dfbaa9e3250
parent0266aa37802a486e65f9259014bb60848fc4be23 (diff)
Correctly handle nested switch statements in CFGBuilder when on switch statement has a condition that evaluates to a constant.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126977 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Analysis/CFG.cpp23
-rw-r--r--test/SemaCXX/array-bounds.cpp13
2 files changed, 25 insertions, 11 deletions
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index 6d8d5c53f6..833d583907 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -279,14 +279,14 @@ class CFGBuilder {
// State to track for building switch statements.
bool switchExclusivelyCovered;
- Expr::EvalResult switchCond;
+ Expr::EvalResult *switchCond;
public:
explicit CFGBuilder() : cfg(new CFG()), // crew a new CFG
Block(NULL), Succ(NULL),
SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL),
TryTerminatedBlock(NULL), badCFG(false),
- switchExclusivelyCovered(false) {}
+ switchExclusivelyCovered(false), switchCond(0) {}
// buildCFG - Used by external clients to construct the CFG.
CFG* buildCFG(const Decl *D, Stmt *Statement, ASTContext *C,
@@ -2197,13 +2197,13 @@ CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) {
// for tracking the condition value.
SaveAndRestore<bool> save_switchExclusivelyCovered(switchExclusivelyCovered,
false);
- SaveAndRestore<Expr::EvalResult> save_switchCond(switchCond);
-
-
+
// Determine if the switch condition can be explicitly evaluated.
assert(Terminator->getCond() && "switch condition must be non-NULL");
- tryEvaluate(Terminator->getCond(), switchCond);
-
+ Expr::EvalResult result;
+ tryEvaluate(Terminator->getCond(), result);
+ SaveAndRestore<Expr::EvalResult*> save_switchCond(switchCond, &result);
+
// If body is not a compound statement create implicit scope
// and add destructors.
if (!isa<CompoundStmt>(Terminator->getBody()))
@@ -2243,7 +2243,7 @@ static bool shouldAddCase(bool &switchExclusivelyCovered,
const CaseStmt *CS,
ASTContext &Ctx) {
bool addCase = false;
-
+
if (!switchExclusivelyCovered) {
if (switchCond.Val.isInt()) {
// Evaluate the LHS of the case value.
@@ -2280,7 +2280,8 @@ CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* CS) {
// CaseStmts are essentially labels, so they are the first statement in a
// block.
CFGBlock *TopBlock = 0, *LastBlock = 0;
-
+ assert(switchCond);
+
if (Stmt *Sub = CS->getSubStmt()) {
// For deeply nested chains of CaseStmts, instead of doing a recursion
// (which can blow out the stack), manually unroll and create blocks
@@ -2295,7 +2296,7 @@ CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* CS) {
TopBlock = currentBlock;
addSuccessor(SwitchTerminatedBlock,
- shouldAddCase(switchExclusivelyCovered, switchCond,
+ shouldAddCase(switchExclusivelyCovered, *switchCond,
CS, *Context)
? currentBlock : 0);
@@ -2322,7 +2323,7 @@ CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* CS) {
// statement.
assert(SwitchTerminatedBlock);
addSuccessor(SwitchTerminatedBlock,
- shouldAddCase(switchExclusivelyCovered, switchCond,
+ shouldAddCase(switchExclusivelyCovered, *switchCond,
CS, *Context)
? CaseBlock : 0);
diff --git a/test/SemaCXX/array-bounds.cpp b/test/SemaCXX/array-bounds.cpp
index 5db9c1f6c9..62b4d520cc 100644
--- a/test/SemaCXX/array-bounds.cpp
+++ b/test/SemaCXX/array-bounds.cpp
@@ -147,3 +147,16 @@ void test_switch() {
}
}
+// Test nested switch statements.
+enum enumA { enumA_A, enumA_B, enumA_C, enumA_D, enumA_E };
+enum enumB { enumB_X, enumB_Y, enumB_Z };
+static enum enumB myVal = enumB_X;
+void test_nested_switch()
+{
+ switch (enumA_E) { // expected-warning {{no case matching constant}}
+ switch (myVal) { // expected-warning {{enumeration values 'enumB_X' and 'enumB_Z' not handled in switch}}
+ case enumB_Y: ;
+ }
+ }
+}
+