]> granicus.if.org Git - clang/commitdiff
finish off switch case overlap checking, adding support for
authorChris Lattner <sabre@nondot.org>
Thu, 23 Aug 2007 18:29:20 +0000 (18:29 +0000)
committerChris Lattner <sabre@nondot.org>
Thu, 23 Aug 2007 18:29:20 +0000 (18:29 +0000)
verifying case ranges.

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

Sema/SemaStmt.cpp
test/Sema/switch.c

index 6a8c18ced65d8b9b2737f119eb77bebef928a622..dff057456e28aa4a64ea4a4c12fcb3fe1db60e19 100644 (file)
@@ -198,6 +198,19 @@ void Sema::ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &Val,
   }
 }
 
+namespace {
+  struct CaseCompareFunctor {
+    bool operator()(const std::pair<llvm::APSInt, CaseStmt*> &LHS,
+                    const llvm::APSInt &RHS) {
+      return LHS.first < RHS;
+    }
+    bool operator()(const llvm::APSInt &LHS,
+                    const std::pair<llvm::APSInt, CaseStmt*> &RHS) {
+      return LHS < RHS.first;
+    }
+  };
+}
+
 Action::StmtResult
 Sema::FinishSwitchStmt(SourceLocation SwitchLoc, StmtTy *Switch, ExprTy *Body) {
   Stmt *BodyStmt = (Stmt*)Body;
@@ -225,7 +238,8 @@ Sema::FinishSwitchStmt(SourceLocation SwitchLoc, StmtTy *Switch, ExprTy *Body) {
   // Accumulate all of the case values in a vector so that we can sort them
   // and detect duplicates.  This vector contains the APInt for the case after
   // it has been converted to the condition type.
-  llvm::SmallVector<std::pair<llvm::APSInt, CaseStmt*>, 64> CaseVals;
+  typedef llvm::SmallVector<std::pair<llvm::APSInt, CaseStmt*>, 64> CaseValsTy;
+  CaseValsTy CaseVals;
   
   // Keep track of any GNU case ranges we see.  The APSInt is the low value.
   std::vector<std::pair<llvm::APSInt, CaseStmt*> > CaseRanges;
@@ -294,7 +308,7 @@ Sema::FinishSwitchStmt(SourceLocation SwitchLoc, StmtTy *Switch, ExprTy *Body) {
   if (!CaseRanges.empty()) {
     // Sort all the case ranges by their low value so we can easily detect
     // overlaps between ranges.
-    std::stable_sort(CaseVals.begin(), CaseVals.end());
+    std::stable_sort(CaseRanges.begin(), CaseRanges.end());
     
     // Scan the ranges, computing the high values and removing empty ranges.
     std::vector<llvm::APSInt> HiVals;
@@ -321,12 +335,50 @@ Sema::FinishSwitchStmt(SourceLocation SwitchLoc, StmtTy *Switch, ExprTy *Body) {
     }
 
     // Rescan the ranges, looking for overlap with singleton values and other
-    // ranges.
+    // ranges.  Since the range list is sorted, we only need to compare case
+    // ranges with their neighbors.
     for (unsigned i = 0, e = CaseRanges.size(); i != e; ++i) {
-      //llvm::APSInt &CRLow = CaseRanges[i].first;
-      //CaseStmt *CR = CaseRanges[i].second;
+      llvm::APSInt &CRLo = CaseRanges[i].first;
+      llvm::APSInt &CRHi = HiVals[i];
+      CaseStmt *CR = CaseRanges[i].second;
+      
+      // Check to see whether the case range overlaps with any singleton cases.
+      CaseStmt *OverlapStmt = 0;
+      llvm::APSInt OverlapVal(32);
+      
+      // Find the smallest value >= the lower bound.  If I is in the case range,
+      // then we have overlap.
+      CaseValsTy::iterator I = std::lower_bound(CaseVals.begin(),
+                                                CaseVals.end(), CRLo,
+                                                CaseCompareFunctor());
+      if (I != CaseVals.end() && I->first < CRHi) {
+        OverlapVal  = I->first;   // Found overlap with scalar.
+        OverlapStmt = I->second;
+      }
+
+      // Find the smallest value bigger than the upper bound.
+      I = std::upper_bound(I, CaseVals.end(), CRHi, CaseCompareFunctor());
+      if (I != CaseVals.begin() && (I-1)->first >= CRLo) {
+        OverlapVal  = (I-1)->first;      // Found overlap with scalar.
+        OverlapStmt = (I-1)->second;
+      }
+
+      // Check to see if this case stmt overlaps with the subsequent case range.
+      if (i && CRLo <= HiVals[i-1]) {
+        OverlapVal  = HiVals[i-1];       // Found overlap with range.
+        OverlapStmt = CaseRanges[i-1].second;
+      }
       
-      // FIXME: TODO.
+      if (OverlapStmt) {
+        // If we have a duplicate, report it.
+        Diag(CR->getLHS()->getLocStart(),
+             diag::err_duplicate_case, OverlapVal.toString());
+        Diag(OverlapStmt->getLHS()->getLocStart(), 
+             diag::err_duplicate_case_prev);
+        // FIXME: We really want to remove the bogus case stmt from the substmt,
+        // but we have no way to do this right now.
+        CaseListIsErroneous = true;
+      }
     }
   }
   
index 0128a216e5a32aae8841c0d7c54c6b2a90b349e2..eacd3c285014169739b997f4d8d8ed20f299a112 100644 (file)
@@ -2,22 +2,29 @@
 
 void f (int z) { 
   while (z) { 
-    default: z--;   // expected-error {{statement not in switch}}
+    default: z--;            // expected-error {{statement not in switch}}
   } 
 }
 
 void foo(int X) {
   switch (X) {
-  case 42: ;          // expected-error {{previous case value}}
-  case 5000000000LL:  // expected-warning {{overflow}}
-  case 42:            // expected-error {{duplicate case value}}
+  case 42: ;                 // expected-error {{previous case value}}
+  case 5000000000LL:         // expected-warning {{overflow}}
+  case 42:                   // expected-error {{duplicate case value}}
    ;
 
-  case 100 ... 99: ;  // expected-warning {{empty case range}}
+  case 100 ... 99: ;         // expected-warning {{empty case range}}
+
+  case 43: ;                 // expected-error {{previous case value}}
+  case 43 ... 45:  ;         // expected-error {{duplicate case value}}
+
+  case 100 ... 20000:;       // expected-error {{previous case value}}
+  case 15000 ... 40000000:;  // expected-error {{duplicate case value}}
   }
 }
 
 void test3(void) { 
+  // empty switch;
   switch (0); 
 }