]> granicus.if.org Git - clang/commitdiff
Implement C++11 [conv.prom]p4: an enumeration with a fixed underlying type has
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 13 Sep 2012 21:18:54 +0000 (21:18 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 13 Sep 2012 21:18:54 +0000 (21:18 +0000)
integral promotions to both its underlying type and to its underlying type's
promoted type. This matters now that boolean conversions aren't permitted in
converted constant expressions (a la DR1407): an enumerator with a fixed
underlying type of bool still can be.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@163841 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaOverload.cpp
test/CXX/conv/conv.prom/p4.cpp

index 4dca91db138d5cab8735d0678e0ef676ccd651cf..72701dd423388ec406d320245b879e909e7f6d55 100644 (file)
@@ -2593,8 +2593,16 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
 
   case ICK_Integral_Promotion:
   case ICK_Integral_Conversion:
-    From = ImpCastExprToType(From, ToType, CK_IntegralCast, 
-                             VK_RValue, /*BasePath=*/0, CCK).take();
+    if (ToType->isBooleanType()) {
+      assert(FromType->castAs<EnumType>()->getDecl()->isFixed() &&
+             SCS.Second == ICK_Integral_Promotion &&
+             "only enums with fixed underlying type can promote to bool");
+      From = ImpCastExprToType(From, ToType, CK_IntegralToBoolean,
+                               VK_RValue, /*BasePath=*/0, CCK).take();
+    } else {
+      From = ImpCastExprToType(From, ToType, CK_IntegralCast,
+                               VK_RValue, /*BasePath=*/0, CCK).take();
+    }
     break;
 
   case ICK_Floating_Promotion:
index b607ab63b4053dec95b038439c5b007973489ade..4d8795ea962f3cd1dcb08a189adf0b27e41b58cd 100644 (file)
@@ -1674,7 +1674,7 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) {
     return To->getKind() == BuiltinType::UInt;
   }
 
-  // C++0x [conv.prom]p3:
+  // C++11 [conv.prom]p3:
   //   A prvalue of an unscoped enumeration type whose underlying type is not
   //   fixed (7.2) can be converted to an rvalue a prvalue of the first of the
   //   following types that can represent all the values of the enumeration
@@ -1686,12 +1686,26 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) {
   //   with lowest integer conversion rank (4.13) greater than the rank of long
   //   long in which all the values of the enumeration can be represented. If
   //   there are two such extended types, the signed one is chosen.
+  // C++11 [conv.prom]p4:
+  //   A prvalue of an unscoped enumeration type whose underlying type is fixed
+  //   can be converted to a prvalue of its underlying type. Moreover, if
+  //   integral promotion can be applied to its underlying type, a prvalue of an
+  //   unscoped enumeration type whose underlying type is fixed can also be
+  //   converted to a prvalue of the promoted underlying type.
   if (const EnumType *FromEnumType = FromType->getAs<EnumType>()) {
     // C++0x 7.2p9: Note that this implicit enum to int conversion is not
     // provided for a scoped enumeration.
     if (FromEnumType->getDecl()->isScoped())
       return false;
 
+    // We can perform an integral promotion to the underlying type of the enum,
+    // even if that's not the promoted type.
+    if (FromEnumType->getDecl()->isFixed()) {
+      QualType Underlying = FromEnumType->getDecl()->getIntegerType();
+      return Context.hasSameUnqualifiedType(Underlying, ToType) ||
+             IsIntegralPromotion(From, Underlying, ToType);
+    }
+
     // We have already pre-calculated the promotion type, so this is trivial.
     if (ToType->isIntegerType() &&
         !RequireCompleteType(From->getLocStart(), FromType, 0))
index 02a91cd521b4fb97061e7f5b0e2538b23084fbfe..26aeee102e2ff3b141416a1ebbe31c0cf4a97b9e 100644 (file)
@@ -7,3 +7,20 @@ extern int x;
 enum Y : long { C, D };
 extern decltype(+C) y;
 extern long y;
+
+// An enum with a fixed underlying type has an integral promotion to that type,
+// and to its promoted type.
+enum B : bool { false_, true_ };
+template<bool> struct T {};
+T<false_> f;
+T<true_> t;
+T<+true_> t; // expected-error {{conversion from 'int' to 'bool'}}
+
+enum B2 : bool {
+  a = false,
+  b = true,
+  c = false_,
+  d = true_,
+  e = +false_ // expected-error {{conversion from 'int' to 'bool'}} \
+              // FIXME: expected-error {{enumerator value 2 is not representable}}
+};