]> granicus.if.org Git - clang/commitdiff
Don't warn on fall-through from unreachable code.
authorAlexander Kornienko <alexfh@google.com>
Wed, 30 Jan 2013 03:49:44 +0000 (03:49 +0000)
committerAlexander Kornienko <alexfh@google.com>
Wed, 30 Jan 2013 03:49:44 +0000 (03:49 +0000)
Summary:
A motivating example:
class ClassWithDtor {
public:
  ~ClassWithDtor() {}
};
void fallthrough3(int n) {
  switch (n) {
    case 2:
      do {
        ClassWithDtor temp;
        return;
      } while (0);  // This generates a chain of unreachable CFG blocks.
    case 3:
      break;
  }
}

Reviewers: rsmith, doug.gregor, alexfh

Reviewed By: alexfh

CC: cfe-commits
Differential Revision: http://llvm-reviews.chandlerc.com/D330

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

lib/Sema/AnalysisBasedWarnings.cpp
test/SemaCXX/switch-implicit-fallthrough.cpp

index 1687f69f47a67f6eff4df3d1103d367e48c966a3..b362239163371a9490822540e1728571bd065c75 100644 (file)
@@ -702,7 +702,27 @@ namespace {
       return FallthroughStmts;
     }
 
+    void fillReachableBlocks(CFG *Cfg) {
+      assert(ReachableBlocks.empty() && "ReachableBlocks already filled");
+      std::deque<const CFGBlock *> BlockQueue;
+
+      ReachableBlocks.insert(&Cfg->getEntry());
+      BlockQueue.push_back(&Cfg->getEntry());
+      while (!BlockQueue.empty()) {
+        const CFGBlock *P = BlockQueue.front();
+        BlockQueue.pop_front();
+        for (CFGBlock::const_succ_iterator I = P->succ_begin(),
+                                           E = P->succ_end();
+             I != E; ++I) {
+          if (ReachableBlocks.insert(*I))
+            BlockQueue.push_back(*I);
+        }
+      }
+    }
+
     bool checkFallThroughIntoBlock(const CFGBlock &B, int &AnnotatedCnt) {
+      assert(!ReachableBlocks.empty() && "ReachableBlocks empty");
+
       int UnannotatedCnt = 0;
       AnnotatedCnt = 0;
 
@@ -726,8 +746,7 @@ namespace {
         if (L && L->getSubStmt() == B.getLabel() && P->begin() == P->end())
           continue; // Case label is preceded with a normal label, good.
 
-        if (P->pred_begin() == P->pred_end()) {  // The block is unreachable.
-          // This only catches trivially unreachable blocks.
+        if (!ReachableBlocks.count(P)) {
           for (CFGBlock::const_iterator ElIt = P->begin(), ElEnd = P->end();
                ElIt != ElEnd; ++ElIt) {
             if (const CFGStmt *CS = ElIt->getAs<CFGStmt>()){
@@ -816,6 +835,7 @@ namespace {
     bool FoundSwitchStatements;
     AttrStmts FallthroughStmts;
     Sema &S;
+    llvm::SmallPtrSet<const CFGBlock *, 16> ReachableBlocks;
   };
 }
 
@@ -847,7 +867,7 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
   if (!Cfg)
     return;
 
-  int AnnotatedCnt;
+  FM.fillReachableBlocks(Cfg);
 
   for (CFG::reverse_iterator I = Cfg->rbegin(), E = Cfg->rend(); I != E; ++I) {
     const CFGBlock *B = *I;
@@ -856,6 +876,8 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
     if (!Label || !isa<SwitchCase>(Label))
       continue;
 
+    int AnnotatedCnt;
+
     if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt))
       continue;
 
index 93e724e86c6b38cdd80ddb2f8c8d1ef87574171c..912b21ebfdb58d4b3ad368a30ad2f0f0a11d9e31 100644 (file)
@@ -10,7 +10,7 @@ int fallthrough(int n) {
       } else if (n - 3) {
         n = 102;
       }
-    case -1: // expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert '[[clang::fallthrough]];' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}}
+    case -1:  // no warning here, ignore fall-through from unreachable code
       ;
     case 0: {// expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert '[[clang::fallthrough]];' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}}
     }
@@ -39,14 +39,13 @@ int fallthrough(int n) {
       break;
   }
   switch (n / 15) {
-label_case_70:
-    case 70:
+label_default:
+    default:
       n += 333;
+      if (n % 10)
+        goto label_default;
       break;
-    case 71:
-      n += 334;
-      goto label_case_70;
-    case 72:
+    case 70:
       n += 335;
       break;
   }
@@ -130,6 +129,22 @@ void fallthrough2(int n) {
   }
 }
 
+void fallthrough3(int n) {
+  switch (n) {
+    case 1:
+      do {
+        return;
+      } while (0);
+    case 2:
+      do {
+        ClassWithDtor temp;
+        return;
+      } while (0);
+    case 3:
+      break;
+  }
+}
+
 #define MY_SWITCH(X, Y, Z, U, V) switch (X) { case Y: Z; case U: V; }
 #define MY_SWITCH2(X, Y, Z) switch (X) { Y; Z; }
 #define MY_CASE(X, Y) case X: Y