re PR c/85704 (cc1 run out of memory when it compile)
authorJakub Jelinek <jakub@redhat.com>
Wed, 1 Aug 2018 09:10:31 +0000 (11:10 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 1 Aug 2018 09:10:31 +0000 (11:10 +0200)
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

gcc/c/ChangeLog
gcc/c/c-typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/compile/pr85704.c [new file with mode: 0644]

index 424b6a12bff9f00a06ca3087626a53658f4e3ba9..0c845e27c6d6180bbf04cae5dd962c6440f88340 100644 (file)
@@ -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
index 90ae306c99ac2cd33124747150d6c95aaed9beff..f6a326c8152cde22adb092bc7f47a1064f798d20 100644 (file)
@@ -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;
index d6e0a62f5fedc7bb45d1048c3ddd0a651f28a789..c4561cd4594dabb440953a7b6057c3c4e3a1af5a 100644 (file)
@@ -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 (file)
index 0000000..52dd504
--- /dev/null
@@ -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 = {} } };
+}