Index: lib/Sema/SemaStmt.cpp =================================================================== --- lib/Sema/SemaStmt.cpp +++ lib/Sema/SemaStmt.cpp @@ -659,6 +659,29 @@ 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 @@ 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 @@ 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 @@ 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 Index: test/Sema/switch.c =================================================================== --- test/Sema/switch.c +++ test/Sema/switch.c @@ -349,3 +349,29 @@ 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'}} + } +} +