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

Reply via email to