[cfe-commits] [PATCH] Don't warn on fall-through from unreachable code.

Alexander Kornienko alexfh at google.com
Fri Jan 25 10:54:46 PST 2013


Hi rsmith, doug.gregor,

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;
  }
}

http://llvm-reviews.chandlerc.com/D330

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

Index: lib/Sema/AnalysisBasedWarnings.cpp
===================================================================
--- lib/Sema/AnalysisBasedWarnings.cpp
+++ lib/Sema/AnalysisBasedWarnings.cpp
@@ -685,7 +685,8 @@
   public:
     FallthroughMapper(Sema &S)
       : FoundSwitchStatements(false),
-        S(S) {
+        S(S),
+        ReachableBlocksFilled(false) {
     }
 
     bool foundSwitchStatements() const { return FoundSwitchStatements; }
@@ -702,12 +703,25 @@
       return FallthroughStmts;
     }
 
-    bool checkFallThroughIntoBlock(const CFGBlock &B, int &AnnotatedCnt) {
+    bool checkFallThroughIntoBlock(const CFGBlock &B, int &AnnotatedCnt,
+                                   CFG *Cfg) {
+      std::deque<const CFGBlock *> BlockQueue;
+
+      if (!ReachableBlocksFilled) {
+        BlockQueue.push_back(*Cfg->rbegin());
+        while (!BlockQueue.empty()) {
+          const CFGBlock *P = BlockQueue.front();
+          BlockQueue.pop_front();
+          ReachableBlocks.insert(P);
+          std::copy(P->succ_begin(), P->succ_end(),
+                    std::back_inserter(BlockQueue));
+        }
+        ReachableBlocksFilled = true;
+      }
+
       int UnannotatedCnt = 0;
       AnnotatedCnt = 0;
 
-      std::deque<const CFGBlock*> BlockQueue;
-
       std::copy(B.pred_begin(), B.pred_end(), std::back_inserter(BlockQueue));
 
       while (!BlockQueue.empty()) {
@@ -722,8 +736,11 @@
         if (SW && SW->getSubStmt() == B.getLabel() && P->begin() == P->end())
           continue; // Previous case label has no statements, good.
 
-        if (P->pred_begin() == P->pred_end()) {  // The block is unreachable.
-          // This only catches trivially unreachable blocks.
+        const LabelStmt *L = dyn_cast_or_null<LabelStmt>(P->getLabel());
+        if (L && L->getSubStmt() == B.getLabel() && P->begin() == P->end())
+          continue; // Case label is preceded with a normal label, good.
+
+        if (!ReachableBlocks.count(P)) {
           for (CFGBlock::const_iterator ElIt = P->begin(), ElEnd = P->end();
                ElIt != ElEnd; ++ElIt) {
             if (const CFGStmt *CS = ElIt->getAs<CFGStmt>()){
@@ -812,6 +829,8 @@
     bool FoundSwitchStatements;
     AttrStmts FallthroughStmts;
     Sema &S;
+    bool ReachableBlocksFilled;
+    llvm::SmallPtrSet<const CFGBlock *, 16> ReachableBlocks;
   };
 }
 
@@ -852,7 +871,7 @@
     if (!Label || !isa<SwitchCase>(Label))
       continue;
 
-    if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt))
+    if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt, Cfg))
       continue;
 
     S.Diag(Label->getLocStart(),
Index: test/SemaCXX/switch-implicit-fallthrough.cpp
===================================================================
--- test/SemaCXX/switch-implicit-fallthrough.cpp
+++ test/SemaCXX/switch-implicit-fallthrough.cpp
@@ -10,7 +10,7 @@
       } 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}}
     }
@@ -38,6 +38,18 @@
     case 68:
       break;
   }
+  switch (n / 15) {
+label_case_70:
+    case 70:
+      n += 333;
+      break;
+    case 71:
+      n += 334;
+      goto label_case_70;
+    case 72:
+      n += 335;
+      break;
+  }
   switch (n / 20) {
     case 7:
       n += 400;
@@ -118,6 +130,22 @@
   }
 }
 
+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
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D330.1.patch
Type: text/x-patch
Size: 4142 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130125/eb1ce529/attachment.bin>


More information about the cfe-commits mailing list