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;
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.
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;
}
return;
// Suppress trivial 'return' statements that are dead.
- if (isTrivialReturn(B, S))
+ if (isTrivialReturnOrDoWhile(B, S))
return;
SourceRange R1, R2;
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;
+}
+