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

Reid Kleckner via cfe-commits cfe-commits at lists.llvm.org
Mon Mar 28 13:20:01 PDT 2016


I made the test pass in r264642 with a triple. We should deal with this
properly at some point, though.

On Sun, Mar 27, 2016 at 11:08 PM, Richard Smith via cfe-commits <
cfe-commits at lists.llvm.org> wrote:

> 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>
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20160328/ad7d55e9/attachment-0001.html>


More information about the cfe-commits mailing list