Commit d664d76d by Jakub Jelinek Committed by Jakub Jelinek

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

	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.

From-SVN: r240449
parent 24cae8cb
2016-09-23 Jakub Jelinek <jakub@redhat.com> 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.
* Make-lang.in (check-c++1z): Pass RUNTESTFLAGS down to * Make-lang.in (check-c++1z): Pass RUNTESTFLAGS down to
make check-g++. make check-g++.
......
...@@ -5829,6 +5829,7 @@ extern tree check_elaborated_type_specifier (enum tag_types, tree, bool); ...@@ -5829,6 +5829,7 @@ extern tree check_elaborated_type_specifier (enum tag_types, tree, bool);
extern void warn_extern_redeclared_static (tree, tree); extern void warn_extern_redeclared_static (tree, tree);
extern tree cxx_comdat_group (tree); extern tree cxx_comdat_group (tree);
extern bool cp_missing_noreturn_ok_p (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 void initialize_artificial_var (tree, vec<constructor_elt, va_gc> *);
extern tree check_var_type (tree, tree); extern tree check_var_type (tree, tree);
extern tree reshape_init (tree, tree, tsubst_flags_t); extern tree reshape_init (tree, tree, tsubst_flags_t);
......
...@@ -5581,6 +5581,22 @@ next_initializable_field (tree field) ...@@ -5581,6 +5581,22 @@ next_initializable_field (tree field)
return 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 /* 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 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), INTEGER_CST representing the size of the array minus one (the maximum index),
...@@ -6026,6 +6042,17 @@ reshape_init (tree type, tree init, tsubst_flags_t complain) ...@@ -6026,6 +6042,17 @@ reshape_init (tree type, tree init, tsubst_flags_t complain)
if (vec_safe_is_empty (v)) if (vec_safe_is_empty (v))
return init; 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. */ /* Recurse on this CONSTRUCTOR. */
d.cur = &(*v)[0]; d.cur = &(*v)[0];
d.end = d.cur + v->length (); d.end = d.cur + v->length ();
......
...@@ -8266,6 +8266,17 @@ convert_for_assignment (tree type, tree rhs, ...@@ -8266,6 +8266,17 @@ convert_for_assignment (tree type, tree rhs,
if (TREE_CODE (rhs) == NON_LVALUE_EXPR) if (TREE_CODE (rhs) == NON_LVALUE_EXPR)
rhs = TREE_OPERAND (rhs, 0); 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); rhstype = TREE_TYPE (rhs);
coder = TREE_CODE (rhstype); coder = TREE_CODE (rhstype);
......
2016-09-23 Jakub Jelinek <jakub@redhat.com>
Implement P0138R2, C++17 construction rules for enum class values
* g++.dg/cpp1z/direct-enum-init1.C: New test.
2016-09-23 David Malcolm <dmalcolm@redhat.com> 2016-09-23 David Malcolm <dmalcolm@redhat.com>
PR preprocessor/77672 PR preprocessor/77672
......
// 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 }
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment