aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaStmt.cpp
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2010-09-09 00:05:53 +0000
committerTed Kremenek <kremenek@apple.com>2010-09-09 00:05:53 +0000
commit559fb554602bedb57dbbf3cc14ac8a38264b4547 (patch)
treeb104938f48e69198ff5051b9ff456497ddd395f8 /lib/Sema/SemaStmt.cpp
parent1efb6c716397f2c4e3ede3a4853c5efebb375441 (diff)
When building SwitchStmts in Sema, record whether all the enum values of a switch(enum) where
covered by individual case statements. Flow-based analyses may wish to consult this information, and recording this in the AST allows us to obviate reconstructing this information later when we build the CFG. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@113447 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaStmt.cpp')
-rw-r--r--lib/Sema/SemaStmt.cpp82
1 files changed, 47 insertions, 35 deletions
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 083e4dba85..fa23654e0d 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -696,14 +696,14 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
}
// Check to see if switch is over an Enum and handles all of its
- // values. We don't need to do this if there's a default
- // statement or if we have a constant condition.
+ // values. We only issue a warning if there is not 'default:', but
+ // we still do the analysis to preserve this information in the AST
+ // (which can be used by flow-based analyes).
//
- // TODO: we might want to check whether case values are out of the
- // enum even if we don't want to check whether all cases are handled.
const EnumType* ET = CondTypeBeforePromotion->getAs<EnumType>();
+
// If switch has default case, then ignore it.
- if (!CaseListIsErroneous && !TheDefaultStmt && !HasConstantCond && ET) {
+ if (!CaseListIsErroneous && !HasConstantCond && ET) {
const EnumDecl *ED = ET->getDecl();
typedef llvm::SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> EnumValsTy;
EnumValsTy EnumVals;
@@ -723,40 +723,46 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals);
EnumValsTy::iterator EIend =
std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals);
- // See which case values aren't in enum
- EnumValsTy::const_iterator EI = EnumVals.begin();
- for (CaseValsTy::const_iterator CI = CaseVals.begin();
+
+ // See which case values aren't in enum.
+ // TODO: we might want to check whether case values are out of the
+ // enum even if we don't want to check whether all cases are handled.
+ if (!TheDefaultStmt) {
+ EnumValsTy::const_iterator EI = EnumVals.begin();
+ for (CaseValsTy::const_iterator CI = CaseVals.begin();
CI != CaseVals.end(); CI++) {
- while (EI != EIend && EI->first < CI->first)
- EI++;
- if (EI == EIend || EI->first > CI->first)
+ while (EI != EIend && EI->first < CI->first)
+ EI++;
+ if (EI == EIend || EI->first > CI->first)
Diag(CI->second->getLHS()->getExprLoc(), diag::warn_not_in_enum)
<< ED->getDeclName();
- }
- // See which of case ranges aren't in enum
- EI = EnumVals.begin();
- for (CaseRangesTy::const_iterator RI = CaseRanges.begin();
+ }
+ // See which of case ranges aren't in enum
+ EI = EnumVals.begin();
+ for (CaseRangesTy::const_iterator RI = CaseRanges.begin();
RI != CaseRanges.end() && EI != EIend; RI++) {
- while (EI != EIend && EI->first < RI->first)
- EI++;
+ while (EI != EIend && EI->first < RI->first)
+ EI++;
- if (EI == EIend || EI->first != RI->first) {
- Diag(RI->second->getLHS()->getExprLoc(), diag::warn_not_in_enum)
- << ED->getDeclName();
- }
-
- llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context);
- while (EI != EIend && EI->first < Hi)
- EI++;
- if (EI == EIend || EI->first != Hi)
- Diag(RI->second->getRHS()->getExprLoc(), diag::warn_not_in_enum)
- << ED->getDeclName();
+ if (EI == EIend || EI->first != RI->first) {
+ Diag(RI->second->getLHS()->getExprLoc(), diag::warn_not_in_enum)
+ << ED->getDeclName();
+ }
+
+ llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context);
+ while (EI != EIend && EI->first < Hi)
+ EI++;
+ if (EI == EIend || EI->first != Hi)
+ Diag(RI->second->getRHS()->getExprLoc(), diag::warn_not_in_enum)
+ << ED->getDeclName();
+ }
}
- //Check which enum vals aren't in switch
+ // Check which enum vals aren't in switch
CaseValsTy::const_iterator CI = CaseVals.begin();
CaseRangesTy::const_iterator RI = CaseRanges.begin();
- EI = EnumVals.begin();
- for (; EI != EIend; EI++) {
+ bool hasCasesNotInSwitch = false;
+
+ for (EnumValsTy::const_iterator EI = EnumVals.begin(); EI != EIend; EI++){
//Drop unneeded case values
llvm::APSInt CIVal;
while (CI != CaseVals.end() && CI->first < EI->first)
@@ -765,17 +771,23 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
if (CI != CaseVals.end() && CI->first == EI->first)
continue;
- //Drop unneeded case ranges
+ // Drop unneeded case ranges
for (; RI != CaseRanges.end(); RI++) {
llvm::APSInt Hi = RI->second->getRHS()->EvaluateAsInt(Context);
if (EI->first <= Hi)
break;
}
- if (RI == CaseRanges.end() || EI->first < RI->first)
- Diag(CondExpr->getExprLoc(), diag::warn_missing_cases)
- << EI->second->getDeclName();
+ if (RI == CaseRanges.end() || EI->first < RI->first) {
+ hasCasesNotInSwitch = true;
+ if (!TheDefaultStmt)
+ Diag(CondExpr->getExprLoc(), diag::warn_missing_cases)
+ << EI->second->getDeclName();
+ }
}
+
+ if (!hasCasesNotInSwitch)
+ SS->setAllEnumCasesCovered();
}
}