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