<div dir="ltr">I made the test pass in r264642 with a triple. We should deal with this properly at some point, though.</div><div class="gmail_extra"><br><div class="gmail_quote">On Sun, Mar 27, 2016 at 11:08 PM, Richard Smith via cfe-commits <span dir="ltr"><<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: rsmith<br>
Date: Mon Mar 28 01:08:37 2016<br>
New Revision: 264564<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=264564&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=264564&view=rev</a><br>
Log:<br>
P0138R2: Allow direct-list-initialization of an enumeration from an integral<br>
value that can convert to the enum's underlying type.<br>
<br>
Added:<br>
    cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3.cpp<br>
      - copied, changed from r264563, cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp<br>
Removed:<br>
    cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp<br>
Modified:<br>
    cfe/trunk/lib/Sema/SemaInit.cpp<br>
    cfe/trunk/lib/Sema/SemaOverload.cpp<br>
    cfe/trunk/www/cxx_status.html<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaInit.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=264564&r1=264563&r2=264564&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=264564&r1=264563&r2=264564&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaInit.cpp Mon Mar 28 01:08:37 2016<br>
@@ -3862,8 +3862,48 @@ static void TryListInitialization(Sema &<br>
   }<br>
<br>
   if (S.getLangOpts().CPlusPlus && !DestType->isAggregateType() &&<br>
-      InitList->getNumInits() == 1 &&<br>
-      InitList->getInit(0)->getType()->isRecordType()) {<br>
+      InitList->getNumInits() == 1) {<br>
+    Expr *E = InitList->getInit(0);<br>
+<br>
+    //   - Otherwise, if T is an enumeration with a fixed underlying type,<br>
+    //     the initializer-list has a single element v, and the initialization<br>
+    //     is direct-list-initialization, the object is initialized with the<br>
+    //     value T(v); if a narrowing conversion is required to convert v to<br>
+    //     the underlying type of T, the program is ill-formed.<br>
+    auto *ET = DestType->getAs<EnumType>();<br>
+    if (S.getLangOpts().CPlusPlus1z &&<br>
+        Kind.getKind() == InitializationKind::IK_DirectList &&<br>
+        ET && ET->getDecl()->isFixed() &&<br>
+        !S.Context.hasSameUnqualifiedType(E->getType(), DestType) &&<br>
+        (E->getType()->isIntegralOrEnumerationType() ||<br>
+         E->getType()->isFloatingType())) {<br>
+      // There are two ways that T(v) can work when T is an enumeration type.<br>
+      // If there is either an implicit conversion sequence from v to T or<br>
+      // a conversion function that can convert from v to T, then we use that.<br>
+      // Otherwise, if v is of integral, enumeration, or floating-point type,<br>
+      // it is converted to the enumeration type via its underlying type.<br>
+      // There is no overlap possible between these two cases (except when the<br>
+      // source value is already of the destination type), and the first<br>
+      // case is handled by the general case for single-element lists below.<br>
+      ImplicitConversionSequence ICS;<br>
+      ICS.setStandard();<br>
+      ICS.Standard.setAsIdentityConversion();<br>
+      // If E is of a floating-point type, then the conversion is ill-formed<br>
+      // due to narrowing, but go through the motions in order to produce the<br>
+      // right diagnostic.<br>
+      ICS.Standard.Second = E->getType()->isFloatingType()<br>
+                                ? ICK_Floating_Integral<br>
+                                : ICK_Integral_Conversion;<br>
+      ICS.Standard.setFromType(E->getType());<br>
+      ICS.Standard.setToType(0, E->getType());<br>
+      ICS.Standard.setToType(1, DestType);<br>
+      ICS.Standard.setToType(2, DestType);<br>
+      Sequence.AddConversionSequenceStep(ICS, ICS.Standard.getToType(2),<br>
+                                         /*TopLevelOfInitList*/true);<br>
+      Sequence.RewrapReferenceInitList(Entity.getType(), InitList);<br>
+      return;<br>
+    }<br>
+<br>
     //   - Otherwise, if the initializer list has a single element of type E<br>
     //     [...references are handled above...], the object or reference is<br>
     //     initialized from that element (by copy-initialization for<br>
@@ -3877,19 +3917,21 @@ static void TryListInitialization(Sema &<br>
     // copy-initialization. This only matters if we might use an 'explicit'<br>
     // conversion operator, so we only need to handle the cases where the source<br>
     // is of record type.<br>
-    InitializationKind SubKind =<br>
-        Kind.getKind() == InitializationKind::IK_DirectList<br>
-            ? InitializationKind::CreateDirect(Kind.getLocation(),<br>
-                                               InitList->getLBraceLoc(),<br>
-                                               InitList->getRBraceLoc())<br>
-            : Kind;<br>
-    Expr *SubInit[1] = { InitList->getInit(0) };<br>
-    Sequence.InitializeFrom(S, Entity, SubKind, SubInit,<br>
-                            /*TopLevelOfInitList*/true,<br>
-                            TreatUnavailableAsInvalid);<br>
-    if (Sequence)<br>
-      Sequence.RewrapReferenceInitList(Entity.getType(), InitList);<br>
-    return;<br>
+    if (InitList->getInit(0)->getType()->isRecordType()) {<br>
+      InitializationKind SubKind =<br>
+          Kind.getKind() == InitializationKind::IK_DirectList<br>
+              ? InitializationKind::CreateDirect(Kind.getLocation(),<br>
+                                                 InitList->getLBraceLoc(),<br>
+                                                 InitList->getRBraceLoc())<br>
+              : Kind;<br>
+      Expr *SubInit[1] = { InitList->getInit(0) };<br>
+      Sequence.InitializeFrom(S, Entity, SubKind, SubInit,<br>
+                              /*TopLevelOfInitList*/true,<br>
+                              TreatUnavailableAsInvalid);<br>
+      if (Sequence)<br>
+        Sequence.RewrapReferenceInitList(Entity.getType(), InitList);<br>
+      return;<br>
+    }<br>
   }<br>
<br>
   InitListChecker CheckInitList(S, Entity, InitList,<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=264564&r1=264563&r2=264564&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=264564&r1=264563&r2=264564&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Mon Mar 28 01:08:37 2016<br>
@@ -293,6 +293,13 @@ StandardConversionSequence::getNarrowing<br>
   //   A narrowing conversion is an implicit conversion ...<br>
   QualType FromType = getToType(0);<br>
   QualType ToType = getToType(1);<br>
+<br>
+  // A conversion to an enumeration type is narrowing if the conversion to<br>
+  // the underlying type is narrowing. This only arises for expressions of<br>
+  // the form 'Enum{init}'.<br>
+  if (auto *ET = ToType->getAs<EnumType>())<br>
+    ToType = ET->getDecl()->getIntegerType();<br>
+<br>
   switch (Second) {<br>
   // 'bool' is an integral type; dispatch to the right place to handle it.<br>
   case ICK_Boolean_Conversion:<br>
<br>
Removed: cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp?rev=264563&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp?rev=264563&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp (original)<br>
+++ cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp (removed)<br>
@@ -1,127 +0,0 @@<br>
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s<br>
-<br>
-namespace std {<br>
-  typedef decltype(sizeof(int)) size_t;<br>
-<br>
-  template <typename E><br>
-  struct initializer_list<br>
-  {<br>
-    const E *p;<br>
-    size_t n;<br>
-    initializer_list(const E *p, size_t n) : p(p), n(n) {}<br>
-  };<br>
-<br>
-  struct string {<br>
-    string(const char *);<br>
-  };<br>
-<br>
-  template<typename A, typename B><br>
-  struct pair {<br>
-    pair(const A&, const B&);<br>
-  };<br>
-}<br>
-<br>
-namespace bullet1 {<br>
-  double ad[] = { 1, 2.0 };<br>
-  int ai[] = { 1, 2.0 };  // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{silence}}<br>
-<br>
-  struct S2 {<br>
-    int m1;<br>
-    double m2, m3;<br>
-  };<br>
-<br>
-  S2 s21 = { 1, 2, 3.0 };<br>
-  S2 s22 { 1.0, 2, 3 };  // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{silence}}<br>
-  S2 s23 { };<br>
-}<br>
-<br>
-namespace bullet4_example1 {<br>
-  struct S {<br>
-    S(std::initializer_list<double> d) {}<br>
-    S(std::initializer_list<int> i) {}<br>
-    S() {}<br>
-  };<br>
-<br>
-  S s1 = { 1.0, 2.0, 3.0 };<br>
-  S s2 = { 1, 2, 3 };<br>
-  S s3 = { };<br>
-}<br>
-<br>
-namespace bullet4_example2 {<br>
-  struct Map {<br>
-    Map(std::initializer_list<std::pair<std::string,int>>) {}<br>
-  };<br>
-<br>
-  Map ship = {{"Sophie",14}, {"Surprise",28}};<br>
-}<br>
-<br>
-namespace bullet4_example3 {<br>
-  struct S {<br>
-    S(int, double, double) {}<br>
-    S() {}<br>
-  };<br>
-<br>
-  S s1 = { 1, 2, 3.0 };<br>
-  S s2 { 1.0, 2, 3 }; // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{silence}}<br>
-  S s3 {};<br>
-}<br>
-<br>
-namespace bullet5 {<br>
-  int x1 {2};<br>
-  int x2 {2.0};  // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{silence}}<br>
-}<br>
-<br>
-namespace bullet6 {<br>
-  struct S {<br>
-    S(std::initializer_list<double>) {}<br>
-    S(const std::string &) {}<br>
-  };<br>
-<br>
-  const S& r1 = { 1, 2, 3.0 };<br>
-  const S& r2 = { "Spinach" };<br>
-  S& r3 = { 1, 2, 3 };  // expected-error {{non-const lvalue reference to type 'bullet6::S' cannot bind to an initializer list temporary}}<br>
-  const int& i1 = { 1 };<br>
-  const int& i2 = { 1.1 };  // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{silence}} expected-warning {{implicit conversion}}<br>
-  const int (&iar)[2] = { 1, 2 };<br>
-}<br>
-<br>
-namespace bullet7 {<br>
-  int** pp {};<br>
-}<br>
-<br>
-namespace bullet8 {<br>
-  struct A { int i; int j; };<br>
-  A a1 { 1, 2 };<br>
-  A a2 { 1.2 };  // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{silence}} expected-warning {{implicit conversion}}<br>
-<br>
-  struct B {<br>
-    B(std::initializer_list<int> i) {}<br>
-  };<br>
-  B b1 { 1, 2 };<br>
-  B b2 { 1, 2.0 }; // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{silence}}<br>
-<br>
-  struct C {<br>
-    C(int i, double j) {}<br>
-  };<br>
-  C c1 = { 1, 2.2 };<br>
-  // FIXME: Suppress the narrowing warning in the cases where we issue a narrowing error.<br>
-  C c2 = { 1.1, 2 }; // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{silence}} expected-warning {{implicit conversion}}<br>
-<br>
-  int j { 1 };<br>
-  int k { };<br>
-}<br>
-<br>
-namespace rdar13395022 {<br>
-  struct MoveOnly { // expected-note {{candidate}}<br>
-    MoveOnly(MoveOnly&&); // expected-note 2{{copy constructor is implicitly deleted because}} expected-note {{candidate}}<br>
-  };<br>
-<br>
-  void test(MoveOnly mo) {<br>
-    auto &&list1 = {mo}; // expected-error {{call to implicitly-deleted copy constructor}} expected-note {{in initialization of temporary of type 'std::initializer_list}}<br>
-    MoveOnly (&&list2)[1] = {mo}; // expected-error {{call to implicitly-deleted copy constructor}} expected-note {{in initialization of temporary of type 'rdar13395022::MoveOnly [1]'}}<br>
-    std::initializer_list<MoveOnly> &&list3 = {};<br>
-    MoveOnly (&&list4)[1] = {}; // expected-error {{no matching constructor}}<br>
-    // expected-note@-1 {{in implicit initialization of array element 0 with omitted initializer}}<br>
-    // expected-note@-2 {{in initialization of temporary of type 'rdar13395022::MoveOnly [1]' created to list-initialize this reference}}<br>
-  }<br>
-}<br>
<br>
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)<br>
URL: <a href="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" rel="noreferrer" target="_blank">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</a><br>
==============================================================================<br>
--- cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp (original)<br>
+++ cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3.cpp Mon Mar 28 01:08:37 2016<br>
@@ -1,4 +1,6 @@<br>
 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s<br>
+// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify %s<br>
+// RUN: %clang_cc1 -std=c++1z -fsyntax-only -verify %s<br>
<br>
 namespace std {<br>
   typedef decltype(sizeof(int)) size_t;<br>
@@ -125,3 +127,128 @@ namespace rdar13395022 {<br>
     // expected-note@-2 {{in initialization of temporary of type 'rdar13395022::MoveOnly [1]' created to list-initialize this reference}}<br>
   }<br>
 }<br>
+<br>
+namespace cxx1z_direct_enum_init {<br>
+  enum A {};<br>
+  enum B : char {};<br>
+  enum class C {};<br>
+  enum class D : char {};<br>
+  enum class E : char { k = 5 };<br>
+<br>
+  template<typename T> void good() {<br>
+    (void)T{0};<br>
+    T t1{0};<br>
+    T t2 = T{0};<br>
+<br>
+    struct S { T t; };<br>
+    S s{T{0}};<br>
+<br>
+    struct U { T t{0}; } u; // expected-note 0+{{instantiation of}}<br>
+<br>
+    struct V { T t; V() : t{0} {} }; // expected-note 0+{{instantiation of}}<br>
+<br>
+    void f(T);<br>
+    f(T{0});<br>
+  }<br>
+#if __cplusplus <= 201402L<br>
+  // expected-error@-15 5{{cannot initialize}}<br>
+  // expected-error@-15 5{{cannot initialize}}<br>
+  // expected-error@-15 5{{cannot initialize}}<br>
+  //<br>
+  //<br>
+  // expected-error@-15 5{{cannot initialize}}<br>
+  //<br>
+  // expected-error@-15 5{{cannot initialize}}<br>
+  //<br>
+  // expected-error@-15 5{{cannot initialize}}<br>
+  //<br>
+  //<br>
+  // expected-error@-15 5{{cannot initialize}}<br>
+#else<br>
+  // expected-error@-29 {{cannot initialize}}<br>
+  // expected-error@-29 {{cannot initialize}}<br>
+  // expected-error@-29 {{cannot initialize}}<br>
+  //<br>
+  //<br>
+  // expected-error@-29 {{cannot initialize}}<br>
+  //<br>
+  // expected-error@-29 {{cannot initialize}}<br>
+  //<br>
+  // expected-error@-29 {{cannot initialize}}<br>
+  //<br>
+  //<br>
+  // expected-error@-29 {{cannot initialize}}<br>
+#endif<br>
+<br>
+  template<typename T> void bad() {<br>
+    T t = {0};<br>
+<br>
+    struct S { T t; };<br>
+    S s1{0};<br>
+    S s2{{0}};<br>
+<br>
+    struct U { T t = {0}; } u; // expected-note 0+{{instantiation of}}<br>
+<br>
+    struct V { T t; V() : t({0}) {} }; // expected-note 0+{{instantiation of}}<br>
+<br>
+    void f(T); // expected-note 0+{{passing argument}}<br>
+    f({0});<br>
+  }<br>
+  // expected-error@-13 5{{cannot initialize}}<br>
+  //<br>
+  //<br>
+  // expected-error@-13 5{{cannot initialize}}<br>
+  // expected-error@-13 5{{cannot initialize}}<br>
+  //<br>
+  // expected-error@-13 5{{cannot initialize}}<br>
+  //<br>
+  // expected-error@-13 5{{cannot initialize}}<br>
+  //<br>
+  //<br>
+  // expected-error@-13 5{{cannot initialize}}<br>
+<br>
+  template<typename T> void ugly() {<br>
+    extern char c;<br>
+    T t1{char('0' + c)};<br>
+    T t2{'0' + c};<br>
+    T t3{1234};<br>
+  }<br>
+#if __cplusplus <= 201402L<br>
+  // expected-error@-5 4{{cannot initialize}}<br>
+  // expected-error@-5 4{{cannot initialize}}<br>
+  // expected-error@-5 4{{cannot initialize}}<br>
+#else<br>
+  // expected-error@-8 3{{non-constant-expression cannot be narrowed}}<br>
+  // expected-error@-8 3{{constant expression evaluates to 1234 which cannot be narrowed}} expected-warning@-8 {{changes value}}<br>
+#endif<br>
+<br>
+  void test() {<br>
+    good<A>(); // expected-note 4{{instantiation of}}<br>
+    good<B>();<br>
+    good<C>();<br>
+    good<D>();<br>
+    good<E>();<br>
+#if __cplusplus <= 201402L<br>
+    // expected-note@-5 4{{instantiation of}}<br>
+    // expected-note@-5 4{{instantiation of}}<br>
+    // expected-note@-5 4{{instantiation of}}<br>
+    // expected-note@-5 4{{instantiation of}}<br>
+#endif<br>
+<br>
+    bad<A>(); // expected-note 4{{instantiation of}}<br>
+    bad<B>(); // expected-note 4{{instantiation of}}<br>
+    bad<C>(); // expected-note 4{{instantiation of}}<br>
+    bad<D>(); // expected-note 4{{instantiation of}}<br>
+    bad<E>(); // expected-note 4{{instantiation of}}<br>
+<br>
+    ugly<B>(); // expected-note {{instantiation of}}<br>
+    ugly<C>(); // ok<br>
+    ugly<D>(); // expected-note {{instantiation of}}<br>
+    ugly<E>(); // expected-note {{instantiation of}}<br>
+#if __cplusplus <= 201402L<br>
+    // expected-note@-4 {{instantiation of}}<br>
+#else<br>
+    (void)B{0.0}; // expected-error {{type 'double' cannot be narrowed}}<br>
+#endif<br>
+  }<br>
+}<br>
<br>
Modified: cfe/trunk/www/cxx_status.html<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=264564&r1=264563&r2=264564&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=264564&r1=264563&r2=264564&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/www/cxx_status.html (original)<br>
+++ cfe/trunk/www/cxx_status.html Mon Mar 28 01:08:37 2016<br>
@@ -664,7 +664,7 @@ as the draft C++1z standard evolves.</p><br>
     <tr><br>
       <td>Direct-list-initialization of <tt>enum</tt>s</td><br>
       <td><a href="<a href="http://wg21.link/p0138r2" rel="noreferrer" target="_blank">http://wg21.link/p0138r2</a>">P0138R2</a></td><br>
-      <td class="none" align="center">No</td><br>
+      <td class="svn" align="center">SVN</td><br>
     </tr><br>
     <tr><br>
       <td>Hexadecimal floating-point literals</td><br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>