aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2018-08-01 11:10:31 +0200
committerJakub Jelinek <jakub@gcc.gnu.org>2018-08-01 11:10:31 +0200
commit5922dcb5cc82f48862cd42bd84e3c85733cac0ce (patch)
tree5da99f1c888c027956275da6051673c2ce41f66f
parentd1b05d128dca0009642908dd2fb490c1ee27e72e (diff)
downloadgcc-5922dcb5cc82f48862cd42bd84e3c85733cac0ce.zip
gcc-5922dcb5cc82f48862cd42bd84e3c85733cac0ce.tar.gz
gcc-5922dcb5cc82f48862cd42bd84e3c85733cac0ce.tar.bz2
re PR c/85704 (cc1 run out of memory when it compile)
PR c/85704 * c-typeck.c (init_field_decl_cmp): New function. (output_pending_init_elements): Use it for field comparisons instead of pure bit_position comparisons. * gcc.c-torture/compile/pr85704.c: New test. From-SVN: r263198
-rw-r--r--gcc/c/ChangeLog7
-rw-r--r--gcc/c/c-typeck.c86
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.c-torture/compile/pr85704.c10
4 files changed, 91 insertions, 17 deletions
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index 424b6a1..0c845e2 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,10 @@
+2018-08-01 Jakub Jelinek <jakub@redhat.com>
+
+ PR c/85704
+ * c-typeck.c (init_field_decl_cmp): New function.
+ (output_pending_init_elements): Use it for field comparisons
+ instead of pure bit_position comparisons.
+
2018-07-12 Jakub Jelinek <jakub@redhat.com>
* c-decl.c (c_decl_attributes): Don't diagnose vars without mappable
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 90ae306..f6a326c 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -9330,6 +9330,65 @@ output_init_element (location_t loc, tree value, tree origtype,
output_pending_init_elements (0, braced_init_obstack);
}
+/* For two FIELD_DECLs in the same chain, return -1 if field1
+ comes before field2, 1 if field1 comes after field2 and
+ 0 if field1 == field2. */
+
+static int
+init_field_decl_cmp (tree field1, tree field2)
+{
+ if (field1 == field2)
+ return 0;
+
+ tree bitpos1 = bit_position (field1);
+ tree bitpos2 = bit_position (field2);
+ if (tree_int_cst_equal (bitpos1, bitpos2))
+ {
+ /* If one of the fields has non-zero bitsize, then that
+ field must be the last one in a sequence of zero
+ sized fields, fields after it will have bigger
+ bit_position. */
+ if (TREE_TYPE (field1) != error_mark_node
+ && COMPLETE_TYPE_P (TREE_TYPE (field1))
+ && integer_nonzerop (TREE_TYPE (field1)))
+ return 1;
+ if (TREE_TYPE (field2) != error_mark_node
+ && COMPLETE_TYPE_P (TREE_TYPE (field2))
+ && integer_nonzerop (TREE_TYPE (field2)))
+ return -1;
+ /* Otherwise, fallback to DECL_CHAIN walk to find out
+ which field comes earlier. Walk chains of both
+ fields, so that if field1 and field2 are close to each
+ other in either order, it is found soon even for large
+ sequences of zero sized fields. */
+ tree f1 = field1, f2 = field2;
+ while (1)
+ {
+ f1 = DECL_CHAIN (f1);
+ f2 = DECL_CHAIN (f2);
+ if (f1 == NULL_TREE)
+ {
+ gcc_assert (f2);
+ return 1;
+ }
+ if (f2 == NULL_TREE)
+ return -1;
+ if (f1 == field2)
+ return -1;
+ if (f2 == field1)
+ return 1;
+ if (!tree_int_cst_equal (bit_position (f1), bitpos1))
+ return 1;
+ if (!tree_int_cst_equal (bit_position (f2), bitpos1))
+ return -1;
+ }
+ }
+ else if (tree_int_cst_lt (bitpos1, bitpos2))
+ return -1;
+ else
+ return 1;
+}
+
/* Output any pending elements which have become next.
As we output elements, constructor_unfilled_{fields,index}
advances, which may cause other elements to become next;
@@ -9401,25 +9460,18 @@ output_pending_init_elements (int all, struct obstack * braced_init_obstack)
}
else if (RECORD_OR_UNION_TYPE_P (constructor_type))
{
- tree ctor_unfilled_bitpos, elt_bitpos;
-
/* If the current record is complete we are done. */
if (constructor_unfilled_fields == NULL_TREE)
break;
- ctor_unfilled_bitpos = bit_position (constructor_unfilled_fields);
- elt_bitpos = bit_position (elt->purpose);
- /* We can't compare fields here because there might be empty
- fields in between. */
- if (tree_int_cst_equal (elt_bitpos, ctor_unfilled_bitpos))
- {
- constructor_unfilled_fields = elt->purpose;
- output_init_element (input_location, elt->value, elt->origtype,
- true, TREE_TYPE (elt->purpose),
- elt->purpose, false, false,
- braced_init_obstack);
- }
- else if (tree_int_cst_lt (ctor_unfilled_bitpos, elt_bitpos))
+ int cmp = init_field_decl_cmp (constructor_unfilled_fields,
+ elt->purpose);
+ if (cmp == 0)
+ output_init_element (input_location, elt->value, elt->origtype,
+ true, TREE_TYPE (elt->purpose),
+ elt->purpose, false, false,
+ braced_init_obstack);
+ else if (cmp < 0)
{
/* Advance to the next smaller node. */
if (elt->left)
@@ -9445,8 +9497,8 @@ output_pending_init_elements (int all, struct obstack * braced_init_obstack)
elt = elt->parent;
elt = elt->parent;
if (elt
- && (tree_int_cst_lt (ctor_unfilled_bitpos,
- bit_position (elt->purpose))))
+ && init_field_decl_cmp (constructor_unfilled_fields,
+ elt->purpose) < 0)
{
next = elt->purpose;
break;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index d6e0a62..c4561cd 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2018-08-01 Jakub Jelinek <jakub@redhat.com>
+
+ PR c/85704
+ * gcc.c-torture/compile/pr85704.c: New test.
+
2018-07-31 Alexandre Oliva <oliva@adacore.com>
Olivier Hainque <hainque@adacore.com>
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr85704.c b/gcc/testsuite/gcc.c-torture/compile/pr85704.c
new file mode 100644
index 0000000..52dd504
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/pr85704.c
@@ -0,0 +1,10 @@
+/* PR c/85704 */
+
+struct C { struct {} c; };
+struct D { int d; struct C e; int f; };
+
+void
+foo (struct D *x)
+{
+ *x = (struct D) { .e = (struct C) { .c = {} } };
+}