Index: cfe/trunk/lib/Analysis/CFG.cpp =================================================================== --- cfe/trunk/lib/Analysis/CFG.cpp +++ cfe/trunk/lib/Analysis/CFG.cpp @@ -3581,11 +3581,13 @@ autoCreateBlock(); appendStmt(Block, DE); QualType DTy = DE->getDestroyedType(); - DTy = DTy.getNonReferenceType(); - CXXRecordDecl *RD = Context->getBaseElementType(DTy)->getAsCXXRecordDecl(); - if (RD) { - if (RD->isCompleteDefinition() && !RD->hasTrivialDestructor()) - appendDeleteDtor(Block, RD, DE); + if (!DTy.isNull()) { + DTy = DTy.getNonReferenceType(); + CXXRecordDecl *RD = Context->getBaseElementType(DTy)->getAsCXXRecordDecl(); + if (RD) { + if (RD->isCompleteDefinition() && !RD->hasTrivialDestructor()) + appendDeleteDtor(Block, RD, DE); + } } return VisitChildren(DE); Index: cfe/trunk/unittests/Analysis/CFGTest.cpp =================================================================== --- cfe/trunk/unittests/Analysis/CFGTest.cpp +++ cfe/trunk/unittests/Analysis/CFGTest.cpp @@ -18,6 +18,41 @@ namespace analysis { namespace { +enum BuildResult { + ToolFailed, + ToolRan, + SawFunctionBody, + BuiltCFG, +}; + +class CFGCallback : public ast_matchers::MatchFinder::MatchCallback { +public: + BuildResult TheBuildResult = ToolRan; + + void run(const ast_matchers::MatchFinder::MatchResult &Result) override { + const auto *Func = Result.Nodes.getNodeAs("func"); + Stmt *Body = Func->getBody(); + if (!Body) + return; + TheBuildResult = SawFunctionBody; + if (CFG::buildCFG(nullptr, Body, Result.Context, CFG::BuildOptions())) + TheBuildResult = BuiltCFG; + } +}; + +BuildResult BuildCFG(const char *Code) { + CFGCallback Callback; + + 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)) + return ToolFailed; + return Callback.TheBuildResult; +} + // Constructing a CFG for a range-based for over a dependent type fails (but // should not crash). TEST(CFG, RangeBasedForOverDependentType) { @@ -27,30 +62,17 @@ " for (const Foo *TheFoo : Range) {\n" " }\n" "}\n"; + EXPECT_EQ(SawFunctionBody, BuildCFG(Code)); +} - class CFGCallback : public ast_matchers::MatchFinder::MatchCallback { - public: - bool SawFunctionBody = false; - - void run(const ast_matchers::MatchFinder::MatchResult &Result) override { - const auto *Func = Result.Nodes.getNodeAs("func"); - Stmt *Body = Func->getBody(); - if (!Body) - return; - SawFunctionBody = true; - std::unique_ptr cfg = - CFG::buildCFG(nullptr, Body, Result.Context, CFG::BuildOptions()); - EXPECT_EQ(nullptr, cfg); - } - } Callback; - - 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"}; - ASSERT_TRUE(tooling::runToolOnCodeWithArgs(Factory->create(), Code, Args)); - EXPECT_TRUE(Callback.SawFunctionBody); +// Constructing a CFG containing a delete expression on a dependent type should +// not crash. +TEST(CFG, DeleteExpressionOnDependentType) { + const char *Code = "template\n" + "void f(T t) {\n" + " delete t;\n" + "}\n"; + EXPECT_EQ(BuiltCFG, BuildCFG(Code)); } } // namespace