From: Mike Stump Date: Fri, 17 Jul 2009 01:04:31 +0000 (+0000) Subject: Make noreturn functions alter the CFG. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=cd7bf230a77c550115e4a78ee371fc49a7563692;p=clang Make noreturn functions alter the CFG. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@76133 91177308-0d34-0410-b5e6-96231b3b80d8 --- 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(Terminator); @@ -478,6 +478,36 @@ CFGBlock* CFGBuilder::WalkAST(Stmt* Terminator, bool AlwaysAddStmt = false) { case Stmt::ParenExprClass: return WalkAST(cast(Terminator)->getSubExpr(), AlwaysAddStmt); + case Stmt::CallExprClass: { + bool NoReturn = false; + CallExpr *C = cast(Terminator); + Expr *CEE = C->getCallee()->IgnoreParenCasts(); + if (DeclRefExpr *DRE = dyn_cast(CEE)) { + // FIXME: We can follow objective-c methods and C++ member functions... + if (FunctionDecl *FD = dyn_cast(DRE->getDecl())) { + if (FD->hasAttr()) + 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); diff --git a/test/Analysis/dead-stores.c b/test/Analysis/dead-stores.c index e644b1ead7..1aa971422a 100644 --- a/test/Analysis/dead-stores.c +++ b/test/Analysis/dead-stores.c @@ -138,7 +138,8 @@ int f17() { // // The values of dead stores are only "consumed" in an enclosing expression -// what that value is actually used. In other words, don't say "Although the value stored to 'x' is used...". +// what that value is actually used. In other words, don't say "Although the +// value stored to 'x' is used...". int f18() { int x = 0; // no-warning if (1) @@ -173,3 +174,14 @@ void f20(void) { #pragma unused(x) } +void halt() __attribute__((noreturn)); +int f21() { + int x = 4; + + ++x; // expected-warning{{never read}} + if (1) { + halt(); + (void)x; + } + return 1; +}