diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index 6d8d5c53f60f..833d583907b4 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/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 save_switchExclusivelyCovered(switchExclusivelyCovered, false); - SaveAndRestore 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 save_switchCond(switchCond, &result); + // If body is not a compound statement create implicit scope // and add destructors. if (!isa(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/clang/test/SemaCXX/array-bounds.cpp b/clang/test/SemaCXX/array-bounds.cpp index 5db9c1f6c98d..62b4d520cc7f 100644 --- a/clang/test/SemaCXX/array-bounds.cpp +++ b/clang/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: ; + } + } +} +