aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Stump <mrs@apple.com>2009-07-17 01:04:31 +0000
committerMike Stump <mrs@apple.com>2009-07-17 01:04:31 +0000
commitcd7bf230a77c550115e4a78ee371fc49a7563692 (patch)
tree778a02d781a6d77845671340d6a4a5fa6df64ed2
parent808825cd08704d1cccef605f8cd3ef83c93eac78 (diff)
Make noreturn functions alter the CFG.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@76133 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Analysis/CFG.cpp38
-rw-r--r--test/Analysis/dead-stores.c14
2 files changed, 47 insertions, 5 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);
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() {
// <rdar://problem/6506065>
// 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;
+}