diff options
-rw-r--r-- | gcc/cp/call.c | 48 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 1 | ||||
-rw-r--r-- | gcc/cp/typeck2.c | 48 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr12.C | 36 |
4 files changed, 92 insertions, 41 deletions
diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 3068c0f..c7e13f3 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -895,28 +895,38 @@ strip_standard_conversion (conversion *conv) return conv; } -/* Subroutine of build_aggr_conv: check whether CTOR, a braced-init-list, - is a valid aggregate initializer for array type ATYPE. */ +/* Subroutine of build_aggr_conv: check whether FROM is a valid aggregate + initializer for array type ATYPE. */ static bool -can_convert_array (tree atype, tree ctor, int flags, tsubst_flags_t complain) +can_convert_array (tree atype, tree from, int flags, tsubst_flags_t complain) { - unsigned i; tree elttype = TREE_TYPE (atype); - for (i = 0; i < CONSTRUCTOR_NELTS (ctor); ++i) + unsigned i; + + if (TREE_CODE (from) == CONSTRUCTOR) { - tree val = CONSTRUCTOR_ELT (ctor, i)->value; - bool ok; - if (TREE_CODE (elttype) == ARRAY_TYPE - && TREE_CODE (val) == CONSTRUCTOR) - ok = can_convert_array (elttype, val, flags, complain); - else - ok = can_convert_arg (elttype, TREE_TYPE (val), val, flags, - complain); - if (!ok) - return false; + for (i = 0; i < CONSTRUCTOR_NELTS (from); ++i) + { + tree val = CONSTRUCTOR_ELT (from, i)->value; + bool ok; + if (TREE_CODE (elttype) == ARRAY_TYPE) + ok = can_convert_array (elttype, val, flags, complain); + else + ok = can_convert_arg (elttype, TREE_TYPE (val), val, flags, + complain); + if (!ok) + return false; + } + return true; } - return true; + + if (char_type_p (TYPE_MAIN_VARIANT (elttype)) + && TREE_CODE (tree_strip_any_location_wrapper (from)) == STRING_CST) + return array_string_literal_compatible_p (atype, from); + + /* No other valid way to aggregate initialize an array. */ + return false; } /* Helper for build_aggr_conv. Return true if FIELD is in PSET, or if @@ -973,8 +983,7 @@ build_aggr_conv (tree type, tree ctor, int flags, tsubst_flags_t complain) tree ftype = TREE_TYPE (idx); bool ok; - if (TREE_CODE (ftype) == ARRAY_TYPE - && TREE_CODE (val) == CONSTRUCTOR) + if (TREE_CODE (ftype) == ARRAY_TYPE) ok = can_convert_array (ftype, val, flags, complain); else ok = can_convert_arg (ftype, TREE_TYPE (val), val, flags, @@ -1021,8 +1030,7 @@ build_aggr_conv (tree type, tree ctor, int flags, tsubst_flags_t complain) val = empty_ctor; } - if (TREE_CODE (ftype) == ARRAY_TYPE - && TREE_CODE (val) == CONSTRUCTOR) + if (TREE_CODE (ftype) == ARRAY_TYPE) ok = can_convert_array (ftype, val, flags, complain); else ok = can_convert_arg (ftype, TREE_TYPE (val), val, flags, diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index aed85d7..970ed5e 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7949,6 +7949,7 @@ extern tree split_nonconstant_init (tree, tree); extern bool check_narrowing (tree, tree, tsubst_flags_t, bool = false); extern bool ordinary_char_type_p (tree); +extern bool array_string_literal_compatible_p (tree, tree); extern tree digest_init (tree, tree, tsubst_flags_t); extern tree digest_init_flags (tree, tree, int, tsubst_flags_t); extern tree digest_nsdmi_init (tree, tree, tsubst_flags_t); diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 9ba2897..bde305b 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1003,6 +1003,29 @@ ordinary_char_type_p (tree type) || type == unsigned_char_type_node); } +/* True iff the string literal INIT has a type suitable for initializing array + TYPE. */ + +bool +array_string_literal_compatible_p (tree type, tree init) +{ + tree to_char_type = TYPE_MAIN_VARIANT (TREE_TYPE (type)); + tree from_char_type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (init))); + + if (to_char_type == from_char_type) + return true; + /* The array element type does not match the initializing string + literal element type; this is only allowed when both types are + ordinary character type. There are no string literals of + signed or unsigned char type in the language, but we can get + them internally from converting braced-init-lists to + STRING_CST. */ + if (ordinary_char_type_p (to_char_type) + && ordinary_char_type_p (from_char_type)) + return true; + return false; +} + /* Process the initializer INIT for a variable of type TYPE, emitting diagnostics for invalid initializers and converting the initializer as appropriate. @@ -1070,30 +1093,13 @@ digest_init_r (tree type, tree init, int nested, int flags, if (char_type_p (typ1) && TREE_CODE (stripped_init) == STRING_CST) { - tree char_type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (init))); - bool incompat_string_cst = false; - - if (typ1 != char_type) - { - /* The array element type does not match the initializing string - literal element type; this is only allowed when both types are - ordinary character type. There are no string literals of - signed or unsigned char type in the language, but we can get - them internally from converting braced-init-lists to - STRING_CST. */ - if (ordinary_char_type_p (typ1) - && ordinary_char_type_p (char_type)) - /* OK */; - else - incompat_string_cst = true; - } - - if (incompat_string_cst) + if (!array_string_literal_compatible_p (type, init)) { if (complain & tf_error) error_at (loc, "cannot initialize array of %qT from " - "a string literal with type array of %qT", - typ1, char_type); + "a string literal with type array of %qT", + typ1, + TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (init)))); return error_mark_node; } diff --git a/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr12.C b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr12.C new file mode 100644 index 0000000..fcc1f50 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr12.C @@ -0,0 +1,36 @@ +// PR c++/90926 +// { dg-do run { target c++14 } } + +#include <cassert> + +struct A +{ + char str[4] = "foo"; + char str_array[2][4] = {"bar", "baz"}; +}; + +struct B +{ + char16_t str[10]; +}; + +int called = 0; +void f(A) { called = 1;}; +void f(B) { called = 2;}; + +int +main () +{ + A a; + a.str[0] = 'g'; + a.str_array[0][0] = 'g'; + a = {}; + + if (__builtin_strcmp (a.str, "foo") != 0) + __builtin_abort(); + if (__builtin_strcmp (a.str_array[0], "bar") != 0) + __builtin_abort(); + + f({"foo"}); assert(called == 1); + f({u"foo"}); assert(called == 2); +} |