Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -2956,6 +2956,10 @@ "cast to %1 from smaller integer type %0">, InGroup; +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">, + InGroup>; 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">, Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -7828,6 +7828,24 @@ return false; // White-list bool bitfields. + QualType BitfieldType = Bitfield->getType(); + if (BitfieldType->isBooleanType()) + return false; + + if (BitfieldType->isEnumeralType()) { + EnumDecl *BitfieldEnumDecl = BitfieldType->getAs()->getDecl(); + // If the underlying integer type was not explicitly stated in the source + // code, 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; @@ -7858,7 +7876,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); Index: test/CXX/drs/dr0xx.cpp =================================================================== --- test/CXX/drs/dr0xx.cpp +++ test/CXX/drs/dr0xx.cpp @@ -1,7 +1,7 @@ -// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -Wno-bind-to-temporary-copy -// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -triple %itanium_abi_triple -// RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -triple %itanium_abi_triple -// RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -triple %itanium_abi_triple +// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -Wno-signed-enum-bitfield -Wno-bind-to-temporary-copy +// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -Wno-signed-enum-bitfield -triple %itanium_abi_triple +// RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -Wno-signed-enum-bitfield -triple %itanium_abi_triple +// RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -Wno-signed-enum-bitfield -triple %itanium_abi_triple namespace dr1 { // dr1: no namespace X { extern "C" void dr1_f(int a = 1); } Index: test/SemaCXX/warn-msvc-enum-bitfield.cpp =================================================================== --- test/SemaCXX/warn-msvc-enum-bitfield.cpp +++ test/SemaCXX/warn-msvc-enum-bitfield.cpp @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -fsyntax-only -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}} + s.f1 = F1; // expected-warning {{enums in the Microsoft ABI are signed integers by default; consider giving the enum F an unsigned underlying type}} + + 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; +}