mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-22 11:31:05 +08:00
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.
This commit is contained in:
parent
aa652fb2a0
commit
e6cc142ad9
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
36
gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr12.C
Normal file
36
gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr12.C
Normal file
@ -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);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user