diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -4215,10 +4215,12 @@ else TopBlock = currentBlock; - addSuccessor(SwitchTerminatedBlock, - shouldAddCase(switchExclusivelyCovered, switchCond, - CS, *Context) - ? currentBlock : nullptr); + if (SwitchTerminatedBlock) + addSuccessor( + SwitchTerminatedBlock, + shouldAddCase(switchExclusivelyCovered, switchCond, CS, *Context) + ? currentBlock + : nullptr); LastBlock = currentBlock; CS = cast(Sub); @@ -4241,10 +4243,10 @@ // Add this block to the list of successors for the block with the switch // statement. - assert(SwitchTerminatedBlock); - addSuccessor(SwitchTerminatedBlock, CaseBlock, - shouldAddCase(switchExclusivelyCovered, switchCond, - CS, *Context)); + if (SwitchTerminatedBlock) + addSuccessor( + SwitchTerminatedBlock, CaseBlock, + shouldAddCase(switchExclusivelyCovered, switchCond, CS, *Context)); // We set Block to NULL to allow lazy creation of a new block (if necessary) Block = nullptr; diff --git a/clang/unittests/Analysis/CFGTest.cpp b/clang/unittests/Analysis/CFGTest.cpp --- a/clang/unittests/Analysis/CFGTest.cpp +++ b/clang/unittests/Analysis/CFGTest.cpp @@ -268,6 +268,28 @@ } } +// It is valid to create a CFG for a single statement. Creating a CFG for an +// isolated `CaseStmt` should not crash.` +TEST(CFG, SwitchCase) { + const char *Code = "void f(int i) {\n" + " switch (i) {\n" + " case 0:\n" + " return;\n" + " }\n" + "}\n"; + std::vector Args = {"-std=c++11", + "-fno-delayed-template-parsing"}; + std::unique_ptr AST = tooling::buildASTFromCodeWithArgs(Code, Args); + ASSERT_NE(AST, nullptr); + + auto Matches = ast_matchers::match(ast_matchers::caseStmt().bind("case"), + AST->getASTContext()); + auto *Case = ast_matchers::selectFirst("case", Matches); + std::unique_ptr Cfg = + CFG::buildCFG(nullptr, const_cast(Case), + &AST->getASTContext(), CFG::BuildOptions{}); +} + } // namespace } // namespace analysis } // namespace clang