aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2025-01-18 09:14:27 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2025-01-18 09:14:27 +0100
commit413985b632afb07032d3b32d992029fced187814 (patch)
tree81ffc2295b1b68ac0e2e5b374dbc93e48ecde1ab
parent3c34cea666c6fffc3959b8e1a4bbc4afdbd7009f (diff)
downloadgcc-413985b632afb07032d3b32d992029fced187814.zip
gcc-413985b632afb07032d3b32d992029fced187814.tar.gz
gcc-413985b632afb07032d3b32d992029fced187814.tar.bz2
c++: Fix up find_array_ctor_elt RAW_DATA_CST handling [PR118534]
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. 2025-01-18 Jakub Jelinek <jakub@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.
-rw-r--r--gcc/cp/constexpr.cc15
-rw-r--r--gcc/testsuite/g++.dg/cpp/embed-24.C30
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/pr118534.C31
3 files changed, 71 insertions, 5 deletions
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index c898e3b..7ff38f8 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -4155,12 +4155,17 @@ find_array_ctor_elt (tree ary, tree dindex, bool insert)
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;
diff --git a/gcc/testsuite/g++.dg/cpp/embed-24.C b/gcc/testsuite/g++.dg/cpp/embed-24.C
new file mode 100644
index 0000000..baaad72
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp/embed-24.C
@@ -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> (), "");
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr118534.C b/gcc/testsuite/g++.dg/cpp1y/pr118534.C
new file mode 100644
index 0000000..72ffdd3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/pr118534.C
@@ -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> (), "");
+}