summaryrefslogtreecommitdiff
path: root/lib/Analysis/ReachableCode.cpp
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2014-02-27 00:24:08 +0000
committerTed Kremenek <kremenek@apple.com>2014-02-27 00:24:08 +0000
commit05a09c8f63fb61abaeb1e3bb4da9db87aaa4ec8d (patch)
treef2f72dd4de4dbaa6b95b0ca5b52d4dcd7799126f /lib/Analysis/ReachableCode.cpp
parent7e6444be66752afdbca2bf08ff2092bd64ee809d (diff)
downloadclang-05a09c8f63fb61abaeb1e3bb4da9db87aaa4ec8d.tar.gz
[-Wunreachable-code] Prune out unreachable warnings where a 'break' is preceded by a call to a 'noreturn' function.
For example: unreachable(); break; This code is idiomatic and defensive. The fact that 'break' is unreachable here is not interesting. This occurs frequently in LLVM/Clang itself. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@202328 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis/ReachableCode.cpp')
-rw-r--r--lib/Analysis/ReachableCode.cpp50
1 files changed, 43 insertions, 7 deletions
diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp
index a2d19c0508..599779871f 100644
--- a/lib/Analysis/ReachableCode.cpp
+++ b/lib/Analysis/ReachableCode.cpp
@@ -49,7 +49,8 @@ public:
const Stmt *findDeadCode(const CFGBlock *Block);
- void reportDeadCode(const Stmt *S,
+ void reportDeadCode(const CFGBlock *B,
+ const Stmt *S,
clang::reachable_code::Callback &CB);
};
}
@@ -153,7 +154,7 @@ unsigned DeadCodeScan::scanBackwards(const clang::CFGBlock *Start,
}
if (isDeadCodeRoot(Block)) {
- reportDeadCode(S, CB);
+ reportDeadCode(Block, S, CB);
count += clang::reachable_code::ScanReachableFromBlock(Block, Reachable);
}
else {
@@ -170,11 +171,11 @@ unsigned DeadCodeScan::scanBackwards(const clang::CFGBlock *Start,
llvm::array_pod_sort(DeferredLocs.begin(), DeferredLocs.end(), SrcCmp);
for (DeferredLocsTy::iterator I = DeferredLocs.begin(),
E = DeferredLocs.end(); I != E; ++I) {
- const CFGBlock *block = I->first;
- if (Reachable[block->getBlockID()])
+ const CFGBlock *Block = I->first;
+ if (Reachable[Block->getBlockID()])
continue;
- reportDeadCode(I->second, CB);
- count += clang::reachable_code::ScanReachableFromBlock(block, Reachable);
+ reportDeadCode(Block, I->second, CB);
+ count += clang::reachable_code::ScanReachableFromBlock(Block, Reachable);
}
}
@@ -246,8 +247,43 @@ static SourceLocation GetUnreachableLoc(const Stmt *S,
return S->getLocStart();
}
-void DeadCodeScan::reportDeadCode(const Stmt *S,
+static bool bodyEndsWithNoReturn(const CFGBlock *B) {
+ for (CFGBlock::const_reverse_iterator I = B->rbegin(), E = B->rend();
+ I != E; ++I) {
+ if (Optional<CFGStmt> CS = I->getAs<CFGStmt>()) {
+ if (const CallExpr *CE = dyn_cast<CallExpr>(CS->getStmt())) {
+ QualType CalleeType = CE->getCallee()->getType();
+ if (getFunctionExtInfo(*CalleeType).getNoReturn())
+ return true;
+ }
+ break;
+ }
+ }
+ return false;
+}
+
+static bool isBreakPrecededByNoReturn(const CFGBlock *B,
+ const Stmt *S) {
+ if (!isa<BreakStmt>(S) || B->pred_empty())
+ return false;
+
+ assert(B->empty());
+ assert(B->pred_size() == 1);
+ const CFGBlock::AdjacentBlock &AB = *B->pred_begin();
+ const CFGBlock *Pred = AB.getPossiblyUnreachableBlock();
+ assert(!AB.isReachable() && Pred);
+ return bodyEndsWithNoReturn(Pred);
+}
+
+void DeadCodeScan::reportDeadCode(const CFGBlock *B,
+ const Stmt *S,
clang::reachable_code::Callback &CB) {
+ // Suppress idiomatic cases of calling a noreturn function just
+ // before executing a 'break'. If there is other code after the 'break'
+ // in the block then don't suppress the warning.
+ if (isBreakPrecededByNoReturn(B, S))
+ return;
+
SourceRange R1, R2;
SourceLocation Loc = GetUnreachableLoc(S, R1, R2);
CB.HandleUnreachable(Loc, R1, R2);