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.
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
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,
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,
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);
|| 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.
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;
}
--- /dev/null
+// 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);
+}