r335925 - PR37979: integral promotions in C++ treat enum bit-fields like enums,

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Thu Jun 28 14:17:55 PDT 2018


Author: rsmith
Date: Thu Jun 28 14:17:55 2018
New Revision: 335925

URL: http://llvm.org/viewvc/llvm-project?rev=335925&view=rev
Log:
PR37979: integral promotions in C++ treat enum bit-fields like enums,
not like bit-fields.

We used to get this right "by accident", because conversions for the
selected built-in overloaded operator would convert the enum bit-field
to its corresponding underlying type early. But after DR1687 that no
longer happens.

Technically this change should also apply to C, where bit-fields only
have special promotion rules if the bit-field's declared type is
_Bool, int, signed int, or unsigned int, but for GCC compatibility we
only look at the bit-width and not the underlying type when performing
bit-field integral promotions in C.

Added:
    cfe/trunk/test/CXX/conv/conv.prom/p5.cpp
Modified:
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=335925&r1=335924&r2=335925&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Thu Jun 28 14:17:55 2018
@@ -5456,6 +5456,12 @@ QualType ASTContext::isPromotableBitFiel
   if (E->isTypeDependent() || E->isValueDependent())
     return {};
 
+  // C++ [conv.prom]p5:
+  //    If the bit-field has an enumerated type, it is treated as any other
+  //    value of that type for promotion purposes.
+  if (getLangOpts().CPlusPlus && E->getType()->isEnumeralType())
+    return {};
+
   // FIXME: We should not do this unless E->refersToBitField() is true. This
   // matters in C where getSourceBitField() will find bit-fields for various
   // cases where the source expression is not a bit-field designator.
@@ -5482,13 +5488,15 @@ QualType ASTContext::isPromotableBitFiel
   //
   // FIXME: C does not permit promotion of a 'long : 3' bitfield to int.
   //        We perform that promotion here to match GCC and C++.
+  // FIXME: C does not permit promotion of an enum bit-field whose rank is
+  //        greater than that of 'int'. We perform that promotion to match GCC.
   if (BitWidth < IntSize)
     return IntTy;
 
   if (BitWidth == IntSize)
     return FT->isSignedIntegerType() ? IntTy : UnsignedIntTy;
 
-  // Types bigger than int are not subject to promotions, and therefore act
+  // Bit-fields wider than int are not subject to promotions, and therefore act
   // like the base type. GCC has some weird bugs in this area that we
   // deliberately do not follow (GCC follows a pre-standard resolution to
   // C's DR315 which treats bit-width as being part of the type, and this leaks

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=335925&r1=335924&r2=335925&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Thu Jun 28 14:17:55 2018
@@ -2007,6 +2007,14 @@ bool Sema::IsIntegralPromotion(Expr *Fro
         isCompleteType(From->getLocStart(), FromType))
       return Context.hasSameUnqualifiedType(
           ToType, FromEnumType->getDecl()->getPromotionType());
+
+    // C++ [conv.prom]p5:
+    //   If the bit-field has an enumerated type, it is treated as any other
+    //   value of that type for promotion purposes.
+    //
+    // ... so do not fall through into the bit-field checks below in C++.
+    if (getLangOpts().CPlusPlus)
+      return false;
   }
 
   // C++0x [conv.prom]p2:
@@ -2054,6 +2062,11 @@ bool Sema::IsIntegralPromotion(Expr *Fro
   // other value of that type for promotion purposes (C++ 4.5p3).
   // FIXME: We should delay checking of bit-fields until we actually perform the
   // conversion.
+  //
+  // FIXME: In C, only bit-fields of types _Bool, int, or unsigned int may be
+  // promoted, per C11 6.3.1.1/2. We promote all bit-fields (including enum
+  // bit-fields and those whose underlying type is larger than int) for GCC
+  // compatibility.
   if (From) {
     if (FieldDecl *MemberDecl = From->getSourceBitField()) {
       llvm::APSInt BitWidth;

Added: cfe/trunk/test/CXX/conv/conv.prom/p5.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/conv/conv.prom/p5.cpp?rev=335925&view=auto
==============================================================================
--- cfe/trunk/test/CXX/conv/conv.prom/p5.cpp (added)
+++ cfe/trunk/test/CXX/conv/conv.prom/p5.cpp Thu Jun 28 14:17:55 2018
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -verify %s
+// expected-no-diagnostics
+
+// A prvalue for an integral bit-field can be converted to a prvalue of type
+// int if int can represent all the values of the bit-field
+struct X { long long e : 1; };
+static_assert(sizeof(+X().e) == sizeof(int), "");
+static_assert(sizeof(X().e + 1) == sizeof(int), "");
+static_assert(sizeof(true ? X().e : 0) == sizeof(int), "");
+
+enum E { a = __LONG_LONG_MAX__ };
+static_assert(sizeof(E{}) == sizeof(long long), "");
+
+// If the bit-field has an enumerated type, it is treated as any other value of
+// that [enumerated] type for promotion purposes.
+struct Y { E e : 1; };
+static_assert(sizeof(+Y().e) == sizeof(long long), "");
+static_assert(sizeof(Y().e + 1) == sizeof(long long), "");
+static_assert(sizeof(true ? Y().e : 0) == sizeof(long long), "");




More information about the cfe-commits mailing list