C/C++ PATCH: Move statement-tree facilities to C

Mark Mitchell mark@codesourcery.com
Wed Sep 6 18:37:00 GMT 2000


As part of the preparation for C function-at-a-time mode, this patch
moves a bunch of g++'s statement-tree facilities into c-common and
related files.

--
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

2000-09-06  Mark Mitchell  <mark@codesourcery.com>

	Move statement-tree facilities from C++ to C front-end.
	* c-common.h (c_tree_index): Add CTI_VOID_ZERO.
	(void_zero_node): New macro.
	(struct stmt_tree_s): New type.
	(stmt_tree): New typedef.
	(struct language_function): New type.
	(last_tree): New macro.
	(last_expr_type): Likewise.
	(walk_tree_fn): New typedef.
	(current_stmt_tree): New function.
	(begin_stmt_tree): Likewise.
	(add_stmt): Likewise.
	(finish_stmt_tree): Likewise.
	(statement_code_p): Likewise.
	(lang_statement_code_p): New variable.
	(walk_stmt_tree): New function.
	(STMT_IS_FULL_EXPR_P): New macro.
	* c-common.c (lang_statement_code_p): New variable.
	(c_common_nodes_and_builtins): Initialize void_zero_node.
	(statement_code_p): New function.
	(walk_stmt_tree): Likewise.
	* c-decl.c (language_function): Rename to ...
	(c_language_function): ... this.  Include language_function.
	(push_c_function_context): Adjust accordingly.
	(pop_c_function_context): Likewise.
	(mark_c_function_context): Likewise.
	(current_stmt_tree): Define.
	* c-semantics.c (begin_stmt_tree): New function.
	(add_stmt): Likewise.
	(prune_unused_decls): Likewise.
	(finish_stmt_tree): Likewise.

2000-09-06  Mark Mitchell  <mark@codesourcery.com>

	Move statement-tree facilities from C++ to C front-end.
	* cp-tree.h (cp_tree_index): Remove CPTI_VOID_ZERO.
	(void_zero_node): Remove.
	(stmt_tree): Likewise.
	(scope_chain): Adjust.
	(language_function): Rename to cp_language_function.
	(cp_function_chain): Adjust.
	(current_stmt_tree): Remove.
	(last_tree): Likewise.
	(last_expr_type): Likewise.
	(struct lang_decl): Adjust.
	(STMT_IS_FULL_EXPR_P): Remove.
	(add_tree): Remove.
	(begin_stmt_tree): Likewise.
	(finish_stmt_tree): Likewise.
	(walk_tree_fn): Likewise.
	(walk_stmt_tree): Likewise.
	* class.c (finish_struct): Replace use of add_tree with add_stmt.
	* decl.c (mark_stmt_tree): Adjust type.
	(init_decl_processing): Don't build void_zero_node.
	(initialize_local_var): Adjust usage of current_stmt_tree.
	(finish_enum): Use add_stmt, not add_tree.
	(save_function_data): Adjust use of language_function.
	(finish_constructor_body): Use add_stmt, not add_tree.
	(finish_destructor_body): Likewise.
	(push_cp_function_context): Adjust use of language_function.
	(pop_cp_function_context): Likewise.
	(mark_lang_function): Likewise.
	(mark_cp_function_context): Likewise.
	* init.c (build_aggr_init): Adjust use of current_stmt_tree.
	(build_vec_init): Likewise.
	* semantics.c (SET_LAST_STMT): Remove.
	(RECHAIN_STMTS): Don't use it.
	(stmts_are_full_exprs_p): Adjust use of current_stmt_tree.
	(current_stmt_tree): Define.
	(add_tree): Remove.
	(finish_goto_stmt): Use add_stmt, not add_tree.
	(finish_expr_stmt): Likewise.
	(begin_if_stmt): Likewise.
	(finish_then_clause): Likewise.
	(begin_while_stmt): Likewise.
	(begin_do_stmt): Likewise.
	(finish_return_stmt): Likewise.
	(begin_for_stmt): Likewise.
	(finish_break_stmt): Likewise.
	(finish_continue_stmt): Likewise.
	(begin_switch_stmt): Likewise.
	(finish_case_label): Likewise.
	(begin_try_block): Likewise.
	(begin_function_try_block): Likewise.
	(begin_handler): Likewise.
	(begin_catch_block): Likewise.
	(begin_compound_stmt): Likewise.
	(begin_asm_stmt): Likewise.
	(finish_asm_stmt): Likewise.
	(finish_label_stmt): Likewise.
	(add_decl_stmt): Likewise.
	(finish_subobject): Likewise.
	(finish_decl_cleanup): Likewise.
	(finish_named_return_value): Likewise.
	(setup_vtbl_ptr): Likewise.
	(add_scope_stmt): Likewise.
	(finish_stmt_expr): Likewise.
	(prune_unused_decls): Remove.
	(begin_stmt_tree): Likewise.
	(finish_stmt_tree): Likewise.
	(prep_stmt): Adjust use of current_stmt_tree.
	(lang_expand_stmt): Likewise.
	* tree.c (statement_code_p): Remove.
	(cp_statement_code_p): New function.
	(walk_stmt_tree): Remove.
	(init_tree): Set lang_statement_code_p.

Index: c-common.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/c-common.c,v
retrieving revision 1.146
diff -c -p -r1.146 c-common.c
*** c-common.c	2000/09/01 22:09:55	1.146
--- c-common.c	2000/09/07 01:15:38
*************** tree *ridpointers;
*** 146,151 ****
--- 146,155 ----
  
  tree (*make_fname_decl)                PARAMS ((tree, const char *, int));
  
+ /* If non-NULL, the address of a language-specific function that
+    returns 1 for language-specific statement codes.  */
+ int (*lang_statement_code_p)           PARAMS ((enum tree_code));
+ 
  /* Nonzero means the expression being parsed will never be evaluated.
     This is a count, since unevaluated expressions can nest.  */
  int skip_evaluation;
*************** c_common_nodes_and_builtins (cplus_mode,
*** 3970,3975 ****
--- 3974,3982 ----
  							    sizetype,
  							    endlink))));
  
+   void_zero_node = build_int_2 (0, 0);
+   TREE_TYPE (void_zero_node) = void_type_node;
+ 
    /* Prototype for strcpy.  */
    string_ftype_ptr_ptr
      = build_function_type (string_type_node,
*************** expand_tree_builtin (function, params, c
*** 4476,4481 ****
--- 4483,4593 ----
      }
  
    return NULL_TREE;
+ }
+ 
+ /* Returns non-zero if CODE is the code for a statement.  */
+ 
+ int
+ statement_code_p (code)
+      enum tree_code code;
+ {
+   switch (code)
+     {
+     case EXPR_STMT:
+     case COMPOUND_STMT:
+     case DECL_STMT:
+     case IF_STMT:
+     case FOR_STMT:
+     case WHILE_STMT:
+     case DO_STMT:
+     case RETURN_STMT:
+     case BREAK_STMT:
+     case CONTINUE_STMT:
+     case SWITCH_STMT:
+     case GOTO_STMT:
+     case LABEL_STMT:
+     case ASM_STMT:
+     case CASE_LABEL:
+       return 1;
+ 
+     default:
+       if (lang_statement_code_p)
+ 	return (*lang_statement_code_p) (code);
+       return 0;
+     }
+ }
+ 
+ /* Walk the statemen tree, rooted at *tp.  Apply FUNC to all the
+    sub-trees of *TP in a pre-order traversal.  FUNC is called with the
+    DATA and the address of each sub-tree.  If FUNC returns a non-NULL
+    value, the traversal is aborted, and the value returned by FUNC is
+    returned.  If FUNC sets WALK_SUBTREES to zero, then the subtrees of
+    the node being visited are not walked.
+ 
+    We don't need a without_duplicates variant of this one because the
+    statement tree is a tree, not a graph.  */
+ 
+ tree 
+ walk_stmt_tree (tp, func, data)
+      tree *tp;
+      walk_tree_fn func;
+      void *data;
+ {
+   enum tree_code code;
+   int walk_subtrees;
+   tree result;
+   int i, len;
+ 
+ #define WALK_SUBTREE(NODE)				\
+   do							\
+     {							\
+       result = walk_stmt_tree (&(NODE), func, data);	\
+       if (result)					\
+ 	return result;					\
+     }							\
+   while (0)
+ 
+   /* Skip empty subtrees.  */
+   if (!*tp)
+     return NULL_TREE;
+ 
+   /* Skip subtrees below non-statement nodes.  */
+   if (!statement_code_p (TREE_CODE (*tp)))
+     return NULL_TREE;
+ 
+   /* Call the function.  */
+   walk_subtrees = 1;
+   result = (*func) (tp, &walk_subtrees, data);
+ 
+   /* If we found something, return it.  */
+   if (result)
+     return result;
+ 
+   /* Even if we didn't, FUNC may have decided that there was nothing
+      interesting below this point in the tree.  */
+   if (!walk_subtrees)
+     return NULL_TREE;
+ 
+   /* FUNC may have modified the tree, recheck that we're looking at a
+      statement node.  */
+   code = TREE_CODE (*tp);
+   if (!statement_code_p (code))
+     return NULL_TREE;
+ 
+   /* Walk over all the sub-trees of this operand.  Statement nodes never
+      contain RTL, and we needn't worry about TARGET_EXPRs.  */
+   len = TREE_CODE_LENGTH (code);
+ 
+   /* Go through the subtrees.  We need to do this in forward order so
+      that the scope of a FOR_EXPR is handled properly.  */
+   for (i = 0; i < len; ++i)
+     WALK_SUBTREE (TREE_OPERAND (*tp, i));
+ 
+   /* Finally visit the chain.  This can be tail-recursion optimized if
+      we write it this way.  */
+   return walk_stmt_tree (&TREE_CHAIN (*tp), func, data);
+ 
+ #undef WALK_SUBTREE
  }
  
  /* Tree code classes. */
Index: c-common.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/c-common.h,v
retrieving revision 1.33
diff -c -p -r1.33 c-common.h
*** c-common.h	2000/09/06 21:24:56	1.33
--- c-common.h	2000/09/07 01:15:39
*************** enum c_tree_index
*** 124,129 ****
--- 124,131 ----
      CTI_PRETTY_FUNCTION_ID,
      CTI_FUNC_ID,
  
+     CTI_VOID_ZERO,
+ 
      CTI_MAX
  };
  
*************** enum c_tree_index
*** 164,169 ****
--- 166,174 ----
  #define pretty_function_id_node		c_global_trees[CTI_PRETTY_FUNCTION_ID]
  #define func_id_node			c_global_trees[CTI_FUNC_ID]
  
+ /* A node for `((void) 0)'.  */
+ #define void_zero_node                  c_global_trees[CTI_VOID_ZERO]
+ 
  extern tree c_global_trees[CTI_MAX];
  
  typedef enum c_language_kind
*************** typedef enum c_language_kind
*** 175,180 ****
--- 180,247 ----
  } 
  c_language_kind;
  
+ /* Information about a statement tree.  */
+ 
+ struct stmt_tree_s {
+   /* The last statement added to the tree.  */
+   tree x_last_stmt;
+   /* The type of the last expression statement.  (This information is
+      needed to implement the statement-expression extension.)  */
+   tree x_last_expr_type;
+   /* In C++, Non-zero if we should treat statements as full
+      expressions.  In particular, this variable is no-zero if at the
+      end of a statement we should destroy any temporaries created
+      during that statement.  Similarly, if, at the end of a block, we
+      should destroy any local variables in this block.  Normally, this
+      variable is non-zero, since those are the normal semantics of
+      C++.
+ 
+      However, in order to represent aggregate initialization code as
+      tree structure, we use statement-expressions.  The statements
+      within the statement expression should not result in cleanups
+      being run until the entire enclosing statement is complete.  
+ 
+      This flag has no effect in C.  */
+   int stmts_are_full_exprs_p; 
+ };
+ 
+ typedef struct stmt_tree_s *stmt_tree;
+ 
+ /* Global state pertinent to the current function.  Some C dialects
+    extend this structure with additional fields.  */
+ 
+ struct language_function {
+   /* While we are parsing the function, this contains information
+      about the statement-tree that we are building.  */
+   struct stmt_tree_s x_stmt_tree;
+ };
+ 
+ /* When building a statement-tree, this is the last statement added to
+    the tree.  */
+ 
+ #define last_tree (current_stmt_tree ()->x_last_stmt)
+ 
+ /* The type of the last expression-statement we have seen.  */
+ 
+ #define last_expr_type (current_stmt_tree ()->x_last_expr_type)
+ 
+ /* The type of a function that walks over tree structure.  */
+ 
+ typedef tree (*walk_tree_fn)                    PARAMS ((tree *, 
+ 							 int *, 
+ 							 void *));
+ 
+ extern stmt_tree current_stmt_tree              PARAMS ((void));
+ extern void begin_stmt_tree                     PARAMS ((tree *));
+ extern void add_stmt				PARAMS ((tree));
+ extern void finish_stmt_tree                    PARAMS ((tree *));
+ 
+ extern int statement_code_p                     PARAMS ((enum tree_code));
+ extern int (*lang_statement_code_p)             PARAMS ((enum tree_code));
+ extern tree walk_stmt_tree			PARAMS ((tree *,
+ 							 walk_tree_fn,
+ 							 void *));
+ 
  /* The variant of the C language being processed.  Each C language
     front-end defines this variable.  */
  
*************** extern tree build_va_arg			PARAMS ((tree
*** 313,321 ****
  
  extern int self_promoting_args_p		PARAMS ((tree));
  extern tree simple_type_promotes_to		PARAMS ((tree));
  
! /* These macros provide convenient access to the various _STMT nodes
!    created when parsing template declarations.  */
  
  /* IF_STMT accessors. These give access to the condtion of the if
     statement, the then block of the if statement, and the else block
--- 380,393 ----
  
  extern int self_promoting_args_p		PARAMS ((tree));
  extern tree simple_type_promotes_to		PARAMS ((tree));
+ 
+ /* These macros provide convenient access to the various _STMT nodes.  */
  
! /* Nonzero if this statement should be considered a full-expression,
!    i.e., if temporaries created during this statement should have
!    their destructors run at the end of this statement.  (In C, this
!    will always be false, since there are no destructors.)  */
! #define STMT_IS_FULL_EXPR_P(NODE) TREE_LANG_FLAG_1 ((NODE))
  
  /* IF_STMT accessors. These give access to the condtion of the if
     statement, the then block of the if statement, and the else block
Index: c-decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/c-decl.c,v
retrieving revision 1.151
diff -c -p -r1.151 c-decl.c
*** c-decl.c	2000/09/06 06:06:46	1.151
--- c-decl.c	2000/09/07 01:15:43
*************** finish_function (nested)
*** 6746,6753 ****
     that keep track of the progress of compilation of the current function.
     Used for nested functions.  */
  
! struct language_function
  {
    tree named_labels;
    tree shadowed_labels;
    int returns_value;
--- 6746,6754 ----
     that keep track of the progress of compilation of the current function.
     Used for nested functions.  */
  
! struct c_language_function
  {
+   struct language_function base;
    tree named_labels;
    tree shadowed_labels;
    int returns_value;
*************** void
*** 6764,6772 ****
  push_c_function_context (f)
       struct function *f;
  {
!   struct language_function *p;
!   p = (struct language_function *) xmalloc (sizeof (struct language_function));
!   f->language = p;
  
    p->named_labels = named_labels;
    p->shadowed_labels = shadowed_labels;
--- 6765,6774 ----
  push_c_function_context (f)
       struct function *f;
  {
!   struct c_language_function *p;
!   p = ((struct c_language_function *) 
!        xmalloc (sizeof (struct c_language_function)));
!   f->language = (struct language_function *) p;
  
    p->named_labels = named_labels;
    p->shadowed_labels = shadowed_labels;
*************** void
*** 6783,6789 ****
  pop_c_function_context (f)
       struct function *f;
  {
!   struct language_function *p = f->language;
    tree link;
  
    /* Bring back all the labels that were shadowed.  */
--- 6785,6792 ----
  pop_c_function_context (f)
       struct function *f;
  {
!   struct c_language_function *p 
!     = (struct c_language_function *) f->language;
    tree link;
  
    /* Bring back all the labels that were shadowed.  */
*************** void
*** 6819,6825 ****
  mark_c_function_context (f)
       struct function *f;
  {
!   struct language_function *p = f->language;
  
    if (p == 0)
      return;
--- 6822,6829 ----
  mark_c_function_context (f)
       struct function *f;
  {
!   struct c_language_function *p 
!     = (struct c_language_function *) f->language;
  
    if (p == 0)
      return;
*************** int
*** 6882,6887 ****
--- 6886,6901 ----
  stmts_are_full_exprs_p ()
  {
    return 0;
+ }
+ 
+ /* Returns the stmt_tree (if any) to which statements are currently
+    being added.  If there is no active statement-tree, NULL is
+    returned.  */
+ 
+ stmt_tree
+ current_stmt_tree ()
+ {
+   return cfun ? &cfun->language->x_stmt_tree : NULL;
  }
  
  /* Nonzero if TYPE is an anonymous union or struct type.  Always 0 in
Index: c-semantics.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/c-semantics.c,v
retrieving revision 1.4
diff -c -p -r1.4 c-semantics.c
*** c-semantics.c	2000/07/23 19:59:40	1.4
--- c-semantics.c	2000/09/07 01:15:43
*************** Boston, MA 02111-1307, USA.  */
*** 36,41 ****
--- 36,154 ----
  #include "output.h"
  #include "timevar.h"
  
+ static tree prune_unused_decls PARAMS ((tree *, int *, void *));
+ 
+ /* Create an empty statement tree rooted at T.  */
+ 
+ void
+ begin_stmt_tree (t)
+      tree *t;
+ {
+   /* We create a trivial EXPR_STMT so that last_tree is never NULL in
+      what follows.  We remove the extraneous statement in
+      finish_stmt_tree.  */
+   *t = build_nt (EXPR_STMT, void_zero_node);
+   last_tree = *t;
+   last_expr_type = NULL_TREE;
+ }
+ 
+ /* T is a statement.  Add it to the statement-tree.  */
+ 
+ void
+ add_stmt (t)
+      tree t;
+ {
+   /* Add T to the statement-tree.  */
+   TREE_CHAIN (last_tree) = t;
+   last_tree = t;
+   /* When we expand a statement-tree, we must know whether or not the
+      statements are full-expresions.  We record that fact here.  */
+   STMT_IS_FULL_EXPR_P (last_tree) = stmts_are_full_exprs_p ();
+ }
+ 
+ /* Remove declarations of internal variables that are not used from a
+    stmt tree.  To qualify, the variable must have a name and must have
+    a zero DECL_SOURCE_LINE.  We tried to remove all variables for
+    which TREE_USED was false, but it turns out that there's tons of
+    variables for which TREE_USED is false but that are still in fact
+    used.  */
+ 
+ static tree
+ prune_unused_decls (tp, walk_subtrees, data)
+      tree *tp;
+      int *walk_subtrees ATTRIBUTE_UNUSED;
+      void *data ATTRIBUTE_UNUSED;
+ {
+   tree t = *tp;
+ 
+   if (t == NULL_TREE)
+     {
+       *walk_subtrees = 0;
+       return NULL_TREE;
+     }
+ 
+   if (TREE_CODE (t) == DECL_STMT)
+     {
+       tree d = DECL_STMT_DECL (t);
+       if (!TREE_USED (d) && DECL_NAME (d) && DECL_SOURCE_LINE (d) == 0)
+ 	{
+ 	  *tp = TREE_CHAIN (t);
+ 	  /* Recurse on the new value of tp, otherwise we will skip
+ 	     the next statement.  */
+ 	  return prune_unused_decls (tp, walk_subtrees, data);
+ 	}
+     }
+   else if (TREE_CODE (t) == SCOPE_STMT)
+     {
+       /* Remove all unused decls from the BLOCK of this SCOPE_STMT.  */
+       tree block = SCOPE_STMT_BLOCK (t);
+ 
+       if (block)
+ 	{
+ 	  tree *vp;
+ 
+ 	  for (vp = &BLOCK_VARS (block); *vp; )
+ 	    {
+ 	      tree v = *vp;
+ 	      if (! TREE_USED (v) && DECL_NAME (v) && DECL_SOURCE_LINE (v) == 0)
+ 		*vp = TREE_CHAIN (v);  /* drop */
+ 	      else
+ 		vp = &TREE_CHAIN (v);  /* advance */
+ 	    }
+ 	  /* If there are now no variables, the entire BLOCK can be dropped.
+ 	     (This causes SCOPE_NULLIFIED_P (t) to be true.)  */
+ 	  if (BLOCK_VARS (block) == NULL_TREE)
+ 	    SCOPE_STMT_BLOCK (t) = NULL_TREE;
+ 	}
+     }
+   return NULL_TREE;
+ }
+ 
+ /* Finish the statement tree rooted at T.  */
+ 
+ void
+ finish_stmt_tree (t)
+      tree *t;
+ {
+   tree stmt;
+   
+   /* Remove the fake extra statement added in begin_stmt_tree.  */
+   stmt = TREE_CHAIN (*t);
+   *t = stmt;
+   last_tree = NULL_TREE;
+ 
+   /* Remove unused decls from the stmt tree.  */
+   walk_stmt_tree (t, prune_unused_decls, NULL);
+ 
+   if (cfun)
+     {
+       /* The line-number recorded in the outermost statement in a function
+ 	 is the line number of the end of the function.  */
+       STMT_LINENO (stmt) = lineno;
+       STMT_LINENO_FOR_FN_P (stmt) = 1;
+     }
+ }
+ 
  /* Build a generic statement based on the given type of node and
     arguments. Similar to `build_nt', except that we set
     TREE_COMPLEXITY to be the current line number.  */
Index: cp/class.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/class.c,v
retrieving revision 1.336
diff -c -p -r1.336 class.c
*** class.c	2000/09/06 08:53:44	1.336
--- class.c	2000/09/07 01:15:49
*************** finish_struct (t, attributes)
*** 5268,5274 ****
      {
        tree scope = current_scope ();
        if (scope && TREE_CODE (scope) == FUNCTION_DECL)
! 	add_tree (build_min (TAG_DEFN, t));
      }
  
    return t;
--- 5268,5274 ----
      {
        tree scope = current_scope ();
        if (scope && TREE_CODE (scope) == FUNCTION_DECL)
! 	add_stmt (build_min (TAG_DEFN, t));
      }
  
    return t;
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.523
diff -c -p -r1.523 cp-tree.h
*** cp-tree.h	2000/09/06 21:24:57	1.523
--- cp-tree.h	2000/09/07 01:15:53
*************** enum cp_tree_index
*** 554,560 ****
      CPTI_JAVA_CHAR_TYPE,
      CPTI_JAVA_BOOLEAN_TYPE,
  
-     CPTI_VOID_ZERO,
      CPTI_WCHAR_DECL,
      CPTI_VTABLE_ENTRY_TYPE,
      CPTI_DELTA_TYPE,
--- 554,559 ----
*************** extern tree cp_global_trees[CPTI_MAX];
*** 647,653 ****
  #define java_char_type_node		cp_global_trees[CPTI_JAVA_CHAR_TYPE]
  #define java_boolean_type_node		cp_global_trees[CPTI_JAVA_BOOLEAN_TYPE]
  
- #define void_zero_node			cp_global_trees[CPTI_VOID_ZERO]
  #define wchar_decl_node			cp_global_trees[CPTI_WCHAR_DECL]
  #define vtable_entry_type		cp_global_trees[CPTI_VTABLE_ENTRY_TYPE]
  /* The type used to represent an offset by which to adjust the `this'
--- 646,651 ----
*************** extern tree cp_global_trees[CPTI_MAX];
*** 779,801 ****
  
  /* Global state.  */
  
- struct stmt_tree {
-   tree x_last_stmt;
-   tree x_last_expr_type;
- /* Non-zero if we should treat statements as full expressions.  In
-    particular, this variable is no-zero if at the end of a statement
-    we should destroy any temporaries created during that statement.
-    Similarly, if, at the end of a block, we should destroy any local
-    variables in this block.  Normally, this variable is non-zero,
-    since those are the normal semantics of C++.
- 
-    However, in order to represent aggregate initialization code as
-    tree structure, we use statement-expressions.  The statements
-    within the statement expression should not result in cleanups being
-    run until the entire enclosing statement is complete.  */
-   int stmts_are_full_exprs_p; 
- };
- 
  struct saved_scope {
    tree old_bindings;
    tree old_namespace;
--- 777,782 ----
*************** struct saved_scope {
*** 819,825 ****
    int x_processing_explicit_instantiation;
    int need_pop_function_context;
  
!   struct stmt_tree x_stmt_tree;
  
    struct binding_level *class_bindings;
    struct binding_level *bindings;
--- 800,806 ----
    int x_processing_explicit_instantiation;
    int need_pop_function_context;
  
!   struct stmt_tree_s x_stmt_tree;
  
    struct binding_level *class_bindings;
    struct binding_level *bindings;
*************** extern struct saved_scope *scope_chain;
*** 885,892 ****
  
  /* Global state pertinent to the current function.  */
  
! struct language_function
  {
    tree x_ctor_label;
    tree x_dtor_label;
    tree x_current_class_ptr;
--- 866,875 ----
  
  /* Global state pertinent to the current function.  */
  
! struct cp_language_function
  {
+   struct language_function base;
+ 
    tree x_ctor_label;
    tree x_dtor_label;
    tree x_current_class_ptr;
*************** struct language_function
*** 907,914 ****
    int name_declared;
    int vtbls_set_up_p;
  
-   struct stmt_tree x_stmt_tree;
- 
    struct named_label_use_list *x_named_label_uses;
    struct named_label_list *x_named_labels;
    struct binding_level *bindings;
--- 890,895 ----
*************** struct language_function
*** 918,924 ****
  
  /* The current C++-specific per-function global variables.  */
  
! #define cp_function_chain (cfun->language)
  
  /* In a destructor, the point at which all derived class destroying
     has been done, just before any base class destroying will be done.  */
--- 899,906 ----
  
  /* The current C++-specific per-function global variables.  */
  
! #define cp_function_chain \
!   ((struct cp_language_function *) (cfun->language))
  
  /* In a destructor, the point at which all derived class destroying
     has been done, just before any base class destroying will be done.  */
*************** struct language_function
*** 939,962 ****
  #define current_class_ref \
    (cfun ? cp_function_chain->x_current_class_ref : NULL_TREE)
  
- /* Information about the current statement tree.  */
- 
- #define current_stmt_tree			\
-   (cfun						\
-    ? &cp_function_chain->x_stmt_tree		\
-    : &scope_chain->x_stmt_tree)
- 
- /* When building a statement-tree, this is the last statement added to
-    the tree.  */
- 
- #define last_tree current_stmt_tree->x_last_stmt
- 
- /* The type of the last expression-statement we have seen.  This is
-    required because the type of a statement-expression is the type of
-    the last expression statement.  */
- 
- #define last_expr_type current_stmt_tree->x_last_expr_type
- 
  /* The TRY_BLOCK for the exception-specifiers for the current
     function, if any.  */
  
--- 921,926 ----
*************** struct lang_decl
*** 1912,1918 ****
    {
      tree sorted_fields;
      struct pending_inline *pending_inline_info;
!     struct language_function *saved_language_function;
    } u;
  
    union {
--- 1876,1882 ----
    {
      tree sorted_fields;
      struct pending_inline *pending_inline_info;
!     struct cp_language_function *saved_language_function;
    } u;
  
    union {
*************** struct lang_decl
*** 2461,2469 ****
  #define AGGR_INIT_VIA_CTOR_P(NODE) \
    TREE_LANG_FLAG_0 (AGGR_INIT_EXPR_CHECK (NODE))
  
- /* Nonzero if this statement should be considered a full-expression.  */
- #define STMT_IS_FULL_EXPR_P(NODE) TREE_LANG_FLAG_1 ((NODE))
- 
  /* The TYPE_MAIN_DECL for a class template type is a TYPE_DECL, not a
     TEMPLATE_DECL.  This macro determines whether or not a given class
     type is really a template type, as opposed to an instantiation or
--- 2425,2430 ----
*************** extern void do_decl_instantiation		PARAM
*** 4249,4255 ****
  extern void do_type_instantiation		PARAMS ((tree, tree, int));
  extern tree instantiate_decl			PARAMS ((tree, int));
  extern tree get_bindings			PARAMS ((tree, tree, tree));
- extern void add_tree				PARAMS ((tree));
  extern void add_maybe_template			PARAMS ((tree, tree));
  extern void pop_tinst_level			PARAMS ((void));
  extern int more_specialized_class		PARAMS ((tree, tree));
--- 4210,4215 ----
*************** extern void add_decl_stmt               
*** 4427,4434 ****
  extern void finish_decl_cleanup                 PARAMS ((tree, tree));
  extern void finish_named_return_value           PARAMS ((tree, tree));
  extern void expand_body                         PARAMS ((tree));
- extern void begin_stmt_tree                     PARAMS ((tree *));
- extern void finish_stmt_tree                    PARAMS ((tree *));
  extern void prep_stmt                           PARAMS ((tree));
  extern tree add_scope_stmt                      PARAMS ((int, int));
  extern void do_pushlevel                        PARAMS ((void));
--- 4387,4392 ----
*************** extern void debug_binfo				PARAMS ((tree
*** 4512,4526 ****
  extern tree build_dummy_object			PARAMS ((tree));
  extern tree maybe_dummy_object			PARAMS ((tree, tree *));
  extern int is_dummy_object			PARAMS ((tree));
- typedef tree (*walk_tree_fn)                    PARAMS ((tree *, int *, void *));
  extern tree walk_tree                           PARAMS ((tree *,
  							 walk_tree_fn,
  							 void *, 
  							 htab_t));
  extern tree walk_tree_without_duplicates        PARAMS ((tree *,
- 							 walk_tree_fn,
- 							 void *));
- extern tree walk_stmt_tree			PARAMS ((tree *,
  							 walk_tree_fn,
  							 void *));
  extern tree copy_tree_r                         PARAMS ((tree *, int *, void *));
--- 4470,4480 ----
Index: cp/decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl.c,v
retrieving revision 1.683
diff -c -p -r1.683 decl.c
*** decl.c	2000/09/06 21:24:57	1.683
--- decl.c	2000/09/07 01:16:01
*************** static void mark_binding_level PARAMS ((
*** 169,176 ****
  static void mark_named_label_lists PARAMS ((void *, void *));
  static void mark_cp_function_context PARAMS ((struct function *));
  static void mark_saved_scope PARAMS ((void *));
! static void mark_lang_function PARAMS ((struct language_function *));
! static void mark_stmt_tree PARAMS ((struct stmt_tree *));
  static void save_function_data PARAMS ((tree));
  static void check_function_type PARAMS ((tree));
  static void destroy_local_var PARAMS ((tree));
--- 169,176 ----
  static void mark_named_label_lists PARAMS ((void *, void *));
  static void mark_cp_function_context PARAMS ((struct function *));
  static void mark_saved_scope PARAMS ((void *));
! static void mark_lang_function PARAMS ((struct cp_language_function *));
! static void mark_stmt_tree PARAMS ((stmt_tree));
  static void save_function_data PARAMS ((tree));
  static void check_function_type PARAMS ((tree));
  static void destroy_local_var PARAMS ((tree));
*************** tree error_mark_list;
*** 200,206 ****
  
     C++ extensions
  	tree wchar_decl_node;
- 	tree void_zero_node;
  
  	tree vtable_entry_type;
  	tree delta_type_node;
--- 200,205 ----
*************** struct saved_scope *scope_chain;
*** 2453,2459 ****
  
  static void
  mark_stmt_tree (st)
!      struct stmt_tree *st;
  {
    ggc_mark_tree (st->x_last_stmt);
    ggc_mark_tree (st->x_last_expr_type);
--- 2452,2458 ----
  
  static void
  mark_stmt_tree (st)
!      stmt_tree st;
  {
    ggc_mark_tree (st->x_last_stmt);
    ggc_mark_tree (st->x_last_expr_type);
*************** init_decl_processing ()
*** 6471,6480 ****
    void_list_node = build_tree_list (NULL_TREE, void_type_node);
    TREE_PARMLIST (void_list_node) = 1;
  
-   /* Used for expressions that do nothing, but are not errors.  */
-   void_zero_node = build_int_2 (0, 0);
-   TREE_TYPE (void_zero_node) = void_type_node;
- 
    string_type_node = build_pointer_type (char_type_node);
    const_string_type_node
      = build_pointer_type (build_qualified_type (char_type_node,
--- 6470,6475 ----
*************** initialize_local_var (decl, init, flags)
*** 7965,7976 ****
  	  emit_line_note (DECL_SOURCE_FILE (decl),
  			  DECL_SOURCE_LINE (decl));
  	  saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p ();
! 	  current_stmt_tree->stmts_are_full_exprs_p = 1;
  	  if (building_stmt_tree ())
  	    finish_expr_stmt (build_aggr_init (decl, init, flags));
  	  else
  	    genrtl_expr_stmt (build_aggr_init (decl, init, flags));
! 	  current_stmt_tree->stmts_are_full_exprs_p = saved_stmts_are_full_exprs_p;
  	}
  
        /* Set this to 0 so we can tell whether an aggregate which was
--- 7960,7972 ----
  	  emit_line_note (DECL_SOURCE_FILE (decl),
  			  DECL_SOURCE_LINE (decl));
  	  saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p ();
! 	  current_stmt_tree ()->stmts_are_full_exprs_p = 1;
  	  if (building_stmt_tree ())
  	    finish_expr_stmt (build_aggr_init (decl, init, flags));
  	  else
  	    genrtl_expr_stmt (build_aggr_init (decl, init, flags));
! 	  current_stmt_tree ()->stmts_are_full_exprs_p = 
! 	    saved_stmts_are_full_exprs_p;
  	}
  
        /* Set this to 0 so we can tell whether an aggregate which was
*************** finish_enum (enumtype)
*** 13244,13250 ****
      {
        tree scope = current_scope ();
        if (scope && TREE_CODE (scope) == FUNCTION_DECL)
! 	add_tree (build_min (TAG_DEFN, enumtype));
      }
    else
      {
--- 13240,13246 ----
      {
        tree scope = current_scope ();
        if (scope && TREE_CODE (scope) == FUNCTION_DECL)
! 	add_stmt (build_min (TAG_DEFN, enumtype));
      }
    else
      {
*************** static void
*** 14037,14043 ****
  save_function_data (decl)
       tree decl;
  {
!   struct language_function *f;
  
    /* Save the language-specific per-function data so that we can
       get it back when we really expand this function.  */
--- 14033,14039 ----
  save_function_data (decl)
       tree decl;
  {
!   struct cp_language_function *f;
  
    /* Save the language-specific per-function data so that we can
       get it back when we really expand this function.  */
*************** save_function_data (decl)
*** 14045,14059 ****
  		      19990908);
  
    /* Make a copy.  */
!   f = ((struct language_function *)
!        xmalloc (sizeof (struct language_function)));
    bcopy ((char *) cp_function_chain, (char *) f,
! 	 sizeof (struct language_function));
    DECL_SAVED_FUNCTION_DATA (decl) = f;
  
    /* Clear out the bits we don't need.  */
!   f->x_stmt_tree.x_last_stmt = NULL_TREE;
!   f->x_stmt_tree.x_last_expr_type = NULL_TREE;
    f->x_result_rtx = NULL_RTX;
    f->x_named_label_uses = NULL;
    f->bindings = NULL;
--- 14041,14055 ----
  		      19990908);
  
    /* Make a copy.  */
!   f = ((struct cp_language_function *)
!        xmalloc (sizeof (struct cp_language_function)));
    bcopy ((char *) cp_function_chain, (char *) f,
! 	 sizeof (struct cp_language_function));
    DECL_SAVED_FUNCTION_DATA (decl) = f;
  
    /* Clear out the bits we don't need.  */
!   f->base.x_stmt_tree.x_last_stmt = NULL_TREE;
!   f->base.x_stmt_tree.x_last_expr_type = NULL_TREE;
    f->x_result_rtx = NULL_RTX;
    f->x_named_label_uses = NULL;
    f->bindings = NULL;
*************** finish_constructor_body ()
*** 14075,14081 ****
  {
    /* Any return from a constructor will end up here.  */
    if (ctor_label)
!     add_tree (build_stmt (LABEL_STMT, ctor_label));
  
    /* Clear CTOR_LABEL so that finish_return_stmt knows to really
       generate the return, rather than a goto to CTOR_LABEL.  */
--- 14071,14077 ----
  {
    /* Any return from a constructor will end up here.  */
    if (ctor_label)
!     add_stmt (build_stmt (LABEL_STMT, ctor_label));
  
    /* Clear CTOR_LABEL so that finish_return_stmt knows to really
       generate the return, rather than a goto to CTOR_LABEL.  */
*************** finish_constructor_body ()
*** 14084,14090 ****
       constructor to a return of `this'.  */
    finish_return_stmt (NULL_TREE);
    /* Mark the end of the constructor.  */
!   add_tree (build_stmt (CTOR_STMT));
  }
  
  /* At the end of every destructor we generate code to restore virtual
--- 14080,14086 ----
       constructor to a return of `this'.  */
    finish_return_stmt (NULL_TREE);
    /* Mark the end of the constructor.  */
!   add_stmt (build_stmt (CTOR_STMT));
  }
  
  /* At the end of every destructor we generate code to restore virtual
*************** finish_destructor_body ()
*** 14103,14109 ****
    compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
  
    /* Any return from a destructor will end up here.  */
!   add_tree (build_stmt (LABEL_STMT, dtor_label));
  
    /* Generate the code to call destructor on base class.  If this
       destructor belongs to a class with virtual functions, then set
--- 14099,14105 ----
    compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
  
    /* Any return from a destructor will end up here.  */
!   add_stmt (build_stmt (LABEL_STMT, dtor_label));
  
    /* Generate the code to call destructor on base class.  If this
       destructor belongs to a class with virtual functions, then set
*************** static void
*** 14896,14905 ****
  push_cp_function_context (f)
       struct function *f;
  {
!   struct language_function *p
!     = ((struct language_function *)
!        xcalloc (1, sizeof (struct language_function)));
!   f->language = p;
  
    /* It takes an explicit call to expand_body to generate RTL for a
       function.  */
--- 14892,14901 ----
  push_cp_function_context (f)
       struct function *f;
  {
!   struct cp_language_function *p
!     = ((struct cp_language_function *)
!        xcalloc (1, sizeof (struct cp_language_function)));
!   f->language = (struct language_function *) p;
  
    /* It takes an explicit call to expand_body to generate RTL for a
       function.  */
*************** push_cp_function_context (f)
*** 14907,14913 ****
  
    /* Whenever we start a new function, we destroy temporaries in the
       usual way.  */
!   current_stmt_tree->stmts_are_full_exprs_p = 1;
  }
  
  /* Free the language-specific parts of F, now that we've finished
--- 14903,14909 ----
  
    /* Whenever we start a new function, we destroy temporaries in the
       usual way.  */
!   current_stmt_tree ()->stmts_are_full_exprs_p = 1;
  }
  
  /* Free the language-specific parts of F, now that we've finished
*************** pop_cp_function_context (f)
*** 14926,14932 ****
  
  static void
  mark_lang_function (p)
!      struct language_function *p;
  {
    if (!p)
      return;
--- 14922,14928 ----
  
  static void
  mark_lang_function (p)
!      struct cp_language_function *p;
  {
    if (!p)
      return;
*************** mark_lang_function (p)
*** 14941,14947 ****
    ggc_mark_rtx (p->x_result_rtx);
  
    mark_named_label_lists (&p->x_named_labels, &p->x_named_label_uses);
!   mark_stmt_tree (&p->x_stmt_tree);
    mark_binding_level (&p->bindings);
  }
  
--- 14937,14943 ----
    ggc_mark_rtx (p->x_result_rtx);
  
    mark_named_label_lists (&p->x_named_labels, &p->x_named_label_uses);
!   mark_stmt_tree (&p->base.x_stmt_tree);
    mark_binding_level (&p->bindings);
  }
  
*************** static void
*** 14951,14957 ****
  mark_cp_function_context (f)
       struct function *f;
  {
!   mark_lang_function (f->language);
  }
  
  void
--- 14947,14953 ----
  mark_cp_function_context (f)
       struct function *f;
  {
!   mark_lang_function ((struct cp_language_function *) f->language);
  }
  
  void
Index: cp/init.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/init.c,v
retrieving revision 1.216
diff -c -p -r1.216 init.c
*** init.c	2000/09/06 09:04:00	1.216
--- init.c	2000/09/07 01:16:04
*************** build_aggr_init (exp, init, flags)
*** 1228,1238 ****
    TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type);
    begin_init_stmts (&stmt_expr, &compound_stmt);
    destroy_temps = stmts_are_full_exprs_p ();
!   current_stmt_tree->stmts_are_full_exprs_p = 0;
    expand_aggr_init_1 (TYPE_BINFO (type), exp, exp,
  		      init, LOOKUP_NORMAL|flags);
    stmt_expr = finish_init_stmts (stmt_expr, compound_stmt);
!   current_stmt_tree->stmts_are_full_exprs_p = destroy_temps;
    TREE_TYPE (exp) = type;
    TREE_READONLY (exp) = was_const;
    TREE_THIS_VOLATILE (exp) = was_volatile;
--- 1228,1238 ----
    TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type);
    begin_init_stmts (&stmt_expr, &compound_stmt);
    destroy_temps = stmts_are_full_exprs_p ();
!   current_stmt_tree ()->stmts_are_full_exprs_p = 0;
    expand_aggr_init_1 (TYPE_BINFO (type), exp, exp,
  		      init, LOOKUP_NORMAL|flags);
    stmt_expr = finish_init_stmts (stmt_expr, compound_stmt);
!   current_stmt_tree ()->stmts_are_full_exprs_p = destroy_temps;
    TREE_TYPE (exp) = type;
    TREE_READONLY (exp) = was_const;
    TREE_THIS_VOLATILE (exp) = was_volatile;
*************** build_vec_init (decl, base, maxindex, in
*** 2873,2879 ****
  
    begin_init_stmts (&stmt_expr, &compound_stmt);
    destroy_temps = stmts_are_full_exprs_p ();
!   current_stmt_tree->stmts_are_full_exprs_p = 0;
    rval = get_temp_regvar (ptype, 
  			  cp_convert (ptype, default_conversion (base)));
    base = get_temp_regvar (ptype, rval);
--- 2873,2879 ----
  
    begin_init_stmts (&stmt_expr, &compound_stmt);
    destroy_temps = stmts_are_full_exprs_p ();
!   current_stmt_tree ()->stmts_are_full_exprs_p = 0;
    rval = get_temp_regvar (ptype, 
  			  cp_convert (ptype, default_conversion (base)));
    base = get_temp_regvar (ptype, rval);
*************** build_vec_init (decl, base, maxindex, in
*** 3035,3043 ****
  	}
        else
  	{
! 	  current_stmt_tree->stmts_are_full_exprs_p = 1;
  	  finish_expr_stmt (elt_init);
! 	  current_stmt_tree->stmts_are_full_exprs_p = 0;
  	}
  
        finish_expr_stmt (build_modify_expr
--- 3035,3043 ----
  	}
        else
  	{
! 	  current_stmt_tree ()->stmts_are_full_exprs_p = 1;
  	  finish_expr_stmt (elt_init);
! 	  current_stmt_tree ()->stmts_are_full_exprs_p = 0;
  	}
  
        finish_expr_stmt (build_modify_expr
*************** build_vec_init (decl, base, maxindex, in
*** 3087,3093 ****
    finish_expr_stmt (rval);
  
    stmt_expr = finish_init_stmts (stmt_expr, compound_stmt);
!   current_stmt_tree->stmts_are_full_exprs_p = destroy_temps;
    return stmt_expr;
  }
  
--- 3087,3093 ----
    finish_expr_stmt (rval);
  
    stmt_expr = finish_init_stmts (stmt_expr, compound_stmt);
!   current_stmt_tree ()->stmts_are_full_exprs_p = destroy_temps;
    return stmt_expr;
  }
  
Index: cp/semantics.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/semantics.c,v
retrieving revision 1.168
diff -c -p -r1.168 semantics.c
*** semantics.c	2000/09/06 21:24:58	1.168
--- semantics.c	2000/09/07 01:16:07
***************
*** 48,74 ****
  
  static tree maybe_convert_cond PARAMS ((tree));
  static tree simplify_aggr_init_exprs_r PARAMS ((tree *, int *, void *));
- static tree prune_unused_decls PARAMS ((tree *, int *, void *));
  static void deferred_type_access_control PARAMS ((void));
  static void emit_associated_thunks PARAMS ((tree));
  
- /* Record the fact that STMT was the last statement added to the
-    statement tree.  */
- 
- #define SET_LAST_STMT(stmt) \
-   (current_stmt_tree->x_last_stmt = (stmt))
- 
  /* When parsing a template, LAST_TREE contains the last statement
     parsed.  These are chained together through the TREE_CHAIN field,
     but often need to be re-organized since the parse is performed
     bottom-up.  This macro makes LAST_TREE the indicated SUBSTMT of
     STMT.  */
  
! #define RECHAIN_STMTS(stmt, substmt)	\
!   do {					\
!     substmt = TREE_CHAIN (stmt);	\
!     TREE_CHAIN (stmt) = NULL_TREE;	\
!     SET_LAST_STMT (stmt);		\
    } while (0)
  
  /* Finish processing the COND, the SUBSTMT condition for STMT.  */
--- 48,67 ----
  
  static tree maybe_convert_cond PARAMS ((tree));
  static tree simplify_aggr_init_exprs_r PARAMS ((tree *, int *, void *));
  static void deferred_type_access_control PARAMS ((void));
  static void emit_associated_thunks PARAMS ((tree));
  
  /* When parsing a template, LAST_TREE contains the last statement
     parsed.  These are chained together through the TREE_CHAIN field,
     but often need to be re-organized since the parse is performed
     bottom-up.  This macro makes LAST_TREE the indicated SUBSTMT of
     STMT.  */
  
! #define RECHAIN_STMTS(stmt, substmt)		\
!   do {						\
!     substmt = TREE_CHAIN (stmt);		\
!     TREE_CHAIN (stmt) = NULL_TREE;		\
!     last_tree = stmt;				\
    } while (0)
  
  /* Finish processing the COND, the SUBSTMT condition for STMT.  */
*************** set_current_function_name_declared (i)
*** 107,114 ****
  
  int
  stmts_are_full_exprs_p ()
  {
!   return current_stmt_tree->stmts_are_full_exprs_p;
  }
  
  /* One if we have already declared __FUNCTION__ (and related
--- 100,119 ----
  
  int
  stmts_are_full_exprs_p ()
+ {
+   return current_stmt_tree ()->stmts_are_full_exprs_p;
+ }
+ 
+ /* Returns the stmt_tree (if any) to which statements are currently
+    being added.  If there is no active statement-tree, NULL is
+    returned.  */
+ 
+ stmt_tree
+ current_stmt_tree ()
  {
!   return (cfun 
! 	  ? &cfun->language->x_stmt_tree 
! 	  : &scope_chain->x_stmt_tree);
  }
  
  /* One if we have already declared __FUNCTION__ (and related
*************** do_pushlevel ()
*** 170,189 ****
      }
  }
  
- /* T is a statement.  Add it to the statement-tree.  */
- 
- void
- add_tree (t)
-      tree t;
- {
-   /* Add T to the statement-tree.  */
-   TREE_CHAIN (last_tree) = t;
-   SET_LAST_STMT (t);
-   /* When we expand a statement-tree, we must know whether or not the
-      statements are full-expresions.  We record that fact here.  */
-   STMT_IS_FULL_EXPR_P (last_tree) = stmts_are_full_exprs_p ();
- }
- 
  /* Finish a goto-statement.  */
  
  void
--- 175,180 ----
*************** finish_goto_stmt (destination)
*** 207,213 ****
    
    check_goto (destination);
  
!   add_tree (build_stmt (GOTO_STMT, destination));
  }
  
  /* COND is the condition-expression for an if, while, etc.,
--- 198,204 ----
    
    check_goto (destination);
  
!   add_stmt (build_stmt (GOTO_STMT, destination));
  }
  
  /* COND is the condition-expression for an if, while, etc.,
*************** finish_expr_stmt (expr)
*** 251,257 ****
        if (!processing_template_decl)
  	expr = break_out_cleanups (expr);
        
!       add_tree (build_stmt (EXPR_STMT, expr));
      }
  
    finish_stmt ();
--- 242,248 ----
        if (!processing_template_decl)
  	expr = break_out_cleanups (expr);
        
!       add_stmt (build_stmt (EXPR_STMT, expr));
      }
  
    finish_stmt ();
*************** begin_if_stmt ()
*** 271,277 ****
    tree r;
    do_pushlevel ();
    r = build_stmt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
!   add_tree (r);
    return r;
  }
  
--- 262,268 ----
    tree r;
    do_pushlevel ();
    r = build_stmt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
!   add_stmt (r);
    return r;
  }
  
*************** finish_then_clause (if_stmt)
*** 295,301 ****
       tree if_stmt;
  {
    RECHAIN_STMTS (if_stmt, THEN_CLAUSE (if_stmt));
!   SET_LAST_STMT (if_stmt);
    return if_stmt;
  }
  
--- 286,292 ----
       tree if_stmt;
  {
    RECHAIN_STMTS (if_stmt, THEN_CLAUSE (if_stmt));
!   last_tree = if_stmt;
    return if_stmt;
  }
  
*************** begin_while_stmt ()
*** 346,352 ****
  {
    tree r;
    r = build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE);
!   add_tree (r);
    do_pushlevel ();
    return r;
  }
--- 337,343 ----
  {
    tree r;
    r = build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE);
!   add_stmt (r);
    do_pushlevel ();
    return r;
  }
*************** tree
*** 382,388 ****
  begin_do_stmt ()
  {
    tree r = build_stmt (DO_STMT, NULL_TREE, NULL_TREE);
!   add_tree (r);
    return r;
  }
  
--- 373,379 ----
  begin_do_stmt ()
  {
    tree r = build_stmt (DO_STMT, NULL_TREE, NULL_TREE);
!   add_stmt (r);
    return r;
  }
  
*************** finish_return_stmt (expr)
*** 440,446 ****
  	  return;
  	}
      }
!   add_tree (build_stmt (RETURN_STMT, expr));
    finish_stmt ();
  }
  
--- 431,437 ----
  	  return;
  	}
      }
!   add_stmt (build_stmt (RETURN_STMT, expr));
    finish_stmt ();
  }
  
*************** begin_for_stmt ()
*** 454,460 ****
    r = build_stmt (FOR_STMT, NULL_TREE, NULL_TREE, 
  		  NULL_TREE, NULL_TREE);
    NEW_FOR_SCOPE_P (r) = flag_new_for_scope > 0;
!   add_tree (r);
    if (NEW_FOR_SCOPE_P (r))
      {
        do_pushlevel ();
--- 445,451 ----
    r = build_stmt (FOR_STMT, NULL_TREE, NULL_TREE, 
  		  NULL_TREE, NULL_TREE);
    NEW_FOR_SCOPE_P (r) = flag_new_for_scope > 0;
!   add_stmt (r);
    if (NEW_FOR_SCOPE_P (r))
      {
        do_pushlevel ();
*************** finish_for_stmt (for_stmt)
*** 521,527 ****
  void
  finish_break_stmt ()
  {
!   add_tree (build_stmt (BREAK_STMT));
  }
  
  /* Finish a continue-statement.  */
--- 512,518 ----
  void
  finish_break_stmt ()
  {
!   add_stmt (build_stmt (BREAK_STMT));
  }
  
  /* Finish a continue-statement.  */
*************** finish_break_stmt ()
*** 529,535 ****
  void
  finish_continue_stmt ()
  {
!   add_tree (build_stmt (CONTINUE_STMT));
  }
  
  /* Begin a switch-statement.  Returns a new SWITCH_STMT if
--- 520,526 ----
  void
  finish_continue_stmt ()
  {
!   add_stmt (build_stmt (CONTINUE_STMT));
  }
  
  /* Begin a switch-statement.  Returns a new SWITCH_STMT if
*************** begin_switch_stmt ()
*** 540,546 ****
  {
    tree r;
    r = build_stmt (SWITCH_STMT, NULL_TREE, NULL_TREE);
!   add_tree (r);
    do_pushlevel ();
    return r;
  }
--- 531,537 ----
  {
    tree r;
    r = build_stmt (SWITCH_STMT, NULL_TREE, NULL_TREE);
!   add_stmt (r);
    do_pushlevel ();
    return r;
  }
*************** finish_case_label (low_value, high_value
*** 593,599 ****
  {
    /* Add a representation for the case label to the statement
       tree.  */
!   add_tree (build_stmt (CASE_LABEL, low_value, high_value));
    /* And warn about crossing initializations, etc.  */
    if (!processing_template_decl)
      define_case_label ();
--- 584,590 ----
  {
    /* Add a representation for the case label to the statement
       tree.  */
!   add_stmt (build_stmt (CASE_LABEL, low_value, high_value));
    /* And warn about crossing initializations, etc.  */
    if (!processing_template_decl)
      define_case_label ();
*************** tree
*** 649,655 ****
  begin_try_block ()
  {
    tree r = build_stmt (TRY_BLOCK, NULL_TREE, NULL_TREE);
!   add_tree (r);
    return r;
  }
  
--- 640,646 ----
  begin_try_block ()
  {
    tree r = build_stmt (TRY_BLOCK, NULL_TREE, NULL_TREE);
!   add_stmt (r);
    return r;
  }
  
*************** begin_function_try_block ()
*** 660,666 ****
  {
    tree r = build_stmt (TRY_BLOCK, NULL_TREE, NULL_TREE);
    FN_TRY_BLOCK_P (r) = 1;
!   add_tree (r);
    return r;
  }
  
--- 651,657 ----
  {
    tree r = build_stmt (TRY_BLOCK, NULL_TREE, NULL_TREE);
    FN_TRY_BLOCK_P (r) = 1;
!   add_stmt (r);
    return r;
  }
  
*************** begin_handler ()
*** 761,767 ****
  {
    tree r;
    r = build_stmt (HANDLER, NULL_TREE, NULL_TREE);
!   add_tree (r);
    do_pushlevel ();
    return r;
  }
--- 752,758 ----
  {
    tree r;
    r = build_stmt (HANDLER, NULL_TREE, NULL_TREE);
!   add_stmt (r);
    do_pushlevel ();
    return r;
  }
*************** void
*** 813,819 ****
  begin_catch_block (type)
       tree type;
  {
!   add_tree (build (START_CATCH_STMT, type));
  }
  
  /* Finish a handler, which may be given by HANDLER.  The BLOCKs are
--- 804,810 ----
  begin_catch_block (type)
       tree type;
  {
!   add_stmt (build (START_CATCH_STMT, type));
  }
  
  /* Finish a handler, which may be given by HANDLER.  The BLOCKs are
*************** begin_compound_stmt (has_no_scope)
*** 861,867 ****
    if (last_tree && TREE_CODE (last_tree) == TRY_BLOCK)
      is_try = 1;
  
!   add_tree (r);
    if (has_no_scope)
      COMPOUND_STMT_NO_SCOPE (r) = 1;
  
--- 852,858 ----
    if (last_tree && TREE_CODE (last_tree) == TRY_BLOCK)
      is_try = 1;
  
!   add_stmt (r);
    if (has_no_scope)
      COMPOUND_STMT_NO_SCOPE (r) = 1;
  
*************** finish_asm_stmt (cv_qualifier, string, o
*** 957,963 ****
    r = build_stmt (ASM_STMT, cv_qualifier, string,
  		  output_operands, input_operands,
  		  clobbers);
!   add_tree (r);
  }
  
  /* Finish a label with the indicated NAME.  */
--- 948,954 ----
    r = build_stmt (ASM_STMT, cv_qualifier, string,
  		  output_operands, input_operands,
  		  clobbers);
!   add_stmt (r);
  }
  
  /* Finish a label with the indicated NAME.  */
*************** finish_label_stmt (name)
*** 967,973 ****
       tree name;
  {
    tree decl = define_label (input_filename, lineno, name);
!   add_tree (build_stmt (LABEL_STMT, decl));
  }
  
  /* Finish a series of declarations for local labels.  G++ allows users
--- 958,964 ----
       tree name;
  {
    tree decl = define_label (input_filename, lineno, name);
!   add_stmt (build_stmt (LABEL_STMT, decl));
  }
  
  /* Finish a series of declarations for local labels.  G++ allows users
*************** add_decl_stmt (decl)
*** 993,999 ****
  
    /* We need the type to last until instantiation time.  */
    decl_stmt = build_stmt (DECL_STMT, decl);
!   add_tree (decl_stmt); 
  }
  
  /* Generate the RTL for a SUBOBJECT. */
--- 984,990 ----
  
    /* We need the type to last until instantiation time.  */
    decl_stmt = build_stmt (DECL_STMT, decl);
!   add_stmt (decl_stmt); 
  }
  
  /* Generate the RTL for a SUBOBJECT. */
*************** finish_subobject (cleanup)
*** 1014,1020 ****
       tree cleanup;
  {
    tree r = build_stmt (SUBOBJECT, cleanup);
!   add_tree (r);
  }
  
  /* When DECL goes out of scope, make sure that CLEANUP is executed.  */
--- 1005,1011 ----
       tree cleanup;
  {
    tree r = build_stmt (SUBOBJECT, cleanup);
!   add_stmt (r);
  }
  
  /* When DECL goes out of scope, make sure that CLEANUP is executed.  */
*************** finish_decl_cleanup (decl, cleanup)
*** 1024,1030 ****
       tree decl;
       tree cleanup;
  {
!   add_tree (build_stmt (CLEANUP_STMT, decl, cleanup));
  }
  
  /* Generate the RTL for a RETURN_INIT. */
--- 1015,1021 ----
       tree decl;
       tree cleanup;
  {
!   add_stmt (build_stmt (CLEANUP_STMT, decl, cleanup));
  }
  
  /* Generate the RTL for a RETURN_INIT. */
*************** finish_named_return_value (return_id, in
*** 1103,1112 ****
        if (!processing_template_decl) 
  	{
  	  cp_finish_decl (decl, init, NULL_TREE, 0);
! 	  add_tree (build_stmt (RETURN_INIT, NULL_TREE, NULL_TREE));
  	}
        else
! 	add_tree (build_stmt (RETURN_INIT, return_id, init));
      }
  
    /* Don't use tree-inlining for functions with named return values.
--- 1094,1103 ----
        if (!processing_template_decl) 
  	{
  	  cp_finish_decl (decl, init, NULL_TREE, 0);
! 	  add_stmt (build_stmt (RETURN_INIT, NULL_TREE, NULL_TREE));
  	}
        else
! 	add_stmt (build_stmt (RETURN_INIT, return_id, init));
      }
  
    /* Don't use tree-inlining for functions with named return values.
*************** setup_vtbl_ptr (member_init_list, base_i
*** 1192,1198 ****
    if (DECL_CONSTRUCTOR_P (current_function_decl))
      {
        if (processing_template_decl)
! 	add_tree (build_min_nt
  		  (CTOR_INITIALIZER,
  		   member_init_list, base_init_list));
        else
--- 1183,1189 ----
    if (DECL_CONSTRUCTOR_P (current_function_decl))
      {
        if (processing_template_decl)
! 	add_stmt (build_min_nt
  		  (CTOR_INITIALIZER,
  		   member_init_list, base_init_list));
        else
*************** setup_vtbl_ptr (member_init_list, base_i
*** 1202,1208 ****
  	  /* Mark the beginning of the constructor.  */
  	  ctor_stmt = build_stmt (CTOR_STMT);
  	  CTOR_BEGIN_P (ctor_stmt) = 1;
! 	  add_tree (ctor_stmt);
  	  
  	  /* And actually initialize the base-classes and members.  */
  	  emit_base_init (member_init_list, base_init_list);
--- 1193,1199 ----
  	  /* Mark the beginning of the constructor.  */
  	  ctor_stmt = build_stmt (CTOR_STMT);
  	  CTOR_BEGIN_P (ctor_stmt) = 1;
! 	  add_stmt (ctor_stmt);
  	  
  	  /* And actually initialize the base-classes and members.  */
  	  emit_base_init (member_init_list, base_init_list);
*************** add_scope_stmt (begin_p, partial_p)
*** 1299,1305 ****
      }
  
    /* Add the new statement to the statement-tree.  */
!   add_tree (ss);
  
    return top;
  }
--- 1290,1296 ----
      }
  
    /* Add the new statement to the statement-tree.  */
!   add_stmt (ss);
  
    return top;
  }
*************** finish_stmt_expr (rtl_expr)
*** 1391,1397 ****
    
    /* Remove the compound statement from the tree structure; it is
       now saved in the STMT_EXPR.  */
!   SET_LAST_STMT (rtl_expr);
    TREE_CHAIN (last_tree) = NULL_TREE;
  
    /* If we created a statement-tree for this statement-expression,
--- 1382,1388 ----
    
    /* Remove the compound statement from the tree structure; it is
       now saved in the STMT_EXPR.  */
!   last_tree = rtl_expr;
    TREE_CHAIN (last_tree) = NULL_TREE;
  
    /* If we created a statement-tree for this statement-expression,
*************** finish_typeof (expr)
*** 2224,2326 ****
    return TREE_TYPE (expr);
  }
  
- /* Remove declarations of internal variables that are not used from a
-    stmt tree.  To qualify, the variable must have a name and must have
-    a zero DECL_SOURCE_LINE.  We tried to remove all variables for
-    which TREE_USED was false, but it turns out that there's tons of
-    variables for which TREE_USED is false but that are still in fact
-    used.  */
- 
- static tree
- prune_unused_decls (tp, walk_subtrees, data)
-      tree *tp;
-      int *walk_subtrees ATTRIBUTE_UNUSED;
-      void *data ATTRIBUTE_UNUSED;
- {
-   tree t = *tp;
- 
-   if (t == NULL_TREE)
-     {
-       *walk_subtrees = 0;
-       return NULL_TREE;
-     }
- 
-   if (TREE_CODE (t) == DECL_STMT)
-     {
-       tree d = DECL_STMT_DECL (t);
-       if (!TREE_USED (d) && DECL_NAME (d) && DECL_SOURCE_LINE (d) == 0)
- 	{
- 	  *tp = TREE_CHAIN (t);
- 	  /* Recurse on the new value of tp, otherwise we will skip
- 	     the next statement.  */
- 	  return prune_unused_decls (tp, walk_subtrees, data);
- 	}
-     }
-   else if (TREE_CODE (t) == SCOPE_STMT)
-     {
-       /* Remove all unused decls from the BLOCK of this SCOPE_STMT.  */
-       tree block = SCOPE_STMT_BLOCK (t);
- 
-       if (block)
- 	{
- 	  tree *vp;
- 
- 	  for (vp = &BLOCK_VARS (block); *vp; )
- 	    {
- 	      tree v = *vp;
- 	      if (! TREE_USED (v) && DECL_NAME (v) && DECL_SOURCE_LINE (v) == 0)
- 		*vp = TREE_CHAIN (v);  /* drop */
- 	      else
- 		vp = &TREE_CHAIN (v);  /* advance */
- 	    }
- 	  /* If there are now no variables, the entire BLOCK can be dropped.
- 	     (This causes SCOPE_NULLIFIED_P (t) to be true.)  */
- 	  if (BLOCK_VARS (block) == NULL_TREE)
- 	    SCOPE_STMT_BLOCK (t) = NULL_TREE;
- 	}
-     }
-   return NULL_TREE;
- }
- 
- /* Create an empty statement tree rooted at T.  */
- 
- void
- begin_stmt_tree (t)
-      tree *t;
- {
-   /* We create a trivial EXPR_STMT so that last_tree is never NULL in
-      what follows.  We remove the extraneous statement in
-      finish_stmt_tree.  */
-   *t = build_nt (EXPR_STMT, void_zero_node);
-   SET_LAST_STMT (*t);
-   last_expr_type = NULL_TREE;
- }
- 
- /* Finish the statement tree rooted at T.  */
- 
- void
- finish_stmt_tree (t)
-      tree *t;
- {
-   tree stmt;
-   
-   /* Remove the fake extra statement added in begin_stmt_tree.  */
-   stmt = TREE_CHAIN (*t);
-   *t = stmt;
-   SET_LAST_STMT (NULL_TREE);
- 
-   /* Remove unused decls from the stmt tree.  */
-   walk_stmt_tree (t, prune_unused_decls, NULL);
- 
-   if (cfun)
-     {
-       /* The line-number recorded in the outermost statement in a function
- 	 is the line number of the end of the function.  */
-       STMT_LINENO (stmt) = lineno;
-       STMT_LINENO_FOR_FN_P (stmt) = 1;
-     }
- }
- 
  /* We're about to expand T, a statement.  Set up appropriate context
     for the substitution.  */
  
--- 2215,2220 ----
*************** prep_stmt (t)
*** 2330,2336 ****
  {
    if (!STMT_LINENO_FOR_FN_P (t))
      lineno = STMT_LINENO (t);
!   current_stmt_tree->stmts_are_full_exprs_p = STMT_IS_FULL_EXPR_P (t);
  }
  
  /* Generate RTL for the statement T, and its substatements, and any
--- 2224,2230 ----
  {
    if (!STMT_LINENO_FOR_FN_P (t))
      lineno = STMT_LINENO (t);
!   current_stmt_tree ()->stmts_are_full_exprs_p = STMT_IS_FULL_EXPR_P (t);
  }
  
  /* Generate RTL for the statement T, and its substatements, and any
*************** lang_expand_stmt (t)
*** 2454,2460 ****
  	}
  
        /* Restore saved state.  */
!       current_stmt_tree->stmts_are_full_exprs_p = saved_stmts_are_full_exprs_p;
  
        /* Go on to the next statement in this scope.  */
        t = TREE_CHAIN (t);
--- 2348,2355 ----
  	}
  
        /* Restore saved state.  */
!       current_stmt_tree ()->stmts_are_full_exprs_p = 
! 	saved_stmts_are_full_exprs_p;
  
        /* Go on to the next statement in this scope.  */
        t = TREE_CHAIN (t);
Index: cp/tree.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/tree.c,v
retrieving revision 1.214
diff -c -p -r1.214 tree.c
*** tree.c	2000/09/06 05:52:51	1.214
--- tree.c	2000/09/07 01:16:08
*************** static cp_lvalue_kind lvalue_p_1 PARAMS 
*** 42,48 ****
  static tree no_linkage_helper PARAMS ((tree *, int *, void *));
  static tree build_srcloc PARAMS ((const char *, int));
  static void mark_list_hash PARAMS ((void *));
- static int statement_code_p PARAMS ((enum tree_code));
  static tree mark_local_for_remap_r PARAMS ((tree *, int *, void *));
  static tree cp_unsave_r PARAMS ((tree *, int *, void *));
  static void cp_unsave PARAMS ((tree *));
--- 42,47 ----
*************** static tree build_target_expr PARAMS ((t
*** 50,55 ****
--- 49,55 ----
  static tree count_trees_r PARAMS ((tree *, int *, void *));
  static tree verify_stmt_tree_r PARAMS ((tree *, int *, void *));
  static tree find_tree_r PARAMS ((tree *, int *, void *));
+ extern int cp_statement_code_p PARAMS ((enum tree_code));
  
  /* If REF is an lvalue, returns the kind of lvalue that REF is.
     Otherwise, returns clk_none.  If TREAT_CLASS_RVALUES_AS_LVALUES is
*************** is_aggr_type_2 (t1, t2)
*** 1071,1103 ****
  
  /* Returns non-zero if CODE is the code for a statement.  */
  
! static int
! statement_code_p (code)
       enum tree_code code;
  {
    switch (code)
      {
-     case EXPR_STMT:
-     case COMPOUND_STMT:
-     case DECL_STMT:
-     case IF_STMT:
-     case FOR_STMT:
-     case WHILE_STMT:
-     case DO_STMT:
-     case RETURN_STMT:
-     case BREAK_STMT:
-     case CONTINUE_STMT:
-     case SWITCH_STMT:
-     case GOTO_STMT:
-     case LABEL_STMT:
-     case ASM_STMT:
      case SUBOBJECT:
      case CLEANUP_STMT:
      case START_CATCH_STMT:
      case CTOR_STMT:
      case SCOPE_STMT:
      case CTOR_INITIALIZER:
-     case CASE_LABEL:
      case RETURN_INIT:
      case TRY_BLOCK:
      case HANDLER:
--- 1071,1088 ----
  
  /* Returns non-zero if CODE is the code for a statement.  */
  
! int
! cp_statement_code_p (code)
       enum tree_code code;
  {
    switch (code)
      {
      case SUBOBJECT:
      case CLEANUP_STMT:
      case START_CATCH_STMT:
      case CTOR_STMT:
      case SCOPE_STMT:
      case CTOR_INITIALIZER:
      case RETURN_INIT:
      case TRY_BLOCK:
      case HANDLER:
*************** copy_template_template_parm (t, newargs)
*** 1223,1231 ****
  /* Apply FUNC to all the sub-trees of TP in a pre-order traversal.
     FUNC is called with the DATA and the address of each sub-tree.  If
     FUNC returns a non-NULL value, the traversal is aborted, and the
!    value returned by FUNC is returned.  The FLAGS govern the way in
!    which nodes are walked.  If HTAB is non-NULL it is used to record
!    the nodes visited, and to avoid visiting a node more than once.  */
  
  tree 
  walk_tree (tp, func, data, htab)
--- 1208,1216 ----
  /* Apply FUNC to all the sub-trees of TP in a pre-order traversal.
     FUNC is called with the DATA and the address of each sub-tree.  If
     FUNC returns a non-NULL value, the traversal is aborted, and the
!    value returned by FUNC is returned.  If HTAB is non-NULL it is used
!    to record the nodes visited, and to avoid visiting a node more than
!    once.  */
  
  tree 
  walk_tree (tp, func, data, htab)
*************** walk_tree_without_duplicates (tp, func, 
*** 1455,1527 ****
    return result;
  }
  
- /* Like walk_tree, but only examines statement nodes.  We don't need a
-    without_duplicates variant of this one because the statement tree is
-    a tree, not a graph.  */
- 
- tree 
- walk_stmt_tree (tp, func, data)
-      tree *tp;
-      walk_tree_fn func;
-      void *data;
- {
-   enum tree_code code;
-   int walk_subtrees;
-   tree result;
-   int i, len;
- 
- #define WALK_SUBTREE(NODE)				\
-   do							\
-     {							\
-       result = walk_stmt_tree (&(NODE), func, data);	\
-       if (result)					\
- 	return result;					\
-     }							\
-   while (0)
- 
-   /* Skip empty subtrees.  */
-   if (!*tp)
-     return NULL_TREE;
- 
-   /* Skip subtrees below non-statement nodes.  */
-   if (!statement_code_p (TREE_CODE (*tp)))
-     return NULL_TREE;
- 
-   /* Call the function.  */
-   walk_subtrees = 1;
-   result = (*func) (tp, &walk_subtrees, data);
- 
-   /* If we found something, return it.  */
-   if (result)
-     return result;
- 
-   /* Even if we didn't, FUNC may have decided that there was nothing
-      interesting below this point in the tree.  */
-   if (!walk_subtrees)
-     return NULL_TREE;
- 
-   /* FUNC may have modified the tree, recheck that we're looking at a
-      statement node.  */
-   code = TREE_CODE (*tp);
-   if (!statement_code_p (code))
-     return NULL_TREE;
- 
-   /* Walk over all the sub-trees of this operand.  Statement nodes never
-      contain RTL, and we needn't worry about TARGET_EXPRs.  */
-   len = TREE_CODE_LENGTH (code);
- 
-   /* Go through the subtrees.  We need to do this in forward order so
-      that the scope of a FOR_EXPR is handled properly.  */
-   for (i = 0; i < len; ++i)
-     WALK_SUBTREE (TREE_OPERAND (*tp, i));
- 
-   /* Finally visit the chain.  This can be tail-recursion optimized if
-      we write it this way.  */
-   return walk_stmt_tree (&TREE_CHAIN (*tp), func, data);
- 
- #undef WALK_SUBTREE
- }
- 
  /* Called from count_trees via walk_tree.  */
  
  static tree
--- 1440,1445 ----
*************** init_tree ()
*** 2477,2482 ****
--- 2395,2401 ----
  {
    make_lang_type_fn = cp_make_lang_type;
    lang_unsave = cp_unsave;
+   lang_statement_code_p = cp_statement_code_p;
    ggc_add_root (list_hash_table, 
  		ARRAY_SIZE (list_hash_table),
  		sizeof (struct list_hash *),


More information about the Gcc-patches mailing list