]> granicus.if.org Git - clang/commitdiff
Factor out enumerator APSInt adjustment into
authorGabor Greif <ggreif@gmail.com>
Fri, 1 Oct 2010 22:05:14 +0000 (22:05 +0000)
committerGabor Greif <ggreif@gmail.com>
Fri, 1 Oct 2010 22:05:14 +0000 (22:05 +0000)
a helper function (AdjustAPSInt) and use that
for adjusting the high bounds of case ranges
before APSInt comparisons. Fixes
http://llvm.org/bugs/show_bug.cgi?id=8135

Some minor refacorings while I am here.

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

lib/Sema/SemaStmt.cpp
test/SemaCXX/gnu-case-ranges.cpp [new file with mode: 0644]

index 7acadc541c727805fdd8b5e57774f712b4c1f9be..1e7912cbdca367fe71d9d221e6d310c6fc07754d 100644 (file)
@@ -459,6 +459,14 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond,
   return Owned(SS);
 }
 
+static void AdjustAPSInt(llvm::APSInt &Val, unsigned BitWidth, bool IsSigned) {
+  if (Val.getBitWidth() < BitWidth)
+    Val.extend(BitWidth);
+  else if (Val.getBitWidth() > BitWidth)
+    Val.trunc(BitWidth);
+  Val.setIsSigned(IsSigned);
+}
+
 StmtResult
 Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
                             Stmt *BodyStmt) {
@@ -560,7 +568,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
 
       // Convert the value to the same width/sign as the condition.
       ConvertIntegerToTypeWarnOnOverflow(LoVal, CondWidth, CondIsSigned,
-                                         CS->getLHS()->getLocStart(),
+                                         Lo->getLocStart(),
                                          diag::warn_case_value_overflow);
 
       // If the LHS is not the same type as the condition, insert an implicit
@@ -639,7 +647,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
 
         // Convert the value to the same width/sign as the condition.
         ConvertIntegerToTypeWarnOnOverflow(HiVal, CondWidth, CondIsSigned,
-                                           CR->getRHS()->getLocStart(),
+                                           Hi->getLocStart(),
                                            diag::warn_case_value_overflow);
 
         // If the LHS is not the same type as the condition, insert an implicit
@@ -651,7 +659,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
         if (LoVal > HiVal) {
           Diag(CR->getLHS()->getLocStart(), diag::warn_case_empty_range)
             << SourceRange(CR->getLHS()->getLocStart(),
-                           CR->getRHS()->getLocEnd());
+                           Hi->getLocEnd());
           CaseRanges.erase(CaseRanges.begin()+i);
           --i, --e;
           continue;
@@ -740,14 +748,10 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
       // Gather all enum values, set their type and sort them,
       // allowing easier comparison with CaseVals.
       for (EnumDecl::enumerator_iterator EDI = ED->enumerator_begin();
-             EDI != ED->enumerator_end(); EDI++) {
-        llvm::APSInt Val = (*EDI)->getInitVal();
-        if(Val.getBitWidth() < CondWidth)
-          Val.extend(CondWidth);
-        else if (Val.getBitWidth() > CondWidth)
-          Val.trunc(CondWidth);
-        Val.setIsSigned(CondIsSigned);
-        EnumVals.push_back(std::make_pair(Val, (*EDI)));
+           EDI != ED->enumerator_end(); ++EDI) {
+        llvm::APSInt Val = EDI->getInitVal();
+        AdjustAPSInt(Val, CondWidth, CondIsSigned);
+        EnumVals.push_back(std::make_pair(Val, *EDI));
       }
       std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals);
       EnumValsTy::iterator EIend =
@@ -779,6 +783,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
           }
 
           llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context);
+          AdjustAPSInt(Hi, CondWidth, CondIsSigned);
           while (EI != EIend && EI->first < Hi)
             EI++;
           if (EI == EIend || EI->first != Hi)
@@ -806,6 +811,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
         // Drop unneeded case ranges
         for (; RI != CaseRanges.end(); RI++) {
           llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context);
+          AdjustAPSInt(Hi, CondWidth, CondIsSigned);
           if (EI->first <= Hi)
             break;
         }
diff --git a/test/SemaCXX/gnu-case-ranges.cpp b/test/SemaCXX/gnu-case-ranges.cpp
new file mode 100644 (file)
index 0000000..d15cca1
--- /dev/null
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -o /dev/null -verify %s
+
+enum E {
+    one,
+    two,
+    three,
+    four
+};
+
+
+int test(enum E e) 
+{
+    switch (e) 
+    {
+        case one:
+            return 7;
+        case two ... two + 1:
+            return 42;
+        case four:
+            return 25;
+        default:
+            return 0;
+    }
+}