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; +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits