On Thu, Dec 19, 2024 at 11:44:54AM -0500, Jason Merrill wrote:
> > --- gcc/cp/call.cc.jj       2024-12-19 16:10:12.977071898 +0100
> > +++ gcc/cp/call.cc  2024-12-19 16:55:40.953546502 +0100
> > @@ -4386,7 +4386,13 @@ maybe_init_list_as_array (tree elttype,
> >     if (!is_xible (INIT_EXPR, elttype, copy_argtypes))
> >       return NULL_TREE;
> > -  tree arr = build_array_of_n_type (init_elttype, CONSTRUCTOR_NELTS 
> > (init));
> > +  unsigned int len = CONSTRUCTOR_NELTS (init);
> > +  if (INTEGRAL_TYPE_P (init_elttype))
> > +    for (constructor_elt &e: CONSTRUCTOR_ELTS (init))
> > +      if (TREE_CODE (e.value) == RAW_DATA_CST)
> > +   len += RAW_DATA_LENGTH (e.value) - 1;
> 
> Really seems like we could use a function to ask how many elements a
> CONSTRUCTOR initializes, perhaps as a wrapper around
> categorize_ctor_elements?

I think categorize_ctor_elements is heavy-weight and computes tons of info
we don't need here, but more importantly does something different, it recurses
into each of the elements as well.  True, { { 0, 1 }, { 2, 3 } } would likely 
fail
braced_init_element_type, but still...  And it would be upset about ctors
with yet to be determined types.
Another question is if the function for this purpose should count
RANGE_EXPRs or not, e.g. I think convert_like_internal will simply not
handle them, when the loop is FOR_EACH_CONSTRUCTOR_VALUE it simply doesn't
consider them at all.  I think we currently reject
A a { 1, 2, [ 2 ... 6 ] = 3 };
And am not really sure a function like that would be useful for other FEs
or middle-end, given that C designated initializers can skip or initialize
elements out of order, so simply counting them isn't good enough, one would
need to find the highest index (implicit or explicit) or something similar.

This version just adds a static function so far used just here.

Also, I'm worried about build_array_of_n_type, which currently takes int
argument.  It is true that vectors, CONSTRUCTOR_ELTS etc. usually count
stuff in unsigned int or sometimes even in int, so without #embed
or RAW_DATA_CST it isn't really possible to have 2GB+ or 4GB+ elt
initializers (and without them it would be a compile time nightmare anyway).
With #embed/RAW_DATA_CST it isn't that hard to cross that boundary though,
so the patch changes it to uhwi.  One still needs to be careful not to
case breakup of the huge RAW_DATA_CSTs, but at least simple
std::initializer_list<char> from say 16GB #embed should work.

2024-12-19  Jakub Jelinek  <ja...@redhat.com>

        PR c++/118124
        * cp-tree.h (build_array_of_n_type): Change second argument type
        from int to unsigned HOST_WIDE_INT.
        * tree.cc (build_array_of_n_type): Likewise.
        * call.cc (count_ctor_elements): New function.
        (maybe_init_list_as_array): Use it instead of CONSTRUCTOR_NELTS.
        (convert_like_internal): Use length from init's type instead of
        len when handling the maybe_init_list_as_array case.

        * g++.dg/cpp0x/initlist-opt5.C: New test.

--- gcc/cp/cp-tree.h.jj 2024-12-19 18:47:01.444498895 +0100
+++ gcc/cp/cp-tree.h    2024-12-19 19:12:10.252716265 +0100
@@ -8156,7 +8156,7 @@ extern tree build_aggr_init_expr          (tree,
 extern tree get_target_expr                    (tree,
                                                 tsubst_flags_t = 
tf_warning_or_error);
 extern tree build_cplus_array_type             (tree, tree, int is_dep = -1);
-extern tree build_array_of_n_type              (tree, int);
+extern tree build_array_of_n_type              (tree, unsigned HOST_WIDE_INT);
 extern bool array_of_runtime_bound_p           (tree);
 extern bool vla_type_p                         (tree);
 extern tree build_array_copy                   (tree);
--- gcc/cp/tree.cc.jj   2024-12-19 11:35:59.227312977 +0100
+++ gcc/cp/tree.cc      2024-12-19 19:12:34.291385303 +0100
@@ -1207,7 +1207,7 @@ build_cplus_array_type (tree elt_type, t
 /* Return an ARRAY_TYPE with element type ELT and length N.  */
 
 tree
-build_array_of_n_type (tree elt, int n)
+build_array_of_n_type (tree elt, unsigned HOST_WIDE_INT n)
 {
   return build_cplus_array_type (elt, build_index_type (size_int (n - 1)));
 }
--- gcc/cp/call.cc.jj   2024-12-19 18:50:52.478315892 +0100
+++ gcc/cp/call.cc      2024-12-19 19:13:15.528817544 +0100
@@ -4325,6 +4325,20 @@ has_non_trivial_temporaries (tree expr)
   return false;
 }
 
+/* Return number of initialized elements in CTOR.  */
+
+static unsigned HOST_WIDE_INT
+count_ctor_elements (tree ctor)
+{
+  unsigned HOST_WIDE_INT len = 0;
+  for (constructor_elt &e: CONSTRUCTOR_ELTS (ctor))
+    if (TREE_CODE (e.value) == RAW_DATA_CST)
+      len += RAW_DATA_LENGTH (e.value);
+    else
+      ++len;
+  return len;
+}
+
 /* We're initializing an array of ELTTYPE from INIT.  If it seems useful,
    return INIT as an array (of its own type) so the caller can initialize the
    target array in a loop.  */
@@ -4386,7 +4400,8 @@ maybe_init_list_as_array (tree elttype,
   if (!is_xible (INIT_EXPR, elttype, copy_argtypes))
     return NULL_TREE;
 
-  tree arr = build_array_of_n_type (init_elttype, CONSTRUCTOR_NELTS (init));
+  unsigned HOST_WIDE_INT len = count_ctor_elements (init);
+  tree arr = build_array_of_n_type (init_elttype, len);
   arr = finish_compound_literal (arr, init, tf_none);
   DECL_MERGEABLE (TARGET_EXPR_SLOT (arr)) = true;
   return arr;
@@ -8761,14 +8776,16 @@ convert_like_internal (conversion *convs
       {
        /* Conversion to std::initializer_list<T>.  */
        tree elttype = TREE_VEC_ELT (CLASSTYPE_TI_ARGS (totype), 0);
-       unsigned len = CONSTRUCTOR_NELTS (expr);
+       unsigned HOST_WIDE_INT len = CONSTRUCTOR_NELTS (expr);
        tree array;
 
        if (tree init = maybe_init_list_as_array (elttype, expr))
          {
            elttype = cp_build_qualified_type (elttype, cp_type_quals (elttype)
                                                        | TYPE_QUAL_CONST);
-           array = build_array_of_n_type (elttype, len);
+           tree index_type = TYPE_DOMAIN (TREE_TYPE (init));
+           array = build_cplus_array_type (elttype, index_type);
+           len = TREE_INT_CST_LOW (TYPE_MAX_VALUE (index_type)) + 1;
            array = build_vec_init_expr (array, init, complain);
            array = get_target_expr (array);
            array = cp_build_addr_expr (array, complain);
--- gcc/testsuite/g++.dg/cpp0x/initlist-opt5.C.jj       2024-12-19 
19:07:28.725592353 +0100
+++ gcc/testsuite/g++.dg/cpp0x/initlist-opt5.C  2024-12-19 19:07:28.725592353 
+0100
@@ -0,0 +1,23 @@
+// 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;
+  decltype (sizeof 0) _M_len;
+};
+}
+struct B {
+  B (int);
+};
+struct A {
+  A (std::initializer_list<B>);
+};
+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 };


        Jakub

Reply via email to