diff options
author | Mike Stump <mrs@apple.com> | 2009-07-17 01:04:31 +0000 |
---|---|---|
committer | Mike Stump <mrs@apple.com> | 2009-07-17 01:04:31 +0000 |
commit | cd7bf230a77c550115e4a78ee371fc49a7563692 (patch) | |
tree | 778a02d781a6d77845671340d6a4a5fa6df64ed2 /lib/Analysis/CFG.cpp | |
parent | 808825cd08704d1cccef605f8cd3ef83c93eac78 (diff) |
Make noreturn functions alter the CFG.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@76133 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis/CFG.cpp')
-rw-r--r-- | lib/Analysis/CFG.cpp | 38 |
1 files changed, 34 insertions, 4 deletions
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index d423716c20..c77f8cebda 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -117,9 +117,9 @@ public: CFGBlock* VisitStmt(Stmt* Statement); CFGBlock* VisitSwitchStmt(SwitchStmt* Terminator); CFGBlock* VisitWhileStmt(WhileStmt* W); - + // FIXME: Add support for ObjC-specific control-flow structures. - + // NYS == Not Yet Supported CFGBlock* NYS() { badCFG = true; @@ -280,7 +280,7 @@ CFGBlock* CFGBuilder::addStmt(Stmt* Terminator) { /// WalkAST - Used by addStmt to walk the subtree of a statement and /// add extra blocks for ternary operators, &&, and ||. We also /// process "," and DeclStmts (which may contain nested control-flow). -CFGBlock* CFGBuilder::WalkAST(Stmt* Terminator, bool AlwaysAddStmt = false) { +CFGBlock* CFGBuilder::WalkAST(Stmt* Terminator, bool AlwaysAddStmt = false) { switch (Terminator->getStmtClass()) { case Stmt::ConditionalOperatorClass: { ConditionalOperator* C = cast<ConditionalOperator>(Terminator); @@ -478,6 +478,36 @@ CFGBlock* CFGBuilder::WalkAST(Stmt* Terminator, bool AlwaysAddStmt = false) { case Stmt::ParenExprClass: return WalkAST(cast<ParenExpr>(Terminator)->getSubExpr(), AlwaysAddStmt); + case Stmt::CallExprClass: { + bool NoReturn = false; + CallExpr *C = cast<CallExpr>(Terminator); + Expr *CEE = C->getCallee()->IgnoreParenCasts(); + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) { + // FIXME: We can follow objective-c methods and C++ member functions... + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(DRE->getDecl())) { + if (FD->hasAttr<NoReturnAttr>()) + NoReturn = true; + } + } + + if (!NoReturn) + break; + + if (Block) { + if (!FinishBlock(Block)) + return 0; + } + + // Create new block with no successor for the remaining pieces. + Block = createBlock(false); + Block->appendStmt(Terminator); + + // Wire this to the exit block directly. + Block->addSuccessor(&cfg->getExit()); + + return WalkAST_VisitChildren(Terminator); + } + default: break; }; @@ -1190,7 +1220,7 @@ CFGBlock* CFGBuilder::VisitBreakStmt(BreakStmt* B) { return 0; } - // Now create a new block that ends with the continue statement. + // Now create a new block that ends with the break statement. Block = createBlock(false); Block->setTerminator(B); |