rnk updated this revision to Diff 91653.
rnk marked an inline comment as done.
rnk added a comment.

- Actually make this warning off by default


https://reviews.llvm.org/D30923

Files:
  include/clang/Basic/DiagnosticGroups.td
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaChecking.cpp
  test/SemaCXX/warn-bitfield-enum-conversion.cpp

Index: test/SemaCXX/warn-bitfield-enum-conversion.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/warn-bitfield-enum-conversion.cpp
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-msvc -verify %s -Wbitfield-enum-conversion
+
+enum TwoBits { Hi1 = 3 } two_bits;
+enum TwoBitsSigned { Lo2 = -2, Hi2 = 1 } two_bits_signed;
+enum ThreeBits { Hi3 = 7 } three_bits;
+enum ThreeBitsSigned { Lo4 = -4, Hi4 = 3 } three_bits_signed;
+enum TwoBitsFixed : unsigned { Hi5 = 3 } two_bits_fixed;
+
+struct Foo {
+  unsigned two_bits : 2;
+  int two_bits_signed : 2;
+  unsigned three_bits : 3;
+  int three_bits_signed : 3;
+
+  ThreeBits three_bits_enum : 3;
+};
+
+void f() {
+  Foo f;
+
+  f.two_bits = two_bits;
+  f.two_bits = two_bits_signed;            // expected-warning {{negative enumerators}}
+  f.two_bits = three_bits;                 // expected-warning {{not wide enough}}
+  f.two_bits = three_bits_signed;          // expected-warning {{negative enumerators}} expected-warning {{not wide enough}}
+  f.two_bits = two_bits_fixed;
+
+  f.two_bits_signed = two_bits;            // expected-warning {{needs an extra bit}}
+  f.two_bits_signed = two_bits_signed;
+  f.two_bits_signed = three_bits;          // expected-warning {{not wide enough}}
+  f.two_bits_signed = three_bits_signed;   // expected-warning {{not wide enough}}
+
+  f.three_bits = two_bits;
+  f.three_bits = two_bits_signed;          // expected-warning {{negative enumerators}}
+  f.three_bits = three_bits;
+  f.three_bits = three_bits_signed;        // expected-warning {{negative enumerators}}
+
+  f.three_bits_signed = two_bits;
+  f.three_bits_signed = two_bits_signed;
+  f.three_bits_signed = three_bits;        // expected-warning {{needs an extra bit}}
+  f.three_bits_signed = three_bits_signed;
+
+  f.three_bits_enum = three_bits;          // expected-warning {{needs an extra bit}}
+}
Index: lib/Sema/SemaChecking.cpp
===================================================================
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -8729,13 +8729,42 @@
     return false;
 
   Expr *OriginalInit = Init->IgnoreParenImpCasts();
+  unsigned FieldWidth = Bitfield->getBitWidthValue(S.Context);
 
   llvm::APSInt Value;
-  if (!OriginalInit->EvaluateAsInt(Value, S.Context, Expr::SE_AllowSideEffects))
+  if (!OriginalInit->EvaluateAsInt(Value, S.Context,
+                                   Expr::SE_AllowSideEffects)) {
+    // The RHS is not constant.  If the RHS has an enum type, make sure the
+    // bitfield is wide enough to hold all the values of the enum without
+    // truncation.
+    if (const auto *EnumTy = OriginalInit->getType()->getAs<EnumType>()) {
+      EnumDecl *ED = EnumTy->getDecl();
+      bool SignedBitfield = BitfieldType->isSignedIntegerType();
+
+      // Check if this might store negative values into an unsigned bitfield.
+      if (!SignedBitfield && ED->getNumNegativeBits() > 0) {
+        S.Diag(InitLoc, diag::warn_unsigned_bitfield_assigned_signed_enum)
+            << Bitfield << ED;
+      }
+
+      // Check for sufficient width.
+      if (ED->getNumPositiveBits() > FieldWidth ||
+          ED->getNumNegativeBits() > FieldWidth) {
+        S.Diag(InitLoc, diag::warn_bitfield_too_small_for_enum)
+            << Bitfield << ED;
+      } else if (SignedBitfield && ED->getNumPositiveBits() == FieldWidth) {
+        // If the bitfield type is signed and the positive field widths are
+        // equal, values with the high bit set will become negative, which is
+        // usually unintended.
+        S.Diag(InitLoc, diag::warn_signed_bitfield_enum_conversion)
+            << Bitfield << ED;
+      }
+    }
+
     return false;
+  }
 
   unsigned OriginalWidth = Value.getBitWidth();
-  unsigned FieldWidth = Bitfield->getBitWidthValue(S.Context);
 
   if (!Value.isSigned() || Value.isNegative())
     if (UnaryOperator *UO = dyn_cast<UnaryOperator>(OriginalInit))
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -4908,6 +4908,17 @@
 def warn_anon_bitfield_width_exceeds_type_width : Warning<
   "width of anonymous bit-field (%0 bits) exceeds width of its type; value "
   "will be truncated to %1 bit%s1">, InGroup<BitFieldWidth>;
+def warn_bitfield_too_small_for_enum: Warning<
+  "bit-field %0 is not wide enough to store all enumerators of enum type %1">,
+  InGroup<BitFieldEnumConversion>, DefaultIgnore;
+def warn_unsigned_bitfield_assigned_signed_enum: Warning<
+  "assigning value of signed enum type %1 to unsigned bit-field %0; "
+  "negative enumerators of enum %1 will be converted to positive values">,
+  InGroup<BitFieldEnumConversion>, DefaultIgnore;
+def warn_signed_bitfield_enum_conversion: Warning<
+  "signed bit-field %0 needs an extra bit to represent the largest positive "
+  "values of enum type %1">,
+  InGroup<BitFieldEnumConversion>, DefaultIgnore;
 
 def warn_missing_braces : Warning<
   "suggest braces around initialization of subobject">,
Index: include/clang/Basic/DiagnosticGroups.td
===================================================================
--- include/clang/Basic/DiagnosticGroups.td
+++ include/clang/Basic/DiagnosticGroups.td
@@ -34,6 +34,7 @@
 def GNUBinaryLiteral : DiagGroup<"gnu-binary-literal">;
 def GNUCompoundLiteralInitializer : DiagGroup<"gnu-compound-literal-initializer">;
 def BitFieldConstantConversion : DiagGroup<"bitfield-constant-conversion">;
+def BitFieldEnumConversion : DiagGroup<"bitfield-enum-conversion">;
 def BitFieldWidth : DiagGroup<"bitfield-width">;
 def ConstantConversion :
   DiagGroup<"constant-conversion", [ BitFieldConstantConversion ] >;
@@ -606,6 +607,7 @@
                            [BoolConversion,
                             ConstantConversion,
                             EnumConversion,
+                            BitFieldEnumConversion,
                             FloatConversion,
                             Shorten64To32,
                             IntConversion,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to