diff options
author | Fariborz Jahanian <fjahanian@apple.com> | 2012-07-17 18:00:08 +0000 |
---|---|---|
committer | Fariborz Jahanian <fjahanian@apple.com> | 2012-07-17 18:00:08 +0000 |
commit | 379b28183a7dcb715c3f3eb2da4b0157d6d8ffbe (patch) | |
tree | ff0370720245e781885b0755e78005ea2fc70069 /lib | |
parent | d5209ae13a7c42e2b7fa641f75a66e545959cbed (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.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 49 |
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) { |