]> granicus.if.org Git - clang/commitdiff
[-Wunreachable-code] always treat 'case:' and 'default:' cases as reachable.
authorTed Kremenek <kremenek@apple.com>
Thu, 27 Feb 2014 21:56:47 +0000 (21:56 +0000)
committerTed Kremenek <kremenek@apple.com>
Thu, 27 Feb 2014 21:56:47 +0000 (21:56 +0000)
This is a heuristic.  Many switch statements, although they look covered
over an enum, may actually handle at runtime more values than in the enum.

This is overly conservative, as there are some cases that clearly
can be ruled as being clearly unreachable, e.g. 'switch (42) { case 1: ... }'.
We can refine this later.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@202436 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Analysis/ReachableCode.cpp
test/Sema/warn-unreachable.c

index 797e02ed6f502cbedadcf23d8f459378d1490184..4a192802e7166f5afd327e4c12cbe8ef789263e7 100644 (file)
@@ -337,12 +337,6 @@ void DeadCodeScan::reportDeadCode(const CFGBlock *B,
   if (isTrivialReturnPrecededByNoReturn(B, S))
     return;
 
-  // Was this an unreachable 'default' case?  Such cases are covered
-  // by -Wcovered-switch-default, if the user so desires.
-  const Stmt *Label = B->getLabel();
-  if (Label && isa<DefaultStmt>(Label))
-    return;
-
   SourceRange R1, R2;
   SourceLocation Loc = GetUnreachableLoc(S, R1, R2);
   CB.HandleUnreachable(Loc, R1, R2);
@@ -374,8 +368,32 @@ unsigned ScanReachableFromBlock(const CFGBlock *Start,
     
     // Look at the successors and mark then reachable.
     for (CFGBlock::const_succ_iterator I = item->succ_begin(), 
-         E = item->succ_end(); I != E; ++I)
-      if (const CFGBlock *B = *I) {
+         E = item->succ_end(); I != E; ++I) {
+      const CFGBlock *B = *I;
+      if (!B) {
+        //
+        // For switch statements, treat all cases as being reachable.
+        // There are many cases where a switch can contain values that
+        // are not in an enumeration but they are still reachable because
+        // other values are possible.
+        //
+        // Note that this is quite conservative.  If one saw:
+        //
+        //  switch (1) {
+        //    case 2: ...
+        //
+        // we should be able to say that 'case 2' is unreachable.  To do
+        // this we can either put more heuristics here, or possibly retain
+        // that information in the CFG itself.
+        //
+        if (const CFGBlock *UB = I->getPossiblyUnreachableBlock()) {
+          const Stmt *Label = UB->getLabel();
+          if (Label && isa<SwitchCase>(Label)) {
+            B = UB;
+          }
+        }
+      }
+      if (B) {
         unsigned blockID = B->getBlockID();
         if (!Reachable[blockID]) {
           Reachable.set(blockID);
@@ -383,6 +401,7 @@ unsigned ScanReachableFromBlock(const CFGBlock *Start,
           ++count;
         }
       }
+    }
   }
   return count;
 }
index a6bc6a94fc1b26166454dcadb858af182bb248b0..630b623b58ab9cd73a81c388a28f957a2e5762c0 100644 (file)
@@ -173,6 +173,9 @@ void unreachable_default(MyEnum e) {
   case Value1:
     calledFun();
     break;
+  case 2: // expected-warning {{case value not in enumerated type 'MyEnum'}}
+    calledFun();
+    break;
   default:
     calledFun(); // no-warning
     break;