aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormsebor <msebor@138bc75d-0d04-0410-961f-82ee72b054a4>2019-03-19 22:43:10 +0000
committermsebor <msebor@138bc75d-0d04-0410-961f-82ee72b054a4>2019-03-19 22:43:10 +0000
commitdc0cf27032c22f246c7dafc816e52b99597c97ab (patch)
tree0d5363919c319be1c5f4edf1f375d47e39dbecf1
parent2bc36e30005b4ad029eb7fa4357766338916ef6e (diff)
PR tree-optimization/89688 - -Wstringop-overflow confused by const 2D array of char
gcc/c/ChangeLog: PR tree-optimization/89688 * c-decl.c (finish_decl): Call braced_lists_to_string for more kinds of initializers. gcc/c-family/ChangeLog: PR tree-optimization/89688 * c-common.c (braced_list_to_string): Make static. (braced_lists_to_strings): Define new function. * c-common.h (braced_list_to_string): Remove. (braced_lists_to_strings): Declare. gcc/cp/ChangeLog: PR tree-optimization/89688 * typeck2.c (store_init_value): Call braced_lists_to_string for more kinds of initializers. gcc/testsuite/ChangeLog: PR tree-optimization/89688 * gcc.dg/strlenopt-61.c: New test. * g++.dg/warn/Wstringop-overflow-2.C: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@269814 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/c-family/ChangeLog8
-rw-r--r--gcc/c-family/c-common.c50
-rw-r--r--gcc/c-family/c-common.h3
-rw-r--r--gcc/c/ChangeLog6
-rw-r--r--gcc/c/c-decl.c9
-rw-r--r--gcc/cp/ChangeLog6
-rw-r--r--gcc/cp/typeck2.c7
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/g++.dg/warn/Wstringop-overflow-2.C29
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-61.c218
10 files changed, 331 insertions, 11 deletions
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 910cee85941..df61b693205 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,11 @@
+2019-03-19 Martin Sebor <msebor@redhat.com>
+
+ PR tree-optimization/89688
+ * c-common.c (braced_list_to_string): Make static.
+ (braced_lists_to_strings): Define new function.
+ * c-common.h (braced_list_to_string): Remove.
+ (braced_lists_to_strings): Declare.
+
2019-03-12 Martin Liska <mliska@suse.cz>
* c-opts.c (c_common_handle_option): Wrap option with %< and %>.
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 019f1082922..0e17fef8818 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -8814,7 +8814,7 @@ maybe_add_include_fixit (rich_location *richloc, const char *header,
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)))
@@ -8895,4 +8895,52 @@ braced_list_to_string (tree type, tree ctor)
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"
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 394a0ea1c89..104c74226de 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1372,7 +1372,8 @@ extern void maybe_add_include_fixit (rich_location *, const char *, bool);
extern void maybe_suggest_missing_token_insertion (rich_location *richloc,
enum cpp_ttype token_type,
location_t prev_token_loc);
-extern tree braced_list_to_string (tree, tree);
+extern tree braced_lists_to_strings (tree, tree);
+
extern bool has_attribute (location_t, tree, tree, tree (*)(tree));
#if CHECKING_P
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index fd3d009f13e..fc8049e832e 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,9 @@
+2019-03-19 Martin Sebor <msebor@redhat.com>
+
+ PR tree-optimization/89688
+ * c-decl.c (finish_decl): Call braced_lists_to_string for more
+ kinds of initializers.
+
2019-03-19 Jakub Jelinek <jakub@redhat.com>
PR c/89734
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index e8b7ca4ae5b..8d5c35ab475 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -5165,11 +5165,10 @@ finish_decl (tree decl, location_t init_loc, tree init,
relayout_decl (decl);
}
- if (TREE_CODE (type) == ARRAY_TYPE
- && TYPE_STRING_FLAG (TREE_TYPE (type))
- && DECL_INITIAL (decl)
- && TREE_CODE (DECL_INITIAL (decl)) == CONSTRUCTOR)
- DECL_INITIAL (decl) = braced_list_to_string (type, DECL_INITIAL (decl));
+ /* Look for braced array initializers for character arrays and
+ recursively convert them into STRING_CSTs. */
+ if (tree init = DECL_INITIAL (decl))
+ DECL_INITIAL (decl) = braced_lists_to_strings (type, init);
if (VAR_P (decl))
{
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 76bc8ffaa68..2157496745e 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,9 @@
+2019-03-19 Martin Sebor <msebor@redhat.com>
+
+ PR tree-optimization/89688
+ * typeck2.c (store_init_value): Call braced_lists_to_string for more
+ kinds of initializers.
+
2019-03-18 Jason Merrill <jason@redhat.com>
PR c++/89630 - ICE with dependent using-decl as template arg.
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 456c4fcb748..e50d6ed83c3 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -824,10 +824,9 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
value = digest_init_flags (type, init, flags, tf_warning_or_error);
}
- if (TREE_CODE (type) == ARRAY_TYPE
- && TYPE_STRING_FLAG (TREE_TYPE (type))
- && TREE_CODE (value) == CONSTRUCTOR)
- value = braced_list_to_string (type, value);
+ /* Look for braced array initializers for character arrays and
+ recursively convert them into STRING_CSTs. */
+ value = braced_lists_to_strings (type, value);
current_ref_temp_count = 0;
value = extend_ref_init_temps (decl, value, cleanups);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 7ad6ccc1e4a..e60ec93ced3 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2019-03-19 Martin Sebor <msebor@redhat.com>
+
+ PR tree-optimization/89688
+ * gcc.dg/strlenopt-61.c: New test.
+ * g++.dg/warn/Wstringop-overflow-2.C: New test.
+
2019-03-19 Jim Wilson <jimw@sifive.com>
PR target/89411
diff --git a/gcc/testsuite/g++.dg/warn/Wstringop-overflow-2.C b/gcc/testsuite/g++.dg/warn/Wstringop-overflow-2.C
new file mode 100644
index 00000000000..425ba83841b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wstringop-overflow-2.C
@@ -0,0 +1,29 @@
+/* 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" } */
+
+extern "C" __SIZE_TYPE__ strlen (const char*);
+
+const char a2[2] = { '1' };
+
+void a2_len ()
+{
+ if (strlen (a2) != 1)
+ __builtin_abort ();
+}
+
+const char a2_2[2][3] = { { '1' }, { '1', '2' } };
+
+void a2_2_len ()
+{
+ if (strlen (a2_2[0]) != 1) // { dg-bogus "-Wstringop-overflow" }
+ __builtin_abort ();
+
+ if (strlen (a2_2[1]) != 2) // { dg-bogus "-Wstringop-overflow" }
+ __builtin_abort ();
+}
+
+
+/* { dg-final { scan-tree-dump-not "abort" "optimized" } }
+ { dg-final { scan-tree-dump-not "strlen" "gimple" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-61.c b/gcc/testsuite/gcc.dg/strlenopt-61.c
new file mode 100644
index 00000000000..4f8e9c053e4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-61.c
@@ -0,0 +1,218 @@
+/* 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" } } */