Fri Apr  9 20:03:38 1993  Jim Wilson  (wilson@wookumz.gnu.ai.mit.edu)

	* c-typeck.c (free_tree_list): New variable.
	(digest_init): Set free_tree_list.
	(process_init_constructor): Use add_double to do arithmetic with
	double integers instead of using fold/build to to arithmetic in
	type of array index.  Use free_tree_list when available instead of
	generating a new tree_list.

*** c-typeck.c.orig	Thu Nov 26 12:30:00 1992
--- c-typeck.c	Sat Apr 17 22:12:17 1993
*************** pedwarn_init (format, local, ofwhat)
*** 4521,4526 ****
--- 4521,4540 ----
    pedwarn (format, buffer);
  }
  
+ /* Keep a pointer to the last free TREE_LIST node as we digest an initializer,
+    so that we can reuse it.  This is set in digest_init, and used in
+    process_init_constructor.
+ 
+    We will never keep more than one free TREE_LIST node here.  This is for
+    two main reasons.  First, we take elements off the old list and add them
+    to the new list one at a time, thus there should never be more than
+    one free TREE_LIST at a time, and thus even if there is, we will never
+    need more than one.  Secondly, to avoid dangling pointers to freed obstacks,
+    we want to always ensure that we have either a pointer to a valid TREE_LIST
+    within the current initializer, or else a pointer to null.  */
+ 
+ static tree free_tree_list = NULL_TREE;
+ 
  /* Digest the parser output INIT as an initializer for type TYPE.
     Return a C expression of type TYPE to represent the initial value.
  
*************** digest_init (type, init, tail, require_c
*** 4554,4566 ****
    tree inside_init = init;
  
    /* By default, assume we use one element from a list.
!      We correct this later in the sole case where it is not true.  */
  
    if (tail)
      {
        old_tail_contents = *tail;
        *tail = TREE_CHAIN (*tail);
      }
  
    if (init == error_mark_node)
      return init;
--- 4568,4588 ----
    tree inside_init = init;
  
    /* By default, assume we use one element from a list.
!      We correct this later in the cases where it is not true.
! 
!      Thus, we update TAIL now to point to the next element, and save the
!      old value in OLD_TAIL_CONTENTS.  If we didn't actually use the first
!      element, then we will reset TAIL before proceeding.  FREE_TREE_LIST
!      is handled similarly.  */
  
    if (tail)
      {
        old_tail_contents = *tail;
        *tail = TREE_CHAIN (*tail);
+       free_tree_list = old_tail_contents;
      }
+   else
+     free_tree_list = 0;
  
    if (init == error_mark_node)
      return init;
*************** digest_init (type, init, tail, require_c
*** 4737,4742 ****
--- 4759,4765 ----
        else if (tail != 0)
  	{
  	  *tail = old_tail_contents;
+ 	  free_tree_list = NULL_TREE;
  	  result = process_init_constructor (type, NULL_TREE, tail,
  					     require_constant,
  					     constructor_constant, ofwhat);
*************** digest_init (type, init, tail, require_c
*** 4833,4838 ****
--- 4856,4862 ----
        else if (tail != 0)
  	{
  	  *tail = old_tail_contents;
+ 	  free_tree_list = NULL_TREE;
  	  return process_init_constructor (type, NULL_TREE, tail,
  					   constructor_constant,
  					   constructor_constant, ofwhat);
*************** process_init_constructor (type, init, el
*** 4917,4954 ****
  
    if (TREE_CODE (type) == ARRAY_TYPE)
      {
!       tree min_index, max_index, current_index, members_index;
!       tree bound_type;
!       tree one;
        /* These are non-zero only within a range initializer.  */
        tree start_index = 0, end_index = 0;
        /* Within a range, this is the value for the elts in the range.  */
        tree range_val = 0;
  
        /* If we have array bounds, set our bounds from that.  Otherwise,
! 	 we have a lower bound of zero and an unknown upper bound.  Also
! 	 set the type of the bounds; use "int" as default.  */
        if (TYPE_DOMAIN (type))
  	{
! 	  min_index = members_index = TYPE_MIN_VALUE (TYPE_DOMAIN (type));
  	  max_index = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
- 	  bound_type = TREE_TYPE (min_index);
  	}
        else
  	{
! 	  min_index = members_index = integer_zero_node;
  	  max_index = 0;
- 	  bound_type = integer_type_node;
  	}
  
!       one = convert (bound_type, integer_one_node);
  
        /* Don't leave the loop based on index if the next item has an explicit
  	 index value that will override it. */
  
!       for (current_index = min_index; tail != 0 || end_index;
! 	   current_index = fold (build (PLUS_EXPR, bound_type,
! 					current_index, one)))
  	{
  	  register tree next1 = 0;
  
--- 4941,4987 ----
  
    if (TREE_CODE (type) == ARRAY_TYPE)
      {
!       tree min_index, max_index;
        /* These are non-zero only within a range initializer.  */
        tree start_index = 0, end_index = 0;
        /* Within a range, this is the value for the elts in the range.  */
        tree range_val = 0;
+       /* Do arithmetic using double integers, but don't use fold/build,
+ 	 because these allocate a new tree object everytime they are called,
+ 	 thus resulting in gcc using too much memory for large
+ 	 initializers.  */
+       union tree_node current_index_node, members_index_node;
+       tree current_index = &current_index_node;
+       tree members_index = &members_index_node;
+       TREE_TYPE (current_index) = integer_type_node;
+       TREE_TYPE (members_index) = integer_type_node;
  
        /* If we have array bounds, set our bounds from that.  Otherwise,
! 	 we have a lower bound of zero and an unknown upper bound.  */
        if (TYPE_DOMAIN (type))
  	{
! 	  min_index = TYPE_MIN_VALUE (TYPE_DOMAIN (type));
  	  max_index = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
  	}
        else
  	{
! 	  min_index = integer_zero_node;
  	  max_index = 0;
  	}
  
!       TREE_INT_CST_LOW (members_index) = TREE_INT_CST_LOW (min_index);
!       TREE_INT_CST_HIGH (members_index) = TREE_INT_CST_HIGH (min_index);
  
        /* Don't leave the loop based on index if the next item has an explicit
  	 index value that will override it. */
  
!       for (TREE_INT_CST_LOW (current_index) = TREE_INT_CST_LOW (min_index),
! 	   TREE_INT_CST_HIGH (current_index) = TREE_INT_CST_HIGH (min_index);
! 	   tail != 0 || end_index;
! 	   add_double (TREE_INT_CST_LOW (current_index),
! 		       TREE_INT_CST_HIGH (current_index), 1, 0,
! 		       &TREE_INT_CST_LOW (current_index),
! 		       &TREE_INT_CST_HIGH (current_index)))
  	{
  	  register tree next1 = 0;
  
*************** process_init_constructor (type, init, el
*** 5095,5114 ****
  	     Make the list longer if necessary.  */
  	  while (! tree_int_cst_lt (current_index, members_index))
  	    {
! 	      members = tree_cons (NULL_TREE, NULL_TREE, members);
! 	      members_index = fold (build (PLUS_EXPR, bound_type,
! 					   members_index, one));
  	    }
  
  	  {
  	    tree temp;
! 	    tree idx;
  
  	    temp = members;
! 	    for (idx = fold (build (MINUS_EXPR, bound_type,
! 				    members_index, one));
  		 tree_int_cst_lt (current_index, idx);
! 		 idx = fold (build (MINUS_EXPR, bound_type, idx, one)))
  	      temp = TREE_CHAIN (temp);
  	    TREE_VALUE (temp) = next1;
  	  }
--- 5128,5165 ----
  	     Make the list longer if necessary.  */
  	  while (! tree_int_cst_lt (current_index, members_index))
  	    {
! 	      if (free_tree_list)
! 		{
! 		  TREE_CHAIN (free_tree_list) = members;
! 		  TREE_PURPOSE (free_tree_list) = NULL_TREE;
! 		  TREE_VALUE (free_tree_list) = NULL_TREE;
! 		  members = free_tree_list;
! 		  free_tree_list = NULL_TREE;
! 		}
! 	      else
! 		members = tree_cons (NULL_TREE, NULL_TREE, members);
! 	      add_double (TREE_INT_CST_LOW (members_index),
! 			  TREE_INT_CST_HIGH (members_index), 1, 0,
! 			  &TREE_INT_CST_LOW (members_index),
! 			  &TREE_INT_CST_HIGH (members_index));
  	    }
  
  	  {
  	    tree temp;
! 	    union tree_node idx_node;
! 	    tree idx = &idx_node;
! 	    TREE_TYPE (idx) = integer_type_node;
  
  	    temp = members;
! 	    for (add_double (TREE_INT_CST_LOW (members_index),
! 			     TREE_INT_CST_HIGH (members_index), -1, -1,
! 			     &TREE_INT_CST_LOW (idx),
! 			     &TREE_INT_CST_HIGH (idx));
  		 tree_int_cst_lt (current_index, idx);
! 		 add_double (TREE_INT_CST_LOW (idx),
! 			     TREE_INT_CST_HIGH (idx), -1, -1,
! 			     &TREE_INT_CST_LOW (idx),
! 			     &TREE_INT_CST_HIGH (idx)))
  	      temp = TREE_CHAIN (temp);
  	    TREE_VALUE (temp) = next1;
  	  }
*************** process_init_constructor (type, init, el
*** 5196,5202 ****
  	     Make the list longer if necessary.  */
  	  while (i >= members_length)
  	    {
! 	      members = tree_cons (NULL_TREE, NULL_TREE, members);
  	      members_length++;
  	    }
  	  {
--- 5247,5262 ----
  	     Make the list longer if necessary.  */
  	  while (i >= members_length)
  	    {
! 	      if (free_tree_list)
! 		{
! 		  TREE_CHAIN (free_tree_list) = members;
! 		  TREE_PURPOSE (free_tree_list) = NULL_TREE;
! 		  TREE_VALUE (free_tree_list) = NULL_TREE;
! 		  members = free_tree_list;
! 		  free_tree_list = NULL_TREE;
! 		}
! 	      else
! 		members = tree_cons (NULL_TREE, NULL_TREE, members);
  	      members_length++;
  	    }
  	  {
*************** process_init_constructor (type, init, el
*** 5284,5291 ****
        else if (!TREE_CONSTANT (next1))
  	allconstant = 0;
        else if (initializer_constant_valid_p (next1, TREE_TYPE (next1)) == 0)
! 	allsimple = 0;
!       members = tree_cons (field, next1, members);
      }
  
    /* If arguments were specified as a list, just remove the ones we used.  */
--- 5344,5360 ----
        else if (!TREE_CONSTANT (next1))
  	allconstant = 0;
        else if (initializer_constant_valid_p (next1, TREE_TYPE (next1)) == 0)
! 	allsimple = 0; 
!      if (free_tree_list)
! 	{
! 	  TREE_CHAIN (free_tree_list) = members;
! 	  TREE_PURPOSE (free_tree_list) = field;
! 	  TREE_VALUE (free_tree_list) = next1;
! 	  members = free_tree_list;
! 	  free_tree_list = NULL_TREE;
! 	}
!       else
! 	members = tree_cons (field, next1, members);
      }
  
    /* If arguments were specified as a list, just remove the ones we used.  */
*************** process_init_constructor (type, init, el
*** 5316,5322 ****
    if (erroneous)
      return error_mark_node;
  
!   result = build (CONSTRUCTOR, type, NULL_TREE, nreverse (members));
    if (allconstant) TREE_CONSTANT (result) = 1;
    if (allconstant && allsimple) TREE_STATIC (result) = 1;
    return result;
--- 5385,5400 ----
    if (erroneous)
      return error_mark_node;
  
!   if (elts)
!     result = build (CONSTRUCTOR, type, NULL_TREE, nreverse (members));
!   else
!     {
!       result = init;
!       CONSTRUCTOR_ELTS (result) = nreverse (members);
!       TREE_TYPE (result) = type;
!       TREE_CONSTANT (result) = 0;
!       TREE_STATIC (result) = 0;
!     }
    if (allconstant) TREE_CONSTANT (result) = 1;
    if (allconstant && allsimple) TREE_STATIC (result) = 1;
    return result;
