Index: clang/lib/Analysis/CFG.cpp =================================================================== --- clang/lib/Analysis/CFG.cpp +++ clang/lib/Analysis/CFG.cpp @@ -5919,7 +5919,7 @@ return nullptr; const Stmt *Cond = StmtElem->getStmt(); - if (isa(Cond)) + if (isa(Cond) || isa(Cond)) return nullptr; // Only ObjCForCollectionStmt is known not to be a non-Expr terminator, hence Index: clang/unittests/Analysis/CFGBuildResult.h =================================================================== --- clang/unittests/Analysis/CFGBuildResult.h +++ clang/unittests/Analysis/CFGBuildResult.h @@ -27,15 +27,19 @@ Status getStatus() const { return S; } CFG *getCFG() const { return Cfg.get(); } + ASTUnit *getAST() const { return AST.get(); } + void setAST(std::unique_ptr AST) { this->AST = std::move(AST); } private: Status S; std::unique_ptr Cfg; + std::unique_ptr AST; }; class CFGCallback : public ast_matchers::MatchFinder::MatchCallback { public: BuildResult TheBuildResult = BuildResult::ToolRan; + CFG::BuildOptions Options; void run(const ast_matchers::MatchFinder::MatchResult &Result) override { const auto *Func = Result.Nodes.getNodeAs("func"); @@ -43,7 +47,6 @@ if (!Body) return; TheBuildResult = BuildResult::SawFunctionBody; - CFG::BuildOptions Options; Options.AddImplicitDtors = true; if (std::unique_ptr Cfg = CFG::buildCFG(nullptr, Body, Result.Context, Options)) @@ -51,17 +54,19 @@ } }; -inline BuildResult BuildCFG(const char *Code) { +inline BuildResult BuildCFG(const char *Code, CFG::BuildOptions Options = {}) { CFGCallback Callback; + Callback.Options = Options; ast_matchers::MatchFinder Finder; Finder.addMatcher(ast_matchers::functionDecl().bind("func"), &Callback); - std::unique_ptr Factory( - tooling::newFrontendActionFactory(&Finder)); std::vector Args = {"-std=c++11", "-fno-delayed-template-parsing"}; - if (!tooling::runToolOnCodeWithArgs(Factory->create(), Code, Args)) + std::unique_ptr AST = tooling::buildASTFromCodeWithArgs(Code, Args); + if (!AST) return BuildResult::ToolFailed; + Finder.matchAST(AST->getASTContext()); + Callback.TheBuildResult.setAST(std::move(AST)); return std::move(Callback.TheBuildResult); } Index: clang/unittests/Analysis/CFGTest.cpp =================================================================== --- clang/unittests/Analysis/CFGTest.cpp +++ clang/unittests/Analysis/CFGTest.cpp @@ -30,6 +30,22 @@ EXPECT_EQ(BuildResult::SawFunctionBody, BuildCFG(Code).getStatus()); } +TEST(CFG, StaticInitializerLastCondition) { + const char *Code = "void f() {\n" + " int i = 5 ;\n" + " static int j = 3 ;\n" + "}\n"; + CFG::BuildOptions Options; + Options.AddStaticInitBranches = true; + Options.setAllAlwaysAdd(); + BuildResult B = BuildCFG(Code, Options); + EXPECT_EQ(BuildResult::BuiltCFG, B.getStatus()); + EXPECT_EQ(1, B.getCFG()->getEntry().succ_size()); + CFGBlock *Block = *B.getCFG()->getEntry().succ_begin(); + EXPECT_TRUE(isa(Block->getTerminatorStmt())); + EXPECT_EQ(nullptr, Block->getLastCondition()); +} + // Constructing a CFG containing a delete expression on a dependent type should // not crash. TEST(CFG, DeleteExpressionOnDependentType) {