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