summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/AST/ASTContext.cpp10
-rw-r--r--clang/lib/Sema/SemaOverload.cpp13
-rw-r--r--clang/test/CXX/conv/conv.prom/p5.cpp19
3 files changed, 41 insertions, 1 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 43577e8640a..ca54d8f6759 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/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/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index e9d2eb6cc5c..6f01f19fc51 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/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/clang/test/CXX/conv/conv.prom/p5.cpp b/clang/test/CXX/conv/conv.prom/p5.cpp
new file mode 100644
index 00000000000..baf51374c8c
--- /dev/null
+++ b/clang/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), "");
OpenPOWER on IntegriCloud