r264564 - P0138R2: Allow direct-list-initialization of an enumeration from an integral

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Sun Mar 27 23:08:38 PDT 2016


Author: rsmith
Date: Mon Mar 28 01:08:37 2016
New Revision: 264564

URL: http://llvm.org/viewvc/llvm-project?rev=264564&view=rev
Log:
P0138R2: Allow direct-list-initialization of an enumeration from an integral
value that can convert to the enum's underlying type.

Added:
    cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3.cpp
      - copied, changed from r264563, cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp
Removed:
    cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp
Modified:
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/www/cxx_status.html

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=264564&r1=264563&r2=264564&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Mon Mar 28 01:08:37 2016
@@ -3862,8 +3862,48 @@ static void TryListInitialization(Sema &
   }
 
   if (S.getLangOpts().CPlusPlus && !DestType->isAggregateType() &&
-      InitList->getNumInits() == 1 &&
-      InitList->getInit(0)->getType()->isRecordType()) {
+      InitList->getNumInits() == 1) {
+    Expr *E = InitList->getInit(0);
+
+    //   - Otherwise, if T is an enumeration with a fixed underlying type,
+    //     the initializer-list has a single element v, and the initialization
+    //     is direct-list-initialization, the object is initialized with the
+    //     value T(v); if a narrowing conversion is required to convert v to
+    //     the underlying type of T, the program is ill-formed.
+    auto *ET = DestType->getAs<EnumType>();
+    if (S.getLangOpts().CPlusPlus1z &&
+        Kind.getKind() == InitializationKind::IK_DirectList &&
+        ET && ET->getDecl()->isFixed() &&
+        !S.Context.hasSameUnqualifiedType(E->getType(), DestType) &&
+        (E->getType()->isIntegralOrEnumerationType() ||
+         E->getType()->isFloatingType())) {
+      // There are two ways that T(v) can work when T is an enumeration type.
+      // If there is either an implicit conversion sequence from v to T or
+      // a conversion function that can convert from v to T, then we use that.
+      // Otherwise, if v is of integral, enumeration, or floating-point type,
+      // it is converted to the enumeration type via its underlying type.
+      // There is no overlap possible between these two cases (except when the
+      // source value is already of the destination type), and the first
+      // case is handled by the general case for single-element lists below.
+      ImplicitConversionSequence ICS;
+      ICS.setStandard();
+      ICS.Standard.setAsIdentityConversion();
+      // If E is of a floating-point type, then the conversion is ill-formed
+      // due to narrowing, but go through the motions in order to produce the
+      // right diagnostic.
+      ICS.Standard.Second = E->getType()->isFloatingType()
+                                ? ICK_Floating_Integral
+                                : ICK_Integral_Conversion;
+      ICS.Standard.setFromType(E->getType());
+      ICS.Standard.setToType(0, E->getType());
+      ICS.Standard.setToType(1, DestType);
+      ICS.Standard.setToType(2, DestType);
+      Sequence.AddConversionSequenceStep(ICS, ICS.Standard.getToType(2),
+                                         /*TopLevelOfInitList*/true);
+      Sequence.RewrapReferenceInitList(Entity.getType(), InitList);
+      return;
+    }
+
     //   - Otherwise, if the initializer list has a single element of type E
     //     [...references are handled above...], the object or reference is
     //     initialized from that element (by copy-initialization for
@@ -3877,19 +3917,21 @@ static void TryListInitialization(Sema &
     // copy-initialization. This only matters if we might use an 'explicit'
     // conversion operator, so we only need to handle the cases where the source
     // is of record type.
-    InitializationKind SubKind =
-        Kind.getKind() == InitializationKind::IK_DirectList
-            ? InitializationKind::CreateDirect(Kind.getLocation(),
-                                               InitList->getLBraceLoc(),
-                                               InitList->getRBraceLoc())
-            : Kind;
-    Expr *SubInit[1] = { InitList->getInit(0) };
-    Sequence.InitializeFrom(S, Entity, SubKind, SubInit,
-                            /*TopLevelOfInitList*/true,
-                            TreatUnavailableAsInvalid);
-    if (Sequence)
-      Sequence.RewrapReferenceInitList(Entity.getType(), InitList);
-    return;
+    if (InitList->getInit(0)->getType()->isRecordType()) {
+      InitializationKind SubKind =
+          Kind.getKind() == InitializationKind::IK_DirectList
+              ? InitializationKind::CreateDirect(Kind.getLocation(),
+                                                 InitList->getLBraceLoc(),
+                                                 InitList->getRBraceLoc())
+              : Kind;
+      Expr *SubInit[1] = { InitList->getInit(0) };
+      Sequence.InitializeFrom(S, Entity, SubKind, SubInit,
+                              /*TopLevelOfInitList*/true,
+                              TreatUnavailableAsInvalid);
+      if (Sequence)
+        Sequence.RewrapReferenceInitList(Entity.getType(), InitList);
+      return;
+    }
   }
 
   InitListChecker CheckInitList(S, Entity, InitList,

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=264564&r1=264563&r2=264564&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Mon Mar 28 01:08:37 2016
@@ -293,6 +293,13 @@ StandardConversionSequence::getNarrowing
   //   A narrowing conversion is an implicit conversion ...
   QualType FromType = getToType(0);
   QualType ToType = getToType(1);
+
+  // A conversion to an enumeration type is narrowing if the conversion to
+  // the underlying type is narrowing. This only arises for expressions of
+  // the form 'Enum{init}'.
+  if (auto *ET = ToType->getAs<EnumType>())
+    ToType = ET->getDecl()->getIntegerType();
+
   switch (Second) {
   // 'bool' is an integral type; dispatch to the right place to handle it.
   case ICK_Boolean_Conversion:

Removed: cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp?rev=264563&view=auto
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp (original)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp (removed)
@@ -1,127 +0,0 @@
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
-
-namespace std {
-  typedef decltype(sizeof(int)) size_t;
-
-  template <typename E>
-  struct initializer_list
-  {
-    const E *p;
-    size_t n;
-    initializer_list(const E *p, size_t n) : p(p), n(n) {}
-  };
-
-  struct string {
-    string(const char *);
-  };
-
-  template<typename A, typename B>
-  struct pair {
-    pair(const A&, const B&);
-  };
-}
-
-namespace bullet1 {
-  double ad[] = { 1, 2.0 };
-  int ai[] = { 1, 2.0 };  // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{silence}}
-
-  struct S2 {
-    int m1;
-    double m2, m3;
-  };
-
-  S2 s21 = { 1, 2, 3.0 };
-  S2 s22 { 1.0, 2, 3 };  // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{silence}}
-  S2 s23 { };
-}
-
-namespace bullet4_example1 {
-  struct S {
-    S(std::initializer_list<double> d) {}
-    S(std::initializer_list<int> i) {}
-    S() {}
-  };
-
-  S s1 = { 1.0, 2.0, 3.0 };
-  S s2 = { 1, 2, 3 };
-  S s3 = { };
-}
-
-namespace bullet4_example2 {
-  struct Map {
-    Map(std::initializer_list<std::pair<std::string,int>>) {}
-  };
-
-  Map ship = {{"Sophie",14}, {"Surprise",28}};
-}
-
-namespace bullet4_example3 {
-  struct S {
-    S(int, double, double) {}
-    S() {}
-  };
-
-  S s1 = { 1, 2, 3.0 };
-  S s2 { 1.0, 2, 3 }; // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{silence}}
-  S s3 {};
-}
-
-namespace bullet5 {
-  int x1 {2};
-  int x2 {2.0};  // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{silence}}
-}
-
-namespace bullet6 {
-  struct S {
-    S(std::initializer_list<double>) {}
-    S(const std::string &) {}
-  };
-
-  const S& r1 = { 1, 2, 3.0 };
-  const S& r2 = { "Spinach" };
-  S& r3 = { 1, 2, 3 };  // expected-error {{non-const lvalue reference to type 'bullet6::S' cannot bind to an initializer list temporary}}
-  const int& i1 = { 1 };
-  const int& i2 = { 1.1 };  // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{silence}} expected-warning {{implicit conversion}}
-  const int (&iar)[2] = { 1, 2 };
-}
-
-namespace bullet7 {
-  int** pp {};
-}
-
-namespace bullet8 {
-  struct A { int i; int j; };
-  A a1 { 1, 2 };
-  A a2 { 1.2 };  // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{silence}} expected-warning {{implicit conversion}}
-
-  struct B {
-    B(std::initializer_list<int> i) {}
-  };
-  B b1 { 1, 2 };
-  B b2 { 1, 2.0 }; // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{silence}}
-
-  struct C {
-    C(int i, double j) {}
-  };
-  C c1 = { 1, 2.2 };
-  // FIXME: Suppress the narrowing warning in the cases where we issue a narrowing error.
-  C c2 = { 1.1, 2 }; // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{silence}} expected-warning {{implicit conversion}}
-
-  int j { 1 };
-  int k { };
-}
-
-namespace rdar13395022 {
-  struct MoveOnly { // expected-note {{candidate}}
-    MoveOnly(MoveOnly&&); // expected-note 2{{copy constructor is implicitly deleted because}} expected-note {{candidate}}
-  };
-
-  void test(MoveOnly mo) {
-    auto &&list1 = {mo}; // expected-error {{call to implicitly-deleted copy constructor}} expected-note {{in initialization of temporary of type 'std::initializer_list}}
-    MoveOnly (&&list2)[1] = {mo}; // expected-error {{call to implicitly-deleted copy constructor}} expected-note {{in initialization of temporary of type 'rdar13395022::MoveOnly [1]'}}
-    std::initializer_list<MoveOnly> &&list3 = {};
-    MoveOnly (&&list4)[1] = {}; // expected-error {{no matching constructor}}
-    // expected-note at -1 {{in implicit initialization of array element 0 with omitted initializer}}
-    // expected-note at -2 {{in initialization of temporary of type 'rdar13395022::MoveOnly [1]' created to list-initialize this reference}}
-  }
-}

Copied: cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3.cpp (from r264563, cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3.cpp?p2=cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3.cpp&p1=cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp&r1=264563&r2=264564&rev=264564&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp (original)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3.cpp Mon Mar 28 01:08:37 2016
@@ -1,4 +1,6 @@
 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++1z -fsyntax-only -verify %s
 
 namespace std {
   typedef decltype(sizeof(int)) size_t;
@@ -125,3 +127,128 @@ namespace rdar13395022 {
     // expected-note at -2 {{in initialization of temporary of type 'rdar13395022::MoveOnly [1]' created to list-initialize this reference}}
   }
 }
+
+namespace cxx1z_direct_enum_init {
+  enum A {};
+  enum B : char {};
+  enum class C {};
+  enum class D : char {};
+  enum class E : char { k = 5 };
+
+  template<typename T> void good() {
+    (void)T{0};
+    T t1{0};
+    T t2 = T{0};
+
+    struct S { T t; };
+    S s{T{0}};
+
+    struct U { T t{0}; } u; // expected-note 0+{{instantiation of}}
+
+    struct V { T t; V() : t{0} {} }; // expected-note 0+{{instantiation of}}
+
+    void f(T);
+    f(T{0});
+  }
+#if __cplusplus <= 201402L
+  // expected-error at -15 5{{cannot initialize}}
+  // expected-error at -15 5{{cannot initialize}}
+  // expected-error at -15 5{{cannot initialize}}
+  //
+  //
+  // expected-error at -15 5{{cannot initialize}}
+  //
+  // expected-error at -15 5{{cannot initialize}}
+  //
+  // expected-error at -15 5{{cannot initialize}}
+  //
+  //
+  // expected-error at -15 5{{cannot initialize}}
+#else
+  // expected-error at -29 {{cannot initialize}}
+  // expected-error at -29 {{cannot initialize}}
+  // expected-error at -29 {{cannot initialize}}
+  //
+  //
+  // expected-error at -29 {{cannot initialize}}
+  //
+  // expected-error at -29 {{cannot initialize}}
+  //
+  // expected-error at -29 {{cannot initialize}}
+  //
+  //
+  // expected-error at -29 {{cannot initialize}}
+#endif
+
+  template<typename T> void bad() {
+    T t = {0};
+
+    struct S { T t; };
+    S s1{0};
+    S s2{{0}};
+
+    struct U { T t = {0}; } u; // expected-note 0+{{instantiation of}}
+
+    struct V { T t; V() : t({0}) {} }; // expected-note 0+{{instantiation of}}
+
+    void f(T); // expected-note 0+{{passing argument}}
+    f({0});
+  }
+  // expected-error at -13 5{{cannot initialize}}
+  //
+  //
+  // expected-error at -13 5{{cannot initialize}}
+  // expected-error at -13 5{{cannot initialize}}
+  //
+  // expected-error at -13 5{{cannot initialize}}
+  //
+  // expected-error at -13 5{{cannot initialize}}
+  //
+  //
+  // expected-error at -13 5{{cannot initialize}}
+
+  template<typename T> void ugly() {
+    extern char c;
+    T t1{char('0' + c)};
+    T t2{'0' + c};
+    T t3{1234};
+  }
+#if __cplusplus <= 201402L
+  // expected-error at -5 4{{cannot initialize}}
+  // expected-error at -5 4{{cannot initialize}}
+  // expected-error at -5 4{{cannot initialize}}
+#else
+  // expected-error at -8 3{{non-constant-expression cannot be narrowed}}
+  // expected-error at -8 3{{constant expression evaluates to 1234 which cannot be narrowed}} expected-warning at -8 {{changes value}}
+#endif
+
+  void test() {
+    good<A>(); // expected-note 4{{instantiation of}}
+    good<B>();
+    good<C>();
+    good<D>();
+    good<E>();
+#if __cplusplus <= 201402L
+    // expected-note at -5 4{{instantiation of}}
+    // expected-note at -5 4{{instantiation of}}
+    // expected-note at -5 4{{instantiation of}}
+    // expected-note at -5 4{{instantiation of}}
+#endif
+
+    bad<A>(); // expected-note 4{{instantiation of}}
+    bad<B>(); // expected-note 4{{instantiation of}}
+    bad<C>(); // expected-note 4{{instantiation of}}
+    bad<D>(); // expected-note 4{{instantiation of}}
+    bad<E>(); // expected-note 4{{instantiation of}}
+
+    ugly<B>(); // expected-note {{instantiation of}}
+    ugly<C>(); // ok
+    ugly<D>(); // expected-note {{instantiation of}}
+    ugly<E>(); // expected-note {{instantiation of}}
+#if __cplusplus <= 201402L
+    // expected-note at -4 {{instantiation of}}
+#else
+    (void)B{0.0}; // expected-error {{type 'double' cannot be narrowed}}
+#endif
+  }
+}

Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=264564&r1=264563&r2=264564&view=diff
==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Mon Mar 28 01:08:37 2016
@@ -664,7 +664,7 @@ as the draft C++1z standard evolves.</p>
     <tr>
       <td>Direct-list-initialization of <tt>enum</tt>s</td>
       <td><a href="http://wg21.link/p0138r2">P0138R2</a></td>
-      <td class="none" align="center">No</td>
+      <td class="svn" align="center">SVN</td>
     </tr>
     <tr>
       <td>Hexadecimal floating-point literals</td>




More information about the cfe-commits mailing list