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

Reply via email to