From: Ted Kremenek Date: Thu, 27 Feb 2014 00:24:08 +0000 (+0000) Subject: [-Wunreachable-code] Prune out unreachable warnings where a 'break' is preceded by... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=05a09c8f63fb61abaeb1e3bb4da9db87aaa4ec8d;p=clang [-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 --- 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 CS = I->getAs()) { + if (const CallExpr *CE = dyn_cast(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(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); diff --git a/test/Sema/warn-unreachable.c b/test/Sema/warn-unreachable.c index 221351b70d..a626fa8dd2 100644 --- a/test/Sema/warn-unreachable.c +++ b/test/Sema/warn-unreachable.c @@ -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; +}