From: Chris Lattner Date: Thu, 23 Aug 2007 18:29:20 +0000 (+0000) Subject: finish off switch case overlap checking, adding support for X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0471f5bc8191e39cdb61fabcaf1870e2af2d42e8;p=clang finish off switch case overlap checking, adding support for verifying case ranges. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@41331 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Sema/SemaStmt.cpp b/Sema/SemaStmt.cpp index 6a8c18ced6..dff057456e 100644 --- a/Sema/SemaStmt.cpp +++ b/Sema/SemaStmt.cpp @@ -198,6 +198,19 @@ void Sema::ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &Val, } } +namespace { + struct CaseCompareFunctor { + bool operator()(const std::pair &LHS, + const llvm::APSInt &RHS) { + return LHS.first < RHS; + } + bool operator()(const llvm::APSInt &LHS, + const std::pair &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, 64> CaseVals; + typedef llvm::SmallVector, 64> CaseValsTy; + CaseValsTy CaseVals; // Keep track of any GNU case ranges we see. The APSInt is the low value. std::vector > 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 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; + } } } diff --git a/test/Sema/switch.c b/test/Sema/switch.c index 0128a216e5..eacd3c2850 100644 --- a/test/Sema/switch.c +++ b/test/Sema/switch.c @@ -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); }