From e6cc142ad99ab8d28581f4ce61056c9cce74dba3 Mon Sep 17 00:00:00 2001 From: "Tom Greenslade (thomgree)" Date: Wed, 3 Feb 2021 11:31:53 +0000 Subject: [PATCH] c++: fix string literal member initializer bug [PR90926] build_aggr_conv did not correctly handle string literal member initializers. Extended can_convert_array to handle this case. For the additional check of compatibility of character types, factored out code from digest_init_r into a new function. gcc/cp/ChangeLog: PR c++/90926 * call.c (can_convert_array): Extend to handle all valid aggregate initializers of an array; including by string literals, not just by brace-init-list. (build_aggr_conv): Call can_convert_array more often, not just in brace-init-list case. * typeck2.c (array_string_literal_compatible_p): New function. (digest_init_r): call array_string_literal_compatible_p * cp-tree.h: (array_string_literal_compatible_p): Declare. gcc/testsuite/ChangeLog: PR c++/90926 * g++.dg/cpp1y/nsdmi-aggr12.C: New test. --- gcc/cp/call.c | 48 +++++++++++++---------- gcc/cp/cp-tree.h | 1 + gcc/cp/typeck2.c | 48 +++++++++++++---------- gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr12.C | 36 +++++++++++++++++ 4 files changed, 92 insertions(+), 41 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr12.C diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 3068c0f8cfd..c7e13f3a22b 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 aed85d79287..970ed5e77bb 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 9ba2897390a..bde305bd38e 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 00000000000..fcc1f50dd81 --- /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 + +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); +} -- 2.30.2