From: Jakub Jelinek Date: Wed, 1 Aug 2018 09:10:31 +0000 (+0200) Subject: re PR c/85704 (cc1 run out of memory when it compile) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=5922dcb5cc82f48862cd42bd84e3c85733cac0ce;p=gcc.git 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 --- diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 424b6a12bff..0c845e27c6d 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,10 @@ +2018-08-01 Jakub Jelinek + + 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 * 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 90ae306c99a..f6a326c8152 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 d6e0a62f5fe..c4561cd4594 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2018-08-01 Jakub Jelinek + + PR c/85704 + * gcc.c-torture/compile/pr85704.c: New test. + 2018-07-31 Alexandre Oliva Olivier Hainque 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 00000000000..52dd50433d6 --- /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 = {} } }; +}