From: Dmitri Gribenko Date: Thu, 5 Dec 2013 22:52:07 +0000 (+0000) Subject: Allow the warning 'case value not in enumerated type' to be silenced with X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8840fa855077e6be0897260d355c29e52bcbf27d;p=clang Allow the warning 'case value not in enumerated type' to be silenced with the following pattern. If 'case' expression refers to a static const variable of the correct enum type, then we count this as a sufficient declaration of intent by the user, so we silence the warning. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@196546 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 6bda42deaa..077282c1bf 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -659,6 +659,29 @@ static void AdjustAPSInt(llvm::APSInt &Val, unsigned BitWidth, bool IsSigned) { Val.setIsSigned(IsSigned); } +/// Returns true if we should emit a diagnostic about this case expression not +/// being a part of the enum used in the switch controlling expression. +static bool ShouldDiagnoseSwitchCaseNotInEnum(const ASTContext &Ctx, + const EnumDecl *ED, + const Expr *CaseExpr) { + // Don't warn if the 'case' expression refers to a static const variable of + // the enum type. + CaseExpr = CaseExpr->IgnoreParenImpCasts(); + if (const DeclRefExpr *DRE = dyn_cast(CaseExpr)) { + if (const VarDecl *VD = dyn_cast(DRE->getDecl())) { + if (!VD->hasGlobalStorage()) + return true; + QualType VarType = VD->getType(); + if (!VarType.isConstQualified()) + return true; + QualType EnumType = Ctx.getTypeDeclType(ED); + if (Ctx.hasSameUnqualifiedType(EnumType, VarType)) + return false; + } + } + return true; +} + StmtResult Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, Stmt *BodyStmt) { @@ -1008,9 +1031,12 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, CI != CaseVals.end(); CI++) { 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) - << CondTypeBeforePromotion; + if (EI == EIend || EI->first > CI->first) { + Expr *CaseExpr = CI->second->getLHS(); + if (ShouldDiagnoseSwitchCaseNotInEnum(Context, ED, CaseExpr)) + Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum) + << CondTypeBeforePromotion; + } } // See which of case ranges aren't in enum EI = EnumVals.begin(); @@ -1020,8 +1046,10 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, EI++; if (EI == EIend || EI->first != RI->first) { - Diag(RI->second->getLHS()->getExprLoc(), diag::warn_not_in_enum) - << CondTypeBeforePromotion; + Expr *CaseExpr = RI->second->getLHS(); + if (ShouldDiagnoseSwitchCaseNotInEnum(Context, ED, CaseExpr)) + Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum) + << CondTypeBeforePromotion; } llvm::APSInt Hi = @@ -1029,9 +1057,12 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, AdjustAPSInt(Hi, CondWidth, CondIsSigned); while (EI != EIend && EI->first < Hi) EI++; - if (EI == EIend || EI->first != Hi) - Diag(RI->second->getRHS()->getExprLoc(), diag::warn_not_in_enum) - << CondTypeBeforePromotion; + if (EI == EIend || EI->first != Hi) { + Expr *CaseExpr = RI->second->getRHS(); + if (ShouldDiagnoseSwitchCaseNotInEnum(Context, ED, CaseExpr)) + Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum) + << CondTypeBeforePromotion; + } } // Check which enum vals aren't in switch diff --git a/test/Sema/switch.c b/test/Sema/switch.c index e37d5da259..a2f87b9d0a 100644 --- a/test/Sema/switch.c +++ b/test/Sema/switch.c @@ -349,3 +349,29 @@ void test19(int i) { break; } } + +// Allow the warning 'case value not in enumerated type' to be silenced with +// the following pattern. +// +// If 'case' expression refers to a static const variable of the correct enum +// type, then we count this as a sufficient declaration of intent by the user, +// so we silence the warning. +enum ExtendedEnum1 { + EE1_a, + EE1_b +}; + +enum ExtendedEnum1_unrelated { EE1_misc }; + +static const enum ExtendedEnum1 EE1_c = 100; +static const enum ExtendedEnum1_unrelated EE1_d = 101; + +void switch_on_ExtendedEnum1(enum ExtendedEnum1 e) { + switch(e) { + case EE1_a: break; + case EE1_b: break; + case EE1_c: break; // no-warning + case EE1_d: break; // expected-warning {{case value not in enumerated type 'enum ExtendedEnum1'}} + } +} +