While trying to fix the suggested overload resolution issue I run into another bug:
struct A { char str[4]; }; void f(A) {}; int main () { f({"foo"}); } Does not compile on GCC: "error: could not convert ‘{"foo"}’ from ‘<brace-enclosed initializer list>’ to ‘A’", but works fine on Clang. Is this a known bug or a new one? -----Original Message----- From: Jason Merrill <ja...@redhat.com> Sent: 22 January 2021 16:30 To: Tom Greenslade (thomgree) <thomg...@cisco.com>; gcc-patches@gcc.gnu.org Subject: Re: [PATCH] c++: fix string literal member initializer bug [PR90926] On 12/17/20 5:12 PM, Thomas Greenslade (thomgree) via Gcc-patches wrote: > build_aggr_conv did not correctly handle string literal member initializers. > Extended can_convert_array to handle this case. The additional checks > of compatibility of character types, and whether string literal will > fit, would be quite complicated, so are deferred until the actual conversion > takes place. It seems that we need to check the type, though not the length. [over.ics.list]: "Otherwise, if the parameter type is a character array 125 and the initializer list has a single element that is an appropriately-typed string-literal (9.4.2), the implicit conversion sequence is the identity conversion." So this should be unambiguous: struct A { char str[10]; }; struct B { char16_t str[10]; }; void f(A); void f(B); int main () { f({"foo"}); // calls A overload f({u"foo"}); // calls B overload } You could factor the type matching code out of digest_init_r and use it here. > Testcase added for this. > > Bootstrapped/regtested on x86_64-pc-linux-gnu. > > 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. > * g++.dg/cpp1y/nsdmi-aggr12.C: New test. > > diff --git a/gcc/cp/call.c b/gcc/cp/call.c index > c2d62e582bf..e4ba31f3f2b 100644 > --- a/gcc/cp/call.c > +++ b/gcc/cp/call.c > @@ -887,28 +887,41 @@ 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) > + /* Defer the other necessary checks (compatibility of character types and > + whether string literal will fit) until the conversion actually takes > + place. */ > + return true; > + > + /* 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 @@ -965,8 +978,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, @@ -1013,9 +1025,8 @@ 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) > - ok = can_convert_array (ftype, val, flags, complain); > + 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, > complain); 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..ce8c95e8aca > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr12.C > @@ -0,0 +1,21 @@ > +// PR c++/90926 > +// { dg-do run { target c++14 } } > + > +struct A > +{ > + char str[4] = "foo"; > + char str_array[2][4] = {"bar", "baz"}; }; > + > +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(); > +} >