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

llvm-svn: 287177
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 56bc3ac..c1db062 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -8518,6 +8518,24 @@
     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 @@
 
   // 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);