TYPE into a STRING_CST for convenience and efficiency. Return
the converted string on success or the original ctor on failure. */
-tree
+static tree
braced_list_to_string (tree type, tree ctor)
{
if (!tree_fits_uhwi_p (TYPE_SIZE_UNIT (type)))
return res;
}
+/* Attempt to convert a CTOR containing braced array initializer lists
+ for array TYPE into one containing STRING_CSTs, for convenience and
+ efficiency. Recurse for arrays of arrays and member initializers.
+ Return the converted CTOR or STRING_CST on success or the original
+ CTOR otherwise. */
+
+tree
+braced_lists_to_strings (tree type, tree ctor)
+{
+ if (TREE_CODE (ctor) != CONSTRUCTOR)
+ return ctor;
+
+ tree_code code = TREE_CODE (type);
+
+ tree ttp;
+ if (code == ARRAY_TYPE)
+ ttp = TREE_TYPE (type);
+ else if (code == RECORD_TYPE)
+ {
+ ttp = TREE_TYPE (ctor);
+ if (TREE_CODE (ttp) == ARRAY_TYPE)
+ {
+ type = ttp;
+ ttp = TREE_TYPE (ttp);
+ }
+ }
+ else
+ return ctor;
+
+ if (TYPE_STRING_FLAG (ttp))
+ return braced_list_to_string (type, ctor);
+
+ code = TREE_CODE (ttp);
+ if (code == ARRAY_TYPE || code == RECORD_TYPE)
+ {
+ /* Handle array of arrays or struct member initializers. */
+ tree val;
+ unsigned HOST_WIDE_INT idx;
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (ctor), idx, val)
+ {
+ val = braced_lists_to_strings (ttp, val);
+ CONSTRUCTOR_ELT (ctor, idx)->value = val;
+ }
+ }
+
+ return ctor;
+}
+
#include "gt-c-family-c-common.h"
--- /dev/null
+/* PR tree-optimization/89688 - -Wstringop-overflow confused by const
+ 2D array of char
+ { dg-do compile }
+ { dg-options "-Wall -fdump-tree-gimple -fdump-tree-optimized" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+size_t strlen (const char*);
+#define CAT(x, y) x ## y
+#define CONCAT(x, y) CAT (x, y)
+#define FAILNAME(name) CONCAT (call_ ## name ##_on_line_, __LINE__)
+
+#define FAIL(name) do { \
+ extern __attribute__ ((noreturn)) void FAILNAME (name) (void); \
+ FAILNAME (name)(); \
+ } while (0)
+
+#define A(ref, len) \
+ if (strlen (ref) != len) FAIL (failure); else (void)0
+
+const char a3_4[3][4] = { { 1 }, { 1, 2 }, { 1, 2, 3 } };
+
+void test_a4_4 (void)
+{
+ A (a3_4[0], 1);
+ A (a3_4[1], 2);
+ A (a3_4[2], 3);
+
+ A (&a3_4[0][0], 1);
+ A (&a3_4[0][1], 0);
+ A (&a3_4[0][2], 0);
+ A (&a3_4[0][3], 0);
+
+ A (&a3_4[1][0], 2);
+ A (&a3_4[1][1], 1);
+ A (&a3_4[1][2], 0);
+ A (&a3_4[1][3], 0);
+
+ A (&a3_4[2][0], 3);
+ A (&a3_4[2][1], 2);
+ A (&a3_4[2][2], 1);
+ A (&a3_4[2][3], 0);
+}
+
+
+const char a3_4_5[3][4][5] =
+ {
+ { { 1 }, { 1, 2 }, { 1, 2, 3 }, { 1, 2, 3, 4 } },
+ { { 1, 2 }, { 1, 2, 3 }, { 1, 2, 3, 4 }, { 1 } },
+ { { 1, 2, 3 }, { 1, 2, 3, 4 }, { 1 }, { 1, 2 } },
+ };
+
+void test_a3_4_5 (void)
+{
+ A (a3_4_5[0][0], 1);
+ A (a3_4_5[0][1], 2);
+ A (a3_4_5[0][2], 3);
+ A (a3_4_5[0][3], 4);
+
+ A (a3_4_5[1][0], 2);
+ A (a3_4_5[1][1], 3);
+ A (a3_4_5[1][2], 4);
+ A (a3_4_5[1][3], 1);
+
+ A (a3_4_5[2][0], 3);
+ A (a3_4_5[2][1], 4);
+ A (a3_4_5[2][2], 1);
+ A (a3_4_5[2][3], 2);
+}
+
+
+struct S
+{
+ char a3[3];
+ char a4_5[4][5];
+};
+
+const struct S sa4[4] =
+ {
+ { .a3 = { 0 },
+ .a4_5 =
+ {
+ { 1 }, { 1, 2 }, { 1, 2, 3 }, { 1, 2, 3, 4 }
+ }
+ },
+ { .a3 = { 1 },
+ .a4_5 =
+ {
+ { 1, 2 }, { 1, 2, 3 }, { 1, 2, 3, 4 }, { 1 }
+ }
+ },
+ { .a3 = { 1, 2 },
+ .a4_5 =
+ {
+ { 1, 2, 3 }, { 1, 2, 3, 4 }, { 1 }, { 1, 2 }
+ }
+ },
+ { .a3 = { 1 },
+ .a4_5 =
+ {
+ { 1, 2, 3, 4 }, "1", { 1, 2 }, "123"
+ }
+ }
+ };
+
+void test_sa4 (void)
+{
+ A (sa4[0].a3, 0);
+ A (sa4[0].a4_5[0], 1);
+ A (sa4[0].a4_5[1], 2);
+ A (sa4[0].a4_5[2], 3);
+ A (sa4[0].a4_5[3], 4);
+
+ A (sa4[1].a3, 1);
+ A (sa4[1].a4_5[0], 2);
+ A (sa4[1].a4_5[1], 3);
+ A (sa4[1].a4_5[2], 4);
+ A (sa4[1].a4_5[3], 1);
+
+ A (sa4[2].a3, 2);
+ A (sa4[2].a4_5[0], 3);
+ A (sa4[2].a4_5[1], 4);
+ A (sa4[2].a4_5[2], 1);
+ A (sa4[2].a4_5[3], 2);
+
+ A (sa4[3].a3, 1);
+ A (sa4[3].a4_5[0], 4);
+ A (sa4[3].a4_5[1], 1);
+ A (sa4[3].a4_5[2], 2);
+ A (sa4[3].a4_5[3], 3);
+}
+
+
+struct T
+{
+ struct S sa2[2];
+ char a4[4];
+};
+
+const struct T ta2[2] =
+ {
+ [0] =
+ {
+ .sa2 =
+ {
+ [0] =
+ { .a3 = { 0 },
+ .a4_5 =
+ {
+ { 1 }, { 1, 2 }, { 1, 2, 3 }, { 1, 2, 3, 4 }
+ }
+ },
+ [1] =
+ { .a3 = { 1 },
+ .a4_5 =
+ {
+ { 1, 2 }, { 1, 2, 3 }, { 1, 2, 3, 4 }, { 1 }
+ }
+ },
+ },
+ .a4 = "12"
+ },
+
+ [1] =
+ {
+ .sa2 =
+ {
+ [0] =
+ { .a3 = { 1, 2 },
+ .a4_5 =
+ {
+ { 1, 2, 3 }, { 1, 2, 3, 4 }, { 1 }, { 1, 2 }
+ }
+ },
+ { .a3 = { 1 },
+ .a4_5 =
+ {
+ { 1, 2, 3, 4 }, "1", { 1, 2 }, "123"
+ }
+ }
+ },
+ .a4 = "123"
+ }
+ };
+
+void test_ta2 (void)
+{
+ A (ta2[0].sa2[0].a3, 0);
+ A (ta2[0].sa2[0].a4_5[0], 1);
+ A (ta2[0].sa2[0].a4_5[1], 2);
+ A (ta2[0].sa2[0].a4_5[2], 3);
+ A (ta2[0].sa2[0].a4_5[3], 4);
+
+ A (ta2[0].sa2[1].a3, 1);
+ A (ta2[0].sa2[1].a4_5[0], 2);
+ A (ta2[0].sa2[1].a4_5[1], 3);
+ A (ta2[0].sa2[1].a4_5[2], 4);
+ A (ta2[0].sa2[1].a4_5[3], 1);
+
+ A (ta2[0].a4, 2);
+
+ A (ta2[1].sa2[0].a3, 2);
+ A (ta2[1].sa2[0].a4_5[0], 3);
+ A (ta2[1].sa2[0].a4_5[1], 4);
+ A (ta2[1].sa2[0].a4_5[2], 1);
+ A (ta2[1].sa2[0].a4_5[3], 2);
+
+ A (ta2[1].sa2[1].a3, 1);
+ A (ta2[1].sa2[1].a4_5[0], 4);
+ A (ta2[1].sa2[1].a4_5[1], 1);
+ A (ta2[1].sa2[1].a4_5[2], 2);
+ A (ta2[1].sa2[1].a4_5[3], 3);
+
+ A (ta2[1].a4, 3);
+}
+
+/* { dg-final { scan-tree-dump-not "failure" "optimized" } }
+ { dg-final { scan-tree-dump-not "strlen" "gimple" } } */