On Thu, Dec 19, 2024 at 11:52:33AM -0500, Jason Merrill wrote: > Please add this paragraph as a comment.
Ok. > > + if (!TYPE_UNSIGNED (elt_type) > > + && (complain & tf_warning) > > We shouldn't check tf_warning here. Oops, you're right. I saw the complain & tf_warning early exit at the start of check_narrowing, but that is for C++98 only and I think C++98 code shouldn't get into ck_list handling. > > + && (TYPE_UNSIGNED (TREE_TYPE (val)) > > + || (TYPE_PRECISION (TREE_TYPE (val)) > > + > CHAR_BIT))) > > + for (int i = 0; i < RAW_DATA_LENGTH (val); ++i) > > + if (RAW_DATA_SCHAR_ELT (val, i) < 0) > > + { > > Instead, check tf_warning_or_error here, and return error_mark_node if it's > not set. check_narrowing actually tests just complain & tf_error: if not cxx98 nor !CONSTANT_CLASS_P (init) (RAW_DATA_CST is necessarily constant): else if (complain & tf_error) { int savederrorcount = errorcount; permerror_opt (loc, OPT_Wnarrowing, "narrowing conversion of %qE from %qH to %qI", init, ftype, type); if (errorcount == savederrorcount) ok = true; } } return ok; So I went with complain & tf_error check and return error_mark_node if that is 0. So far lightly tested, ok for trunk this way if it passes bootstrap & testing? 2024-12-19 Jakub Jelinek <ja...@redhat.com> PR c++/118124 * call.cc (convert_like_internal): Handle RAW_DATA_CST in ck_list handling. Formatting fixes. * g++.dg/cpp/embed-15.C: New test. * g++.dg/cpp/embed-16.C: New test. * g++.dg/cpp0x/initlist-opt3.C: New test. * g++.dg/cpp0x/initlist-opt4.C: New test. --- gcc/cp/call.cc.jj 2024-12-11 17:27:52.481221310 +0100 +++ gcc/cp/call.cc 2024-12-19 18:50:52.478315892 +0100 @@ -8766,8 +8766,8 @@ convert_like_internal (conversion *convs if (tree init = maybe_init_list_as_array (elttype, expr)) { - elttype = cp_build_qualified_type - (elttype, cp_type_quals (elttype) | TYPE_QUAL_CONST); + elttype = cp_build_qualified_type (elttype, cp_type_quals (elttype) + | TYPE_QUAL_CONST); array = build_array_of_n_type (elttype, len); array = build_vec_init_expr (array, init, complain); array = get_target_expr (array); @@ -8775,13 +8775,83 @@ convert_like_internal (conversion *convs } else if (len) { - tree val; unsigned ix; - + tree val; + unsigned ix; tree new_ctor = build_constructor (init_list_type_node, NULL); /* Convert all the elements. */ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (expr), ix, val) { + if (TREE_CODE (val) == RAW_DATA_CST) + { + tree elt_type; + conversion *next; + /* For conversion to initializer_list<unsigned char> or + initializer_list<char> or initializer_list<signed char> + we can optimize and keep RAW_DATA_CST with adjusted + type if we report narrowing errors if needed, for + others this converts each element separately. */ + if (convs->u.list[ix]->kind == ck_std + && (elt_type = convs->u.list[ix]->type) + && (TREE_CODE (elt_type) == INTEGER_TYPE + || is_byte_access_type (elt_type)) + && TYPE_PRECISION (elt_type) == CHAR_BIT + && (next = next_conversion (convs->u.list[ix])) + && next->kind == ck_identity) + { + if (!TYPE_UNSIGNED (elt_type) + && (TYPE_UNSIGNED (TREE_TYPE (val)) + || (TYPE_PRECISION (TREE_TYPE (val)) + > CHAR_BIT))) + for (int i = 0; i < RAW_DATA_LENGTH (val); ++i) + if (RAW_DATA_SCHAR_ELT (val, i) >= 0) + continue; + else if (complain & tf_error) + { + location_t loc + = cp_expr_loc_or_input_loc (val); + int savederrorcount = errorcount; + permerror_opt (loc, OPT_Wnarrowing, + "narrowing conversion of %qd " + "from %qH to %qI", + RAW_DATA_UCHAR_ELT (val, i), + TREE_TYPE (val), elt_type); + if (errorcount != savederrorcount) + return error_mark_node; + } + else + return error_mark_node; + tree sub = copy_node (val); + TREE_TYPE (sub) = elt_type; + CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (new_ctor), + NULL_TREE, sub); + } + else + { + for (int i = 0; i < RAW_DATA_LENGTH (val); ++i) + { + tree elt + = build_int_cst (TREE_TYPE (val), + RAW_DATA_UCHAR_ELT (val, i)); + tree sub + = convert_like (convs->u.list[ix], elt, + fn, argnum, false, false, + /*nested_p=*/true, complain); + if (sub == error_mark_node) + return sub; + if (!check_narrowing (TREE_TYPE (sub), elt, + complain)) + return error_mark_node; + tree nc = new_ctor; + CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (nc), + NULL_TREE, sub); + if (!TREE_CONSTANT (sub)) + TREE_CONSTANT (new_ctor) = false; + } + } + len += RAW_DATA_LENGTH (val) - 1; + continue; + } tree sub = convert_like (convs->u.list[ix], val, fn, argnum, false, false, /*nested_p=*/true, complain); @@ -8796,8 +8866,8 @@ convert_like_internal (conversion *convs TREE_CONSTANT (new_ctor) = false; } /* Build up the array. */ - elttype = cp_build_qualified_type - (elttype, cp_type_quals (elttype) | TYPE_QUAL_CONST); + elttype = cp_build_qualified_type (elttype, cp_type_quals (elttype) + | TYPE_QUAL_CONST); array = build_array_of_n_type (elttype, len); array = finish_compound_literal (array, new_ctor, complain); /* This is dubious now, should be blessed by P2752. */ --- gcc/testsuite/g++.dg/cpp/embed-15.C.jj 2024-12-19 15:07:28.564605983 +0100 +++ gcc/testsuite/g++.dg/cpp/embed-15.C 2024-12-19 15:08:14.194998077 +0100 @@ -0,0 +1,35 @@ +// PR c++/118124 +// { dg-do compile { target c++11 } } +// { dg-options "-O2" } + +namespace std { +template <class T> struct initializer_list { +private: + const T *_M_array; + __SIZE_TYPE__ _M_len; +}; +} +struct A { + A (std::initializer_list<char>); +}; +A a { +#embed __FILE__ +}; +struct B { + B (std::initializer_list<unsigned char>); +}; +B b { +#embed __FILE__ +}; +struct C { + C (std::initializer_list<int>); +}; +C c { +#embed __FILE__ +}; +struct D { + D (std::initializer_list<float>); +}; +D d { +#embed __FILE__ +}; --- gcc/testsuite/g++.dg/cpp/embed-16.C.jj 2024-12-19 15:09:20.929109016 +0100 +++ gcc/testsuite/g++.dg/cpp/embed-16.C 2024-12-19 15:11:12.811618467 +0100 @@ -0,0 +1,18 @@ +// PR c++/118124 +// { dg-do compile { target c++11 } } +// { dg-options "-O2" } +// non-ASCII chars here: áéí + +namespace std { +template <class T> struct initializer_list { +private: + const T *_M_array; + __SIZE_TYPE__ _M_len; +}; +} +struct A { + A (std::initializer_list<signed char>); +}; +A a { +#embed __FILE__ +}; // { dg-error "narrowing conversion of '\[0-9]*' from 'int' to 'signed char'" } --- gcc/testsuite/g++.dg/cpp0x/initlist-opt3.C.jj 2024-12-19 14:52:17.389013179 +0100 +++ gcc/testsuite/g++.dg/cpp0x/initlist-opt3.C 2024-12-19 15:06:28.652404163 +0100 @@ -0,0 +1,47 @@ +// PR c++/118124 +// { dg-do compile { target c++11 } } +// { dg-options "-O2" } + +namespace std { +template <class T> struct initializer_list { +private: + const T *_M_array; + __SIZE_TYPE__ _M_len; +}; +} +struct A { + A (std::initializer_list<char>); +}; +A a { 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5 }; +struct B { + B (std::initializer_list<unsigned char>); +}; +B b { 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5 }; +struct C { + C (std::initializer_list<int>); +}; +C c { 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5 }; +struct D { + D (std::initializer_list<float>); +}; +D d { 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5 }; --- gcc/testsuite/g++.dg/cpp0x/initlist-opt4.C.jj 2024-12-19 14:52:46.517612306 +0100 +++ gcc/testsuite/g++.dg/cpp0x/initlist-opt4.C 2024-12-19 15:06:52.513086275 +0100 @@ -0,0 +1,20 @@ +// PR c++/118124 +// { dg-do compile { target c++11 } } +// { dg-options "-O2" } + +namespace std { +template <class T> struct initializer_list { +private: + const T *_M_array; + __SIZE_TYPE__ _M_len; +}; +} +struct A { + A (std::initializer_list<signed char>); +}; +A a { 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 209, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5 }; // { dg-error "narrowing conversion of '209' from 'int' to 'signed char'" } Jakub