Hi!

This is the third bug discovered today with the
https://gcc.gnu.org/pipermail/gcc-patches/2025-January/673945.html
hack but then turned into proper testcases where embed-24.C FAILed
since introduction of optimized #embed support and the others when
optimizing large C++ initializers using RAW_DATA_CST.

find_array_ctor_elt already has RAW_DATA_CST support, but on the
following testcases it misses one case I've missed.
The CONSTRUCTORs in question went through the braced_list_to_string
optimization which can turn INTEGER_CST RAW_DATA_CST INTEGER_CST
into just larger RAW_DATA_CST covering even those 2 bytes around it
(if they appear there in the underlying RAW_DATA_OWNER).
With this optimization, RAW_DATA_CST can be the last CONSTRUCTOR_ELTS
elt in a CONSTRUCTOR, either the sole one or say preceeded by some
unrelated other elements.  Now, if RAW_DATA_CST is the only one or
if there are no RAW_DATA_CSTs earlier in CONSTRUCTOR_ELTS, we can
trigger a bug in find_array_ctor_elt.
It has a smart optimization for the very common case where
CONSTRUCTOR_ELTS have indexes and index of the last elt is equal
to CONSTRUCTOR_NELTS (ary) - 1, then obviously we know there are
no RAW_DATA_CSTs before it and the indexes just go from 0 to nelts-1,
so when we care about any of those earlier indexes, we can just return i;
and not worry about anything.
Except it uses if (i < end) return i; rather than if (i < end - 1) return i;
For the latter cases, i.e. anything before the last elt, we know there
are no surprises and return i; is right.  But for the if (i == end - 1)
case, return i; is only correct if the last elt is not RAW_DATA_CST, if it
is RAW_DATA_CST, we still need to split it, which is handled by the code
later in the function.  So, for that we need begin = end - 1, so that the
binary search will just care about that last element.

Bootstrapped on x86_64-linux and i686-linux, regtests pending, ok
for trunk if it passes?

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

        PR c++/118534
        * constexpr.cc (find_array_ctor_elt): Don't return i early if
        i == end - 1 and the last elt's value is RAW_DATA_CST.

        * g++.dg/cpp/embed-24.C: New test.
        * g++.dg/cpp1y/pr118534.C: New test.

--- gcc/cp/constexpr.cc.jj      2025-01-17 11:29:33.507691199 +0100
+++ gcc/cp/constexpr.cc 2025-01-17 19:07:36.422646176 +0100
@@ -4155,12 +4155,17 @@ find_array_ctor_elt (tree ary, tree dind
       else if (TREE_CODE (cindex) == INTEGER_CST
               && compare_tree_int (cindex, end - 1) == 0)
        {
-         if (i < end)
-           return i;
          tree value = (*elts)[end - 1].value;
-         if (TREE_CODE (value) == RAW_DATA_CST
-             && wi::to_offset (dindex) < (wi::to_offset (cindex)
-                                          + RAW_DATA_LENGTH (value)))
+         if (i < end)
+           {
+             if (i == end - 1 && TREE_CODE (value) == RAW_DATA_CST)
+               begin = end - 1;
+             else
+               return i;
+           }
+         else if (TREE_CODE (value) == RAW_DATA_CST
+                  && wi::to_offset (dindex) < (wi::to_offset (cindex)
+                                               + RAW_DATA_LENGTH (value)))
            begin = end - 1;
          else
            begin = end;
--- gcc/testsuite/g++.dg/cpp/embed-24.C.jj      2025-01-17 17:55:56.127894446 
+0100
+++ gcc/testsuite/g++.dg/cpp/embed-24.C 2025-01-17 19:15:39.268992556 +0100
@@ -0,0 +1,30 @@
+// PR c++/118534
+// { dg-do compile { target c++14 } }
+// { dg-options "" }
+
+template<typename T>
+constexpr bool
+foo ()
+{
+  T x[160] = {
+#embed __FILE__ limit (160)
+  };
+  const int y[160] = {
+    42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+#embed __FILE__ limit (147) gnu::offset (13)
+  };
+  unsigned long n = 13;
+  for (T *p = x; n; --n, p++)
+    *p = 42;
+  for (int i = 0; i < 160; ++i)
+    if (x[i] != y[i])
+      return false;
+  return true;
+}
+
+int
+main ()
+{
+  static_assert (foo<int> (), "");
+  static_assert (foo<unsigned char> (), "");
+}
--- gcc/testsuite/g++.dg/cpp1y/pr118534.C.jj    2025-01-17 18:28:21.492097114 
+0100
+++ gcc/testsuite/g++.dg/cpp1y/pr118534.C       2025-01-17 19:16:05.362632984 
+0100
@@ -0,0 +1,31 @@
+// PR c++/118534
+// { dg-do compile { target c++14 } }
+
+template<typename T>
+constexpr bool
+foo ()
+{
+  T x[160] = {
+#define I8 1, 2, 3, 4, 5, 6, 7, 8
+#define I64 I8, I8, I8, I8, I8, I8, I8, I8
+    I64, I64, I8, I8, I8, I8
+  };
+  const int y[160] = {
+    42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 6, 7, 8,
+    I64, I64, I8, I8
+  };
+  unsigned long n = 13;
+  for (T *p = x; n; --n, p++)
+    *p = 42;
+  for (int i = 0; i < 160; ++i)
+    if (x[i] != y[i])
+      return false;
+  return true;
+}
+
+int
+main ()
+{
+  static_assert (foo<int> (), "");
+  static_assert (foo<unsigned char> (), "");
+}

        Jakub

Reply via email to