rnkovacs created this revision. `-Wenum-compare` warns if two values with different enumeration types are compared in expressions with binary operators. This patch extends this diagnostic so that comparisons of mixed enumeration types are recognized in switch statements as well.
Example: enum MixedA { A1, A2, A3 }; enum MixedB { B1, B2, B3 }; void MixedEnums(MixedA a) { switch (a) { case A1: break; // OK, same enum types. case B1: break; // Warn, different enum types. } } https://reviews.llvm.org/D36407 Files: lib/Sema/SemaStmt.cpp test/Sema/switch.c test/SemaCXX/warn-enum-compare.cpp Index: test/SemaCXX/warn-enum-compare.cpp =================================================================== --- test/SemaCXX/warn-enum-compare.cpp +++ test/SemaCXX/warn-enum-compare.cpp @@ -209,4 +209,21 @@ while (getBar() > x); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}} while (getBar() < x); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}} + switch (a) { + case name1::F1: break; + case name1::F3: break; + case name2::B2: break; // expected-warning {{comparison of two values with different enumeration types ('name1::Foo' and 'name2::Baz')}} + } + + switch (x) { + case FooB: break; + case FooC: break; + case BarD: break; // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}} + } + + switch(getBar()) { + case BarE: break; + case BarF: break; + case FooA: break; // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}} + } } Index: test/Sema/switch.c =================================================================== --- test/Sema/switch.c +++ test/Sema/switch.c @@ -372,6 +372,7 @@ case EE1_b: break; case EE1_c: break; // no-warning case EE1_d: break; // expected-warning {{case value not in enumerated type 'enum ExtendedEnum1'}} + // expected-warning@-1 {{comparison of two values with different enumeration types ('enum ExtendedEnum1' and 'const enum ExtendedEnum1_unrelated')}} } } Index: lib/Sema/SemaStmt.cpp =================================================================== --- lib/Sema/SemaStmt.cpp +++ lib/Sema/SemaStmt.cpp @@ -743,6 +743,24 @@ return true; } +static void checkEnumTypesInSwitchStmt(Sema &S, Expr *Cond, Expr *Case) { + QualType CondType = GetTypeBeforeIntegralPromotion(Cond); + QualType CaseType = Case->getType(); + + const EnumType *CondEnumType = CondType->getAs<EnumType>(); + const EnumType *CaseEnumType = CaseType->getAs<EnumType>(); + if (!CondEnumType || !CaseEnumType) + return; + + if (S.Context.hasSameUnqualifiedType(CondType, CaseType)) + return; + + SourceLocation Loc = Case->getExprLoc(); + S.Diag(Loc, diag::warn_comparison_of_mixed_enum_types) + << CondType << CaseType << Cond->getSourceRange() + << Case->getSourceRange(); +} + StmtResult Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, Stmt *BodyStmt) { @@ -843,6 +861,8 @@ break; } + checkEnumTypesInSwitchStmt(*this, CondExpr, Lo); + llvm::APSInt LoVal; if (getLangOpts().CPlusPlus11) {
Index: test/SemaCXX/warn-enum-compare.cpp =================================================================== --- test/SemaCXX/warn-enum-compare.cpp +++ test/SemaCXX/warn-enum-compare.cpp @@ -209,4 +209,21 @@ while (getBar() > x); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}} while (getBar() < x); // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}} + switch (a) { + case name1::F1: break; + case name1::F3: break; + case name2::B2: break; // expected-warning {{comparison of two values with different enumeration types ('name1::Foo' and 'name2::Baz')}} + } + + switch (x) { + case FooB: break; + case FooC: break; + case BarD: break; // expected-warning {{comparison of two values with different enumeration types ('Foo' and 'Bar')}} + } + + switch(getBar()) { + case BarE: break; + case BarF: break; + case FooA: break; // expected-warning {{comparison of two values with different enumeration types ('Bar' and 'Foo')}} + } } Index: test/Sema/switch.c =================================================================== --- test/Sema/switch.c +++ test/Sema/switch.c @@ -372,6 +372,7 @@ case EE1_b: break; case EE1_c: break; // no-warning case EE1_d: break; // expected-warning {{case value not in enumerated type 'enum ExtendedEnum1'}} + // expected-warning@-1 {{comparison of two values with different enumeration types ('enum ExtendedEnum1' and 'const enum ExtendedEnum1_unrelated')}} } } Index: lib/Sema/SemaStmt.cpp =================================================================== --- lib/Sema/SemaStmt.cpp +++ lib/Sema/SemaStmt.cpp @@ -743,6 +743,24 @@ return true; } +static void checkEnumTypesInSwitchStmt(Sema &S, Expr *Cond, Expr *Case) { + QualType CondType = GetTypeBeforeIntegralPromotion(Cond); + QualType CaseType = Case->getType(); + + const EnumType *CondEnumType = CondType->getAs<EnumType>(); + const EnumType *CaseEnumType = CaseType->getAs<EnumType>(); + if (!CondEnumType || !CaseEnumType) + return; + + if (S.Context.hasSameUnqualifiedType(CondType, CaseType)) + return; + + SourceLocation Loc = Case->getExprLoc(); + S.Diag(Loc, diag::warn_comparison_of_mixed_enum_types) + << CondType << CaseType << Cond->getSourceRange() + << Case->getSourceRange(); +} + StmtResult Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, Stmt *BodyStmt) { @@ -843,6 +861,8 @@ break; } + checkEnumTypesInSwitchStmt(*this, CondExpr, Lo); + llvm::APSInt LoVal; if (getLangOpts().CPlusPlus11) {
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits