r287177 - Add warning when assigning enums to bitfields without an explicit unsigned underlying type

Reid Kleckner via cfe-commits cfe-commits at lists.llvm.org
Wed Nov 16 15:40:00 PST 2016


Author: rnk
Date: Wed Nov 16 17:40:00 2016
New Revision: 287177

URL: http://llvm.org/viewvc/llvm-project?rev=287177&view=rev
Log:
Add warning when assigning enums to bitfields without an explicit unsigned underlying type

Summary:
Add a warning when assigning enums to bitfields without an explicit
unsigned underlying type. This is to prevent problems with MSVC
compatibility, since the Microsoft ABI defaults to storing enums with a
signed type, causing inconsistencies with saving to/reading from
bitfields.

Also disabled the warning in the dr0xx.cpp test which throws the error,
and added a test for the warning.

The warning can be disabled with -Wno-signed-enum-bitfield.

Patch by Sasha Bermeister!

Reviewers: rnk, aaron.ballman

Subscribers: mehdi_amini, aaron.ballman, cfe-commits, thakis, dcheng

Differential Revision: https://reviews.llvm.org/D24289

Added:
    cfe/trunk/test/SemaCXX/warn-msvc-enum-bitfield.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticGroups.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/SemaChecking.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=287177&r1=287176&r2=287177&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Wed Nov 16 17:40:00 2016
@@ -543,6 +543,7 @@ def GCCWriteStrings : DiagGroup<"write-s
 def CharSubscript : DiagGroup<"char-subscripts">;
 def LargeByValueCopy : DiagGroup<"large-by-value-copy">;
 def DuplicateArgDecl : DiagGroup<"duplicate-method-arg">;
+def SignedEnumBitfield : DiagGroup<"signed-enum-bitfield">;
 
 // Unreachable code warning groups.
 //
@@ -661,6 +662,7 @@ def Most : DiagGroup<"most", [
     ReturnType,
     SelfAssignment,
     SelfMove,
+    SignedEnumBitfield,
     SizeofArrayArgument,
     SizeofArrayDecay,
     StringPlusInt,

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=287177&r1=287176&r2=287177&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Nov 16 17:40:00 2016
@@ -3020,6 +3020,10 @@ def warn_int_to_void_pointer_cast : Warn
   "cast to %1 from smaller integer type %0">,
   InGroup<IntToVoidPointerCast>;
 
+def warn_no_underlying_type_specified_for_enum_bitfield : Warning<
+  "enums in the Microsoft ABI are signed integers by default; consider giving "
+  "the enum %0 an unsigned underlying type to make this code portable">,
+  InGroup<DiagGroup<"signed-enum-bitfield">>, DefaultIgnore;
 def warn_attribute_packed_for_bitfield : Warning<
   "'packed' attribute was ignored on bit-fields with single-byte alignment "
   "in older versions of GCC and Clang">,

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=287177&r1=287176&r2=287177&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Wed Nov 16 17:40:00 2016
@@ -8518,6 +8518,24 @@ bool AnalyzeBitFieldAssignment(Sema &S,
     return false;
 
   // White-list bool bitfields.
+  QualType BitfieldType = Bitfield->getType();
+  if (BitfieldType->isBooleanType())
+     return false;
+
+  if (BitfieldType->isEnumeralType()) {
+    EnumDecl *BitfieldEnumDecl = BitfieldType->getAs<EnumType>()->getDecl();
+    // If the underlying enum type was not explicitly specified as an unsigned
+    // type and the enum contain only positive values, MSVC++ will cause an
+    // inconsistency by storing this as a signed type.
+    if (S.getLangOpts().CPlusPlus11 &&
+        !BitfieldEnumDecl->getIntegerTypeSourceInfo() &&
+        BitfieldEnumDecl->getNumPositiveBits() > 0 &&
+        BitfieldEnumDecl->getNumNegativeBits() == 0) {
+      S.Diag(InitLoc, diag::warn_no_underlying_type_specified_for_enum_bitfield)
+        << BitfieldEnumDecl->getNameAsString();
+    }
+  }
+
   if (Bitfield->getType()->isBooleanType())
     return false;
 
@@ -8547,7 +8565,7 @@ bool AnalyzeBitFieldAssignment(Sema &S,
 
   // Compute the value which the bitfield will contain.
   llvm::APSInt TruncatedValue = Value.trunc(FieldWidth);
-  TruncatedValue.setIsSigned(Bitfield->getType()->isSignedIntegerType());
+  TruncatedValue.setIsSigned(BitfieldType->isSignedIntegerType());
 
   // Check whether the stored value is equal to the original value.
   TruncatedValue = TruncatedValue.extend(OriginalWidth);

Added: cfe/trunk/test/SemaCXX/warn-msvc-enum-bitfield.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-msvc-enum-bitfield.cpp?rev=287177&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/warn-msvc-enum-bitfield.cpp (added)
+++ cfe/trunk/test/SemaCXX/warn-msvc-enum-bitfield.cpp Wed Nov 16 17:40:00 2016
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -fsyntax-only -Wsigned-enum-bitfield -verify %s --std=c++11
+
+// Enums used in bitfields with no explicitly specified underlying type.
+void test0() {
+  enum E { E1, E2 };
+  enum F { F1, F2 };
+  struct { E e1 : 1; E e2; F f1 : 1; F f2; } s;
+
+  s.e1 = E1; // expected-warning {{enums in the Microsoft ABI are signed integers by default; consider giving the enum E an unsigned underlying type to make this code portable}}
+  s.f1 = F1; // expected-warning {{enums in the Microsoft ABI are signed integers by default; consider giving the enum F an unsigned underlying type to make this code portable}}
+
+  s.e2 = E2;
+  s.f2 = F2;
+}
+
+// Enums used in bitfields with an explicit signed underlying type.
+void test1() {
+  enum E : signed { E1, E2 };
+  enum F : long { F1, F2 };
+  struct { E e1 : 1; E e2; F f1 : 1; F f2; } s;
+
+  s.e1 = E1;
+  s.f1 = F1;
+
+  s.e2 = E2;
+  s.f2 = F2;
+}
+
+// Enums used in bitfields with an explicitly unsigned underlying type.
+void test3() {
+  enum E : unsigned { E1, E2 };
+  enum F : unsigned long { F1, F2 };
+  struct { E e1 : 1; E e2; F f1 : 1; F f2; } s;
+
+  s.e1 = E1;
+  s.f1 = F1;
+
+  s.e2 = E2;
+  s.f2 = F2;
+}




More information about the cfe-commits mailing list