[-Wunreachable-code] Handle idiomatic do...while() with an uninteresting condition.

Sometimes do..while() is used to create a scope that can be left early.
In such cases, the unreachable 'while()' test is not usually interesting
unless it actually does something that is observable.

llvm-svn: 203036
This commit is contained in:
Ted Kremenek 2014-03-06 00:17:44 +00:00
parent 4b047f2378
commit 1de2e14f2f
2 changed files with 41 additions and 9 deletions

View File

@ -296,10 +296,7 @@ static bool isTrivialExpression(const Expr *Ex) {
isEnumConstant(Ex);
}
static bool isTrivialReturn(const CFGBlock *B, const Stmt *S) {
if (B->pred_empty())
return false;
static bool isTrivialReturnOrDoWhile(const CFGBlock *B, const Stmt *S) {
const Expr *Ex = dyn_cast<Expr>(S);
if (!Ex)
return false;
@ -307,6 +304,16 @@ static bool isTrivialReturn(const CFGBlock *B, const Stmt *S) {
if (!isTrivialExpression(Ex))
return false;
// Check if the block ends with a do...while() and see if 'S' is the
// condition.
if (const Stmt *Term = B->getTerminator()) {
if (const DoStmt *DS = dyn_cast<DoStmt>(Term))
if (DS->getCond() == S)
return true;
}
// Look to see if the block ends with a 'return', and see if 'S'
// is a substatement. The 'return' may not be the last element in
// the block because of destructors.
@ -317,12 +324,15 @@ static bool isTrivialReturn(const CFGBlock *B, const Stmt *S) {
if (const ReturnStmt *RS = dyn_cast<ReturnStmt>(CS->getStmt())) {
const Expr *RE = RS->getRetValue();
if (RE && RE->IgnoreParenCasts() == Ex)
return true;
break;
}
break;
return false;
}
}
if (B->pred_size() == 1)
return bodyEndsWithNoReturn(*B->pred_begin());
return false;
}
@ -336,7 +346,7 @@ void DeadCodeScan::reportDeadCode(const CFGBlock *B,
return;
// Suppress trivial 'return' statements that are dead.
if (isTrivialReturn(B, S))
if (isTrivialReturnOrDoWhile(B, S))
return;
SourceRange R1, R2;

View File

@ -268,9 +268,31 @@ int test_MyEnum() {
return 2; // no-warning
if (ME_B)
return 3;
// FIXME: we should only need one diagnostic here.
if (!ME_B) // expected-warning {{will never be executed}}
return 4;// expected-warning {{will never be executed}}
return 4; // expected-warning {{will never be executed}}
return 5;
}
// Test for idiomatic do..while.
int test_do_while(int x) {
do {
if (x == calledFun())
break;
++x;
break;
}
while (0); // no-warning
return x;
}
int test_do_while_nontrivial_cond(int x) {
do {
if (x == calledFun())
break;
++x;
break;
}
while (calledFun()); // expected-warning {{will never be executed}}
return x;
}