From: Ted Kremenek Date: Thu, 6 Mar 2014 00:17:44 +0000 (+0000) Subject: [-Wunreachable-code] Handle idiomatic do...while() with an uninteresting condition. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=542df791afd9b958cc3f785ff20d7c861ca97868;p=clang [-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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@203036 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp index 7958840b89..9f6792e2cc 100644 --- a/lib/Analysis/ReachableCode.cpp +++ b/lib/Analysis/ReachableCode.cpp @@ -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(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(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(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; diff --git a/test/Sema/warn-unreachable.c b/test/Sema/warn-unreachable.c index 3c6d891613..bf1e9137eb 100644 --- a/test/Sema/warn-unreachable.c +++ b/test/Sema/warn-unreachable.c @@ -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; +} +