C++ PATCH for inlining-on-trees

Mark Mitchell mark@codesourcery.com
Thu Nov 25 12:31:00 GMT 1999


Here's the inlining-on-trees patch.  The functionality is disabled,
and there is not command-line switch to turn it on.  Such things will
be added when the functionality is a little more complete.  At this
point, the only real limitation is that debugging information inlined
functions is wrong.  If you want to play with the code, set
flag_inline_trees to 1 in decl2.c.

That will enable inlining-on-trees even without -O.  The resulting
compiler passes the regression test-suite on i686-pc-linux-gnu.

At this point, inlining-on-trees doesn't really do much good (although
we do now inline `f<int>' in:

  template <class T> inline void f(){};	
  template void f<int>();
  void g() { f<int>(); }

which we did not before, oddly.)  The real win when will come with the
next phase of this work, where we will not even bother to generate RTL
for a function until we know it needs to be written out.  That should
enable considerable memory savings, especially because the tree-based
inliner knows that given:

  inline void f() {}
  inline void g() { f(); }
  inline void h() { g(); }

there is no need to inline f into g; instead, we can just directly
inline both into h.  This doesn't fire yet because we are still
generating RTL for g, so we need to inline f at that point.

After that phase is done, I'll do the debugging information bit, turn
this on by default (with -O2) in the C++ front-end, and write
something for the web-page.

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

1999-11-22  Mark Mitchell  <mark@codesourcery.com>

	* cp-tree.def (FUNCTION_NAME): New tree node.
	* cp-tree.h (current_function_name_declared): Tweak documentation.
	(lang_decl_flags): Add pretty_function_p, adjust dummy.
	(DECL_PRETTY_FUNCTION_P): New macro.
	* decl.c (cp_finish_decl): Handle declarations of __FUNCTION__,
	etc., in a template function.  Use at_function_scope_p instead of
	expanding it inline.
	* pt.c (tsubst_decl): Handle DECL_PRETTY_FUNCTION_P declarations
	specially.
	(tsubst): Handle FUNCTION_NAME.
	(tsubst_copy): Likewise.
	(instantiate_decl): Prevent redeclarations of __PRETTY_FUNCTION__,
	etc. in instantiation.
	* semantics.c (begin_compound_stmt): Declare __FUNCTION__, etc.,
	even in template functions.
	(setup_vtbl_ptr): Don't declare __PRETTY_FUNCTION in the
	conditional scope at the top of a destructor.
	
	* error.c (dump_function_decl): Use `[ with ... ]' syntax for
	specializations too.

Index: Make-lang.in
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/Make-lang.in,v
retrieving revision 1.40
diff -c -p -r1.40 Make-lang.in
*** Make-lang.in	1999/09/13 03:57:39	1.40
--- Make-lang.in	1999/11/25 19:42:49
*************** CXX_SRCS = $(srcdir)/cp/call.c $(srcdir)
*** 118,124 ****
   $(srcdir)/cp/error.c $(srcdir)/cp/friend.c $(srcdir)/cp/init.c \
   $(srcdir)/cp/parse.y $(srcdir)/cp/typeck2.c \
   $(srcdir)/cp/repo.c $(srcdir)/cp/semantics.c \
!  $(srcdir)/cp/dump.c
  
  cc1plus$(exeext): $(P) $(CXX_SRCS) $(LIBDEPS) stamp-objlist c-common.o \
          c-pragma.o $(srcdir)/cp/cp-tree.h $(srcdir)/cp/cp-tree.def \
--- 118,124 ----
   $(srcdir)/cp/error.c $(srcdir)/cp/friend.c $(srcdir)/cp/init.c \
   $(srcdir)/cp/parse.y $(srcdir)/cp/typeck2.c \
   $(srcdir)/cp/repo.c $(srcdir)/cp/semantics.c \
!  $(srcdir)/cp/dump.c $(srcdir)/cp/optimize.c
  
  cc1plus$(exeext): $(P) $(CXX_SRCS) $(LIBDEPS) stamp-objlist c-common.o \
          c-pragma.o $(srcdir)/cp/cp-tree.h $(srcdir)/cp/cp-tree.def \
Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/Makefile.in,v
retrieving revision 1.75
diff -c -p -r1.75 Makefile.in
*** Makefile.in	1999/11/05 09:21:53	1.75
--- Makefile.in	1999/11/25 19:42:49
*************** INCLUDES = -I. -I.. -I$(srcdir) -I$(srcd
*** 175,181 ****
  CXX_OBJS = call.o decl.o errfn.o expr.o pt.o typeck2.o \
   class.o decl2.o error.o lex.o parse.o ptree.o rtti.o spew.o typeck.o cvt.o \
   except.o friend.o init.o method.o search.o semantics.o tree.o xref.o \
!  repo.o dump.o @extra_cxx_objs@
  
  # Language-independent object files.
  OBJS = `cat ../stamp-objlist` ../c-common.o ../c-pragma.o
--- 175,181 ----
  CXX_OBJS = call.o decl.o errfn.o expr.o pt.o typeck2.o \
   class.o decl2.o error.o lex.o parse.o ptree.o rtti.o spew.o typeck.o cvt.o \
   except.o friend.o init.o method.o search.o semantics.o tree.o xref.o \
!  repo.o dump.o optimize.o @extra_cxx_objs@
  
  # Language-independent object files.
  OBJS = `cat ../stamp-objlist` ../c-common.o ../c-pragma.o
*************** RTL_H = $(srcdir)/../rtl.h $(srcdir)/../
*** 202,213 ****
  TREE_H = $(srcdir)/../tree.h $(srcdir)/../real.h $(srcdir)/../tree.def \
  	$(srcdir)/../machmode.h $(srcdir)/../machmode.def
  CXX_TREE_H = $(TREE_H) cp-tree.h $(srcdir)/../c-common.h cp-tree.def \
! 	$(srcdir)/../function.h $(srcdir)/../varray.h
  PARSE_H = $(srcdir)/parse.h
  PARSE_C = $(srcdir)/parse.c
  EXPR_H = $(srcdir)/../expr.h ../insn-codes.h
  
! parse.o : $(PARSE_C) $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h lex.h \
  	$(srcdir)/../except.h $(srcdir)/../output.h $(srcdir)/../system.h \
  	$(srcdir)/../toplev.h $(srcdir)/../ggc.h
  	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(BIG_SWITCHFLAG) \
--- 202,215 ----
  TREE_H = $(srcdir)/../tree.h $(srcdir)/../real.h $(srcdir)/../tree.def \
  	$(srcdir)/../machmode.h $(srcdir)/../machmode.def
  CXX_TREE_H = $(TREE_H) cp-tree.h $(srcdir)/../c-common.h cp-tree.def \
! 	$(srcdir)/../function.h $(srcdir)/../varray.h \
! 	$(srcdir)/../../include/splay-tree.h \
! 	$(srcdir)/../system.h $(CONFIG_H)
  PARSE_H = $(srcdir)/parse.h
  PARSE_C = $(srcdir)/parse.c
  EXPR_H = $(srcdir)/../expr.h ../insn-codes.h
  
! parse.o : $(PARSE_C) $(CXX_TREE_H) $(srcdir)/../flags.h lex.h \
  	$(srcdir)/../except.h $(srcdir)/../output.h $(srcdir)/../system.h \
  	$(srcdir)/../toplev.h $(srcdir)/../ggc.h
  	$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(BIG_SWITCHFLAG) \
*************** $(srcdir)/hash.h: $(srcdir)/gxx.gperf
*** 239,302 ****
  	echo "	ftp://sourceware.cygnus.com/pub/egcs/infrastructure/gperf* " >&2 ; \
  	exit 1 )
  
! spew.o : spew.c $(CONFIG_H) $(CXX_TREE_H) $(PARSE_H) $(srcdir)/../flags.h \
!   lex.h $(srcdir)/../system.h $(srcdir)/../toplev.h
! lex.o : lex.c $(CONFIG_H) $(CXX_TREE_H) \
    $(PARSE_H) input.c $(srcdir)/../flags.h hash.h lex.h \
!   $(srcdir)/../c-pragma.h $(srcdir)/../system.h $(srcdir)/../toplev.h \
    $(srcdir)/../output.h $(srcdir)/../mbchar.h $(srcdir)/../ggc.h
! decl.o : decl.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
    lex.h decl.h $(srcdir)/../stack.h $(srcdir)/../output.h  \
!   $(srcdir)/../except.h $(srcdir)/../system.h $(srcdir)/../toplev.h \
    $(srcdir)/../hash.h $(srcdir)/../ggc.h $(RTL_H)
! decl2.o : decl2.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
!   lex.h decl.h $(EXPR_H) $(srcdir)/../except.h \
!   $(srcdir)/../output.h $(srcdir)/../except.h $(srcdir)/../system.h \
    $(srcdir)/../toplev.h $(srcdir)/../dwarf2out.h $(srcdir)/../dwarfout.h \
!   $(srcdir)/../../include/splay-tree.h $(srcdir)/../ggc.h $(RTL_H)
! typeck2.o : typeck2.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
!   $(srcdir)/../system.h $(srcdir)/../toplev.h $(srcdir)/../output.h
! typeck.o : typeck.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \
!   $(EXPR_H) $(srcdir)/../system.h $(srcdir)/../toplev.h 
! class.o : class.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
!   $(srcdir)/../system.h $(srcdir)/../toplev.h \
!   $(srcdir)/../../include/splay-tree.h $(RTL_H)
! call.o : call.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
!   $(srcdir)/../system.h $(srcdir)/../toplev.h $(RTL_H)
! friend.o : friend.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \
!   $(srcdir)/../system.h $(srcdir)/../toplev.h
! init.o : init.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \
!   $(EXPR_H) $(srcdir)/../system.h $(srcdir)/../toplev.h $(srcdir)/../ggc.h
! method.o : method.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h \
    $(srcdir)/../toplev.h $(srcdir)/../ggc.h $(RTL_H)
! cvt.o : cvt.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h decl.h \
    $(srcdir)/../flags.h $(srcdir)/../toplev.h $(srcdir)/../convert.h
! search.o : search.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../stack.h \
!   $(srcdir)/../flags.h $(srcdir)/../system.h $(srcdir)/../toplev.h $(RTL_H)
! tree.o : tree.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
!   $(srcdir)/../system.h $(srcdir)/../toplev.h $(srcdir)/../ggc.h $(RTL_H) \
!   $(srcdir)/../../include/splay-tree.h
! ptree.o : ptree.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h
! rtti.o : rtti.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
!   $(srcdir)/../system.h $(srcdir)/../toplev.h
! except.o : except.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \
!   $(srcdir)/../except.h $(srcdir)/../system.h $(srcdir)/../toplev.h
! expr.o : expr.c $(CONFIG_H) $(CXX_TREE_H) $(RTL_H) $(srcdir)/../flags.h \
!   $(EXPR_H) $(srcdir)/../system.h $(srcdir)/../toplev.h $(srcdir)/../except.h
! xref.o : xref.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../input.h \
!   $(srcdir)/../system.h $(srcdir)/../toplev.h
! pt.o : pt.c $(CONFIG_H) $(CXX_TREE_H) decl.h $(PARSE_H) lex.h \
!   $(srcdir)/../system.h $(srcdir)/../toplev.h $(srcdir)/../ggc.h $(RTL_H)
! error.o : error.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h \
    $(srcdir)/../toplev.h
! errfn.o : errfn.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h \
    $(srcdir)/../toplev.h
! repo.o : repo.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h \
    $(srcdir)/../toplev.h $(srcdir)/../ggc.h
! semantics.o: semantics.c $(CONFIG_H) $(CXX_TREE_H) lex.h \
!   $(srcdir)/../except.h $(srcdir)/../system.h $(srcdir)/../toplev.h \
    $(srcdir)/../flags.h $(srcdir)/../ggc.h
! dump.o: dump.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h
  
  #
  # These exist for maintenance purposes.
--- 241,306 ----
  	echo "	ftp://sourceware.cygnus.com/pub/egcs/infrastructure/gperf* " >&2 ; \
  	exit 1 )
  
! spew.o : spew.c $(CXX_TREE_H) $(PARSE_H) $(srcdir)/../flags.h \
!   lex.h $(srcdir)/../toplev.h
! lex.o : lex.c $(CXX_TREE_H) \
    $(PARSE_H) input.c $(srcdir)/../flags.h hash.h lex.h \
!   $(srcdir)/../c-pragma.h $(srcdir)/../toplev.h \
    $(srcdir)/../output.h $(srcdir)/../mbchar.h $(srcdir)/../ggc.h
! decl.o : decl.c $(CXX_TREE_H) $(srcdir)/../flags.h \
    lex.h decl.h $(srcdir)/../stack.h $(srcdir)/../output.h  \
!   $(srcdir)/../except.h $(srcdir)/../toplev.h \
    $(srcdir)/../hash.h $(srcdir)/../ggc.h $(RTL_H)
! decl2.o : decl2.c $(CXX_TREE_H) $(srcdir)/../flags.h \
!   lex.h decl.h $(EXPR_H) $(srcdir)/../output.h $(srcdir)/../except.h \
    $(srcdir)/../toplev.h $(srcdir)/../dwarf2out.h $(srcdir)/../dwarfout.h \
!   $(srcdir)/../ggc.h $(RTL_H)
! typeck2.o : typeck2.c $(CXX_TREE_H) $(srcdir)/../flags.h \
!   $(srcdir)/../toplev.h $(srcdir)/../output.h
! typeck.o : typeck.c $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \
!   $(EXPR_H) $(srcdir)/../toplev.h 
! class.o : class.c $(CXX_TREE_H) $(srcdir)/../flags.h \
!   $(srcdir)/../toplev.h $(RTL_H)
! call.o : call.c $(CXX_TREE_H) $(srcdir)/../flags.h \
!   $(srcdir)/../toplev.h $(RTL_H)
! friend.o : friend.c $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \
!   $(srcdir)/../toplev.h
! init.o : init.c $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \
!   $(EXPR_H) $(srcdir)/../toplev.h $(srcdir)/../ggc.h \
!   $(srcdir)/../except.h
! method.o : method.c $(CXX_TREE_H) \
    $(srcdir)/../toplev.h $(srcdir)/../ggc.h $(RTL_H)
! cvt.o : cvt.c $(CXX_TREE_H) decl.h \
    $(srcdir)/../flags.h $(srcdir)/../toplev.h $(srcdir)/../convert.h
! search.o : search.c $(CXX_TREE_H) $(srcdir)/../stack.h \
!   $(srcdir)/../flags.h $(srcdir)/../toplev.h $(RTL_H)
! tree.o : tree.c $(CXX_TREE_H) $(srcdir)/../flags.h \
!   $(srcdir)/../toplev.h $(srcdir)/../ggc.h $(RTL_H) \
!   ../insn-config.h $(srcdir)/../integrate.h
! ptree.o : ptree.c $(CXX_TREE_H) $(srcdir)/../system.h
! rtti.o : rtti.c $(CXX_TREE_H) $(srcdir)/../flags.h \
!   $(srcdir)/../toplev.h
! except.o : except.c $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \
!   $(srcdir)/../except.h $(srcdir)/../toplev.h
! expr.o : expr.c $(CXX_TREE_H) $(RTL_H) $(srcdir)/../flags.h \
!   $(EXPR_H) $(srcdir)/../toplev.h $(srcdir)/../except.h
! xref.o : xref.c $(CXX_TREE_H) $(srcdir)/../input.h \
!   $(srcdir)/../toplev.h
! pt.o : pt.c $(CXX_TREE_H) decl.h $(PARSE_H) lex.h \
!   $(srcdir)/../toplev.h $(srcdir)/../ggc.h $(RTL_H) \
!   $(srcdir)/../except.h
! error.o : error.c $(CXX_TREE_H) \
    $(srcdir)/../toplev.h
! errfn.o : errfn.c $(CXX_TREE_H) \
    $(srcdir)/../toplev.h
! repo.o : repo.c $(CXX_TREE_H) \
    $(srcdir)/../toplev.h $(srcdir)/../ggc.h
! semantics.o: semantics.c $(CXX_TREE_H) lex.h \
!   $(srcdir)/../except.h $(srcdir)/../toplev.h \
    $(srcdir)/../flags.h $(srcdir)/../ggc.h
! dump.o: dump.c $(CXX_TREE_H)
! optimize.o: optimize.c $(CXX_TREE_H) \
!   $(srcdir)/../rtl.h $(srcdir)/../integrate.h ../insn-config.h
  
  #
  # These exist for maintenance purposes.
Index: class.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/class.c,v
retrieving revision 1.201
diff -c -p -r1.201 class.c
*** class.c	1999/11/16 01:37:38	1.201
--- class.c	1999/11/25 19:42:52
*************** Boston, MA 02111-1307, USA.  */
*** 30,36 ****
  #include "rtl.h"
  #include "output.h"
  #include "toplev.h"
- #include "splay-tree.h"
  #include "ggc.h"
  #include "lex.h"
  
--- 30,35 ----
Index: cp-tree.def
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.def,v
retrieving revision 1.41
diff -c -p -r1.41 cp-tree.def
*** cp-tree.def	1999/11/23 07:31:07	1.41
--- cp-tree.def	1999/11/25 19:42:52
*************** DEFTREECODE (ASM_STMT, "asm_stmt", 'e', 
*** 237,245 ****
     run if an exception is thrown before the end of the enclosing
     function.  */
  DEFTREECODE (SUBOBJECT, "subobject", 'e', 1)
! /* A CTOR_COMPLETE statements marks the end of the main body of the
!    constructor, not including any function try blocks.  */
! DEFTREECODE (CTOR_COMPLETE, "ctor_complete", 'e', 0)
  /* A CLEANUP_STMT marks the point at which a declaration is fully
     constructed.  If, after this point, the CLEANUP_DECL goes out of
     scope, the CLEANUP_EXPR must be run.  */
--- 237,247 ----
     run if an exception is thrown before the end of the enclosing
     function.  */
  DEFTREECODE (SUBOBJECT, "subobject", 'e', 1)
! /* An CTOR_STMT marks the beginning (if CTOR_BEGIN_P holds) or end of
!    a contstructor (if CTOR_END_P) holds.  At the end of a constructor,
!    the cleanups associated with any SUBOBJECT_CLEANUPS need no longer
!    be run.  */
! DEFTREECODE (CTOR_STMT, "ctor_stmt", 'e', 0)
  /* A CLEANUP_STMT marks the point at which a declaration is fully
     constructed.  If, after this point, the CLEANUP_DECL goes out of
     scope, the CLEANUP_EXPR must be run.  */
Index: cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.354
diff -c -p -r1.354 cp-tree.h
*** cp-tree.h	1999/11/23 08:08:53	1.354
--- cp-tree.h	1999/11/25 19:42:55
*************** Boston, MA 02111-1307, USA.  */
*** 21,26 ****
--- 21,27 ----
  
  #include "c-common.h"
  #include "function.h"
+ #include "splay-tree.h"
  #include "varray.h"
  
  #ifndef _CP_TREE_H
*************** Boston, MA 02111-1307, USA.  */
*** 40,45 ****
--- 41,47 ----
        CLEANUP_P (in TRY_BLOCK)
        AGGR_INIT_VIA_CTOR_P (in AGGR_INIT_EXPR)
        SCOPE_BEGIN_P (in SCOPE_STMT)
+       CTOR_BEGIN_P (in CTOR_STMT)
     1: IDENTIFIER_VIRTUAL_P.
        TI_PENDING_TEMPLATE_FLAG.
        TEMPLATE_PARMS_FOR_INLINE.
*************** extern int flag_new_for_scope;
*** 2121,2126 ****
--- 2123,2132 ----
  #define SET_DECL_C_BIT_FIELD(NODE) \
    (DECL_LANG_SPECIFIC (FIELD_DECL_CHECK (NODE))->decl_flags.bitfield = 1)
  
+ /* In a FUNCTION_DECL, nonzero if the function cannot be inlined.  */
+ #define DECL_UNINLINABLE(NODE) \
+   (DECL_LANG_SPECIFIC (NODE)->decl_flags.bitfield)
+ 
  #define INTEGRAL_CODE_P(CODE) \
    (CODE == INTEGER_TYPE || CODE == ENUMERAL_TYPE || CODE == BOOLEAN_TYPE)
  
*************** extern int flag_new_for_scope;
*** 2691,2696 ****
--- 2697,2710 ----
  #define SCOPE_END_P(NODE) \
    (!SCOPE_BEGIN_P (SCOPE_STMT_CHECK (NODE)))
  
+ /* Nonzero if this CTOR_STMT is for the beginning of a constructor.  */
+ #define CTOR_BEGIN_P(NODE) \
+   (TREE_LANG_FLAG_0 (CTOR_STMT_CHECK (NODE)))
+ 
+ /* Nonzero if this CTOR_STMT is for the end of a constructor.  */
+ #define CTOR_END_P(NODE) \
+   (!CTOR_BEGIN_P (NODE))
+ 
  /* Nonzero for a SCOPE_STMT if there were no variables in this scope.  */
  #define SCOPE_NULLIFIED_P(NODE) \
    (TREE_LANG_FLAG_3 (SCOPE_STMT_CHECK (NODE)))
*************** extern int flag_new_abi;
*** 3107,3112 ****
--- 3121,3131 ----
  
  extern int flag_honor_std;
  
+ /* Nonzero if we should expand functions calls inline at the tree
+    level, rather than at the RTL level.  */
+ 
+ extern int flag_inline_trees;
+ 
  /* Nonzero if we're done parsing and into end-of-file activities.  */
  
  extern int at_eof;
*************** extern tree maybe_push_decl             
*** 3532,3537 ****
--- 3551,3558 ----
  extern void emit_local_var                      PROTO((tree));
  extern tree build_target_expr_with_type         PROTO((tree, tree));
  extern void make_rtl_for_local_static           PROTO((tree));
+ extern int local_variable_p                     PROTO((tree));
+ extern int nonstatic_local_decl_p               PROTO((tree));
  
  /* in decl2.c */
  extern void init_decl2				PROTO((void));
*************** extern void emit_thunk				PROTO((tree));
*** 3744,3749 ****
--- 3765,3773 ----
  extern void synthesize_method			PROTO((tree));
  extern tree get_id_2				PROTO((const char *, tree));
  
+ /* In optimize.c */
+ extern void optimize_function                   PROTO((tree));
+ 
  /* in pt.c */
  extern void init_pt                             PROTO ((void));
  extern void check_template_shadow		PROTO ((tree));
*************** extern tree arbitrate_lookup			PROTO((tr
*** 3960,3966 ****
  
  /* in tree.c */
  extern void init_tree			        PROTO((void));
- extern void cplus_unsave_expr_now               PROTO((tree));
  extern int pod_type_p				PROTO((tree));
  extern void unshare_base_binfos			PROTO((tree));
  extern int member_p				PROTO((tree));
--- 3984,3989 ----
*************** extern tree maybe_dummy_object			PROTO((
*** 4028,4036 ****
--- 4051,4061 ----
  extern int is_dummy_object			PROTO((tree));
  typedef tree (*walk_tree_fn)                    PROTO((tree *, int *, void *));
  extern tree walk_tree                           PROTO((tree *, walk_tree_fn, void *));
+ extern tree copy_tree_r                         PROTO((tree *, int *, void *));
  extern int cp_valid_lang_attribute		PROTO((tree, tree, tree, tree));
  extern tree make_ptrmem_cst                     PROTO((tree, tree));
  extern tree cp_build_qualified_type_real        PROTO((tree, int, int));
+ extern void remap_save_expr                     PROTO((tree *, splay_tree, tree));
  #define cp_build_qualified_type(TYPE, QUALS) \
    cp_build_qualified_type_real ((TYPE), (QUALS), /*complain=*/1)
  
Index: decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl.c,v
retrieving revision 1.509
diff -c -p -r1.509 decl.c
*** decl.c	1999/11/23 16:17:52	1.509
--- decl.c	1999/11/25 19:43:04
*************** static boolean typename_compare PROTO((h
*** 141,147 ****
  static void push_binding PROTO((tree, tree, struct binding_level*));
  static int add_binding PROTO((tree, tree));
  static void pop_binding PROTO((tree, tree));
! static tree local_variable_p PROTO((tree *, int *, void *));
  static tree find_binding PROTO((tree, tree));
  static tree select_decl PROTO((tree, int));
  static int lookup_flags PROTO((int, int));
--- 141,147 ----
  static void push_binding PROTO((tree, tree, struct binding_level*));
  static int add_binding PROTO((tree, tree));
  static void pop_binding PROTO((tree, tree));
! static tree local_variable_p_walkfn PROTO((tree *, int *, void *));
  static tree find_binding PROTO((tree, tree));
  static tree select_decl PROTO((tree, int));
  static int lookup_flags PROTO((int, int));
*************** make_rtl_for_local_static (decl)
*** 7362,7387 ****
    tree type = TREE_TYPE (decl);
    const char *asmspec = NULL;
  
!   if (TREE_READONLY (decl)
!       && DECL_INITIAL (decl) != NULL_TREE
!       && DECL_INITIAL (decl) != error_mark_node
!       && ! EMPTY_CONSTRUCTOR_P (DECL_INITIAL (decl))
!       && ! TREE_SIDE_EFFECTS (decl)
!       && ! TREE_PUBLIC (decl)
!       && ! DECL_EXTERNAL (decl)
!       && ! TYPE_NEEDS_DESTRUCTOR (type)
!       && ! TREE_ADDRESSABLE (decl)
!       && DECL_MODE (decl) != BLKmode)
!     {
!       /* As an optimization, we try to put register-sized static
! 	 constants in a register, rather than writing them out.  If we
! 	 take the address of the constant later, we'll make RTL for it
! 	 at that point.  */
!       DECL_RTL (decl) = gen_reg_rtx (DECL_MODE (decl));
!       store_expr (DECL_INITIAL (decl), DECL_RTL (decl), 0);
!       TREE_ASM_WRITTEN (decl) = 1;
!       return;
!     }
  
    if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl))
      {
--- 7362,7371 ----
    tree type = TREE_TYPE (decl);
    const char *asmspec = NULL;
  
!   /* If we inlined this variable, we could see it's declaration
!      again.  */
!   if (DECL_RTL (decl))
!     return;
  
    if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl))
      {
*************** emit_local_var (decl)
*** 7543,7551 ****
  {
    /* Create RTL for this variable.  */
    if (DECL_RTL (decl))
!     /* Only a RESULT_DECL should have non-NULL RTL when
! 		     arriving here.  All other local variables are
! 		     assigned RTL in this function.  */
      my_friendly_assert (TREE_CODE (decl) == RESULT_DECL, 
  			19990828);
    else
--- 7527,7534 ----
  {
    /* Create RTL for this variable.  */
    if (DECL_RTL (decl))
!     /* Only a RESULT_DECL should have non-NULL RTL when arriving here.
!        All other local variables are assigned RTL in this function.  */
      my_friendly_assert (TREE_CODE (decl) == RESULT_DECL, 
  			19990828);
    else
*************** require_complete_types_for_parms (parms)
*** 11141,11167 ****
      }
  }
  
! /* Returns *TP if *TP is a local variable (or parameter).  Returns
!    NULL_TREE otherwise.  */
  
! static tree
! local_variable_p (tp, walk_subtrees, data)
!      tree *tp;
!      int *walk_subtrees ATTRIBUTE_UNUSED;
!      void *data ATTRIBUTE_UNUSED;
  {
-   tree t = *tp;
- 
    if ((TREE_CODE (t) == VAR_DECL 
         /* A VAR_DECL with a context that is a _TYPE is a static data
  	  member.  */
         && !TYPE_P (CP_DECL_CONTEXT (t))
         /* Any other non-local variable must be at namespace scope.  */
!        && TREE_CODE (CP_DECL_CONTEXT (t)) != NAMESPACE_DECL)
        || (TREE_CODE (t) == PARM_DECL))
!     return t;
  
!   return NULL_TREE;
  }
  
  /* Check that ARG, which is a default-argument expression for a
--- 11124,11171 ----
      }
  }
  
! /* Returns non-zero if T is a local variable.  */
  
! int
! local_variable_p (t)
!      tree t;
  {
    if ((TREE_CODE (t) == VAR_DECL 
         /* A VAR_DECL with a context that is a _TYPE is a static data
  	  member.  */
         && !TYPE_P (CP_DECL_CONTEXT (t))
         /* Any other non-local variable must be at namespace scope.  */
!        && !DECL_NAMESPACE_SCOPE_P (t))
        || (TREE_CODE (t) == PARM_DECL))
!     return 1;
  
!   return 0;
! }
! 
! /* Returns non-zero if T is an automatic local variable or a label.
!    (These are the declarations that need to be remapped when the code
!    containing them is duplicated.)  */
! 
! int
! nonstatic_local_decl_p (t)
!      tree t;
! {
!   return ((local_variable_p (t) && !TREE_STATIC (t))
! 	  || TREE_CODE (t) == LABEL_DECL
! 	  || TREE_CODE (t) == RESULT_DECL);
! }
! 
! /* Like local_variable_p, but suitable for use as a tree-walking
!    function.  */
! 
! static tree
! local_variable_p_walkfn (tp, walk_subtrees, data)
!      tree *tp;
!      int *walk_subtrees ATTRIBUTE_UNUSED;
!      void *data ATTRIBUTE_UNUSED;
! {
!   return ((local_variable_p (*tp) && !DECL_ARTIFICIAL (*tp)) 
! 	  ? *tp : NULL_TREE);
  }
  
  /* Check that ARG, which is a default-argument expression for a
*************** check_default_argument (decl, arg)
*** 11230,11236 ****
  
       The keyword `this' shall not be used in a default argument of a
       member function.  */
!   var = walk_tree (&arg, local_variable_p, NULL);
    if (var)
      {
        cp_error ("default argument `%E' uses local variable `%D'",
--- 11234,11240 ----
  
       The keyword `this' shall not be used in a default argument of a
       member function.  */
!   var = walk_tree (&arg, local_variable_p_walkfn, NULL);
    if (var)
      {
        cp_error ("default argument `%E' uses local variable `%D'",
*************** start_function (declspecs, declarator, a
*** 13067,13075 ****
  
    if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl1))
        && DECL_LANGUAGE (decl1) == lang_cplusplus)
!     dtor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
    else if (DECL_CONSTRUCTOR_P (decl1))
!     ctor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
  
    return 1;
  }
--- 13071,13085 ----
  
    if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl1))
        && DECL_LANGUAGE (decl1) == lang_cplusplus)
!     {
!       dtor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
!       DECL_CONTEXT (dtor_label) = current_function_decl;
!     }
    else if (DECL_CONSTRUCTOR_P (decl1))
!     {
!       ctor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
!       DECL_CONTEXT (ctor_label) = current_function_decl;
!     }
  
    return 1;
  }
*************** finish_constructor_body ()
*** 13295,13304 ****
    /* In check_return_expr we translate an empty return from a
       constructor to a return of `this'.  */
    finish_return_stmt (NULL_TREE);
! 
!   /* Mark the end of the main constructor body.  */
!   if (DECL_CONSTRUCTOR_P (current_function_decl))
!     add_tree (build_min_nt (CTOR_COMPLETE));
  }
  
  /* At the end of every destructor we generate code to restore virtual
--- 13305,13312 ----
    /* In check_return_expr we translate an empty return from a
       constructor to a return of `this'.  */
    finish_return_stmt (NULL_TREE);
!   /* Mark the end of the constructor.  */
!   add_tree (build_min_nt (CTOR_STMT));
  }
  
  /* At the end of every destructor we generate code to restore virtual
Index: decl2.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl2.c,v
retrieving revision 1.283
diff -c -p -r1.283 decl2.c
*** decl2.c	1999/11/25 01:56:13	1.283
--- decl2.c	1999/11/25 19:43:08
*************** Boston, MA 02111-1307, USA.  */
*** 42,48 ****
  #include "toplev.h"
  #include "dwarf2out.h"
  #include "dwarfout.h"
- #include "splay-tree.h"
  #include "ggc.h"
  
  #if USE_CPPLIB
--- 42,47 ----
*************** int flag_new_abi;
*** 443,448 ****
--- 442,452 ----
  /* Nonzero to not ignore namespace std. */
  
  int flag_honor_std;
+ 
+ /* Nonzero if we should expand functions calls inline at the tree
+    level, rather than at the RTL level.  */
+ 
+ int flag_inline_trees = 0;
  
  /* Maximum template instantiation depth. Must be at least 17 for ANSI
     compliance. */
Index: dump.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/dump.c,v
retrieving revision 1.26
diff -c -p -r1.26 dump.c
*** dump.c	1999/11/03 06:54:37	1.26
--- dump.c	1999/11/25 19:43:08
*************** Boston, MA 02111-1307, USA.  */
*** 23,29 ****
  #include "system.h"
  #include "tree.h"
  #include "cp-tree.h"
- #include "splay-tree.h"
  
  /* Flags used with queue functions.  */
  #define DUMP_NONE     0
--- 23,28 ----
Index: except.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/except.c,v
retrieving revision 1.89
diff -c -p -r1.89 except.c
*** except.c	1999/11/18 17:52:27	1.89
--- except.c	1999/11/25 19:43:09
*************** expand_end_catch_block (blocks)
*** 564,570 ****
  
    /* Cleanup the EH parameter.  */
    finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_2);
!     /* Cleanup the EH object.  */
    finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_1);
  }
  
--- 564,570 ----
  
    /* Cleanup the EH parameter.  */
    finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_2);
!   /* Cleanup the EH object.  */
    finish_compound_stmt (/*has_no_scope=*/0, compound_stmt_1);
  }
  
*************** expand_end_eh_spec (raises, try_block)
*** 615,620 ****
--- 615,621 ----
    decl = build_decl (VAR_DECL, NULL_TREE, tmp);
    DECL_ARTIFICIAL (decl) = 1;
    DECL_INITIAL (decl) = types;
+   DECL_CONTEXT (decl) = current_function_decl;
    cp_finish_decl (decl, types, NULL_TREE, 0);
  
    decl = decay_conversion (decl);
*************** expand_throw (exp)
*** 804,815 ****
  	  tree object, ptr;
  
  	  /* OK, this is kind of wacky.  The WP says that we call
! 	     terminate
! 
! 	     when the exception handling mechanism, after completing
! 	     evaluation of the expression to be thrown but before the
! 	     exception is caught (_except.throw_), calls a user function
! 	     that exits via an uncaught exception.
  
  	     So we have to protect the actual initialization of the
  	     exception object with terminate(), but evaluate the expression
--- 805,814 ----
  	  tree object, ptr;
  
  	  /* OK, this is kind of wacky.  The WP says that we call
! 	     terminate when the exception handling mechanism, after
! 	     completing evaluation of the expression to be thrown but
! 	     before the exception is caught (_except.throw_), calls a
! 	     user function that exits via an uncaught exception.
  
  	     So we have to protect the actual initialization of the
  	     exception object with terminate(), but evaluate the expression
Index: init.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/init.c,v
retrieving revision 1.152
diff -c -p -r1.152 init.c
*** init.c	1999/11/21 17:44:34	1.152
--- init.c	1999/11/25 19:43:11
*************** build_vec_delete_1 (base, maxindex, type
*** 2470,2476 ****
    /* The below is short by BI_header_size */
    virtual_size = fold (size_binop (MULT_EXPR, size_exp, maxindex));
  
!   tbase = build_decl (VAR_DECL, NULL_TREE, ptype);
    tbase_init = build_modify_expr (tbase, NOP_EXPR,
  				  fold (build (PLUS_EXPR, ptype,
  					       base,
--- 2470,2476 ----
    /* The below is short by BI_header_size */
    virtual_size = fold (size_binop (MULT_EXPR, size_exp, maxindex));
  
!   tbase = create_temporary_var (ptype);
    tbase_init = build_modify_expr (tbase, NOP_EXPR,
  				  fold (build (PLUS_EXPR, ptype,
  					       base,
Index: ir.texi
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/ir.texi,v
retrieving revision 1.21
diff -c -p -r1.21 ir.texi
*** ir.texi	1999/11/23 07:31:07	1.21
--- ir.texi	1999/11/25 19:43:13
*************** following the @code{TREE_CHAIN} link fro
*** 1274,1282 ****
  Used to represent a @code{continue} statement.  There are no additional
  fields.
  
! @item CTOR_COMPLETE
  
! Used to mark the end of the main body of a constructor.
  
  @item DECL_STMT
  
--- 1274,1284 ----
  Used to represent a @code{continue} statement.  There are no additional
  fields.
  
! @item CTOR_STMT
  
! Used to mark the beginning (if @code{CTOR_BEGIN_P} holds) or end (if
! @code{CTOR_END_P} holds of the main body of a constructor.  See also
! @code{SUBOBJECT} for more information on how to use these nodes.
  
  @item DECL_STMT
  
*************** equalit) to @code{CATCH_ALL_TYPE} if thi
*** 1387,1395 ****
  
  In a constructor, these nodes are used to mark the point at which a
  subobject of @code{this} is fully constructed.  If, after this point, an
! exception is thrown before a CTOR_COMPLETE statement is encountered, the
! @code{SUBOBJECT_CLEANUP} must be executed.  The cleanups must be
! executed in the reverse order in which they appear.
  
  @item SWITCH_STMT
  
--- 1389,1397 ----
  
  In a constructor, these nodes are used to mark the point at which a
  subobject of @code{this} is fully constructed.  If, after this point, an
! exception is thrown before a @code{CTOR_STMT} with @code{CTOR_END_P} set
! is encountered, the @code{SUBOBJECT_CLEANUP} must be executed.  The
! cleanups must be executed in the reverse order in which they appear.
  
  @item SWITCH_STMT
  
Index: lex.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/lex.c,v
retrieving revision 1.164
diff -c -p -r1.164 lex.c
*** lex.c	1999/11/23 16:17:52	1.164
--- lex.c	1999/11/25 19:43:15
*************** my_get_run_time ()
*** 405,411 ****
  
  #define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE,
  
! char cplus_tree_code_type[] = {
    'x',
  #include "cp-tree.def"
  };
--- 405,411 ----
  
  #define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE,
  
! static char cplus_tree_code_type[] = {
    'x',
  #include "cp-tree.def"
  };
*************** char cplus_tree_code_type[] = {
*** 417,423 ****
  
  #define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH,
  
! int cplus_tree_code_length[] = {
    0,
  #include "cp-tree.def"
  };
--- 417,423 ----
  
  #define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH,
  
! static int cplus_tree_code_length[] = {
    0,
  #include "cp-tree.def"
  };
*************** int cplus_tree_code_length[] = {
*** 427,433 ****
     Used for printing out the tree and error messages.  */
  #define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME,
  
! const char *cplus_tree_code_name[] = {
    "@@dummy",
  #include "cp-tree.def"
  };
--- 427,433 ----
     Used for printing out the tree and error messages.  */
  #define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME,
  
! static const char *cplus_tree_code_name[] = {
    "@@dummy",
  #include "cp-tree.def"
  };
Index: optimize.c
===================================================================
RCS file: optimize.c
diff -N optimize.c
*** /dev/null	Tue May  5 13:32:27 1998
--- optimize.c	Thu Nov 25 11:43:16 1999
***************
*** 0 ****
--- 1,497 ----
+ /* Perform optimizations on tree structure.
+ 
+    Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+    Written by Mark Michell (mark@codesourcery.com).
+ 
+    This file is part of GNU CC.
+ 
+    GNU CC is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2, or (at your option)
+    any later version.
+    
+    GNU CC is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    General Public License for more details.
+    
+    You should have received a copy of the GNU General Public License
+    along with GNU CC; see the file COPYING.  If not, write to the Free
+    Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+    02111-1307, USA.  */
+ 
+ #include "config.h"
+ #include "system.h"
+ #include "tree.h"
+ #include "cp-tree.h"
+ #include "rtl.h"
+ #include "insn-config.h"
+ #include "integrate.h"
+ #include "varray.h"
+ 
+ /* To Do:
+ 
+    o Provide debugging information for inlined function bodies.  
+ 
+    o In order to make inlining-on-trees work, we pessimized
+      function-local static constants.  In particular, they are now
+      always output, even when not addressed.  Fix this by treating
+      function-local static constants just like global static
+      constants; the back-end already knows not to output them if they
+      are not needed.
+      
+    o Provide heuristics to clamp inlining of recursive template
+      calls?  */
+    
+ /* Data required for function inlining.  */
+ 
+ typedef struct inline_data
+ {
+   /* A stack of the functions we are inlining.  For example, if we are
+      compiling `f', which calls `g', which calls `h', and we are
+      inlining the body of `h', the stack will contain, `h', followed
+      by `g', followed by `f'.  */
+   varray_type fns;
+   /* The top of the FNS stack.  */
+   size_t fns_top;
+   /* The label to jump to when a return statement is encountered.  */
+   tree ret_label;
+   /* The map from local declarations in the inlined function to
+      equivalents in the function into which it is being inlined.  */
+   splay_tree decl_map;
+ } inline_data;
+ 
+ /* Prototypes.  */
+ 
+ static tree initialize_inlined_parameters PROTO((inline_data *, tree));
+ static tree declare_return_variable PROTO((inline_data *, tree *));
+ static tree copy_body_r PROTO((tree *, int *, void *));
+ static tree copy_body PROTO((inline_data *));
+ static tree expand_call_inline PROTO((tree *, int *, void *));
+ static void expand_calls_inline PROTO((tree *, inline_data *));
+ static int inlinable_function_p PROTO((tree, inline_data *));
+ 
+ /* Called from copy_body via walk_tree.  DATA is really an
+    `inline_data *'.  */
+ 
+ static tree
+ copy_body_r (tp, walk_subtrees, data)
+      tree *tp;
+      int *walk_subtrees;
+      void *data;
+ {
+   inline_data* id;
+   tree fn;
+ 
+   /* Set up.  */
+   id = (inline_data *) data;
+   fn = VARRAY_TREE (id->fns, id->fns_top - 1);
+ 
+   /* All automatic variables should have a DECL_CONTEXT indicating
+      what function they come from.  */
+   if ((TREE_CODE (*tp) == VAR_DECL || TREE_CODE (*tp) == LABEL_DECL)
+       && DECL_NAMESPACE_SCOPE_P (*tp))
+     my_friendly_assert (DECL_EXTERNAL (*tp) || TREE_STATIC (*tp),
+ 			19991113);
+ 
+   /* If this is a RETURN_STMT, change it into an EXPR_STMT and a
+      GOTO_STMT with the RET_LABEL as its target.  */
+   if (TREE_CODE (*tp) == RETURN_STMT)
+     {
+       tree return_stmt = *tp;
+       tree goto_stmt;
+ 
+       /* Build the GOTO_STMT.  */
+       goto_stmt = build_min_nt (GOTO_STMT, id->ret_label);
+       TREE_CHAIN (goto_stmt) = TREE_CHAIN (return_stmt);
+ 
+       /* If we're returning something, just turn that into an
+ 	 assignment into the equivalent of the original 
+ 	 RESULT_DECL.  */
+       if (RETURN_EXPR (return_stmt))
+ 	{
+ 	  *tp = build_min_nt (EXPR_STMT, 
+ 			      RETURN_EXPR (return_stmt));
+ 	  /* And then jump to the end of the function.  */
+ 	  TREE_CHAIN (*tp) = goto_stmt;
+ 	}
+       /* If we're not returning anything just do the jump.  */
+       else
+ 	*tp = goto_stmt;
+     }
+   /* Local variables and labels need to be replaced by equivalent
+      variables.  We don't want to copy static variables; there's only
+      one of those, no matter how many times we inline the containing
+      function.  */
+   else if (nonstatic_local_decl_p (*tp) && DECL_CONTEXT (*tp) == fn)
+     {
+       splay_tree_node n;
+ 
+       /* Look up the declaration.  */
+       n = splay_tree_lookup (id->decl_map, (splay_tree_key) *tp);
+ 
+       /* If we didn't already have an equivalent for this declaration,
+ 	 create one now.  */
+       if (!n)
+ 	{
+ 	  tree t;
+ 
+ 	  /* Make a copy of the variable or label.  */
+ 	  t = copy_decl_for_inlining (*tp, fn, 
+ 				      VARRAY_TREE (id->fns, 0));
+ 	  /* Remember it, so that if we encounter this local entity
+ 	     again we can reuse this copy.  */
+ 	  n = splay_tree_insert (id->decl_map, 
+ 				 (splay_tree_key) *tp, 
+ 				 (splay_tree_value) t);
+ 	}
+ 
+       /* Replace this variable with the copy.  */
+       *tp = (tree) n->value;
+     }
+   else if (TREE_CODE (*tp) == SAVE_EXPR)
+     remap_save_expr (tp, id->decl_map, VARRAY_TREE (id->fns, 0));
+   else if (TREE_CODE (*tp) == UNSAVE_EXPR)
+     my_friendly_abort (19991113);
+   /* Otherwise, just copy the node.  Note that copy_tree_r already
+      knows not to copy VAR_DECLs, etc., so this is safe.  */
+   else
+     {
+       copy_tree_r (tp, walk_subtrees, NULL);
+ 
+       /* The copied TARGET_EXPR has never been expanded, even if the
+ 	 original node was expanded already.  */
+       if (TREE_CODE (*tp) == TARGET_EXPR && TREE_OPERAND (*tp, 3))
+ 	TREE_OPERAND (*tp, 1) = TREE_OPERAND (*tp, 3);
+       /* Similarly, if we're copying a CALL_EXPR, the RTL for the
+ 	 result is no longer valid.  */
+       else if (TREE_CODE (*tp) == CALL_EXPR)
+ 	CALL_EXPR_RTL (*tp) = NULL_RTX;
+     }
+ 
+   /* Keep iterating.  */
+   return NULL_TREE;
+ }
+ 
+ /* Make a copy of the body of FN so that it can be inserted inline in
+    another function.  */
+ 
+ static tree
+ copy_body (id)
+      inline_data *id;
+ {
+   tree body;
+ 
+   body = DECL_SAVED_TREE (VARRAY_TREE (id->fns, id->fns_top - 1));
+   walk_tree (&body, copy_body_r, id);
+ 
+   return body;
+ }
+ 
+ /* Generate code to initialize the parameters of the function at the
+    top of the stack in ID from the ARGS (presented as a TREE_LIST).  */
+ 
+ static tree
+ initialize_inlined_parameters (id, args)
+      inline_data *id;
+      tree args;
+ {
+   tree fn;
+   tree init_stmts;
+   tree parms;
+   tree a;
+   tree p;
+ 
+   /* Figure out what the parameters are.  */
+   fn = VARRAY_TREE (id->fns, id->fns_top - 1);
+   parms = DECL_ARGUMENTS (fn);
+ 
+   /* Start with no initializations whatsoever.  */
+   init_stmts = NULL_TREE;
+ 
+   /* Loop through the parameter declarations, replacing each with an
+      equivalent VAR_DECL, appropriately initialized.  */
+   for (p = parms, a = args; p; a = TREE_CHAIN (a), p = TREE_CHAIN (p))
+     {
+       tree init_stmt;
+       tree var;
+ 
+       /* Make an equivalent VAR_DECL.  */
+       var = copy_decl_for_inlining (p, fn, VARRAY_TREE (id->fns, 0));
+       /* Register the VAR_DECL as the equivalent for the PARM_DECL;
+ 	 that way, when the PARM_DECL is encountered, it will be
+ 	 automatically replaced by the VAR_DECL.  */
+       splay_tree_insert (id->decl_map, 
+ 			 (splay_tree_key) p,
+ 			 (splay_tree_value) var);
+       /* Initialize this VAR_DECL from the equivalent argument.  If
+ 	 the argument is an object, created via a constructor or copy,
+ 	 this will not result in an extra copy: the TARGET_EXPR
+ 	 representing the argument will be bound to VAR, and the
+ 	 object will be constructed in VAR.  */
+       init_stmt = build_min_nt (EXPR_STMT,
+ 				build (INIT_EXPR, TREE_TYPE (p),
+ 				       var, TREE_VALUE (a)));
+       /* Declare this new variable.  Note that we do this *after* the
+ 	 initialization because we are going to reverse all the
+ 	 initialization statements below.  */
+       TREE_CHAIN (init_stmt) = build_min_nt (DECL_STMT, var);
+       /* Add this initialization to the list.  */
+       TREE_CHAIN (TREE_CHAIN (init_stmt)) = init_stmts;
+       init_stmts = init_stmt;
+     }
+ 
+   /* The initialization statements have been built up in reverse
+      order.  Straighten them out now.  */
+   return nreverse (init_stmts);
+ }
+ 
+ /* Declare a return variable to replace the RESULT_DECL for the
+    function we are calling.  An appropriate DECL_STMT is returned.
+    The USE_STMT is filled in to contain a use of the declaration to
+    indicate the return value of the function.  */
+ 
+ static tree
+ declare_return_variable (id, use_stmt)
+      struct inline_data *id;
+      tree *use_stmt;
+ {
+   tree fn = VARRAY_TREE (id->fns, id->fns_top - 1);
+   tree result = DECL_RESULT (fn);
+   tree var;
+ 
+   /* We don't need to do anything for functions that don't return
+      anything.  */
+   if (!result || same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (result)), 
+ 			      void_type_node))
+     {
+       *use_stmt = NULL_TREE;
+       return NULL_TREE;
+     }
+ 
+   /* Make an appropriate copy.  */
+   var = copy_decl_for_inlining (result, fn, VARRAY_TREE (id->fns, 0));
+   /* Register the VAR_DECL as the equivalent for the RESULT_DECL; that
+      way, when the RESULT_DECL is encountered, it will be
+      automatically replaced by the VAR_DECL.  */
+   splay_tree_insert (id->decl_map, 
+ 		     (splay_tree_key) result,
+ 		     (splay_tree_value) var);
+ 
+   /* Build the USE_STMT.  */
+   *use_stmt = build_min_nt (EXPR_STMT, var);
+ 
+   /* Build the declaration statement.  */
+   return build_min_nt (DECL_STMT, var);
+ }
+ 
+ /* Returns non-zero if FN is a function that can be inlined.  */
+ 
+ static int
+ inlinable_function_p (fn, id)
+      tree fn;
+      inline_data *id;
+ {
+   int inlinable;
+ 
+   /* If we've already decided this function shouldn't be inlined,
+      there's no need to check again.  */
+   if (DECL_UNINLINABLE (fn))
+     return 0;
+ 
+   /* Assume it is not inlinable.  */
+   inlinable = 0;
+ 
+   /* If the function was not declared `inline', then we don't inline
+      it.  */
+   if (!DECL_INLINE (fn))
+     ;
+   /* If we don't have the function body available, we can't inline
+      it.  */
+   else if (!DECL_SAVED_TREE (fn))
+     ;
+   /* We can't inline varargs functions.  */
+   else if (varargs_function_p (fn))
+     ;
+   /* All is well.  We can inline this function.  Traditionally, GCC
+      has refused to inline functions using setjmp or alloca, or
+      functions whose values are returned in a PARALLEL, and a few
+      other such obscure conditions.  We are not equally constrained at
+      the tree level.  */
+   else
+     inlinable = 1;
+ 
+   /* Squirrel away the result so that we don't have to check again.  */
+   DECL_UNINLINABLE (fn) = !inlinable;
+ 
+   /* Don't do recursive inlining, either.  We don't record this in
+      DECL_UNLINABLE; we may be able to inline this function later.  */
+   if (inlinable)
+     {
+       size_t i;
+ 
+       for (i = 0; i < id->fns_top; ++i)
+ 	if (VARRAY_TREE (id->fns, i) == fn)
+ 	  inlinable = 0;
+     }
+ 
+   /* We can inline a template instantiation only if its fully
+      instantiated.  */
+   if (inlinable
+       && DECL_TEMPLATE_INFO (fn) 
+       && TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (fn)))
+     {
+       fn = instantiate_decl (fn);
+       inlinable = !TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (fn));
+     }
+ 
+   /* Return the result.  */
+   return inlinable;
+ }
+ 
+ /* If *TP is CALL_EXPR, replace it with its inline expansion.  */
+ 
+ static tree
+ expand_call_inline (tp, walk_subtrees, data)
+      tree *tp;
+      int *walk_subtrees;
+      void *data;
+ {
+   inline_data *id;
+   tree t;
+   tree expr;
+   tree chain;
+   tree fn;
+   tree use_stmt;
+   splay_tree st;
+ 
+   /* We're only interested in CALL_EXPRs.  */
+   t = *tp;
+   if (TREE_CODE (t) != CALL_EXPR)
+     return NULL_TREE;
+ 
+   /* First, see if we can figure out what function is being called.
+      If we cannot, then there is no hope of inlining the function.  */
+   fn = get_callee_fndecl (t);
+   if (!fn)
+     return NULL_TREE;
+ 
+   /* Don't try to inline functions that are not well-suited to
+      inlining.  */
+   id = (inline_data *) data;
+   if (!inlinable_function_p (fn, id))
+     return NULL_TREE;
+ 
+   /* Return statements in the function body will be replaced by jumps
+      to the RET_LABEL.  */
+   id->ret_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+   DECL_CONTEXT (id->ret_label) = VARRAY_TREE (id->fns, 0);
+ 
+   /* Build a statement-expression containing code to initialize the
+      arguments, the actual inline expansion of the body, and a label
+      for the return statements within the function to jump to.  The
+      type of the statement expression is the return type of the
+      function call.  */
+   expr = build_min (STMT_EXPR, TREE_TYPE (TREE_TYPE (fn)), NULL_TREE);
+ 
+   /* Record the function we are about to inline so that we can avoid
+      recursing into it.  */
+   if (id->fns_top > id->fns->num_elements)
+     VARRAY_GROW (id->fns, 2 * id->fns->num_elements);
+   VARRAY_TREE (id->fns, id->fns_top++) = fn;
+ 
+   /* Local declarations will be replaced by their equivalents in this
+      map.  */
+   st = id->decl_map;
+   id->decl_map = splay_tree_new (splay_tree_compare_pointers,
+ 				 NULL, NULL);
+ 
+   /* Initialize the parameters.  */
+   STMT_EXPR_STMT (expr) 
+     = initialize_inlined_parameters (id, TREE_OPERAND (t, 1));
+ 
+   /* Declare the return variable for the function.  */
+   STMT_EXPR_STMT (expr)
+     = chainon (STMT_EXPR_STMT (expr), 
+ 	       declare_return_variable (id, &use_stmt));
+   
+   /* After we've initialized the parameters, we insert the body of the
+      function itself.  */
+   STMT_EXPR_STMT (expr)
+     = chainon (STMT_EXPR_STMT (expr), copy_body (id));
+ 
+   /* Finally, mention the returned value so that the value of the
+      statement-expression is the returned value of the function.  */
+   STMT_EXPR_STMT (expr) = chainon (STMT_EXPR_STMT (expr), use_stmt);
+ 
+   /* Clean up.  */
+   splay_tree_delete (id->decl_map);
+   id->decl_map = st;
+ 
+   /* After the body of the function comes the RET_LABEL.  */
+   STMT_EXPR_STMT (expr)
+     = chainon (STMT_EXPR_STMT (expr), 
+ 	       build_min_nt (LABEL_STMT, id->ret_label));
+ 
+   /* The new expression has side-effects if the old one did.  */
+   TREE_SIDE_EFFECTS (expr) = TREE_SIDE_EFFECTS (t);
+   /* If the value of the new expression is ignored, that's OK.  We
+      don't warn about this for CALL_EXPRs, so we shouldn't warn about
+      the equivalent inlined version either.  */
+   TREE_USED (expr) = 1;
+ 
+   /* Replace the call by the inlined body.  */
+   chain = TREE_CHAIN (*tp);
+   *tp = expr;
+   TREE_CHAIN (expr) = chain;
+ 
+   /* Recurse into the body of the just inlined function.  */
+   expand_calls_inline (tp, id);
+   --id->fns_top;
+ 
+   /* Don't walk into subtrees.  We've already handled them above.  */
+   *walk_subtrees = 0;
+ 
+   /* Keep iterating.  */
+   return NULL_TREE;
+ }
+ 
+ /* Walk over the entire tree *TP, replacing CALL_EXPRs with inline
+    expansions as appropriate.  */
+ 
+ static void
+ expand_calls_inline (tp, id)
+      tree *tp;
+      inline_data *id;
+ {
+   /* Search through *TP, replacing all calls to inline functions by
+      appropriate equivalents.  */
+   walk_tree (tp, expand_call_inline, id);
+ }
+ 
+ /* Optimize the body of FN.  */
+ 
+ void
+ optimize_function (fn)
+      tree fn;
+ {
+   /* Expand calls to inline functions.  */
+   if (flag_inline_trees)
+     {
+       inline_data id;
+ 
+       /* Clear out ID.  */
+       bzero (&id, sizeof (id));
+ 
+       /* Don't allow recursion into FN.  */
+       VARRAY_TREE_INIT (id.fns, 32, "fns");
+       VARRAY_TREE (id.fns, id.fns_top++) = fn;
+ 
+       /* Replace all calls to inline functions with the bodies of those
+ 	 functions.  */
+       expand_calls_inline (&DECL_SAVED_TREE (fn), &id);
+ 
+       /* Clean up.  */
+       VARRAY_FREE (id.fns);
+     }
+ }
Index: semantics.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/semantics.c,v
retrieving revision 1.109
diff -c -p -r1.109 semantics.c
*** semantics.c	1999/11/23 07:31:07	1.109
--- semantics.c	1999/11/25 19:43:17
*************** finish_goto_stmt (destination)
*** 658,664 ****
      TREE_USED (destination) = 1;
      
    if (building_stmt_tree ())
!     add_tree (build_min_nt (GOTO_STMT, destination));
    else
      {
        emit_line_note (input_filename, lineno);
--- 658,673 ----
      TREE_USED (destination) = 1;
      
    if (building_stmt_tree ())
!     {
!       if (TREE_CODE (destination) != LABEL_DECL)
! 	/* We don't inline calls to functions with computed gotos.
! 	   Those functions are typically up to some funny business,
! 	   and may be depending on the labels being at particular
! 	   addresses, or some such.  */
! 	DECL_UNINLINABLE (current_function_decl) = 1;
! 
!       add_tree (build_min_nt (GOTO_STMT, destination));
!     }
    else
      {
        emit_line_note (input_filename, lineno);
*************** setup_vtbl_ptr ()
*** 1183,1189 ****
  		  (CTOR_INITIALIZER,
  		   current_member_init_list, current_base_init_list));
        else
! 	finish_expr_stmt (emit_base_init (current_class_type));
      }
    else if (DECL_DESTRUCTOR_P (current_function_decl)
  	   && !processing_template_decl)
--- 1192,1208 ----
  		  (CTOR_INITIALIZER,
  		   current_member_init_list, current_base_init_list));
        else
! 	{
! 	  tree ctor_stmt;
! 
! 	  /* Mark the beginning of the constructor.  */
! 	  ctor_stmt = build_min_nt (CTOR_STMT);
! 	  CTOR_BEGIN_P (ctor_stmt) = 1;
! 	  add_tree (ctor_stmt);
! 	  
! 	  /* And actually initialize the base-classes and members.  */
! 	  finish_expr_stmt (emit_base_init (current_class_type));
! 	}
      }
    else if (DECL_DESTRUCTOR_P (current_function_decl)
  	   && !processing_template_decl)
*************** finish_label_address_expr (label)
*** 1592,1597 ****
--- 1611,1619 ----
        TREE_USED (label) = 1;
        result = build1 (ADDR_EXPR, ptr_type_node, label);
        TREE_CONSTANT (result) = 1;
+       /* This function cannot be inlined.  All jumps to the addressed
+ 	 label should wind up at the same point.  */
+       DECL_UNINLINABLE (current_function_decl) = 1;
      }
  
    return result;
*************** expand_stmt (t)
*** 2268,2278 ****
  	  finish_expr_stmt (EXPR_STMT_EXPR (t));
  	  break;
  
- 	case CTOR_COMPLETE:
- 	  /* All subobjects have been fully constructed at this point.  */
- 	  end_protect_partials ();
- 	  break;
- 
  	case DECL_STMT:
  	  {
  	    tree decl;
--- 2290,2295 ----
*************** expand_stmt (t)
*** 2309,2314 ****
--- 2326,2341 ----
  	  begin_catch_block (TREE_TYPE (t));
  	  break;
  
+ 	case CTOR_STMT:
+ 	  if (CTOR_BEGIN_P (t))
+ 	    begin_protect_partials ();
+ 	  else
+ 	    /* After this point, any exceptions will cause the
+ 	       destructor to be executed, so we no longer need to worry
+ 	       about destroying the various subobjects ourselves.  */
+ 	    end_protect_partials ();
+ 	  break;
+ 
  	case FOR_STMT:
  	  {
  	    tree tmp;
*************** expand_body (fn)
*** 2508,2513 ****
--- 2535,2543 ----
    if (flag_syntax_only)
      return;
  
+   /* Optimize the body of the function before expanding it.  */
+   optimize_function (fn);
+ 
    /* Save the current file name and line number.  When we expand the
       body of the function, we'll set LINENO and INPUT_FILENAME so that
       error-mesages come out in the right places.  */
*************** expand_body (fn)
*** 2538,2546 ****
    /* Generate code for the function.  */
    finish_function (lineno, 0);
  
!   /* We don't need the body any more.  Allow it to be garbage
!      collected.  We can't do this if we're going to dump everything.  */
!   if (!flag_dump_translation_unit)
      DECL_SAVED_TREE (fn) = NULL_TREE;
  
    /* And restore the current source position.  */
--- 2568,2584 ----
    /* Generate code for the function.  */
    finish_function (lineno, 0);
  
!   /* If possible, obliterate the body of the function so that it can
!      be garbage collected.  */
!   if (flag_dump_translation_unit)
!     /* Keep the body; we're going to dump it.  */
!     ;
!   else if (DECL_INLINE (fn) && flag_inline_trees)
!     /* We might need the body of this function so that we can expand
!        it inline somewhere else.  */
!     ;
!   else
!     /* We don't need the body; blow it away.  */
      DECL_SAVED_TREE (fn) = NULL_TREE;
  
    /* And restore the current source position.  */
Index: tree.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/tree.c,v
retrieving revision 1.161
diff -c -p -r1.161 tree.c
*** tree.c	1999/11/14 20:29:06	1.161
--- tree.c	1999/11/25 19:43:18
*************** Boston, MA 02111-1307, USA.  */
*** 28,34 ****
  #include "rtl.h"
  #include "toplev.h"
  #include "ggc.h"
! #include "splay-tree.h"
  
  static tree bot_manip PROTO((tree *, int *, void *));
  static tree bot_replace PROTO((tree *, int *, void *));
--- 28,35 ----
  #include "rtl.h"
  #include "toplev.h"
  #include "ggc.h"
! #include "insn-config.h"
! #include "integrate.h"
  
  static tree bot_manip PROTO((tree *, int *, void *));
  static tree bot_replace PROTO((tree *, int *, void *));
*************** static cp_lvalue_kind lvalue_p_1 PROTO((
*** 42,48 ****
  static tree no_linkage_helper PROTO((tree *, int *, void *));
  static tree build_srcloc PROTO((char *, int));
  static void mark_list_hash PROTO ((void *));
! static tree copy_tree_r PROTO ((tree *, int *, void *));
  static tree build_target_expr PROTO((tree, tree));
  
  #define CEIL(x,y) (((x) + (y) - 1) / (y))
--- 43,52 ----
  static tree no_linkage_helper PROTO((tree *, int *, void *));
  static tree build_srcloc PROTO((char *, int));
  static void mark_list_hash PROTO ((void *));
! static int statement_code_p PROTO((enum tree_code));
! static tree mark_local_for_remap_r PROTO((tree *, int *, void *));
! static tree cp_unsave_r PROTO ((tree *, int *, void *));
! static void cp_unsave PROTO((tree *));
  static tree build_target_expr PROTO((tree, tree));
  
  #define CEIL(x,y) (((x) + (y) - 1) / (y))
*************** build_cplus_new (type, init)
*** 259,264 ****
--- 263,269 ----
  
    slot = build (VAR_DECL, type);
    DECL_ARTIFICIAL (slot) = 1;
+   DECL_CONTEXT (slot) = current_function_decl;
    layout_decl (slot, 0);
  
    /* We split the CALL_EXPR into its function and its arguments here.
*************** is_aggr_type_2 (t1, t2)
*** 1456,1461 ****
--- 1461,1505 ----
      return 0;
    return IS_AGGR_TYPE (t1) && IS_AGGR_TYPE (t2);
  }
+ 
+ /* 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:
+       return 1;
+ 
+     default:
+       return 0;
+     }
+ }
  
  #define PRINT_RING_SIZE 4
  
*************** walk_tree (tp, func, data)
*** 1594,1600 ****
  
    /* Handle commmon cases up front.  */
    if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
!       || TREE_CODE_CLASS (code) == 'r')
      {
        int i;
  
--- 1638,1645 ----
  
    /* Handle commmon cases up front.  */
    if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
!       || TREE_CODE_CLASS (code) == 'r'
!       || TREE_CODE_CLASS (code) == 's')
      {
        int i;
  
*************** walk_tree (tp, func, data)
*** 1602,1607 ****
--- 1647,1657 ----
        for (i = first_rtl_op (code) - 1; i >= 0; --i)
  	WALK_SUBTREE (TREE_OPERAND (*tp, i));
  
+       /* For statements, we also walk the chain so that we cover the
+ 	 entire statement tree.  */
+       if (statement_code_p (code))
+ 	WALK_SUBTREE (TREE_CHAIN (*tp));
+ 
        /* We didn't find what we were looking for.  */
        return NULL_TREE;
      }
*************** walk_tree (tp, func, data)
*** 1706,1712 ****
        if (TYPE_PTRMEMFUNC_P (*tp))
  	WALK_SUBTREE (TYPE_PTRMEMFUNC_FN_TYPE (*tp));
        break;
!       
      default:
        my_friendly_abort (19990803);
      }
--- 1756,1762 ----
        if (TYPE_PTRMEMFUNC_P (*tp))
  	WALK_SUBTREE (TYPE_PTRMEMFUNC_FN_TYPE (*tp));
        break;
! 
      default:
        my_friendly_abort (19990803);
      }
*************** no_linkage_check (t)
*** 1755,1764 ****
  
  /* Passed to walk_tree.  Copies the node pointed to, if appropriate.  */
  
! static tree
  copy_tree_r (tp, walk_subtrees, data)
       tree *tp;
!      int *walk_subtrees ATTRIBUTE_UNUSED;
       void *data ATTRIBUTE_UNUSED;
  {
    enum tree_code code = TREE_CODE (*tp);
--- 1805,1814 ----
  
  /* Passed to walk_tree.  Copies the node pointed to, if appropriate.  */
  
! tree
  copy_tree_r (tp, walk_subtrees, data)
       tree *tp;
!      int *walk_subtrees;
       void *data ATTRIBUTE_UNUSED;
  {
    enum tree_code code = TREE_CODE (*tp);
*************** copy_tree_r (tp, walk_subtrees, data)
*** 1767,1772 ****
--- 1817,1823 ----
    if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
        || TREE_CODE_CLASS (code) == 'r'
        || TREE_CODE_CLASS (code) == 'c'
+       || TREE_CODE_CLASS (code) == 's'
        || code == PARM_DECL
        || code == TREE_LIST
        || code == TREE_VEC
*************** copy_tree_r (tp, walk_subtrees, data)
*** 1781,1792 ****
  
        /* Now, restore the chain, if appropriate.  That will cause
  	 walk_tree to walk into the chain as well.  */
!       if (code == PARM_DECL || code == TREE_LIST || code == OVERLOAD)
  	TREE_CHAIN (*tp) = chain;
      }
    else if (code == TEMPLATE_TEMPLATE_PARM)
      /* These must be copied specially.  */
      *tp = copy_template_template_parm (*tp);
  
    return NULL_TREE;
  }
--- 1832,1852 ----
  
        /* Now, restore the chain, if appropriate.  That will cause
  	 walk_tree to walk into the chain as well.  */
!       if (code == PARM_DECL || code == TREE_LIST || code == OVERLOAD
! 	  || statement_code_p (code))
  	TREE_CHAIN (*tp) = chain;
+ 
+       /* For now, we don't update BLOCKs when we make copies.  So, we
+ 	 have to nullify all scope-statements.  */
+       if (TREE_CODE (*tp) == SCOPE_STMT)
+ 	SCOPE_NULLIFIED_P (*tp) = 1;
      }
    else if (code == TEMPLATE_TEMPLATE_PARM)
      /* These must be copied specially.  */
      *tp = copy_template_template_parm (*tp);
+   else if (TREE_CODE_CLASS (code) == 't')
+     /* There's no need to copy types, or anything beneath them.  */
+     *walk_subtrees = 0;
  
    return NULL_TREE;
  }
*************** void
*** 2605,2645 ****
  init_tree ()
  {
    make_lang_type_fn = cp_make_lang_type;
!   lang_unsave_expr_now = cplus_unsave_expr_now;
    ggc_add_root (list_hash_table, 
  		sizeof (list_hash_table) / sizeof (struct list_hash *),
  		sizeof (struct list_hash *),
  		mark_list_hash);
  }
  
! /* The C++ version of unsave_expr_now.
!    See gcc/tree.c:unsave_expr_now for comments. */
  
  void
! cplus_unsave_expr_now (expr)
!      tree expr;
  {
!   if (expr == NULL)
!     return;
  
!   else if (TREE_CODE (expr) == AGGR_INIT_EXPR)
      {
!       unsave_expr_now (TREE_OPERAND (expr,0));
!       if (TREE_OPERAND (expr, 1)
! 	  && TREE_CODE (TREE_OPERAND (expr, 1)) == TREE_LIST)
! 	{
! 	  tree exp = TREE_OPERAND (expr, 1);
! 	  while (exp)
! 	    {
! 	      unsave_expr_now (TREE_VALUE (exp));
! 	      exp = TREE_CHAIN (exp);
! 	    }
! 	}
!       unsave_expr_now (TREE_OPERAND (expr,2));
!       return;
      }
  
    else
!     return;
  }
  
--- 2665,2807 ----
  init_tree ()
  {
    make_lang_type_fn = cp_make_lang_type;
!   lang_unsave = cp_unsave;
    ggc_add_root (list_hash_table, 
  		sizeof (list_hash_table) / sizeof (struct list_hash *),
  		sizeof (struct list_hash *),
  		mark_list_hash);
  }
  
! /* The SAVE_EXPR pointed to by TP is being copied.  If ST contains
!    information indicating to what new SAVE_EXPR this one should be
!    mapped, use that one.  Otherwise, create a new node and enter it in
!    ST.  FN is the function into which the copy will be placed.  */
  
  void
! remap_save_expr (tp, st, fn)
!      tree *tp;
!      splay_tree st;
!      tree fn;
  {
!   splay_tree_node n;
  
!   /* See if we already encountered this SAVE_EXPR.  */
!   n = splay_tree_lookup (st, (splay_tree_key) *tp);
!       
!   /* If we didn't already remap this SAVE_EXPR, do so now.  */
!   if (!n)
      {
!       tree t = copy_node (*tp);
! 
!       /* The SAVE_EXPR is now part of the function into which we
! 	 are inlining this body.  */
!       SAVE_EXPR_CONTEXT (t) = fn;
!       /* And we haven't evaluated it yet.  */
!       SAVE_EXPR_RTL (t) = NULL_RTX;
!       /* Remember this SAVE_EXPR.  */
!       n = splay_tree_insert (st,
! 			     (splay_tree_key) *tp,
! 			     (splay_tree_value) t);
      }
  
+   /* Replace this SAVE_EXPR with the copy.  */
+   *tp = (tree) n->value;
+ }
+ 
+ /* Called via walk_tree.  If *TP points to a DECL_STMT for a local
+    declaration, copies the declaration and enters it in the splay_tree
+    pointed to by DATA (which is really a `splay_tree *').  */
+ 
+ static tree
+ mark_local_for_remap_r (tp, walk_subtrees, data)
+      tree *tp;
+      int *walk_subtrees ATTRIBUTE_UNUSED;
+      void *data;
+ {
+   tree t = *tp;
+   splay_tree st = (splay_tree) data;
+ 
+   if ((TREE_CODE (t) == DECL_STMT
+        && nonstatic_local_decl_p (DECL_STMT_DECL (t)))
+       || TREE_CODE (t) == LABEL_STMT)
+     {
+       tree decl;
+       tree copy;
+ 
+       /* Figure out what's being declared.  */
+       decl = (TREE_CODE (t) == DECL_STMT
+ 	      ? DECL_STMT_DECL (t) : LABEL_STMT_LABEL (t));
+       
+       /* Make a copy.  */
+       copy = copy_decl_for_inlining (decl, 
+ 				     DECL_CONTEXT (decl), 
+ 				     DECL_CONTEXT (decl));
+ 
+       /* Remember the copy.  */
+       splay_tree_insert (st,
+ 			 (splay_tree_key) decl, 
+ 			 (splay_tree_value) copy);
+     }
+ 
+   return NULL_TREE;
+ }
+ 
+ /* Called via walk_tree when an expression is unsaved.  Using the
+    splay_tree pointed to by ST (which is really a `splay_tree *'),
+    remaps all local declarations to appropriate replacements.  */
+ 
+ static tree
+ cp_unsave_r (tp, walk_subtrees, data)
+      tree *tp;
+      int *walk_subtrees;
+      void *data;
+ {
+   splay_tree st = (splay_tree) data;
+   splay_tree_node n;
+ 
+   /* Only a local declaration (variable or label).  */
+   if (nonstatic_local_decl_p (*tp))
+     {
+       /* Lookup the declaration.  */
+       n = splay_tree_lookup (st, (splay_tree_key) *tp);
+       
+       /* If it's there, remap it.  */
+       if (n)
+ 	*tp = (tree) n->value;
+     }
+   else if (TREE_CODE (*tp) == SAVE_EXPR)
+     remap_save_expr (tp, st, current_function_decl);
    else
!     {
!       copy_tree_r (tp, walk_subtrees, NULL);
! 
!       /* Do whatever unsaving is required.  */
!       unsave_expr_1 (*tp);
!     }
! 
!   /* Keep iterating.  */
!   return NULL_TREE;
  }
  
+ /* Called by unsave_expr_now whenever an expression (*TP) needs to be
+    unsaved.  */
+ 
+ static void
+ cp_unsave (tp)
+      tree *tp;
+ {
+   splay_tree st;
+ 
+   /* Create a splay-tree to map old local variable declarations to new
+      ones.  */
+   st = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
+ 
+   /* Walk the tree once figuring out what needs to be remapped.  */
+   walk_tree (tp, mark_local_for_remap_r, st);
+ 
+   /* Walk the tree again, copying, remapping, and unsaving.  */
+   walk_tree (tp, cp_unsave_r, st);
+ 
+   /* Clean up.  */
+   splay_tree_delete (st);
+ }



More information about the Gcc-patches mailing list