r202328 - [-Wunreachable-code] Prune out unreachable warnings where a 'break' is preceded by a call to a 'noreturn' function.
Ted Kremenek
kremenek at apple.com
Wed Feb 26 16:24:09 PST 2014
Author: kremenek
Date: Wed Feb 26 18:24:08 2014
New Revision: 202328
URL: http://llvm.org/viewvc/llvm-project?rev=202328&view=rev
Log:
[-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.
Modified:
cfe/trunk/lib/Analysis/ReachableCode.cpp
cfe/trunk/test/Sema/warn-unreachable.c
Modified: cfe/trunk/lib/Analysis/ReachableCode.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ReachableCode.cpp?rev=202328&r1=202327&r2=202328&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/ReachableCode.cpp (original)
+++ cfe/trunk/lib/Analysis/ReachableCode.cpp Wed Feb 26 18:24:08 2014
@@ -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(con
}
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(con
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(
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);
Modified: cfe/trunk/test/Sema/warn-unreachable.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/warn-unreachable.c?rev=202328&r1=202327&r2=202328&view=diff
==============================================================================
--- cfe/trunk/test/Sema/warn-unreachable.c (original)
+++ cfe/trunk/test/Sema/warn-unreachable.c Wed Feb 26 18:24:08 2014
@@ -143,3 +143,24 @@ void test_mul_and_zero(int x) {
if (x * 0) calledFun(); // expected-warning {{will never be executed}}
if (0 * x) calledFun(); // expected-warning {{will never be executed}}
}
+
+void raze() __attribute__((noreturn));
+void warn_here();
+
+int test_break_preceded_by_noreturn(int i) {
+ switch (i) {
+ case 1:
+ raze();
+ break; // no-warning
+ case 2:
+ raze();
+ break; // no-warning
+ warn_here(); // expected-warning {{will never be executed}}
+ case 3:
+ return 1;
+ break; // expected-warning {{will never be executed}}
+ default:
+ break;
+ }
+ return i;
+}
More information about the cfe-commits
mailing list