aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorFariborz Jahanian <fjahanian@apple.com>2012-07-17 18:00:08 +0000
committerFariborz Jahanian <fjahanian@apple.com>2012-07-17 18:00:08 +0000
commit379b28183a7dcb715c3f3eb2da4b0157d6d8ffbe (patch)
treeff0370720245e781885b0755e78005ea2fc70069 /lib
parentd5209ae13a7c42e2b7fa641f75a66e545959cbed (diff)
Issue warning when assigning out-of-range integer values to enums.
Due to performance cost, this is an opt-in option placed under -Wassign-enum. // rdar://11824807 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@160382 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/Sema/SemaExpr.cpp5
-rw-r--r--lib/Sema/SemaStmt.cpp49
2 files changed, 53 insertions, 1 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 34fb9d06a7..915663e622 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -9617,7 +9617,10 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
bool MayHaveFunctionDiff = false;
switch (ConvTy) {
- case Compatible: return false;
+ case Compatible:
+ DiagnoseAssignmentEnum(DstType, SrcType, SrcExpr);
+ return false;
+
case PointerToInt:
DiagKind = diag::ext_typecheck_convert_pointer_int;
ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this);
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 54ec58af41..9affe9823a 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -1059,6 +1059,55 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
return Owned(SS);
}
+void
+Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType,
+ Expr *SrcExpr) {
+ unsigned DIAG = diag::warn_not_in_enum_assignement;
+ if (Diags.getDiagnosticLevel(DIAG, SrcExpr->getExprLoc())
+ == DiagnosticsEngine::Ignored)
+ return;
+
+ if (const EnumType *ET = DstType->getAs<EnumType>())
+ if (!Context.hasSameType(SrcType, DstType) &&
+ SrcType->isIntegerType()) {
+ if (!SrcExpr->isTypeDependent() && !SrcExpr->isValueDependent() &&
+ SrcExpr->isIntegerConstantExpr(Context)) {
+ // Get the bitwidth of the enum value before promotions.
+ unsigned DstWith = Context.getIntWidth(DstType);
+ bool DstIsSigned = DstType->isSignedIntegerOrEnumerationType();
+
+ llvm::APSInt RhsVal = SrcExpr->EvaluateKnownConstInt(Context);
+ const EnumDecl *ED = ET->getDecl();
+ typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64>
+ EnumValsTy;
+ EnumValsTy EnumVals;
+
+ // Gather all enum values, set their type and sort them,
+ // allowing easier comparison with rhs constant.
+ for (EnumDecl::enumerator_iterator EDI = ED->enumerator_begin();
+ EDI != ED->enumerator_end(); ++EDI) {
+ llvm::APSInt Val = EDI->getInitVal();
+ AdjustAPSInt(Val, DstWith, DstIsSigned);
+ EnumVals.push_back(std::make_pair(Val, *EDI));
+ }
+ if (EnumVals.empty())
+ return;
+ 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();
+ while (EI != EIend && EI->first < RhsVal)
+ EI++;
+ if (EI == EIend || EI->first != RhsVal) {
+ Diag(SrcExpr->getExprLoc(), diag::warn_not_in_enum_assignement)
+ << DstType;
+ }
+ }
+ }
+}
+
StmtResult
Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond,
Decl *CondVar, Stmt *Body) {