forked from OSchip/llvm-project
Factor out enumerator APSInt adjustment into
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. llvm-svn: 115355
This commit is contained in:
parent
1969887fc6
commit
16e028617c
|
@ -459,6 +459,14 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond,
|
||||||
return Owned(SS);
|
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
|
StmtResult
|
||||||
Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
|
Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
|
||||||
Stmt *BodyStmt) {
|
Stmt *BodyStmt) {
|
||||||
|
@ -560,7 +568,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
|
||||||
|
|
||||||
// Convert the value to the same width/sign as the condition.
|
// Convert the value to the same width/sign as the condition.
|
||||||
ConvertIntegerToTypeWarnOnOverflow(LoVal, CondWidth, CondIsSigned,
|
ConvertIntegerToTypeWarnOnOverflow(LoVal, CondWidth, CondIsSigned,
|
||||||
CS->getLHS()->getLocStart(),
|
Lo->getLocStart(),
|
||||||
diag::warn_case_value_overflow);
|
diag::warn_case_value_overflow);
|
||||||
|
|
||||||
// If the LHS is not the same type as the condition, insert an implicit
|
// 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.
|
// Convert the value to the same width/sign as the condition.
|
||||||
ConvertIntegerToTypeWarnOnOverflow(HiVal, CondWidth, CondIsSigned,
|
ConvertIntegerToTypeWarnOnOverflow(HiVal, CondWidth, CondIsSigned,
|
||||||
CR->getRHS()->getLocStart(),
|
Hi->getLocStart(),
|
||||||
diag::warn_case_value_overflow);
|
diag::warn_case_value_overflow);
|
||||||
|
|
||||||
// If the LHS is not the same type as the condition, insert an implicit
|
// 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) {
|
if (LoVal > HiVal) {
|
||||||
Diag(CR->getLHS()->getLocStart(), diag::warn_case_empty_range)
|
Diag(CR->getLHS()->getLocStart(), diag::warn_case_empty_range)
|
||||||
<< SourceRange(CR->getLHS()->getLocStart(),
|
<< SourceRange(CR->getLHS()->getLocStart(),
|
||||||
CR->getRHS()->getLocEnd());
|
Hi->getLocEnd());
|
||||||
CaseRanges.erase(CaseRanges.begin()+i);
|
CaseRanges.erase(CaseRanges.begin()+i);
|
||||||
--i, --e;
|
--i, --e;
|
||||||
continue;
|
continue;
|
||||||
|
@ -740,14 +748,10 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
|
||||||
// Gather all enum values, set their type and sort them,
|
// Gather all enum values, set their type and sort them,
|
||||||
// allowing easier comparison with CaseVals.
|
// allowing easier comparison with CaseVals.
|
||||||
for (EnumDecl::enumerator_iterator EDI = ED->enumerator_begin();
|
for (EnumDecl::enumerator_iterator EDI = ED->enumerator_begin();
|
||||||
EDI != ED->enumerator_end(); EDI++) {
|
EDI != ED->enumerator_end(); ++EDI) {
|
||||||
llvm::APSInt Val = (*EDI)->getInitVal();
|
llvm::APSInt Val = EDI->getInitVal();
|
||||||
if(Val.getBitWidth() < CondWidth)
|
AdjustAPSInt(Val, CondWidth, CondIsSigned);
|
||||||
Val.extend(CondWidth);
|
EnumVals.push_back(std::make_pair(Val, *EDI));
|
||||||
else if (Val.getBitWidth() > CondWidth)
|
|
||||||
Val.trunc(CondWidth);
|
|
||||||
Val.setIsSigned(CondIsSigned);
|
|
||||||
EnumVals.push_back(std::make_pair(Val, (*EDI)));
|
|
||||||
}
|
}
|
||||||
std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals);
|
std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals);
|
||||||
EnumValsTy::iterator EIend =
|
EnumValsTy::iterator EIend =
|
||||||
|
@ -779,6 +783,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context);
|
llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context);
|
||||||
|
AdjustAPSInt(Hi, CondWidth, CondIsSigned);
|
||||||
while (EI != EIend && EI->first < Hi)
|
while (EI != EIend && EI->first < Hi)
|
||||||
EI++;
|
EI++;
|
||||||
if (EI == EIend || EI->first != Hi)
|
if (EI == EIend || EI->first != Hi)
|
||||||
|
@ -806,6 +811,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
|
||||||
// Drop unneeded case ranges
|
// Drop unneeded case ranges
|
||||||
for (; RI != CaseRanges.end(); RI++) {
|
for (; RI != CaseRanges.end(); RI++) {
|
||||||
llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context);
|
llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context);
|
||||||
|
AdjustAPSInt(Hi, CondWidth, CondIsSigned);
|
||||||
if (EI->first <= Hi)
|
if (EI->first <= Hi)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue