On 1/18/25 4:04 AM, Jakub Jelinek wrote:
On Fri, Jan 17, 2025 at 07:00:33PM -0500, Jason Merrill wrote:
--- gcc/c-family/c-common.cc.jj 2025-01-02 11:47:29.803228077 +0100
+++ gcc/c-family/c-common.cc    2025-01-17 13:32:53.512294482 +0100
@@ -9016,9 +9016,26 @@ vec<tree, va_gc> *
   make_tree_vector_from_ctor (tree ctor)
   {
     vec<tree,va_gc> *ret = make_tree_vector ();
+  unsigned nelts = CONSTRUCTOR_NELTS (ctor);
     vec_safe_reserve (ret, CONSTRUCTOR_NELTS (ctor));
     for (unsigned i = 0; i < CONSTRUCTOR_NELTS (ctor); ++i)
-    ret->quick_push (CONSTRUCTOR_ELT (ctor, i)->value);
+    if (TREE_CODE (CONSTRUCTOR_ELT (ctor, i)->value) == RAW_DATA_CST)
+      {
+       tree raw_data = CONSTRUCTOR_ELT (ctor, i)->value;
+       nelts += RAW_DATA_LENGTH (raw_data);
+       vec_safe_reserve (ret, nelts);

I notice that the second argument to vec_safe_reserve is the number of empty
spaces to provide, rather than the new desired capacity.  So this will
allocate space for an additional copy of the whole constructor.

You're right.

I guess you want to say reserve (ret, nelts - vec_safe_length (res))? It's
weird that there isn't a more convenient way to express that.

I think vec_safe_reserve (ret, nelts - ret->length ()); is enough, the first
vec_safe_reserve already necessarily make ret non-NULL because if it would
not have reserved anything (nelts == 0), then there would be no ctor
elements to walk.

Agreed.

Note that this behavior differs from the C++ standard library, where reserve
indeed specifies the new capacity.  This seems likely to cause a lot of
confusion (and over-allocation) going forward.  And indeed looking through
exising uses turns up at least two that seem to assume the standard library
semantics (as well as others that assume the actual semantics).

Which ones did you find?
To me cp/name-lookup,cc (name_lookup::preserve_state)
       unsigned length = vec_safe_length (previous->scopes);
       vec_safe_reserve (previous->scopes, length * 2);
looks possibly unintended, as it quick_pushes at most length further
elements.
I've so far skimmed just vec_safe_reserve uses in {c-family,c,cp}
subdirectories, there are 26 further vec_safe_reserve and around 500
.reserve or ->reserve cases.  Most of the vec_safe_reserve and reserve
calls are on empty vectors so it really doesn't matter which one is which.
So, I wonder if at least during the conversion it wouldn't be best to have
all 3 namings, reserve, reserve_space and reserve_capacity, where the first
one would at runtime assert that length () is 0.

I wonder about renaming the existing reserve to reserve_space and adding a
reserve_capacity?

Would it be ok to first handle these PRs (fixed patch below) and go through
the renaming and checking incrementally?

Absolutely.

There was another thinko in the patch, nelts += RAW_DATA_LENGTH (raw_data);
would mean again reserving too much, it needs to be nelts += RAW_DATA_LENGTH
(raw_data) - 1, as we don't push the RAW_DATA_CST itself which was already
accounted for, but replace it with RAW_DATA_LENGTH pushes.
So far tested on
GXX_TESTSUITE_STDS=98,11,14,17,20,23,26 make check-g++ RUNTESTFLAGS="dg.exp='embed* 
class-deduction-aggr*.C explicit*.C pr11853[24]*'"
ok if it passes full bootstrap+regtest?

OK.

2025-01-18  Jakub Jelinek  <ja...@redhat.com>

        PR c++/118528
        * c-common.cc (make_tree_vector_from_ctor): Expand RAW_DATA_CST
        elements from the CONSTRUCTOR to individual INTEGER_CSTs.

        * g++.dg/cpp/embed-21.C: New test.
        * g++.dg/cpp2a/class-deduction-aggr16.C: New test.

--- gcc/c-family/c-common.cc.jj 2025-01-02 11:47:29.803228077 +0100
+++ gcc/c-family/c-common.cc    2025-01-17 13:32:53.512294482 +0100
@@ -9016,9 +9016,26 @@ vec<tree, va_gc> *
  make_tree_vector_from_ctor (tree ctor)
  {
    vec<tree,va_gc> *ret = make_tree_vector ();
+  unsigned nelts = CONSTRUCTOR_NELTS (ctor);
    vec_safe_reserve (ret, CONSTRUCTOR_NELTS (ctor));
    for (unsigned i = 0; i < CONSTRUCTOR_NELTS (ctor); ++i)
-    ret->quick_push (CONSTRUCTOR_ELT (ctor, i)->value);
+    if (TREE_CODE (CONSTRUCTOR_ELT (ctor, i)->value) == RAW_DATA_CST)
+      {
+       tree raw_data = CONSTRUCTOR_ELT (ctor, i)->value;
+       nelts += RAW_DATA_LENGTH (raw_data) - 1;
+       vec_safe_reserve (ret, nelts - ret->length ());
+       if (TYPE_PRECISION (TREE_TYPE (raw_data)) > CHAR_BIT
+           || TYPE_UNSIGNED (TREE_TYPE (raw_data)))
+         for (unsigned j = 0; j < (unsigned) RAW_DATA_LENGTH (raw_data); ++j)
+           ret->quick_push (build_int_cst (TREE_TYPE (raw_data),
+                                           RAW_DATA_UCHAR_ELT (raw_data, j)));
+       else
+         for (unsigned j = 0; j < (unsigned) RAW_DATA_LENGTH (raw_data); ++j)
+           ret->quick_push (build_int_cst (TREE_TYPE (raw_data),
+                                           RAW_DATA_SCHAR_ELT (raw_data, j)));
+      }
+    else
+      ret->quick_push (CONSTRUCTOR_ELT (ctor, i)->value);
    return ret;
  }
--- gcc/testsuite/g++.dg/cpp/embed-21.C.jj 2025-01-17 12:18:00.571912195 +0100
+++ gcc/testsuite/g++.dg/cpp/embed-21.C 2025-01-17 13:37:31.478489868 +0100
@@ -0,0 +1,22 @@
+// PR c++/118528
+// { dg-do compile { target c++20 } }
+// { dg-options "" }
+
+template<class T>
+struct E { T t[130][2]; };
+
+E e1 {
+#embed __FILE__ limit (260)
+};
+
+template<class T>
+struct F { T t[2][130]; };
+
+F f1 {
+#embed __FILE__ limit (260)
+};
+F f2 { { {
+#embed __FILE__ limit (130)
+}, {
+#embed __FILE__ limit (130)
+} } };
--- gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr16.C.jj      2025-01-17 
12:17:23.715424611 +0100
+++ gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr16.C 2025-01-17 
12:17:43.717146527 +0100
@@ -0,0 +1,17 @@
+// PR c++/118528
+// { dg-do compile { target c++20 } }
+
+template<class T>
+struct E { T t[130][2]; };
+
+#define P 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
+#define Q { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 }, { 9, 10 }, { 11, 12 }, \
+         { 13, 14 }, { 15, 16 }
+E e1 { P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, 1, 2, 3, 4 };
+E e2 { { Q, Q, Q, Q, Q, Q, Q, Q, Q, Q, Q, Q, Q, Q, Q, Q, { 1, 2 }, { 3, 4 } } 
};
+
+template<class T>
+struct F { T t[2][130]; };
+
+F f1 { P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, 1, 2, 3, 4 };
+F f2 { { { P, P, P, P, P, P, P, P, 1, 2 }, { P, P, P, P, P, P, P, P, 3, 4 } } 
};


        Jakub


Reply via email to