diff mbox

[C++] Implement P0138R2, C++17 construction rules for enum class values

Message ID 20160923171433.GU7282@tucnak.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek Sept. 23, 2016, 5:14 p.m. UTC
Hi!

The following patch implements direct enum initialization as per C++17.
The change in reshape_init is needed for when it is called from
check_initializer and finish_compound_literal for e.g. E e { 5 } and
E { 5 } respectively, while the convert_for_assignment spot handles all the
other cases, which don't go through reshape_init, but on the other side
reshape_init strips away the CONSTRUCTOR needed to determine when to do this
and when not.

Bootstrapped/regtested on x86_64-linux and i686-linux, additionally
regtested on both with make -C gcc check-c++-all.  Ok for trunk?

2016-09-23  Jakub Jelinek  <jakub@redhat.com>

	Implement P0138R2, C++17 construction rules for enum class values
	* cp-tree.h (is_direct_enum_init): Declare.
	* decl.c (is_direct_enum_init): New function.
	(reshape_init): Use it.
	* typeck.c (convert_for_assignment): Likewise.

	* g++.dg/cpp1z/direct-enum-init1.C: New test.


	Jakub

Comments

Jason Merrill Sept. 23, 2016, 5:35 p.m. UTC | #1
OK.

On Fri, Sep 23, 2016 at 1:14 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> Hi!
>
> The following patch implements direct enum initialization as per C++17.
> The change in reshape_init is needed for when it is called from
> check_initializer and finish_compound_literal for e.g. E e { 5 } and
> E { 5 } respectively, while the convert_for_assignment spot handles all the
> other cases, which don't go through reshape_init, but on the other side
> reshape_init strips away the CONSTRUCTOR needed to determine when to do this
> and when not.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, additionally
> regtested on both with make -C gcc check-c++-all.  Ok for trunk?
>
> 2016-09-23  Jakub Jelinek  <jakub@redhat.com>
>
>         Implement P0138R2, C++17 construction rules for enum class values
>         * cp-tree.h (is_direct_enum_init): Declare.
>         * decl.c (is_direct_enum_init): New function.
>         (reshape_init): Use it.
>         * typeck.c (convert_for_assignment): Likewise.
>
>         * g++.dg/cpp1z/direct-enum-init1.C: New test.
>
> --- gcc/cp/cp-tree.h.jj 2016-09-23 09:32:09.440454087 +0200
> +++ gcc/cp/cp-tree.h    2016-09-23 12:28:47.559905330 +0200
> @@ -5829,6 +5829,7 @@ extern tree check_elaborated_type_specif
>  extern void warn_extern_redeclared_static      (tree, tree);
>  extern tree cxx_comdat_group                   (tree);
>  extern bool cp_missing_noreturn_ok_p           (tree);
> +extern bool is_direct_enum_init                        (tree, tree);
>  extern void initialize_artificial_var          (tree, vec<constructor_elt, va_gc> *);
>  extern tree check_var_type                     (tree, tree);
>  extern tree reshape_init                        (tree, tree, tsubst_flags_t);
> --- gcc/cp/decl.c.jj    2016-09-23 09:33:36.770328046 +0200
> +++ gcc/cp/decl.c       2016-09-23 12:28:47.563905279 +0200
> @@ -5581,6 +5581,22 @@ next_initializable_field (tree field)
>    return field;
>  }
>
> +/* Return true for [dcl.init.list] direct-list-initialization from
> +   single element of enumeration with a fixed underlying type.  */
> +
> +bool
> +is_direct_enum_init (tree type, tree init)
> +{
> +  if (cxx_dialect >= cxx1z
> +      && TREE_CODE (type) == ENUMERAL_TYPE
> +      && ENUM_FIXED_UNDERLYING_TYPE_P (type)
> +      && TREE_CODE (init) == CONSTRUCTOR
> +      && CONSTRUCTOR_IS_DIRECT_INIT (init)
> +      && CONSTRUCTOR_NELTS (init) == 1)
> +    return true;
> +  return false;
> +}
> +
>  /* Subroutine of reshape_init_array and reshape_init_vector, which does
>     the actual work. ELT_TYPE is the element type of the array. MAX_INDEX is an
>     INTEGER_CST representing the size of the array minus one (the maximum index),
> @@ -6026,6 +6042,17 @@ reshape_init (tree type, tree init, tsub
>    if (vec_safe_is_empty (v))
>      return init;
>
> +  /* Handle [dcl.init.list] direct-list-initialization from
> +     single element of enumeration with a fixed underlying type.  */
> +  if (is_direct_enum_init (type, init))
> +    {
> +      tree elt = CONSTRUCTOR_ELT (init, 0)->value;
> +      if (check_narrowing (ENUM_UNDERLYING_TYPE (type), elt, complain))
> +       return cp_build_c_cast (type, elt, tf_warning_or_error);
> +      else
> +       return error_mark_node;
> +    }
> +
>    /* Recurse on this CONSTRUCTOR.  */
>    d.cur = &(*v)[0];
>    d.end = d.cur + v->length ();
> --- gcc/cp/typeck.c.jj  2016-09-14 23:49:03.000000000 +0200
> +++ gcc/cp/typeck.c     2016-09-23 13:35:23.369149388 +0200
> @@ -8266,6 +8266,17 @@ convert_for_assignment (tree type, tree
>    if (TREE_CODE (rhs) == NON_LVALUE_EXPR)
>      rhs = TREE_OPERAND (rhs, 0);
>
> +  /* Handle [dcl.init.list] direct-list-initialization from
> +     single element of enumeration with a fixed underlying type.  */
> +  if (is_direct_enum_init (type, rhs))
> +    {
> +      tree elt = CONSTRUCTOR_ELT (rhs, 0)->value;
> +      if (check_narrowing (ENUM_UNDERLYING_TYPE (type), elt, complain))
> +       rhs = cp_build_c_cast (type, elt, complain);
> +      else
> +       rhs = error_mark_node;
> +    }
> +
>    rhstype = TREE_TYPE (rhs);
>    coder = TREE_CODE (rhstype);
>
> --- gcc/testsuite/g++.dg/cpp1z/direct-enum-init1.C.jj   2016-09-23 12:28:47.565905254 +0200
> +++ gcc/testsuite/g++.dg/cpp1z/direct-enum-init1.C      2016-09-23 16:37:49.596043501 +0200
> @@ -0,0 +1,237 @@
> +// P0138R2 - direct-list-initialization of enums
> +// { dg-do compile { target c++11 } }
> +
> +enum A { G = 26 };
> +enum B : short {};
> +enum class C {};
> +enum struct D : long {};
> +enum class E : unsigned char { e = 7 };
> +struct S { operator C () { return C (s); } int s; } s;
> +struct T { operator long () { return t; } long t; } t;
> +struct V { E v; };
> +long l;
> +long long ll;
> +short c;
> +void bar (E);
> +
> +void
> +foo ()
> +{
> +  A a1 { 5 };          // { dg-error "invalid conversion from 'int' to 'A'" }
> +  B b1 { 7 };          // { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
> +  C c1 { s };
> +  D d1 { D(t) };       // { dg-error "invalid cast from type 'T' to type 'D'" }
> +  D d2 { t };          // { dg-error "cannot convert 'T' to 'D' in initialization" "" { target c++14_down } }
> +                       // { dg-error "invalid cast from type 'T' to type 'D'" "" { target c++1z } .-1 }
> +  D d3 { 9 };          // { dg-error "cannot convert 'int' to 'D' in initialization" "" { target c++14_down } }
> +  D d4 { l };          // { dg-error "cannot convert 'long int' to 'D' in initialization" "" { target c++14_down } }
> +  D d5 { D(l) };
> +  D d6 { G };          // { dg-error "cannot convert 'A' to 'D' in initialization" "" { target c++14_down } }
> +  E e1 { 5 };          // { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
> +  E e2 { -1 };         // { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
> +                       // { dg-error "narrowing conversion of '-1' from 'int' to 'unsigned char' inside" "" { target c++1z } .-1 }
> +  E e3 { 5.0 };                // { dg-error "cannot convert 'double' to 'E' in initialization" "" { target c++14_down } }
> +                       // { dg-error "narrowing conversion of '5.0e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
> +  E e4 { 5.2 };                // { dg-error "cannot convert 'double' to 'E' in initialization" "" { target c++14_down } }
> +                       // { dg-error "narrowing conversion of '5.\[0-9]*e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
> +  B b2 = { 7 };                // { dg-error "invalid conversion from 'int' to 'B'" }
> +  C c2 = { C { 8 } };  // { dg-error "cannot convert 'int' to 'C' in initialization" "" { target c++14_down } }
> +
> +  D *d7 = new D { 9 }; // { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" "" { target c++14_down } }
> +  E *e5 = new E { -4 };        // { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target c++14_down } }
> +                       // { dg-error "narrowing conversion of '-4' from 'int' to 'unsigned char' inside" "" { target c++1z } .-1 }
> +  bar ({ 10 });                // { dg-error "cannot convert \[^\n\r]* to 'E' for argument" }
> +  bar (E { 9 });       // { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
> +  V v1 = { { 11 } };   // { dg-error "braces around scalar initializer for type 'E'" }
> +  V v2 = { E { 12 } }; // { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
> +  V v3 = { E { 5.0 } };        // { dg-error "cannot convert 'double' to 'E' in initialization" "" { target c++14_down } }
> +                       // { dg-error "narrowing conversion of '5.0e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
> +  V v4 = { 13 };       // { dg-error "cannot convert 'int' to 'E' in initialization" }
> +  if (B b3 { 5 })      // { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
> +    ;
> +  if (B b4 { 4.0 })    // { dg-error "cannot convert 'double' to 'B' in initialization" "" { target c++14_down } }
> +    ;                  // { dg-error "narrowing conversion of '4.0e.0' from 'double' to 'short int' inside" "" { target c++1z } .-1 }
> +  C c3 { 8L };         // { dg-error "cannot convert 'long int' to 'C' in initialization" "" { target c++14_down } }
> +  B b4 {short (c + 5)};        // { dg-error "invalid conversion from 'short int' to 'B'" "" { target c++14_down } }
> +  B b5 {c + 5};                // { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
> +                       // { dg-error "narrowing conversion of \[^\n\r]* from 'int' to 'short int' inside" "" { target c++1z } .-1 }
> +  C c4 { ll };         // { dg-error "cannot convert 'long long int' to 'C' in initialization" "" { target c++14_down } }
> +                       // { dg-error "narrowing conversion of 'll' from 'long long int' to 'int' inside" "" { target c++1z } .-1 }
> +  C c5 {short (c + 5)};        // { dg-error "cannot convert 'short int' to 'C' in initialization" "" { target c++14_down } }
> +  C c6 {c + 5};                // { dg-error "cannot convert 'int' to 'C' in initialization" "" { target c++14_down } }
> +}
> +
> +struct U
> +{
> +  U () : e { 5 } {}    // { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target c++14_down } }
> +  U (int) : e { 5.0 } {}// { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target c++14_down } }
> +                       // { dg-error "narrowing conversion of '5.0e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
> +  U (float) : e({ 6 }) {}// { dg-error "list-initializer for non-class type must not be parenthesized" }
> +                       // { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target *-*-* } .-1 }
> +  E e;
> +};
> +
> +struct W
> +{
> +  A a { 5 };           // { dg-error "invalid conversion from 'int' to 'A'" }
> +  B b { 6 };           // { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
> +  C c { 3.0f };                // { dg-error "cannot convert \[^\n\r]* to 'C' in initialization" "" { target c++14_down } }
> +                       // { dg-error "narrowing conversion of '3.0e.0f' from 'float' to 'int' inside" "" { target c++1z } .-1 }
> +  D d = { 7 };         // { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" }
> +};
> +
> +template <int N>
> +void
> +foo2 ()
> +{
> +  A a1 { 5 };          // { dg-error "invalid conversion from 'int' to 'A'" }
> +  B b1 { 7 };          // { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
> +  C c1 { s };
> +  D d1 { D(t) };       // { dg-error "invalid cast from type 'T' to type 'D'" }
> +  D d2 { t };          // { dg-error "cannot convert 'T' to 'D' in initialization" "" { target c++14_down } }
> +                       // { dg-error "invalid cast from type 'T' to type 'D'" "" { target c++1z } .-1 }
> +  D d3 { 9 };          // { dg-error "cannot convert 'int' to 'D' in initialization" "" { target c++14_down } }
> +  D d4 { l };          // { dg-error "cannot convert 'long int' to 'D' in initialization" "" { target c++14_down } }
> +  D d5 { D(l) };
> +  D d6 { G };          // { dg-error "cannot convert 'A' to 'D' in initialization" "" { target c++14_down } }
> +  E e1 { 5 };          // { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
> +  E e2 { -1 };         // { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
> +                       // { dg-error "narrowing conversion of '-1' from 'int' to 'unsigned char' inside" "" { target c++1z } .-1 }
> +  E e3 { 5.0 };                // { dg-error "cannot convert 'double' to 'E' in initialization" "" { target c++14_down } }
> +                       // { dg-error "narrowing conversion of '5.0e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
> +  E e4 { 5.2 };                // { dg-error "cannot convert 'double' to 'E' in initialization" "" { target c++14_down } }
> +                       // { dg-error "narrowing conversion of '5.\[0-9]*e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
> +  B b2 = { 7 };                // { dg-error "invalid conversion from 'int' to 'B'" }
> +  C c2 = { C { 8 } };  // { dg-error "cannot convert 'int' to 'C' in initialization" "" { target c++14_down } }
> +  D *d7 = new D { 9 }; // { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" "" { target c++14_down } }
> +  E *e5 = new E { -4 };        // { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target c++14_down } }
> +                       // { dg-error "narrowing conversion of '-4' from 'int' to 'unsigned char' inside" "" { target c++1z } .-1 }
> +  bar ({ 10 });                // { dg-error "cannot convert \[^\n\r]* to 'E' for argument" }
> +  bar (E { 9 });       // { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
> +  V v1 = { { 11 } };   // { dg-error "braces around scalar initializer for type 'E'" }
> +  V v2 = { E { 12 } }; // { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
> +  V v3 = { E { 5.0 } };        // { dg-error "cannot convert 'double' to 'E' in initialization" "" { target c++14_down } }
> +                       // { dg-error "narrowing conversion of '5.0e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
> +  V v4 = { 13 };       // { dg-error "cannot convert 'int' to 'E' in initialization" }
> +  if (B b3 { 5 })      // { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
> +    ;
> +  if (B b4 { 4.0 })    // { dg-error "cannot convert 'double' to 'B' in initialization" "" { target c++14_down } }
> +    ;                  // { dg-error "narrowing conversion of '4.0e.0' from 'double' to 'short int' inside" "" { target c++1z } .-1 }
> +  C c3 { 8L };         // { dg-error "cannot convert 'long int' to 'C' in initialization" "" { target c++14_down } }
> +  B b4 {short (c + 5)};        // { dg-error "invalid conversion from 'short int' to 'B'" "" { target c++14_down } }
> +  B b5 {c + 5};                // { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
> +                       // { dg-error "narrowing conversion of \[^\n\r]* from 'int' to 'short int' inside" "" { target c++1z } .-1 }
> +  C c4 { ll };         // { dg-error "cannot convert 'long long int' to 'C' in initialization" "" { target c++14_down } }
> +                       // { dg-error "narrowing conversion of 'll' from 'long long int' to 'int' inside" "" { target c++1z } .-1 }
> +  C c5 {short (c + 5)};        // { dg-error "cannot convert 'short int' to 'C' in initialization" "" { target c++14_down } }
> +  C c6 {c + 5};                // { dg-error "cannot convert 'int' to 'C' in initialization" "" { target c++14_down } }
> +}
> +
> +template <int N>
> +struct U2
> +{
> +  U2 () : e { 5 } {}   // { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target c++14_down } }
> +  U2 (int) : e { 5.0 } {}// { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target c++14_down } }
> +                       // { dg-error "narrowing conversion of '5.0e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
> +  U2 (float) : e({ 6 }) {}
> +  E e;
> +};
> +
> +template <int N>
> +struct W2
> +{
> +  A a { 5 };           // { dg-error "invalid conversion from 'int' to 'A'" "" { target *-*-* } .-2 }
> +  B b { 6 };           // { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } .-3 }
> +  C c { 3.0f };                // { dg-error "cannot convert \[^\n\r]* to 'C' in initialization" "" { target c++14_down } .-4 }
> +                       // { dg-error "narrowing conversion of '3.0e.0f' from 'float' to 'int' inside" "" { target c++1z } .-5 }
> +  D d = { 7 };         // { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" "" { target *-*-* } .-6 }
> +};
> +
> +template <typename H, typename I, typename J, typename K, typename L, typename M>
> +void
> +foo3 ()
> +{
> +  void bar3 (L);
> +  H a1 { 5 };          // { dg-error "invalid conversion from 'int' to 'A'" }
> +  I b1 { 7 };          // { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
> +  J c1 { s };
> +  K d1 { K(t) };       // { dg-error "invalid cast from type 'T' to type 'D'" }
> +  K d2 { t };          // { dg-error "cannot convert 'T' to 'D' in initialization" "" { target c++14_down } }
> +                       // { dg-error "invalid cast from type 'T' to type 'D'" "" { target c++1z } .-1 }
> +  K d3 { 9 };          // { dg-error "cannot convert 'int' to 'D' in initialization" "" { target c++14_down } }
> +  K d4 { l };          // { dg-error "cannot convert 'long int' to 'D' in initialization" "" { target c++14_down } }
> +  K d5 { K(l) };
> +  K d6 { G };          // { dg-error "cannot convert 'A' to 'D' in initialization" "" { target c++14_down } }
> +  L e1 { 5 };          // { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
> +  L e2 { -1 };         // { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
> +                       // { dg-error "narrowing conversion of '-1' from 'int' to 'unsigned char' inside" "" { target c++1z } .-1 }
> +  L e3 { 5.0 };                // { dg-error "cannot convert 'double' to 'E' in initialization" "" { target c++14_down } }
> +                       // { dg-error "narrowing conversion of '5.0e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
> +  L e4 { 5.2 };                // { dg-error "cannot convert 'double' to 'E' in initialization" "" { target c++14_down } }
> +                       // { dg-error "narrowing conversion of '5.\[0-9]*e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
> +  I b2 = { 7 };                // { dg-error "invalid conversion from 'int' to 'B'" }
> +  J c2 = { J { 8 } };  // { dg-error "cannot convert 'int' to 'C' in initialization" "" { target c++14_down } }
> +  K *d7 = new K { 9 }; // { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" "" { target c++14_down } }
> +  L *e5 = new L { -4 };        // { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target c++14_down } }
> +                       // { dg-error "narrowing conversion of '-4' from 'int' to 'unsigned char' inside" "" { target c++1z } .-1 }
> +  bar3 ({ 10 });       // { dg-error "cannot convert \[^\n\r]* to 'E' for argument" }
> +  bar3 (E { 9 });      // { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
> +  M v1 = { { 11 } };   // { dg-error "braces around scalar initializer for type 'E'" }
> +  M v2 = { L { 12 } }; // { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
> +  M v3 = { L { 5.0 } };        // { dg-error "cannot convert 'double' to 'E' in initialization" "" { target c++14_down } }
> +                       // { dg-error "narrowing conversion of '5.0e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
> +  M v4 = { 13 };       // { dg-error "cannot convert 'int' to 'E' in initialization" }
> +  if (I b3 { 5 })      // { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
> +    ;
> +  if (I b4 { 4.0 })    // { dg-error "cannot convert 'double' to 'B' in initialization" "" { target c++14_down } }
> +    ;                  // { dg-error "narrowing conversion of '4.0e.0' from 'double' to 'short int' inside" "" { target c++1z } .-1 }
> +  J c3 { 8L };         // { dg-error "cannot convert 'long int' to 'C' in initialization" "" { target c++14_down } }
> +  I b4 {short (c + 5)};        // { dg-error "invalid conversion from 'short int' to 'B'" "" { target c++14_down } }
> +  I b5 {c + 5};                // { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
> +                       // { dg-error "narrowing conversion of \[^\n\r]* from 'int' to 'short int' inside" "" { target c++1z } .-1 }
> +  J c4 { ll };         // { dg-error "cannot convert 'long long int' to 'C' in initialization" "" { target c++14_down } }
> +                       // { dg-error "narrowing conversion of 'll' from 'long long int' to 'int' inside" "" { target c++1z } .-1 }
> +  J c5 {short (c + 5)};        // { dg-error "cannot convert 'short int' to 'C' in initialization" "" { target c++14_down } }
> +  J c6 {c + 5};                // { dg-error "cannot convert 'int' to 'C' in initialization" "" { target c++14_down } }
> +}
> +
> +template <typename L>
> +struct U3
> +{
> +  U3 () : e { 5 } {}   // { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target c++14_down } }
> +  U3 (int) : e { 5.0 } {}// { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target c++14_down } }
> +                       // { dg-error "narrowing conversion of '5.0e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
> +  U3 (float) : e({ 6 }) {}
> +  L e;
> +};
> +
> +template <typename H, typename I, typename J, typename K>
> +struct W3
> +{
> +  H a { 5 };           // { dg-error "invalid conversion from 'int' to 'A'" "" { target *-*-* } .-2 }
> +  I b { 6 };           // { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } .-3 }
> +  J c { 3.0f };                // { dg-error "cannot convert \[^\n\r]* to 'C' in initialization" "" { target c++14_down } .-4 }
> +                       // { dg-error "narrowing conversion of '3.0e.0f' from 'float' to 'int' inside" "" { target c++1z } .-5 }
> +  K d = { 7 };         // { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" "" { target *-*-* } .-6 }
> +};
> +
> +void
> +test ()
> +{
> +  foo2<0> ();
> +  U2<0> u20;
> +  U2<1> u21 (5);
> +  W2<0> w2;            // { dg-error "invalid conversion from 'int' to 'A'" }
> +                       // { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } .-1 }
> +                       // { dg-error "cannot convert \[^\n\r]* to 'C' in initialization" "" { target c++14_down } .-2 }
> +                       // { dg-error "narrowing conversion of '3.0e.0f' from 'float' to 'int' inside" "" { target c++1z } .-3 }
> +                       // { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" "" { target *-*-* } .-4 }
> +  foo3<A, B, C, D, E, V> ();
> +  U3<E> u30;
> +  U3<E> u31 (5);
> +  W3<A, B, C, D> w3;   // { dg-error "invalid conversion from 'int' to 'A'" }
> +                       // { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } .-1 }
> +                       // { dg-error "cannot convert \[^\n\r]* to 'C' in initialization" "" { target c++14_down } .-2 }
> +                       // { dg-error "narrowing conversion of '3.0e.0f' from 'float' to 'int' inside" "" { target c++1z } .-3 }
> +                       // { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" "" { target *-*-* } .-4 }
> +}
>
>         Jakub
diff mbox

Patch

--- gcc/cp/cp-tree.h.jj	2016-09-23 09:32:09.440454087 +0200
+++ gcc/cp/cp-tree.h	2016-09-23 12:28:47.559905330 +0200
@@ -5829,6 +5829,7 @@  extern tree check_elaborated_type_specif
 extern void warn_extern_redeclared_static	(tree, tree);
 extern tree cxx_comdat_group			(tree);
 extern bool cp_missing_noreturn_ok_p		(tree);
+extern bool is_direct_enum_init			(tree, tree);
 extern void initialize_artificial_var		(tree, vec<constructor_elt, va_gc> *);
 extern tree check_var_type			(tree, tree);
 extern tree reshape_init                        (tree, tree, tsubst_flags_t);
--- gcc/cp/decl.c.jj	2016-09-23 09:33:36.770328046 +0200
+++ gcc/cp/decl.c	2016-09-23 12:28:47.563905279 +0200
@@ -5581,6 +5581,22 @@  next_initializable_field (tree field)
   return field;
 }
 
+/* Return true for [dcl.init.list] direct-list-initialization from
+   single element of enumeration with a fixed underlying type.  */
+
+bool
+is_direct_enum_init (tree type, tree init)
+{
+  if (cxx_dialect >= cxx1z
+      && TREE_CODE (type) == ENUMERAL_TYPE
+      && ENUM_FIXED_UNDERLYING_TYPE_P (type)
+      && TREE_CODE (init) == CONSTRUCTOR
+      && CONSTRUCTOR_IS_DIRECT_INIT (init)
+      && CONSTRUCTOR_NELTS (init) == 1)
+    return true;
+  return false;
+}
+
 /* Subroutine of reshape_init_array and reshape_init_vector, which does
    the actual work. ELT_TYPE is the element type of the array. MAX_INDEX is an
    INTEGER_CST representing the size of the array minus one (the maximum index),
@@ -6026,6 +6042,17 @@  reshape_init (tree type, tree init, tsub
   if (vec_safe_is_empty (v))
     return init;
 
+  /* Handle [dcl.init.list] direct-list-initialization from
+     single element of enumeration with a fixed underlying type.  */
+  if (is_direct_enum_init (type, init))
+    {
+      tree elt = CONSTRUCTOR_ELT (init, 0)->value;
+      if (check_narrowing (ENUM_UNDERLYING_TYPE (type), elt, complain))
+	return cp_build_c_cast (type, elt, tf_warning_or_error);
+      else
+	return error_mark_node;
+    }
+
   /* Recurse on this CONSTRUCTOR.  */
   d.cur = &(*v)[0];
   d.end = d.cur + v->length ();
--- gcc/cp/typeck.c.jj	2016-09-14 23:49:03.000000000 +0200
+++ gcc/cp/typeck.c	2016-09-23 13:35:23.369149388 +0200
@@ -8266,6 +8266,17 @@  convert_for_assignment (tree type, tree
   if (TREE_CODE (rhs) == NON_LVALUE_EXPR)
     rhs = TREE_OPERAND (rhs, 0);
 
+  /* Handle [dcl.init.list] direct-list-initialization from
+     single element of enumeration with a fixed underlying type.  */
+  if (is_direct_enum_init (type, rhs))
+    {
+      tree elt = CONSTRUCTOR_ELT (rhs, 0)->value;
+      if (check_narrowing (ENUM_UNDERLYING_TYPE (type), elt, complain))
+	rhs = cp_build_c_cast (type, elt, complain);
+      else
+	rhs = error_mark_node;
+    }
+
   rhstype = TREE_TYPE (rhs);
   coder = TREE_CODE (rhstype);
 
--- gcc/testsuite/g++.dg/cpp1z/direct-enum-init1.C.jj	2016-09-23 12:28:47.565905254 +0200
+++ gcc/testsuite/g++.dg/cpp1z/direct-enum-init1.C	2016-09-23 16:37:49.596043501 +0200
@@ -0,0 +1,237 @@ 
+// P0138R2 - direct-list-initialization of enums
+// { dg-do compile { target c++11 } }
+
+enum A { G = 26 };
+enum B : short {};
+enum class C {};
+enum struct D : long {};
+enum class E : unsigned char { e = 7 };
+struct S { operator C () { return C (s); } int s; } s;
+struct T { operator long () { return t; } long t; } t;
+struct V { E v; };
+long l;
+long long ll;
+short c;
+void bar (E);
+
+void
+foo ()
+{
+  A a1 { 5 };		// { dg-error "invalid conversion from 'int' to 'A'" }
+  B b1 { 7 };		// { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
+  C c1 { s };
+  D d1 { D(t) };	// { dg-error "invalid cast from type 'T' to type 'D'" }
+  D d2 { t };		// { dg-error "cannot convert 'T' to 'D' in initialization" "" { target c++14_down } }
+			// { dg-error "invalid cast from type 'T' to type 'D'" "" { target c++1z } .-1 }
+  D d3 { 9 };		// { dg-error "cannot convert 'int' to 'D' in initialization" "" { target c++14_down } }
+  D d4 { l };		// { dg-error "cannot convert 'long int' to 'D' in initialization" "" { target c++14_down } }
+  D d5 { D(l) };
+  D d6 { G };		// { dg-error "cannot convert 'A' to 'D' in initialization" "" { target c++14_down } }
+  E e1 { 5 };		// { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
+  E e2 { -1 };		// { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
+			// { dg-error "narrowing conversion of '-1' from 'int' to 'unsigned char' inside" "" { target c++1z } .-1 }
+  E e3 { 5.0 };		// { dg-error "cannot convert 'double' to 'E' in initialization" "" { target c++14_down } }
+			// { dg-error "narrowing conversion of '5.0e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
+  E e4 { 5.2 };		// { dg-error "cannot convert 'double' to 'E' in initialization" "" { target c++14_down } }
+			// { dg-error "narrowing conversion of '5.\[0-9]*e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
+  B b2 = { 7 };		// { dg-error "invalid conversion from 'int' to 'B'" }
+  C c2 = { C { 8 } };	// { dg-error "cannot convert 'int' to 'C' in initialization" "" { target c++14_down } }
+
+  D *d7 = new D { 9 };	// { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" "" { target c++14_down } }
+  E *e5 = new E { -4 };	// { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target c++14_down } }
+			// { dg-error "narrowing conversion of '-4' from 'int' to 'unsigned char' inside" "" { target c++1z } .-1 }
+  bar ({ 10 });		// { dg-error "cannot convert \[^\n\r]* to 'E' for argument" }
+  bar (E { 9 });	// { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
+  V v1 = { { 11 } };	// { dg-error "braces around scalar initializer for type 'E'" }
+  V v2 = { E { 12 } };	// { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
+  V v3 = { E { 5.0 } };	// { dg-error "cannot convert 'double' to 'E' in initialization" "" { target c++14_down } }
+			// { dg-error "narrowing conversion of '5.0e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
+  V v4 = { 13 };	// { dg-error "cannot convert 'int' to 'E' in initialization" }
+  if (B b3 { 5 })	// { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
+    ;
+  if (B b4 { 4.0 })	// { dg-error "cannot convert 'double' to 'B' in initialization" "" { target c++14_down } }
+    ;			// { dg-error "narrowing conversion of '4.0e.0' from 'double' to 'short int' inside" "" { target c++1z } .-1 }
+  C c3 { 8L };		// { dg-error "cannot convert 'long int' to 'C' in initialization" "" { target c++14_down } }
+  B b4 {short (c + 5)};	// { dg-error "invalid conversion from 'short int' to 'B'" "" { target c++14_down } }
+  B b5 {c + 5};		// { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
+			// { dg-error "narrowing conversion of \[^\n\r]* from 'int' to 'short int' inside" "" { target c++1z } .-1 }
+  C c4 { ll };		// { dg-error "cannot convert 'long long int' to 'C' in initialization" "" { target c++14_down } }
+			// { dg-error "narrowing conversion of 'll' from 'long long int' to 'int' inside" "" { target c++1z } .-1 }
+  C c5 {short (c + 5)};	// { dg-error "cannot convert 'short int' to 'C' in initialization" "" { target c++14_down } }
+  C c6 {c + 5};		// { dg-error "cannot convert 'int' to 'C' in initialization" "" { target c++14_down } }
+}
+
+struct U
+{
+  U () : e { 5 } {}	// { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target c++14_down } }
+  U (int) : e { 5.0 } {}// { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target c++14_down } }
+			// { dg-error "narrowing conversion of '5.0e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
+  U (float) : e({ 6 }) {}// { dg-error "list-initializer for non-class type must not be parenthesized" }
+			// { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target *-*-* } .-1 }
+  E e;
+};
+
+struct W
+{
+  A a { 5 };		// { dg-error "invalid conversion from 'int' to 'A'" }
+  B b { 6 };		// { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
+  C c { 3.0f };		// { dg-error "cannot convert \[^\n\r]* to 'C' in initialization" "" { target c++14_down } }
+			// { dg-error "narrowing conversion of '3.0e.0f' from 'float' to 'int' inside" "" { target c++1z } .-1 }
+  D d = { 7 };		// { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" }
+};
+
+template <int N>
+void
+foo2 ()
+{
+  A a1 { 5 };		// { dg-error "invalid conversion from 'int' to 'A'" }
+  B b1 { 7 };		// { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
+  C c1 { s };
+  D d1 { D(t) };	// { dg-error "invalid cast from type 'T' to type 'D'" }
+  D d2 { t };		// { dg-error "cannot convert 'T' to 'D' in initialization" "" { target c++14_down } }
+			// { dg-error "invalid cast from type 'T' to type 'D'" "" { target c++1z } .-1 }
+  D d3 { 9 };		// { dg-error "cannot convert 'int' to 'D' in initialization" "" { target c++14_down } }
+  D d4 { l };		// { dg-error "cannot convert 'long int' to 'D' in initialization" "" { target c++14_down } }
+  D d5 { D(l) };
+  D d6 { G };		// { dg-error "cannot convert 'A' to 'D' in initialization" "" { target c++14_down } }
+  E e1 { 5 };		// { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
+  E e2 { -1 };		// { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
+			// { dg-error "narrowing conversion of '-1' from 'int' to 'unsigned char' inside" "" { target c++1z } .-1 }
+  E e3 { 5.0 };		// { dg-error "cannot convert 'double' to 'E' in initialization" "" { target c++14_down } }
+			// { dg-error "narrowing conversion of '5.0e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
+  E e4 { 5.2 };		// { dg-error "cannot convert 'double' to 'E' in initialization" "" { target c++14_down } }
+			// { dg-error "narrowing conversion of '5.\[0-9]*e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
+  B b2 = { 7 };		// { dg-error "invalid conversion from 'int' to 'B'" }
+  C c2 = { C { 8 } };	// { dg-error "cannot convert 'int' to 'C' in initialization" "" { target c++14_down } }
+  D *d7 = new D { 9 };	// { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" "" { target c++14_down } }
+  E *e5 = new E { -4 };	// { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target c++14_down } }
+			// { dg-error "narrowing conversion of '-4' from 'int' to 'unsigned char' inside" "" { target c++1z } .-1 }
+  bar ({ 10 });		// { dg-error "cannot convert \[^\n\r]* to 'E' for argument" }
+  bar (E { 9 });	// { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
+  V v1 = { { 11 } };	// { dg-error "braces around scalar initializer for type 'E'" }
+  V v2 = { E { 12 } };	// { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
+  V v3 = { E { 5.0 } };	// { dg-error "cannot convert 'double' to 'E' in initialization" "" { target c++14_down } }
+			// { dg-error "narrowing conversion of '5.0e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
+  V v4 = { 13 };	// { dg-error "cannot convert 'int' to 'E' in initialization" }
+  if (B b3 { 5 })	// { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
+    ;
+  if (B b4 { 4.0 })	// { dg-error "cannot convert 'double' to 'B' in initialization" "" { target c++14_down } }
+    ;			// { dg-error "narrowing conversion of '4.0e.0' from 'double' to 'short int' inside" "" { target c++1z } .-1 }
+  C c3 { 8L };		// { dg-error "cannot convert 'long int' to 'C' in initialization" "" { target c++14_down } }
+  B b4 {short (c + 5)};	// { dg-error "invalid conversion from 'short int' to 'B'" "" { target c++14_down } }
+  B b5 {c + 5};		// { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
+			// { dg-error "narrowing conversion of \[^\n\r]* from 'int' to 'short int' inside" "" { target c++1z } .-1 }
+  C c4 { ll };		// { dg-error "cannot convert 'long long int' to 'C' in initialization" "" { target c++14_down } }
+			// { dg-error "narrowing conversion of 'll' from 'long long int' to 'int' inside" "" { target c++1z } .-1 }
+  C c5 {short (c + 5)};	// { dg-error "cannot convert 'short int' to 'C' in initialization" "" { target c++14_down } }
+  C c6 {c + 5};		// { dg-error "cannot convert 'int' to 'C' in initialization" "" { target c++14_down } }
+}
+
+template <int N>
+struct U2
+{
+  U2 () : e { 5 } {}	// { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target c++14_down } }
+  U2 (int) : e { 5.0 } {}// { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target c++14_down } }
+			// { dg-error "narrowing conversion of '5.0e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
+  U2 (float) : e({ 6 }) {}
+  E e;
+};
+
+template <int N>
+struct W2
+{
+  A a { 5 };		// { dg-error "invalid conversion from 'int' to 'A'" "" { target *-*-* } .-2 }
+  B b { 6 };		// { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } .-3 }
+  C c { 3.0f };		// { dg-error "cannot convert \[^\n\r]* to 'C' in initialization" "" { target c++14_down } .-4 }
+			// { dg-error "narrowing conversion of '3.0e.0f' from 'float' to 'int' inside" "" { target c++1z } .-5 }
+  D d = { 7 };		// { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" "" { target *-*-* } .-6 }
+};
+
+template <typename H, typename I, typename J, typename K, typename L, typename M>
+void
+foo3 ()
+{
+  void bar3 (L);
+  H a1 { 5 };		// { dg-error "invalid conversion from 'int' to 'A'" }
+  I b1 { 7 };		// { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
+  J c1 { s };
+  K d1 { K(t) };	// { dg-error "invalid cast from type 'T' to type 'D'" }
+  K d2 { t };		// { dg-error "cannot convert 'T' to 'D' in initialization" "" { target c++14_down } }
+			// { dg-error "invalid cast from type 'T' to type 'D'" "" { target c++1z } .-1 }
+  K d3 { 9 };		// { dg-error "cannot convert 'int' to 'D' in initialization" "" { target c++14_down } }
+  K d4 { l };		// { dg-error "cannot convert 'long int' to 'D' in initialization" "" { target c++14_down } }
+  K d5 { K(l) };
+  K d6 { G };		// { dg-error "cannot convert 'A' to 'D' in initialization" "" { target c++14_down } }
+  L e1 { 5 };		// { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
+  L e2 { -1 };		// { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
+			// { dg-error "narrowing conversion of '-1' from 'int' to 'unsigned char' inside" "" { target c++1z } .-1 }
+  L e3 { 5.0 };		// { dg-error "cannot convert 'double' to 'E' in initialization" "" { target c++14_down } }
+			// { dg-error "narrowing conversion of '5.0e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
+  L e4 { 5.2 };		// { dg-error "cannot convert 'double' to 'E' in initialization" "" { target c++14_down } }
+			// { dg-error "narrowing conversion of '5.\[0-9]*e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
+  I b2 = { 7 };		// { dg-error "invalid conversion from 'int' to 'B'" }
+  J c2 = { J { 8 } };	// { dg-error "cannot convert 'int' to 'C' in initialization" "" { target c++14_down } }
+  K *d7 = new K { 9 };	// { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" "" { target c++14_down } }
+  L *e5 = new L { -4 };	// { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target c++14_down } }
+			// { dg-error "narrowing conversion of '-4' from 'int' to 'unsigned char' inside" "" { target c++1z } .-1 }
+  bar3 ({ 10 });	// { dg-error "cannot convert \[^\n\r]* to 'E' for argument" }
+  bar3 (E { 9 });	// { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
+  M v1 = { { 11 } };	// { dg-error "braces around scalar initializer for type 'E'" }
+  M v2 = { L { 12 } };	// { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
+  M v3 = { L { 5.0 } };	// { dg-error "cannot convert 'double' to 'E' in initialization" "" { target c++14_down } }
+			// { dg-error "narrowing conversion of '5.0e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
+  M v4 = { 13 };	// { dg-error "cannot convert 'int' to 'E' in initialization" }
+  if (I b3 { 5 })	// { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
+    ;
+  if (I b4 { 4.0 })	// { dg-error "cannot convert 'double' to 'B' in initialization" "" { target c++14_down } }
+    ;			// { dg-error "narrowing conversion of '4.0e.0' from 'double' to 'short int' inside" "" { target c++1z } .-1 }
+  J c3 { 8L };		// { dg-error "cannot convert 'long int' to 'C' in initialization" "" { target c++14_down } }
+  I b4 {short (c + 5)};	// { dg-error "invalid conversion from 'short int' to 'B'" "" { target c++14_down } }
+  I b5 {c + 5};		// { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
+			// { dg-error "narrowing conversion of \[^\n\r]* from 'int' to 'short int' inside" "" { target c++1z } .-1 }
+  J c4 { ll };		// { dg-error "cannot convert 'long long int' to 'C' in initialization" "" { target c++14_down } }
+			// { dg-error "narrowing conversion of 'll' from 'long long int' to 'int' inside" "" { target c++1z } .-1 }
+  J c5 {short (c + 5)};	// { dg-error "cannot convert 'short int' to 'C' in initialization" "" { target c++14_down } }
+  J c6 {c + 5};		// { dg-error "cannot convert 'int' to 'C' in initialization" "" { target c++14_down } }
+}
+
+template <typename L>
+struct U3
+{
+  U3 () : e { 5 } {}	// { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target c++14_down } }
+  U3 (int) : e { 5.0 } {}// { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target c++14_down } }
+			// { dg-error "narrowing conversion of '5.0e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
+  U3 (float) : e({ 6 }) {}
+  L e;
+};
+
+template <typename H, typename I, typename J, typename K>
+struct W3
+{
+  H a { 5 };		// { dg-error "invalid conversion from 'int' to 'A'" "" { target *-*-* } .-2 }
+  I b { 6 };		// { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } .-3 }
+  J c { 3.0f };		// { dg-error "cannot convert \[^\n\r]* to 'C' in initialization" "" { target c++14_down } .-4 }
+			// { dg-error "narrowing conversion of '3.0e.0f' from 'float' to 'int' inside" "" { target c++1z } .-5 }
+  K d = { 7 };		// { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" "" { target *-*-* } .-6 }
+};
+
+void
+test ()
+{
+  foo2<0> ();
+  U2<0> u20;
+  U2<1> u21 (5);
+  W2<0> w2;		// { dg-error "invalid conversion from 'int' to 'A'" }
+			// { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } .-1 }
+			// { dg-error "cannot convert \[^\n\r]* to 'C' in initialization" "" { target c++14_down } .-2 }
+			// { dg-error "narrowing conversion of '3.0e.0f' from 'float' to 'int' inside" "" { target c++1z } .-3 }
+			// { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" "" { target *-*-* } .-4 }
+  foo3<A, B, C, D, E, V> ();
+  U3<E> u30;
+  U3<E> u31 (5);
+  W3<A, B, C, D> w3;	// { dg-error "invalid conversion from 'int' to 'A'" }
+			// { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } .-1 }
+			// { dg-error "cannot convert \[^\n\r]* to 'C' in initialization" "" { target c++14_down } .-2 }
+			// { dg-error "narrowing conversion of '3.0e.0f' from 'float' to 'int' inside" "" { target c++1z } .-3 }
+			// { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" "" { target *-*-* } .-4 }
+}