From: Richard Smith Date: Thu, 28 Jun 2018 21:17:55 +0000 (+0000) Subject: PR37979: integral promotions in C++ treat enum bit-fields like enums, X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ff6b0ecacdfc5a066f35b140db832b02082f9731;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@335925 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 43577e8640..ca54d8f675 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -5456,6 +5456,12 @@ QualType ASTContext::isPromotableBitField(Expr *E) const { 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::isPromotableBitField(Expr *E) const { // // 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 diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index e9d2eb6cc5..6f01f19fc5 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -2007,6 +2007,14 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) { 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 *From, QualType FromType, QualType ToType) { // 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; diff --git a/test/CXX/conv/conv.prom/p5.cpp b/test/CXX/conv/conv.prom/p5.cpp new file mode 100644 index 0000000000..baf51374c8 --- /dev/null +++ b/test/CXX/conv/conv.prom/p5.cpp @@ -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), "");