OSDN Git Service

* decl.c (initialize_local_var): Handle static variables here.
[pf3gnuchains/gcc-fork.git] / gcc / cp / decl.c
index 1b6b268..00043d6 100644 (file)
@@ -42,12 +42,12 @@ Boston, MA 02111-1307, USA.  */
 #include "except.h"
 #include "toplev.h"
 #include "../hash.h"
+#include "defaults.h"
+#include "ggc.h"
 
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
 
-extern tree builtin_return_address_fndecl;
-
 extern struct obstack permanent_obstack;
 extern struct obstack* saveable_obstack;
 
@@ -55,54 +55,20 @@ extern int current_class_depth;
 
 extern tree static_ctors, static_dtors;
 
-extern int static_labelno;
-
-extern tree current_namespace;
 extern tree global_namespace;
 
-extern void (*print_error_function) PROTO((char *));
 extern int (*valid_lang_attribute) PROTO ((tree, tree, tree, tree));
 
-/* Obstack used for remembering local class declarations (like
-   enums and static (const) members.  */
-#include "stack.h"
-struct obstack decl_obstack;
-static struct stack_level *decl_stack;
-
-#ifndef CHAR_TYPE_SIZE
-#define CHAR_TYPE_SIZE BITS_PER_UNIT
-#endif
-
-#ifndef SHORT_TYPE_SIZE
-#define SHORT_TYPE_SIZE (BITS_PER_UNIT * MIN ((UNITS_PER_WORD + 1) / 2, 2))
-#endif
-
-#ifndef INT_TYPE_SIZE
-#define INT_TYPE_SIZE BITS_PER_WORD
-#endif
-
-#ifndef LONG_TYPE_SIZE
-#define LONG_TYPE_SIZE BITS_PER_WORD
-#endif
+/* Use garbage collection.  */
 
-#ifndef LONG_LONG_TYPE_SIZE
-#define LONG_LONG_TYPE_SIZE (BITS_PER_WORD * 2)
-#endif
+int ggc_p = 1;
 
 #ifndef WCHAR_UNSIGNED
 #define WCHAR_UNSIGNED 0
 #endif
 
-#ifndef FLOAT_TYPE_SIZE
-#define FLOAT_TYPE_SIZE BITS_PER_WORD
-#endif
-
-#ifndef DOUBLE_TYPE_SIZE
-#define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
-#endif
-
-#ifndef LONG_DOUBLE_TYPE_SIZE
-#define LONG_DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
+#ifndef CHAR_TYPE_SIZE
+#define CHAR_TYPE_SIZE BITS_PER_UNIT
 #endif
 
 #ifndef BOOL_TYPE_SIZE
@@ -132,11 +98,8 @@ static struct stack_level *decl_stack;
 #endif
 
 static tree grokparms                          PROTO((tree, int));
-static tree lookup_nested_type                 PROTO((tree, tree));
 static const char *redeclaration_error_message PROTO((tree, tree));
 
-static struct stack_level *push_decl_level PROTO((struct stack_level *,
-                                                 struct obstack *));
 static void push_binding_level PROTO((struct binding_level *, int,
                                      int));
 static void pop_binding_level PROTO((void));
@@ -170,7 +133,7 @@ static void record_unknown_type PROTO((tree, const char *));
 static int member_function_or_else PROTO((tree, tree, const char *));
 static void bad_specifiers PROTO((tree, const char *, int, int, int, int,
                                  int));
-static void lang_print_error_function PROTO((char *));
+static void lang_print_error_function PROTO((const char *));
 static tree maybe_process_template_type_declaration PROTO((tree, int, struct binding_level*));
 static void check_for_uninitialized_const_var PROTO((tree));
 static unsigned long typename_hash PROTO((hash_table_key));
@@ -178,274 +141,151 @@ static boolean typename_compare PROTO((hash_table_key, hash_table_key));
 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));
+static tree local_variable_p PROTO((tree *));
 static tree find_binding PROTO((tree, tree));
 static tree select_decl PROTO((tree, int));
-static tree unqualified_namespace_lookup PROTO((tree, int));
 static int lookup_flags PROTO((int, int));
 static tree qualify_lookup PROTO((tree, int));
 static tree record_builtin_java_type PROTO((const char *, int));
 static const char *tag_name PROTO((enum tag_types code));
 static void find_class_binding_level PROTO((void));
 static struct binding_level *innermost_nonclass_level PROTO((void));
-static tree poplevel_class PROTO((void));
 static void warn_about_implicit_typename_lookup PROTO((tree, tree));
 static int walk_namespaces_r PROTO((tree, walk_namespaces_fn, void *));
 static int walk_globals_r PROTO((tree, void *));
+static void add_decl_to_level PROTO((tree, struct binding_level *));
+static tree make_label_decl PROTO((tree, int));
+static void pop_label PROTO((tree));
+static void pop_labels PROTO((tree));
+static void maybe_deduce_size_from_array_init PROTO((tree, tree));
+static void layout_var_decl PROTO((tree));
+static void maybe_commonize_var PROTO((tree));
+static tree check_initializer PROTO((tree, tree));
+static void make_rtl_for_nonlocal_decl PROTO((tree, tree, const char *));
+static void push_cp_function_context PROTO((struct function *));
+static void pop_cp_function_context PROTO((struct function *));
+static void mark_binding_level PROTO((void *));
+static void mark_cp_function_context PROTO((struct function *));
+static void mark_saved_scope PROTO((void *));
+static void mark_lang_function PROTO((struct language_function *));
+static void save_function_data PROTO((tree));
+static void check_function_type PROTO((tree));
+static void destroy_local_static PROTO((tree));
+static void destroy_local_var PROTO((tree));
+static void finish_constructor_body PROTO((void));
+static void finish_destructor_body PROTO((void));
 
 #if defined (DEBUG_CP_BINDING_LEVELS)
 static void indent PROTO((void));
 #endif
 
-/* A node which has tree code ERROR_MARK, and whose type is itself.
-   All erroneous expressions are replaced with this node.  All functions
-   that accept nodes as arguments should avoid generating error messages
-   if this node is one of the arguments, since it is undesirable to get
-   multiple error messages from one error in the input.  */
-
-tree error_mark_node;
-
 /* Erroneous argument lists can use this *IFF* they do not modify it.  */
 tree error_mark_list;
 
-/* INTEGER_TYPE and REAL_TYPE nodes for the standard data types */
-
-tree short_integer_type_node;
-tree integer_type_node;
-tree long_integer_type_node;
-tree long_long_integer_type_node;
-
-tree short_unsigned_type_node;
-tree unsigned_type_node;
-tree long_unsigned_type_node;
-tree long_long_unsigned_type_node;
-
-/* These are used for integer literals that are larger than 
-   a long long.  The largest integer literals we can handle
-   are the width of two HOST_WIDE_INTs.  If two HOST_WIDE_INTs
-   are not larger than the target's long long, then these
-   will never be used. */
-tree widest_integer_literal_type_node;
-tree widest_unsigned_literal_type_node;
-
-tree ptrdiff_type_node;
-
-tree unsigned_char_type_node;
-tree signed_char_type_node;
-tree char_type_node;
-tree wchar_type_node;
-tree signed_wchar_type_node;
-tree unsigned_wchar_type_node;
-
-tree wchar_decl_node;
-
-tree float_type_node;
-tree double_type_node;
-tree long_double_type_node;
-
-tree complex_integer_type_node;
-tree complex_float_type_node;
-tree complex_double_type_node;
-tree complex_long_double_type_node;
-
-tree intQI_type_node;
-tree intHI_type_node;
-tree intSI_type_node;
-tree intDI_type_node;
-#if HOST_BITS_PER_WIDE_INT >= 64
-tree intTI_type_node;
-#endif
-
-tree unsigned_intQI_type_node;
-tree unsigned_intHI_type_node;
-tree unsigned_intSI_type_node;
-tree unsigned_intDI_type_node;
-#if HOST_BITS_PER_WIDE_INT >= 64
-tree unsigned_intTI_type_node;
-#endif
-
-tree java_byte_type_node;
-tree java_short_type_node;
-tree java_int_type_node;
-tree java_long_type_node;
-tree java_float_type_node;
-tree java_double_type_node;
-tree java_char_type_node;
-tree java_boolean_type_node;
-
-/* A VOID_TYPE node, and the same, packaged in a TREE_LIST.  */
-
-tree void_type_node, void_list_node;
-tree void_zero_node;
-
-/* Nodes for types `void *' and `const void *'.  */
-
-tree ptr_type_node;
-tree const_ptr_type_node;
+/* The following symbols are subsumed in the cp_global_trees array, and
+   listed here individually for documentation purposes. 
 
-/* Nodes for types `char *' and `const char *'.  */
+   C++ extensions
+       tree wchar_decl_node;
+       tree void_zero_node;
 
-tree string_type_node, const_string_type_node;
-
-/* Type `char[256]' or something like it.
-   Used when an array of char is needed and the size is irrelevant.  */
+       tree vtable_entry_type;
+       tree delta_type_node;
+#if 0
+   Old rtti stuff.
+       tree __baselist_desc_type_node;
+       tree __i_desc_type_node, __m_desc_type_node;
+       tree __t_desc_array_type, __i_desc_array_type, __m_desc_array_type;
+#endif
+       tree __t_desc_type_node;
+#if 0
+       tree __tp_desc_type_node;
+#endif
+       tree __access_mode_type_node;
+       tree __bltn_desc_type_node, __user_desc_type_node, __class_desc_type_node;
+       tree __ptr_desc_type_node, __attr_desc_type_node, __func_desc_type_node;
+       tree __ptmf_desc_type_node, __ptmd_desc_type_node;
+#if 0
+   Not needed yet?  May be needed one day?
+       tree __bltn_desc_array_type, __user_desc_array_type, __class_desc_array_type;
+       tree __ptr_desc_array_type, __attr_dec_array_type, __func_desc_array_type;
+       tree __ptmf_desc_array_type, __ptmd_desc_array_type;
+#endif
 
-tree char_array_type_node;
+       tree class_star_type_node;
+       tree class_type_node, record_type_node, union_type_node, enum_type_node;
+       tree unknown_type_node;
 
-/* Type `int[256]' or something like it.
-   Used when an array of int needed and the size is irrelevant.  */
+   Array type `vtable_entry_type[]'
 
-tree int_array_type_node;
+       tree vtbl_type_node;
+       tree vtbl_ptr_type_node;
 
-/* Type `wchar_t[256]' or something like it.
-   Used when a wide string literal is created.  */
+   Nnamespace std
 
-tree wchar_array_type_node;
+       tree std_node;
 
-/* The bool data type, and constants */
-tree boolean_type_node, boolean_true_node, boolean_false_node;
+   A FUNCTION_DECL which can call `abort'.  Not necessarily the
+   one that the user will declare, but sufficient to be called
+   by routines that want to abort the program.
 
-/* Type `int ()' -- used for implicit declaration of functions.  */
+       tree abort_fndecl;
 
-tree default_function_type;
+   The FUNCTION_DECL for the default `::operator delete'.
 
-/* Function types `double (double)' and `double (double, double)', etc.  */
+       tree global_delete_fndecl;
 
-static tree double_ftype_double, double_ftype_double_double;
-static tree int_ftype_int, long_ftype_long;
-static tree float_ftype_float;
-static tree ldouble_ftype_ldouble;
+   Used by RTTI
+       tree type_info_type_node, tinfo_fn_id, tinfo_fn_type;
 
-/* Function type `int (const void *, const void *, size_t)' */
-static tree int_ftype_cptr_cptr_sizet;
+*/
 
-/* C++ extensions */
-tree vtable_entry_type;
-tree delta_type_node;
-#if 0
-/* Old rtti stuff.  */
-tree __baselist_desc_type_node;
-tree __i_desc_type_node, __m_desc_type_node;
-tree __t_desc_array_type, __i_desc_array_type, __m_desc_array_type;
-#endif
-tree __t_desc_type_node;
-#if 0
-tree __tp_desc_type_node;
-#endif
-tree __access_mode_type_node;
-tree __bltn_desc_type_node, __user_desc_type_node, __class_desc_type_node;
-tree __ptr_desc_type_node, __attr_desc_type_node, __func_desc_type_node;
-tree __ptmf_desc_type_node, __ptmd_desc_type_node;
-#if 0
-/* Not needed yet?  May be needed one day?  */
-tree __bltn_desc_array_type, __user_desc_array_type, __class_desc_array_type;
-tree __ptr_desc_array_type, __attr_dec_array_type, __func_desc_array_type;
-tree __ptmf_desc_array_type, __ptmd_desc_array_type;
-#endif
+tree cp_global_trees[CPTI_MAX];
 
 /* Indicates that there is a type value in some namespace, although
-   that is not necessarily in scope at the moment. */
+   that is not necessarily in scope at the moment.  */
 
 static tree global_type_node;
 
-tree class_star_type_node;
-tree class_type_node, record_type_node, union_type_node, enum_type_node;
-tree unknown_type_node;
-tree opaque_type_node, signature_type_node;
-tree sigtable_entry_type;
-
-/* Array type `vtable_entry_type[]' */
-tree vtbl_type_node;
-tree vtbl_ptr_type_node;
-
-/* namespace std */
-tree std_node;
-int in_std = 0;
+/* Namespace std.  */
+int in_std;
 
 /* Expect only namespace names now. */
 static int only_namespace_names;
 
-/* In a destructor, the point at which all derived class destroying
-   has been done, just before any base class destroying will be done.  */
-
-tree dtor_label;
-
 /* In a destructor, the last insn emitted after the start of the
    function and the parms.  */
 
-static rtx last_dtor_insn;
+#define last_dtor_insn cp_function_chain->x_last_dtor_insn
 
 /* In a constructor, the last insn emitted after the start of the
    function and the parms, the exception specification and any
    function-try-block.  The constructor initializers are emitted after
    this insn.  */
 
-static rtx last_parm_cleanup_insn;
-
-/* In a constructor, the point at which we are ready to return
-   the pointer to the initialized object.  */
-
-tree ctor_label;
-
-/* A FUNCTION_DECL which can call `abort'.  Not necessarily the
-   one that the user will declare, but sufficient to be called
-   by routines that want to abort the program.  */
-
-tree abort_fndecl;
-
-/* A FUNCTION_DECL for the default `::operator delete'.  */
-
-tree global_delete_fndecl;
-
-extern rtx cleanup_label, return_label;
+#define last_parm_cleanup_insn cp_function_chain->x_last_parm_cleanup_insn
 
 /* If original DECL_RESULT of current function was a register,
    but due to being an addressable named return value, would up
    on the stack, this variable holds the named return value's
    original location.  */
-static rtx original_result_rtx;
 
-/* Sequence of insns which represents base initialization.  */
-tree base_init_expr;
-
-/* C++: Keep these around to reduce calls to `get_identifier'.
-   Identifiers for `this' in member functions and the auto-delete
-   parameter for destructors.  */
-tree this_identifier, in_charge_identifier;
-tree ctor_identifier, dtor_identifier;
-/* Used in pointer to member functions, in vtables, and in sigtables.  */
-tree pfn_identifier, index_identifier, delta_identifier, delta2_identifier;
-tree pfn_or_delta2_identifier, tag_identifier;
-tree vt_off_identifier;
+#define original_result_rtx cp_function_chain->x_result_rtx
 
 struct named_label_list
 {
   struct binding_level *binding_level;
   tree names_in_scope;
   tree label_decl;
-  char *filename_o_goto;
+  const char *filename_o_goto;
   int lineno_o_goto;
   struct named_label_list *next;
 };
 
-/* A list (chain of TREE_LIST nodes) of named label uses.
-   The TREE_PURPOSE field is the list of variables defined
-   in the label's scope defined at the point of use.
-   The TREE_VALUE field is the LABEL_DECL used.
-   The TREE_TYPE field holds `current_binding_level' at the
-   point of the label's use.
-
-   BWAHAHAAHAHahhahahahaah.  No, no, no, said the little chicken.
+/* Used only for jumps to as-yet undefined labels, since jumps to
+   defined labels can have their validity checked by stmt.c.  */
 
-   Look at the pretty struct named_label_list. See the pretty struct
-   with the pretty named fields that describe what they do. See the
-   pretty lack of gratuitous casts. Notice the code got a lot cleaner.
-
-   Used only for jumps to as-yet undefined labels, since
-   jumps to defined labels can have their validity checked
-   by stmt.c.  */
-
-static struct named_label_list *named_label_uses = NULL;
+#define named_label_uses cp_function_chain->x_named_label_uses
 
 /* A list of objects which have constructors or destructors
    which reside in the global scope.  The decl is stored in
@@ -455,19 +295,9 @@ tree static_aggregates;
 
 /* -- end of C++ */
 
-/* Two expressions that are constants with value zero.
-   The first is of type `int', the second of type `void *'.  */
-
-tree integer_zero_node;
-tree null_pointer_node;
-
-/* The value for __null (NULL), namely, a zero of an integer type with
-   the same number of bits as a pointer.  */
-tree null_node;
+/* A node for the integer constants 2, and 3.  */
 
-/* A node for the integer constants 1, 2, and 3.  */
-
-tree integer_one_node, integer_two_node, integer_three_node;
+tree integer_two_node, integer_three_node;
 
 /* While defining an enum type, this is 1 plus the last enumerator
    constant value.  */
@@ -478,49 +308,26 @@ static tree enum_next_value;
 
 static int enum_overflow;
 
-/* Parsing a function declarator leaves a list of parameter names
-   or a chain or parameter decls here.  */
-
-tree last_function_parms;
-
 /* Parsing a function declarator leaves here a chain of structure
    and enum types declared in the parmlist.  */
 
 static tree last_function_parm_tags;
 
-/* After parsing the declarator that starts a function definition,
-   `start_function' puts here the list of parameter names or chain of decls.
-   `store_parm_decls' finds it here.  */
-
-static tree current_function_parms;
-
 /* Similar, for last_function_parm_tags.  */
+tree last_function_parms;
 static tree current_function_parm_tags;
 
 /* A list (chain of TREE_LIST nodes) of all LABEL_DECLs in the function
    that have names.  Here so we can clear out their names' definitions
-   at the end of the function.  */
-
-static tree named_labels;
+   at the end of the function.  The TREE_VALUE is a LABEL_DECL; the
+   TREE_PURPOSE is the previous binding of the label.  */
 
-/* A list of LABEL_DECLs from outer contexts that are currently shadowed.  */
-
-static tree shadowed_labels;
+#define named_labels cp_function_chain->x_named_labels
 
 /* The FUNCTION_DECL for the function currently being compiled,
    or 0 if between functions.  */
 tree current_function_decl;
 
-/* Set to 0 at beginning of a function definition, set to 1 if
-   a return statement that specifies a return value is seen.  */
-
-int current_function_returns_value;
-
-/* Set to 0 at beginning of a function definition, set to 1 if
-   a return statement with no argument is seen.  */
-
-int current_function_returns_null;
-
 /* Set to 0 at beginning of a function definition, and whenever
    a label (case or named) is defined.  Set to value of expression
    returned from function when that value can be transformed into
@@ -555,33 +362,13 @@ extern int flag_huge_objects;
    .common instead of .data at the expense of not flagging multiple
    definitions.  */
 extern int flag_conserve_space;
-
-/* Pointers to the base and current top of the language name stack.  */
-
-extern tree *current_lang_base, *current_lang_stack;
 \f
 /* C and C++ flags are in decl2.c.  */
 
-/* Set to 0 at beginning of a constructor, set to 1
-   if that function does an allocation before referencing its
-   instance variable.  */
-static int current_function_assigns_this;
-int current_function_just_assigned_this;
-
-/* Set to 0 at beginning of a function.  Set non-zero when
-   store_parm_decls is called.  Don't call store_parm_decls
-   if this flag is non-zero!  */
-int current_function_parms_stored;
-
 /* Flag used when debugging spew.c */
 
 extern int spew_debug;
 
-/* This is a copy of the class_shadowed list of the previous class binding
-   contour when at global scope.  It's used to reset IDENTIFIER_CLASS_VALUEs
-   when entering another class scope (i.e. a cache miss).  */
-extern tree previous_class_values;
-
 /* A expression of value 0 with the same precision as a sizetype
    node, but signed.  */
 tree signed_size_zero_node;
@@ -591,20 +378,6 @@ tree signed_size_zero_node;
 tree anonymous_namespace_name;
 
 \f
-/* Allocate a level of searching.  */
-
-static
-struct stack_level *
-push_decl_level (stack, obstack)
-     struct stack_level *stack;
-     struct obstack *obstack;
-{
-  struct stack_level tem;
-  tem.prev = stack;
-
-  return push_stack_level (obstack, (char *)&tem, sizeof (tem));
-}
-\f
 /* For each binding contour we allocate a binding_level structure
    which records the names defined in that contour.
    Contours include:
@@ -667,6 +440,11 @@ struct binding_level
        is used for all binding levels.  */
     tree type_shadowed;
 
+    /* A TREE_LIST.  Each TREE_VALUE is the LABEL_DECL for a local
+       label in this scope.  The TREE_PURPOSE is the previous value of
+       the IDENTIFIER_LABEL VALUE.  */
+    tree shadowed_labels;
+
     /* For each level (except not the global one),
        a chain of BLOCK nodes for all the levels
        that were entered and exited one level down.  */
@@ -718,7 +496,10 @@ struct binding_level
        worry about ambiguous (ARM or ANSI) scope rules.  */
     unsigned is_for_scope : 1;
 
-    /* Two bits left for this word.  */
+    /* True if this level corresponds to an EH region, as for a try block.  */
+    unsigned eh_region : 1;
+
+    /* One bit left for this word.  */
 
 #if defined(DEBUG_CP_BINDING_LEVELS)
     /* Binding depth at which this level began.  */
@@ -730,11 +511,14 @@ struct binding_level
   
 /* The binding level currently in effect.  */
 
-static struct binding_level *current_binding_level;
+#define current_binding_level                  \
+  (current_function                            \
+   ? cp_function_chain->bindings               \
+   : scope_chain->bindings)
 
 /* The binding level of the current class, if any.  */
 
-static struct binding_level *class_binding_level;
+#define class_binding_level scope_chain->class_bindings
 
 /* A chain of binding_level structures awaiting reuse.  */
 
@@ -746,10 +530,6 @@ static struct binding_level *free_binding_level;
 
 static struct binding_level *global_binding_level;
 
-/* Binding level structures are initialized by copying this one.  */
-
-static struct binding_level clear_binding_level;
-
 /* Nonzero means unconditionally make a BLOCK for the next level pushed.  */
 
 static int keep_next_level_flag;
@@ -777,11 +557,17 @@ push_binding_level (newlevel, tag_transparent, keep)
 {
   /* Add this level to the front of the chain (stack) of levels that
      are active.  */
-  *newlevel = clear_binding_level;
+  bzero ((char*) newlevel, sizeof (struct binding_level));
   newlevel->level_chain = current_binding_level;
   current_binding_level = newlevel;
   newlevel->tag_transparent = tag_transparent;
   newlevel->more_cleanups_ok = 1;
+
+  /* We are called before expand_start_bindings, but after
+     expand_eh_region_start for a try block; so we check this now,
+     before the EH block is covered up.  */
+  newlevel->eh_region = is_eh_region ();
+
   newlevel->keep = keep;
 #if defined(DEBUG_CP_BINDING_LEVELS)
   newlevel->binding_depth = binding_depth;
@@ -953,10 +739,15 @@ namespace_bindings_p ()
   return b->namespace_p;
 }
 
+/* If KEEP is non-zero, make a BLOCK node for the next binding level,
+   unconditionally.  Otherwise, use the normal logic to decide whether
+   or not to create a BLOCK.  */
+
 void
-keep_next_level ()
+keep_next_level (keep)
+     int keep;
 {
-  keep_next_level_flag = 1;
+  keep_next_level_flag = keep;
 }
 
 /* Nonzero if the current level needs to have a BLOCK made.  */
@@ -971,14 +762,6 @@ kept_level_p ()
              && !current_binding_level->tag_transparent));
 }
 
-/* Identify this binding level as a level of parameters.  */
-
-void
-declare_parm_level ()
-{
-  current_binding_level->parm_flag = 1;
-}
-
 void
 declare_pseudo_global_level ()
 {
@@ -994,9 +777,7 @@ declare_namespace_level ()
 int
 pseudo_global_level_p ()
 {
-  struct binding_level *b = innermost_nonclass_level ();
-
-  return b->pseudo_global;
+  return current_binding_level->pseudo_global;
 }
 
 void
@@ -1014,17 +795,12 @@ void
 pushlevel (tag_transparent)
      int tag_transparent;
 {
-  register struct binding_level *newlevel = NULL_BINDING_LEVEL;
+  struct binding_level *newlevel;
 
-  /* If this is the top level of a function,
-     just make sure that NAMED_LABELS is 0.
-     They should have been set to 0 at the end of the previous function.  */
-
-  if (current_binding_level == global_binding_level)
-    my_friendly_assert (named_labels == NULL_TREE, 134);
+  if (current_function && !doing_semantic_analysis_p ())
+    return;
 
   /* Reuse or create a struct for this binding level.  */
-
 #if defined(DEBUG_CP_BINDING_LEVELS)
   if (0)
 #else /* !defined(DEBUG_CP_BINDING_LEVELS) */
@@ -1035,9 +811,7 @@ pushlevel (tag_transparent)
       free_binding_level = free_binding_level->level_chain;
     }
   else
-    {
-      newlevel = make_binding_level ();
-    }
+    newlevel = make_binding_level ();
 
   push_binding_level (newlevel, tag_transparent, keep_next_level_flag);
   GNU_xref_start_scope ((HOST_WIDE_INT) newlevel);
@@ -1070,11 +844,6 @@ pushlevel_temporary (tag_transparent)
 #define BINDING_LEVEL(NODE) \
    (((struct tree_binding*)NODE)->scope.level)
 
-/* These are currently unused, but permanent, CPLUS_BINDING nodes.
-   They are kept here because they are allocated from the permanent
-   obstack and cannot be easily freed.  */
-static tree free_binding_nodes;
-
 /* Make DECL the innermost binding for ID.  The LEVEL is the binding
    level at which this declaration is being bound.  */
 
@@ -1086,22 +855,7 @@ push_binding (id, decl, level)
 {
   tree binding;
 
-  if (!free_binding_nodes)
-    {
-      /* There are no free nodes, so we must build one here.  */
-      push_obstacks_nochange ();
-      end_temporary_allocation ();
-      binding = make_node (CPLUS_BINDING);
-      pop_obstacks ();
-    }
-  else
-    {
-      /* There are nodes on the free list.  Grab the first one.  */
-      binding = free_binding_nodes;
-      
-      /* And update the free list.  */
-      free_binding_nodes = TREE_CHAIN (free_binding_nodes);
-    }
+  binding = make_node (CPLUS_BINDING);
 
   /* Now, fill in the binding information.  */
   BINDING_VALUE (binding) = decl;
@@ -1109,6 +863,7 @@ push_binding (id, decl, level)
   BINDING_LEVEL (binding) = level;
   INHERITED_VALUE_BINDING_P (binding) = 0;
   LOCAL_BINDING_P (binding) = (level != class_binding_level);
+  BINDING_HAS_LEVEL_P (binding) = 1;
 
   /* And put it on the front of the list of bindings for ID.  */
   TREE_CHAIN (binding) = IDENTIFIER_BINDING (id);
@@ -1174,9 +929,23 @@ add_binding (id, decl)
   return ok;
 }
 
-/* Bind DECL to ID in the current_binding_level.
-   If PUSH_USING is set in FLAGS, we know that DECL doesn't really belong
-   to this binding level, that it got here through a using-declaration.  */
+/* Add DECL to the list of things declared in B.  */
+
+static void
+add_decl_to_level (decl, b)
+     tree decl;
+     struct binding_level *b;
+{
+  /* We build up the list in reverse order, and reverse it later if
+     necessary.  */
+  TREE_CHAIN (decl) = b->names;
+  b->names = decl;
+}
+
+/* Bind DECL to ID in the current_binding_level, assumed to be a local
+   binding level.  If PUSH_USING is set in FLAGS, we know that DECL
+   doesn't really belong to this binding level, that it got here
+   through a using-declaration.  */
 
 void
 push_local_binding (id, decl, flags)
@@ -1213,8 +982,7 @@ push_local_binding (id, decl, flags)
 
   /* And put DECL on the list of things declared by the current
      binding level.  */
-  TREE_CHAIN (decl) = b->names;
-  b->names = decl;
+  add_decl_to_level (decl, b);
 }
 
 /* Bind DECL to ID in the class_binding_level.  Returns nonzero if the
@@ -1256,8 +1024,7 @@ push_class_binding (id, decl)
         context for an implicit typename declaration is always
         the derived class in which the lookup was done, so the checks
         based on the context of DECL below will not trigger.  */
-      if (TREE_CODE (decl) == TYPE_DECL 
-         && IMPLICIT_TYPENAME_P (TREE_TYPE (decl)))
+      if (IMPLICIT_TYPENAME_TYPE_DECL_P (decl))
        INHERITED_VALUE_BINDING_P (binding) = 1;
       else
        {
@@ -1317,15 +1084,57 @@ pop_binding (id, decl)
     my_friendly_abort (0);
 
   if (!BINDING_VALUE (binding) && !BINDING_TYPE (binding))
+    /* We're completely done with the innermost binding for this
+       identifier.  Unhook it from the list of bindings.  */
+    IDENTIFIER_BINDING (id) = TREE_CHAIN (binding);
+}
+
+/* When a label goes out of scope, check to see if that label was used
+   in a valid manner, and issue any appropriate warnings or errors.  */
+
+static void
+pop_label (link)
+     tree link;
+{
+  tree label = TREE_VALUE (link);
+
+  if (!processing_template_decl && doing_semantic_analysis_p ())
     {
-      /* We're completely done with the innermost binding for this
-        identifier.  Unhook it from the list of bindings.  */
-      IDENTIFIER_BINDING (id) = TREE_CHAIN (binding);
+      if (DECL_INITIAL (label) == NULL_TREE)
+       {
+         cp_error_at ("label `%D' used but not defined", label);
+         /* Avoid crashing later.  */
+         define_label (input_filename, 1, DECL_NAME (label));
+       }
+      else if (warn_unused && !TREE_USED (label))
+       cp_warning_at ("label `%D' defined but not used", label);
+    }
+
+  SET_IDENTIFIER_LABEL_VALUE (DECL_NAME (label), TREE_PURPOSE (link));
+}
+
+/* At the end of a function, all labels declared within the fucntion
+   go out of scope.  BLOCK is the top-level block for the 
+   function.  */
+
+static void
+pop_labels (block)
+     tree block;
+{
+  tree link;
 
-      /* And place it on the free list.  */
-      TREE_CHAIN (binding) = free_binding_nodes;
-      free_binding_nodes = binding;
+  /* Clear out the definitions of all label names, since their scopes
+     end here.  */
+  for (link = named_labels; link; link = TREE_CHAIN (link))
+    {
+      pop_label (link);
+      /* Put the labels into the "variables" of the top-level block,
+        so debugger can see them.  */
+      TREE_CHAIN (TREE_VALUE (link)) = BLOCK_VARS (block);
+      BLOCK_VARS (block) = TREE_VALUE (link);
     }
+
+  named_labels = NULL_TREE;
 }
 
 /* Exit a binding level.
@@ -1354,17 +1163,24 @@ poplevel (keep, reverse, functionbody)
      Put it into forward order, just for cleanliness.  */
   tree decls;
   int tmp = functionbody;
-  int real_functionbody = current_binding_level->keep == 2
-    ? ((functionbody = 0), tmp) : functionbody;
-  tree tags = functionbody >= 0 ? current_binding_level->tags : 0;
-  tree subblocks = functionbody >= 0 ? current_binding_level->blocks : 0;
+  int real_functionbody;
+  tree tags;
+  tree subblocks;
   tree block = NULL_TREE;
   tree decl;
   int block_previously_created;
   int leaving_for_scope;
 
-  if (current_binding_level->parm_flag == 2)
-    return poplevel_class ();
+  if (current_function && !doing_semantic_analysis_p ())
+    return NULL_TREE;
+
+  my_friendly_assert (current_binding_level->parm_flag != 2,
+                     19990916);
+
+  real_functionbody = (current_binding_level->keep == 2
+                      ? ((functionbody = 0), tmp) : functionbody);
+  tags = functionbody >= 0 ? current_binding_level->tags : 0;
+  subblocks = functionbody >= 0 ? current_binding_level->blocks : 0;
 
   my_friendly_assert (!current_binding_level->class_shadowed,
                      19990414);
@@ -1563,7 +1379,13 @@ poplevel (keep, reverse, functionbody)
   for (link = current_binding_level->type_shadowed;
        link; link = TREE_CHAIN (link))
     SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (link), TREE_VALUE (link));
-  
+
+  /* Restore the IDENTIFIER_LABEL_VALUEs for local labels.  */
+  for (link = current_binding_level->shadowed_labels;
+       link; 
+       link = TREE_CHAIN (link))
+    pop_label (link);
+
   /* There may be OVERLOADs (wrapped in TREE_LISTs) on the BLOCK_VARs
      list if a `using' declaration put them there.  The debugging
      back-ends won't understand OVERLOAD, so we remove them here.
@@ -1585,58 +1407,32 @@ poplevel (keep, reverse, functionbody)
 
   /* If the level being exited is the top level of a function,
      check over all the labels.  */
-
   if (functionbody)
     {
-      /* If this is the top level block of a function,
-         the vars are the function's parameters.
-         Don't leave them in the BLOCK because they are
-         found in the FUNCTION_DECL instead.  */
-
+      /* Since this is the top level block of a function, the vars are
+        the function's parameters.  Don't leave them in the BLOCK
+        because they are found in the FUNCTION_DECL instead.  */
       BLOCK_VARS (block) = 0;
-
-      /* Clear out the definitions of all label names,
-        since their scopes end here.  */
-
-      for (link = named_labels; link; link = TREE_CHAIN (link))
-       {
-         register tree label = TREE_VALUE (link);
-
-         if (DECL_INITIAL (label) == NULL_TREE)
-           {
-             cp_error_at ("label `%D' used but not defined", label);
-             /* Avoid crashing later.  */
-             define_label (input_filename, 1, DECL_NAME (label));
-           }
-         else if (warn_unused && !TREE_USED (label))
-           cp_warning_at ("label `%D' defined but not used", label);
-         SET_IDENTIFIER_LABEL_VALUE (DECL_NAME (label), NULL_TREE);
-
-          /* Put the labels into the "variables" of the
-             top-level block, so debugger can see them.  */
-          TREE_CHAIN (label) = BLOCK_VARS (block);
-          BLOCK_VARS (block) = label;
-       }
-
-      named_labels = NULL_TREE;
+      pop_labels (block);
     }
 
   /* Any uses of undefined labels now operate under constraints
      of next binding contour.  */
-  {
-    struct binding_level *level_chain;
-    level_chain = current_binding_level->level_chain;
-    if (level_chain)
-      {
-       struct named_label_list *labels;
-       for (labels = named_label_uses; labels; labels = labels->next)
-         if (labels->binding_level == current_binding_level)
-           {
-             labels->binding_level = level_chain;
-             labels->names_in_scope = level_chain->names;
-           }
-      }
-  }
+  if (current_function)
+    {
+      struct binding_level *level_chain;
+      level_chain = current_binding_level->level_chain;
+      if (level_chain)
+       {
+         struct named_label_list *labels;
+         for (labels = named_label_uses; labels; labels = labels->next)
+           if (labels->binding_level == current_binding_level)
+             {
+               labels->binding_level = level_chain;
+               labels->names_in_scope = level_chain->names;
+             }
+       }
+    }
 
   tmp = current_binding_level->keep;
 
@@ -1751,14 +1547,13 @@ pushlevel_class ()
 
   push_binding_level (newlevel, 0, 0);
 
-  decl_stack = push_decl_level (decl_stack, &decl_obstack);
   class_binding_level = current_binding_level;
   class_binding_level->parm_flag = 2;
 }
 
 /* ...and a poplevel for class declarations.  */
 
-static tree
+void
 poplevel_class ()
 {
   register struct binding_level *level = class_binding_level;
@@ -1766,7 +1561,6 @@ poplevel_class ()
 
   my_friendly_assert (level != 0, 354);
   
-  decl_stack = pop_stack_level (decl_stack);
   /* If we're leaving a toplevel class, don't bother to do the setting
      of IDENTIFIER_CLASS_VALUE to NULL_TREE, since first of all this slot
      shouldn't even be used when current_class_type isn't set, and second,
@@ -1834,8 +1628,6 @@ poplevel_class ()
 #endif /* defined(DEBUG_CP_BINDING_LEVELS) */
 
   pop_binding_level ();
-
-  return NULL_TREE;
 }
 
 /* We are entering the scope of a class.  Clear IDENTIFIER_CLASS_VALUE
@@ -1879,16 +1671,13 @@ vtype_decl_p (t, data)
          && CLASSTYPE_VSIZE (TREE_TYPE (t)));
 }
 
-/* Returns non-zero if T is a signature table.  */
+/* Return the declarations that are members of the namespace NS.  */
 
-int 
-sigtable_decl_p (t, data)
-     tree t;
-     void *data ATTRIBUTE_UNUSED;
+tree
+cp_namespace_decls (ns)
+     tree ns;
 {
-  return (TREE_CODE (t) == VAR_DECL
-         && TREE_TYPE (t) != error_mark_node
-         && IS_SIGNATURE (TREE_TYPE (t)));
+  return NAMESPACE_LEVEL (ns)->names;
 }
 
 /* Walk all the namespaces contained NAMESPACE, including NAMESPACE
@@ -1905,7 +1694,7 @@ walk_namespaces_r (namespace, f, data)
 
   result |= (*f) (namespace, data);
 
-  for (current = NAMESPACE_LEVEL (namespace)->names;
+  for (current = cp_namespace_decls (namespace);
        current;
        current = TREE_CHAIN (current))
     {
@@ -2004,7 +1793,7 @@ wrapup_globals_for_namespace (namespace, data)
      tree namespace;
      void *data;
 {
-  tree globals = NAMESPACE_LEVEL (namespace)->names;
+  tree globals = cp_namespace_decls (namespace);
   int len = list_length (globals);
   tree *vec = (tree *) alloca (sizeof (tree) * len);
   int i;
@@ -2054,6 +1843,32 @@ wrapup_globals_for_namespace (namespace, data)
 }
 
 \f
+/* Mark ARG (which is really a struct binding_level **) for GC.  */
+
+static void
+mark_binding_level (arg)
+     void *arg;
+{
+  struct binding_level *lvl = *(struct binding_level **)arg;
+
+  while (lvl)
+    {
+      ggc_mark_tree (lvl->names);
+      ggc_mark_tree (lvl->tags);
+      ggc_mark_tree (lvl->usings);
+      ggc_mark_tree (lvl->using_directives);
+      ggc_mark_tree (lvl->class_shadowed);
+      ggc_mark_tree (lvl->type_shadowed);
+      ggc_mark_tree (lvl->shadowed_labels);
+      ggc_mark_tree (lvl->blocks);
+      ggc_mark_tree (lvl->this_block);
+      ggc_mark_tree (lvl->incomplete);
+      ggc_mark_tree (lvl->dead_vars_from_for);
+
+      lvl = lvl->level_chain;
+    }
+}
+\f
 /* For debugging.  */
 static int no_print_functions = 0;
 static int no_print_builtins = 0;
@@ -2227,7 +2042,7 @@ find_binding (name, scope)
       my_friendly_assert (TREE_CODE (iter) == CPLUS_BINDING, 374);
       if (BINDING_SCOPE (iter) == scope)
        {
-         /* Move binding found to the fron of the list, so
+         /* Move binding found to the front of the list, so
              subsequent lookups will find it faster. */
          if (prev)
            {
@@ -2454,32 +2269,35 @@ pop_nested_namespace (ns)
    local-value slots of all identifiers, so that only the global values
    are at all visible.  Simply setting current_binding_level to the global
    scope isn't enough, because more binding levels may be pushed.  */
-struct saved_scope {
-  struct binding_level *old_binding_level;
-  tree old_bindings;
-  tree old_namespace;
-  struct saved_scope *prev;
-  tree class_name, class_type;
-  tree access_specifier;
-  tree function_decl;
-  struct binding_level *class_bindings;
-  tree *lang_base, *lang_stack, lang_name;
-  int lang_stacksize;
-  int minimal_parse_mode;
-  tree last_function_parms;
-  tree template_parms;
-  HOST_WIDE_INT processing_template_decl;
-  tree previous_class_type, previous_class_values;
-  int processing_specialization;
-  int processing_explicit_instantiation;
-  char *class_cache_firstobj;
-};
-static struct saved_scope *current_saved_scope;
+struct saved_scope *scope_chain;
+
+/* Mark ARG (which is really a struct saved_scope **) for GC.  */
 
-/* A chain of the binding vecs created by store_bindings.  We create a
-   whole bunch of these during compilation, on permanent_obstack, so we
-   can't just throw them away.  */
-static tree free_binding_vecs;
+static void
+mark_saved_scope (arg)
+     void *arg;
+{
+  struct saved_scope *t = *(struct saved_scope **)arg;
+  while (t)
+    {
+      mark_binding_level (&t->class_bindings);
+      ggc_mark_tree (t->old_bindings);
+      ggc_mark_tree (t->old_namespace);
+      ggc_mark_tree (t->class_name);
+      ggc_mark_tree (t->class_type);
+      ggc_mark_tree (t->access_specifier);
+      ggc_mark_tree (t->function_decl);
+      if (t->lang_base)
+       ggc_mark_tree_varray (t->lang_base);
+      ggc_mark_tree (t->lang_name);
+      ggc_mark_tree (t->x_function_parms);
+      ggc_mark_tree (t->template_parms);
+      ggc_mark_tree (t->x_previous_class_type);
+      ggc_mark_tree (t->x_previous_class_values);
+      mark_binding_level (&t->bindings);
+      t = t->prev;
+    }
+}
 
 static tree
 store_bindings (names, old_bindings)
@@ -2506,13 +2324,7 @@ store_bindings (names, old_bindings)
        if (TREE_VEC_ELT (t1, 0) == id)
          goto skip_it;
 
-      if (free_binding_vecs)
-       {
-         binding = free_binding_vecs;
-         free_binding_vecs = TREE_CHAIN (free_binding_vecs);
-       }
-      else
-       binding = make_tree_vec (4);
+      binding = make_tree_vec (4);
 
       if (id)
        {
@@ -2536,15 +2348,26 @@ void
 maybe_push_to_top_level (pseudo)
      int pseudo;
 {
-  extern int current_lang_stacksize;
-  struct saved_scope *s
-    = (struct saved_scope *) xmalloc (sizeof (struct saved_scope));
-  struct binding_level *b = current_binding_level;
-  tree old_bindings = NULL_TREE;
+  struct saved_scope *s;
+  struct binding_level *b;
+  tree old_bindings;
+  int need_pop;
 
-  push_cp_function_context (NULL_TREE);
+  s = (struct saved_scope *) xcalloc (1, sizeof (struct saved_scope));
 
-  if (previous_class_type)
+  b = scope_chain ? current_binding_level : 0;
+
+  /* If we're in the middle of some function, save our state.  */
+  if (current_function)
+    {
+      need_pop = 1;
+      push_function_context_to (NULL_TREE);
+    }
+  else
+    need_pop = 0;
+
+  old_bindings = NULL_TREE;
+  if (scope_chain && previous_class_type)
     old_bindings = store_bindings (previous_class_values, old_bindings);
 
   /* Have to include global_binding_level, because class-level decls
@@ -2570,53 +2393,20 @@ maybe_push_to_top_level (pseudo)
       for (t = b->type_shadowed; t; t = TREE_CHAIN (t))
        SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (t), TREE_VALUE (t));
     }
-
-  s->old_binding_level = current_binding_level;
-  current_binding_level = b;
-
-  s->old_namespace = current_namespace;
-  s->class_name = current_class_name;
-  s->class_type = current_class_type;
-  s->access_specifier = current_access_specifier;
+  s->prev = scope_chain;
+  s->old_bindings = old_bindings;
+  s->bindings = b;
+  s->need_pop_function_context = need_pop;
   s->function_decl = current_function_decl;
-  s->class_bindings = class_binding_level;
-  s->lang_stack = current_lang_stack;
-  s->lang_base = current_lang_base;
-  s->lang_stacksize = current_lang_stacksize;
-  s->lang_name = current_lang_name;
-  s->minimal_parse_mode = minimal_parse_mode;
-  s->last_function_parms = last_function_parms;
-  s->template_parms = current_template_parms;
-  s->processing_template_decl = processing_template_decl;
-  s->previous_class_type = previous_class_type;
-  s->previous_class_values = previous_class_values;
-  s->class_cache_firstobj = class_cache_firstobj;
-  s->processing_specialization = processing_specialization;
-  s->processing_explicit_instantiation = processing_explicit_instantiation;
-
-  current_class_name = current_class_type = NULL_TREE;
+
+  scope_chain = s;
   current_function_decl = NULL_TREE;
-  class_binding_level = (struct binding_level *)0;
-  current_lang_stacksize = 10;
-  current_lang_stack = current_lang_base
-    = (tree *) xmalloc (current_lang_stacksize * sizeof (tree));
+  VARRAY_TREE_INIT (current_lang_base, 10, "current_lang_base");
+  current_lang_stack = &VARRAY_TREE (current_lang_base, 0);
   current_lang_name = lang_name_cplusplus;
   strict_prototype = strict_prototypes_lang_cplusplus;
-  named_labels = NULL_TREE;
-  shadowed_labels = NULL_TREE;
-  minimal_parse_mode = 0;
-  previous_class_type = previous_class_values = NULL_TREE;
-  class_cache_firstobj = 0;
-  processing_specialization = 0;
-  processing_explicit_instantiation = 0;
-  current_template_parms = NULL_TREE;
-  processing_template_decl = 0;
   current_namespace = global_namespace;
 
-  s->prev = current_saved_scope;
-  s->old_bindings = old_bindings;
-  current_saved_scope = s;
-
   push_obstacks (&permanent_obstack, &permanent_obstack);
 }
 
@@ -2629,8 +2419,7 @@ push_to_top_level ()
 void
 pop_from_top_level ()
 {
-  extern int current_lang_stacksize;
-  struct saved_scope *s = current_saved_scope;
+  struct saved_scope *s = scope_chain;
   tree t;
 
   /* Clear out class-level bindings cache.  */
@@ -2639,50 +2428,32 @@ pop_from_top_level ()
 
   pop_obstacks ();
 
-  current_binding_level = s->old_binding_level;
-  current_saved_scope = s->prev;
-  for (t = s->old_bindings; t; )
+  VARRAY_FREE (current_lang_base);
+
+  scope_chain = s->prev;
+  for (t = s->old_bindings; t; t = TREE_CHAIN (t))
     {
-      tree save = t;
       tree id = TREE_VEC_ELT (t, 0);
       if (id)
        {
          SET_IDENTIFIER_TYPE_VALUE (id, TREE_VEC_ELT (t, 1));
          IDENTIFIER_BINDING (id) = TREE_VEC_ELT (t, 2);
          IDENTIFIER_CLASS_VALUE (id) = TREE_VEC_ELT (t, 3);
-       }
-      t = TREE_CHAIN (t);
-      TREE_CHAIN (save) = free_binding_vecs;
-      free_binding_vecs = save;
+       }
     }
-  current_namespace = s->old_namespace;
-  current_class_name = s->class_name;
-  current_class_type = s->class_type;
-  current_access_specifier = s->access_specifier;
-  current_function_decl = s->function_decl;
-  class_binding_level = s->class_bindings;
-  free (current_lang_base);
-  current_lang_base = s->lang_base;
-  current_lang_stack = s->lang_stack;
-  current_lang_name = s->lang_name;
-  current_lang_stacksize = s->lang_stacksize;
+
   if (current_lang_name == lang_name_cplusplus)
     strict_prototype = strict_prototypes_lang_cplusplus;
   else if (current_lang_name == lang_name_c)
     strict_prototype = strict_prototypes_lang_c;
-  minimal_parse_mode = s->minimal_parse_mode;
-  last_function_parms = s->last_function_parms;
-  current_template_parms = s->template_parms;
-  processing_template_decl = s->processing_template_decl;
-  previous_class_type = s->previous_class_type;
-  previous_class_values = s->previous_class_values;
-  processing_specialization = s->processing_specialization;
-  processing_explicit_instantiation = s->processing_explicit_instantiation;
-  class_cache_firstobj = s->class_cache_firstobj;
 
-  free (s);
+  /* If we were in the middle of compiling a function, restore our
+     state.  */
+  if (s->need_pop_function_context)
+    pop_function_context_from (NULL_TREE);
+  current_function_decl = s->function_decl;
 
-  pop_cp_function_context (NULL_TREE);
+  free (s);
 }
 \f
 /* Push a definition of struct, union or enum tag "name".
@@ -2830,7 +2601,7 @@ maybe_process_template_type_declaration (type, globalize, b)
                 that won't happen below because B is not the class
                 binding level, but is instead the pseudo-global level.  */
              b->level_chain->tags = 
-               saveable_tree_cons (name, type, b->level_chain->tags);
+               tree_cons (name, type, b->level_chain->tags);
              if (TYPE_SIZE (current_class_type) == NULL_TREE)
                CLASSTYPE_TAGS (current_class_type) = b->level_chain->tags;
            }
@@ -2840,6 +2611,29 @@ maybe_process_template_type_declaration (type, globalize, b)
   return decl;
 }
 
+/* In C++, you don't have to write `struct S' to refer to `S'; you
+   can just use `S'.  We accomplish this by creating a TYPE_DECL as
+   if the user had written `typedef struct S S'.  Create and return
+   the TYPE_DECL for TYPE.  */
+
+tree
+create_implicit_typedef (name, type)
+     tree name;
+     tree type;
+{
+  tree decl;
+
+  decl = build_decl (TYPE_DECL, name, type);
+  SET_DECL_ARTIFICIAL (decl);
+  /* There are other implicit type declarations, like the one *within*
+     a class that allows you to write `S::S'.  We must distinguish
+     amongst these.  */
+  SET_DECL_IMPLICIT_TYPEDEF_P (decl);
+  TYPE_NAME (type) = decl;
+
+  return decl;
+}
+
 /* Push a tag name NAME for struct/class/union/enum type TYPE.
    Normally put it into the inner-most non-tag-transparent scope,
    but if GLOBALIZE is true, put it in the inner-most non-class scope.
@@ -2857,10 +2651,7 @@ pushtag (name, type, globalize)
         || (globalize && b->parm_flag == 2))
     b = b->level_chain;
 
-  if (toplevel_bindings_p ())
-    b->tags = perm_tree_cons (name, type, b->tags);
-  else
-    b->tags = saveable_tree_cons (name, type, b->tags);
+  b->tags = tree_cons (name, type, b->tags);
 
   if (name)
     {
@@ -2868,11 +2659,9 @@ pushtag (name, type, globalize)
       if (IDENTIFIER_TYPE_VALUE (name) != type)
         {
           register tree d = NULL_TREE;
-         int newdecl = 0, in_class = 0;
-         tree context;
-         tree c_decl = NULL_TREE;
+         int in_class = 0;
+         tree context = TYPE_CONTEXT (type);
 
-         context = type ? TYPE_CONTEXT (type) : NULL_TREE;
          if (! context)
            {
              tree cs = current_scope ();
@@ -2886,41 +2675,27 @@ pushtag (name, type, globalize)
                   containing the local class, not the namespace scope.  */
                context = hack_decl_function_context (get_type_decl (cs));
            }
-         if (context)
-           c_decl = TREE_CODE (context) == FUNCTION_DECL
-             ? context : TYPE_MAIN_DECL (context);
-
          if (!context)
            context = current_namespace;
 
          if ((b->pseudo_global && b->level_chain->parm_flag == 2)
              || b->parm_flag == 2)
            in_class = 1;
-         else
-           d = lookup_nested_type (type, c_decl);
 
-         if (d == NULL_TREE)
-           {
-             newdecl = 1;
-             d = build_decl (TYPE_DECL, name, type);
-             if (current_lang_name == lang_name_java)
-               TYPE_FOR_JAVA (type) = 1;
-             SET_DECL_ARTIFICIAL (d);
-             if (! in_class)
-               set_identifier_type_value_with_scope (name, type, b);
-           }
-         else
-           d = TYPE_MAIN_DECL (d);
+         if (current_lang_name == lang_name_java)
+           TYPE_FOR_JAVA (type) = 1;
 
-         TYPE_NAME (type) = d;
+         d = create_implicit_typedef (name, type);
          DECL_CONTEXT (d) = FROB_CONTEXT (context);
+         if (! in_class)
+           set_identifier_type_value_with_scope (name, type, b);
 
          d = maybe_process_template_type_declaration (type,
                                                       globalize, b);
 
          if (b->parm_flag == 2)
            {
-             if (newdecl && !PROCESSING_REAL_TEMPLATE_DECL_P ())
+             if (!PROCESSING_REAL_TEMPLATE_DECL_P ())
                /* Put this TYPE_DECL on the TYPE_FIELDS list for the
                   class.  But if it's a member template class, we
                   want the TEMPLATE_DECL, not the TYPE_DECL, so this
@@ -2932,17 +2707,14 @@ pushtag (name, type, globalize)
          else
            d = pushdecl_with_scope (d, b);
 
-         if (newdecl)
-           {
-             if (ANON_AGGRNAME_P (name))
-               DECL_IGNORED_P (d) = 1;
-
-             TYPE_CONTEXT (type) = DECL_CONTEXT (d);
-             DECL_ASSEMBLER_NAME (d) = DECL_NAME (d);
-             if (!uses_template_parms (type))
-               DECL_ASSEMBLER_NAME (d)
-                 = get_identifier (build_overload_name (type, 1, 1));
-           }
+         if (ANON_AGGRNAME_P (name))
+           DECL_IGNORED_P (d) = 1;
+
+         TYPE_CONTEXT (type) = DECL_CONTEXT (d);
+         DECL_ASSEMBLER_NAME (d) = DECL_NAME (d);
+         if (!uses_template_parms (type))
+           DECL_ASSEMBLER_NAME (d)
+             = get_identifier (build_overload_name (type, 1, 1));
         }
       if (b->parm_flag == 2)
        {
@@ -3123,8 +2895,7 @@ decls_match (newdecl, olddecl)
 }
 
 /* If NEWDECL is `static' and an `extern' was seen previously,
-   warn about it.  (OLDDECL may be NULL_TREE; NAME contains
-   information about previous usage as an `extern'.)
+   warn about it.  OLDDECL is the previous declaration.
 
    Note that this does not apply to the C++ case of declaring
    a variable `extern const' and then later `const'.
@@ -3136,34 +2907,37 @@ static void
 warn_extern_redeclared_static (newdecl, olddecl)
      tree newdecl, olddecl;
 {
-  tree name;
-
   static const char *explicit_extern_static_warning
     = "`%D' was declared `extern' and later `static'";
   static const char *implicit_extern_static_warning
     = "`%D' was declared implicitly `extern' and later `static'";
 
+  tree name;
+
   if (TREE_CODE (newdecl) == TYPE_DECL)
     return;
-
+  
+  /* Don't get confused by static member functions; that's a different
+     use of `static'.  */
+  if (TREE_CODE (newdecl) == FUNCTION_DECL
+      && DECL_STATIC_FUNCTION_P (newdecl))
+    return;
+
+  /* If the old declaration was `static', or the new one isn't, then
+     then everything is OK.  */
+  if (DECL_THIS_STATIC (olddecl) || !DECL_THIS_STATIC (newdecl))
+    return;
+
+  /* It's OK to declare a builtin function as `static'.  */
+  if (TREE_CODE (olddecl) == FUNCTION_DECL
+      && DECL_ARTIFICIAL (olddecl))
+    return;
+
   name = DECL_ASSEMBLER_NAME (newdecl);
-  if (TREE_PUBLIC (name) && DECL_THIS_STATIC (newdecl))
-    {
-      /* It's okay to redeclare an ANSI built-in function as static,
-        or to declare a non-ANSI built-in function as anything.  */
-      if (! (TREE_CODE (newdecl) == FUNCTION_DECL
-            && olddecl != NULL_TREE
-            && TREE_CODE (olddecl) == FUNCTION_DECL
-            && (DECL_BUILT_IN (olddecl)
-                || DECL_BUILT_IN_NONANSI (olddecl))))
-       {
-         cp_pedwarn (IDENTIFIER_IMPLICIT_DECL (name)
-                     ? implicit_extern_static_warning
-                     : explicit_extern_static_warning, newdecl);
-         if (olddecl != NULL_TREE)
-           cp_pedwarn_at ("previous declaration of `%D'", olddecl);
-       }
-    }
+  cp_pedwarn (IDENTIFIER_IMPLICIT_DECL (name)
+             ? implicit_extern_static_warning
+             : explicit_extern_static_warning, newdecl);
+  cp_pedwarn_at ("previous declaration of `%D'", olddecl);
 }
 
 /* Handle when a new declaration NEWDECL has the same name as an old
@@ -3177,7 +2951,6 @@ int
 duplicate_decls (newdecl, olddecl)
      tree newdecl, olddecl;
 {
-  extern struct obstack permanent_obstack;
   unsigned olddecl_uid = DECL_UID (olddecl);
   int olddecl_friend = 0, types_match = 0;
   int new_defines_function = 0;
@@ -3198,44 +2971,75 @@ duplicate_decls (newdecl, olddecl)
  
   /* Check for redeclaration and other discrepancies. */
   if (TREE_CODE (olddecl) == FUNCTION_DECL
-      && DECL_ARTIFICIAL (olddecl)
-      && (DECL_BUILT_IN (olddecl) || DECL_BUILT_IN_NONANSI (olddecl)))
-    {
-      /* If you declare a built-in or predefined function name as static,
-        the old definition is overridden, but optionally warn this was a
-        bad choice of name.  Ditto for overloads.  */
-      if (! TREE_PUBLIC (newdecl)
-         || (TREE_CODE (newdecl) == FUNCTION_DECL
-             && DECL_LANGUAGE (newdecl) != DECL_LANGUAGE (olddecl)))
-       {
-         if (warn_shadow)
-           cp_warning ("shadowing %s function `%#D'",
-                       DECL_BUILT_IN (olddecl) ? "built-in" : "library",
+      && DECL_ARTIFICIAL (olddecl))
+    {
+      if (TREE_CODE (newdecl) != FUNCTION_DECL)
+       {
+         /* If you declare a built-in or predefined function name as static,
+            the old definition is overridden, but optionally warn this was a
+            bad choice of name.  */
+         if (! TREE_PUBLIC (newdecl))
+           {
+             if (warn_shadow)
+               cp_warning ("shadowing %s function `%#D'",
+                           DECL_BUILT_IN (olddecl) ? "built-in" : "library",
+                           olddecl);
+             /* Discard the old built-in function.  */
+             return 0;
+           }
+         /* If the built-in is not ansi, then programs can override
+            it even globally without an error.  */
+         else if (! DECL_BUILT_IN (olddecl))
+           cp_warning ("library function `%#D' redeclared as non-function `%#D'",
+                       olddecl, newdecl);
+         else
+           {
+             cp_error ("declaration of `%#D'", newdecl);
+             cp_error ("conflicts with built-in declaration `%#D'",
                        olddecl);
-         /* Discard the old built-in function.  */
+           }
          return 0;
        }
-      else if (! types_match)
+      else if (!types_match)
        {
-         if (TREE_CODE (newdecl) != FUNCTION_DECL)
+         if ((DECL_LANGUAGE (newdecl) == lang_c
+              && DECL_LANGUAGE (olddecl) == lang_c)
+             || compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)),
+                           TYPE_ARG_TYPES (TREE_TYPE (olddecl))))
            {
-             /* If the built-in is not ansi, then programs can override
-                it even globally without an error.  */
-             if (! DECL_BUILT_IN (olddecl))
-               cp_warning ("library function `%#D' redeclared as non-function `%#D'",
-                           olddecl, newdecl);
-             else
+             /* A near match; override the builtin.  */
+
+             if (TREE_PUBLIC (newdecl))
                {
-                 cp_error ("declaration of `%#D'", newdecl);
-                 cp_error ("conflicts with built-in declaration `%#D'",
-                           olddecl);
+                 cp_warning ("new declaration `%#D'", newdecl);
+                 cp_warning ("ambiguates built-in declaration `%#D'",
+                             olddecl);
                }
-             return 0;
+             else if (warn_shadow)
+               cp_warning ("shadowing %s function `%#D'",
+                           DECL_BUILT_IN (olddecl) ? "built-in" : "library",
+                           olddecl);
            }
+         else
+           /* Discard the old built-in function.  */
+           return 0;
+       }
+      
+      if (DECL_THIS_STATIC (newdecl) && !DECL_THIS_STATIC (olddecl))
+       {
+         /* If a builtin function is redeclared as `static', merge
+            the declarations, but make the original one static.  */
+         DECL_THIS_STATIC (olddecl) = 1;
+         TREE_PUBLIC (olddecl) = 0;
 
-         cp_warning ("declaration of `%#D'", newdecl);
-         cp_warning ("conflicts with built-in declaration `%#D'",
-                     olddecl);
+         /* Make the olddeclaration consistent with the new one so that
+            all remnants of the builtin-ness of this function will be
+            banished.  */
+         DECL_LANGUAGE (olddecl) = DECL_LANGUAGE (newdecl);
+         DECL_RTL (olddecl) = DECL_RTL (newdecl);
+         DECL_ASSEMBLER_NAME (olddecl) = DECL_ASSEMBLER_NAME (newdecl);
+         SET_IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (newdecl),
+                                      newdecl);
        }
     }
   else if (TREE_CODE (olddecl) != TREE_CODE (newdecl))
@@ -3390,7 +3194,8 @@ duplicate_decls (newdecl, olddecl)
          /* extern "C" int foo ();
             int foo () { bar (); }
             is OK.  */
-         if (current_lang_stack == current_lang_base)
+         if (current_lang_stack
+             == &VARRAY_TREE (current_lang_base, 0))
            DECL_LANGUAGE (newdecl) = DECL_LANGUAGE (olddecl);
          else
            {
@@ -3471,6 +3276,7 @@ duplicate_decls (newdecl, olddecl)
       DECL_ABSTRACT_VIRTUAL_P (newdecl) |= DECL_ABSTRACT_VIRTUAL_P (olddecl);
       DECL_VIRTUAL_P (newdecl) |= DECL_VIRTUAL_P (olddecl);
       DECL_NEEDS_FINAL_OVERRIDER_P (newdecl) |= DECL_NEEDS_FINAL_OVERRIDER_P (olddecl);
+      DECL_THIS_STATIC (newdecl) |= DECL_THIS_STATIC (olddecl);
       new_defines_function = DECL_INITIAL (newdecl) != NULL_TREE;
       
       /* Optionally warn about more than one declaration for the same
@@ -3531,10 +3337,7 @@ duplicate_decls (newdecl, olddecl)
       if (oldtype)
        push_obstacks (TYPE_OBSTACK (oldtype), TYPE_OBSTACK (oldtype));
       else
-       {
-         push_obstacks_nochange ();
-         end_temporary_allocation ();
-       }
+       push_permanent_obstack ();
 
       /* Merge the data types specified in the two decls.  */
       newtype = common_type (TREE_TYPE (newdecl), TREE_TYPE (olddecl));
@@ -3555,11 +3358,12 @@ duplicate_decls (newdecl, olddecl)
          if ((pedantic || ! DECL_IN_SYSTEM_HEADER (olddecl))
              && DECL_SOURCE_LINE (olddecl) != 0
              && flag_exceptions
-             && ! compexcepttypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl)))
+             && !comp_except_specs (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (newdecl)),
+                                    TYPE_RAISES_EXCEPTIONS (TREE_TYPE (olddecl)), 1))
            {
-             cp_pedwarn ("declaration of `%D' throws different exceptions",
+             cp_error ("declaration of `%F' throws different exceptions",
                        newdecl);
-             cp_pedwarn_at ("previous declaration here", olddecl);
+             cp_error_at ("to previous declaration `%F'", olddecl);
            }
        }
       TREE_TYPE (newdecl) = TREE_TYPE (olddecl) = newtype;
@@ -3591,7 +3395,8 @@ duplicate_decls (newdecl, olddecl)
          DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
          DECL_SOURCE_FILE (newdecl) = DECL_SOURCE_FILE (olddecl);
          DECL_SOURCE_LINE (newdecl) = DECL_SOURCE_LINE (olddecl);
-         if (DECL_LANG_SPECIFIC (newdecl)
+         if (CAN_HAVE_FULL_LANG_DECL_P (newdecl)
+             && DECL_LANG_SPECIFIC (newdecl)
              && DECL_LANG_SPECIFIC (olddecl))
            DECL_SAVED_TREE (newdecl) = DECL_SAVED_TREE (olddecl);
        }
@@ -3603,12 +3408,8 @@ duplicate_decls (newdecl, olddecl)
       if (DECL_SECTION_NAME (newdecl) == NULL_TREE)
        DECL_SECTION_NAME (newdecl) = DECL_SECTION_NAME (olddecl);
 
-      /* Keep the old rtl since we can safely use it, unless it's the
-        call to abort() used for abstract virtuals.  */
-      if ((DECL_LANG_SPECIFIC (olddecl)
-          && !DECL_ABSTRACT_VIRTUAL_P (olddecl))
-         || DECL_RTL (olddecl) != DECL_RTL (abort_fndecl))
-       DECL_RTL (newdecl) = DECL_RTL (olddecl);
+      /* Keep the old rtl since we can safely use it.  */
+      DECL_RTL (newdecl) = DECL_RTL (olddecl);
 
       pop_obstacks ();
     }
@@ -3699,7 +3500,9 @@ duplicate_decls (newdecl, olddecl)
        }
       if (! types_match || new_defines_function)
        {
-         /* These need to be copied so that the names are available.  */
+         /* These need to be copied so that the names are available.
+            Note that if the types do match, we'll preserve inline
+            info and other bits, but if not, we won't.  */
          DECL_ARGUMENTS (olddecl) = DECL_ARGUMENTS (newdecl);
          DECL_RESULT (olddecl) = DECL_RESULT (newdecl);
        }
@@ -3707,13 +3510,13 @@ duplicate_decls (newdecl, olddecl)
        /* If defining a function declared with other language
           linkage, use the previously declared language linkage.  */
        DECL_LANGUAGE (newdecl) = DECL_LANGUAGE (olddecl);
-      else
+      else if (types_match)
        {
          /* If redeclaring a builtin function, and not a definition,
             it stays built in.  */
          if (DECL_BUILT_IN (olddecl))
            {
-             DECL_BUILT_IN (newdecl) = 1;
+             DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl);
              DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
              /* If we're keeping the built-in definition, keep the rtl,
                 regardless of declaration matches.  */
@@ -3749,8 +3552,6 @@ duplicate_decls (newdecl, olddecl)
   if (TREE_CODE (newdecl) == FUNCTION_DECL)
     {
       int function_size;
-      struct lang_decl *ol = DECL_LANG_SPECIFIC (olddecl);
-      struct lang_decl *nl = DECL_LANG_SPECIFIC (newdecl);
 
       function_size = sizeof (struct tree_decl);
 
@@ -3758,11 +3559,6 @@ duplicate_decls (newdecl, olddecl)
             (char *) olddecl + sizeof (struct tree_common),
             function_size - sizeof (struct tree_common));
 
-      /* Can we safely free the storage used by newdecl?  */
-
-#define ROUND(x) ((x + obstack_alignment_mask (&permanent_obstack)) \
-                 & ~ obstack_alignment_mask (&permanent_obstack))
-
       if (DECL_TEMPLATE_INSTANTIATION (newdecl))
        {
          /* If newdecl is a template instantiation, it is possible that
@@ -3794,39 +3590,6 @@ duplicate_decls (newdecl, olddecl)
            if (TREE_VALUE (decls) == newdecl)
              TREE_VALUE (decls) = olddecl;
        }
-
-      if (((char *)newdecl + ROUND (function_size) == (char *)nl
-          && ((char *)newdecl + ROUND (function_size)
-              + ROUND (sizeof (struct lang_decl))
-              == obstack_next_free (&permanent_obstack)))
-         || ((char *)newdecl + ROUND (function_size)
-             == obstack_next_free (&permanent_obstack)))
-       {
-         DECL_MAIN_VARIANT (newdecl) = olddecl;
-         DECL_LANG_SPECIFIC (olddecl) = ol;
-         bcopy ((char *)nl, (char *)ol, sizeof (struct lang_decl));
-
-         obstack_free (&permanent_obstack, newdecl);
-       }
-      else if (LANG_DECL_PERMANENT (ol) && ol != nl)
-       {
-         if (DECL_MAIN_VARIANT (olddecl) == olddecl)
-           {
-             /* Save these lang_decls that would otherwise be lost.  */
-             extern tree free_lang_decl_chain;
-             tree free_lang_decl = (tree) ol;
-
-             if (DECL_LANG_SPECIFIC (olddecl) == ol)
-               abort ();
-
-             TREE_CHAIN (free_lang_decl) = free_lang_decl_chain;
-             free_lang_decl_chain = free_lang_decl;
-           }
-         else
-           {
-             /* Storage leak.  */;
-           }
-       }
     }
   else
     {
@@ -3860,8 +3623,16 @@ pushdecl (x)
      tree x;
 {
   register tree t;
-  register tree name = DECL_ASSEMBLER_NAME (x);
-  int need_new_binding = 1;
+  register tree name;
+  int need_new_binding;
+
+  /* We shouldn't be calling pushdecl when we're generating RTL for a
+     function that we already did semantic analysis on previously.  */
+  my_friendly_assert (!current_function || doing_semantic_analysis_p (),
+                     19990913);
+
+  name = DECL_ASSEMBLER_NAME (x);
+  need_new_binding = 1;
 
   if (DECL_TEMPLATE_PARM_P (x))
     /* Template parameters have no context; they are not X::T even
@@ -3872,7 +3643,11 @@ pushdecl (x)
       if (current_function_decl && x != current_function_decl
          /* A local declaration for a function doesn't constitute
              nesting.  */
-         && (TREE_CODE (x) != FUNCTION_DECL || DECL_INITIAL (x))
+         && !(TREE_CODE (x) == FUNCTION_DECL && !DECL_INITIAL (x))
+         /* A local declaration for an `extern' variable is in the
+            scoped of the current namespace, not the current
+            function.  */
+         && !(TREE_CODE (x) == VAR_DECL && DECL_EXTERNAL (x))
          /* Don't change DECL_CONTEXT of virtual methods.  */
          && (TREE_CODE (x) != FUNCTION_DECL || !DECL_VIRTUAL_P (x))
          && !DECL_CONTEXT (x))
@@ -4012,7 +3787,7 @@ pushdecl (x)
       if (TREE_CODE (x) == FUNCTION_DECL && ! DECL_FUNCTION_MEMBER_P (x))
        {
          t = push_overloaded_decl (x, PUSH_LOCAL);
-         if (t != x || DECL_LANGUAGE (x) == lang_c)
+         if (t != x)
            return t;
          if (!namespace_bindings_p ())
            /* We do not need to create a binding for this name;
@@ -4021,7 +3796,12 @@ pushdecl (x)
            need_new_binding = 0;
        }
       else if (DECL_FUNCTION_TEMPLATE_P (x) && DECL_NAMESPACE_SCOPE_P (x))
-       return push_overloaded_decl (x, PUSH_GLOBAL);
+       {
+         t = push_overloaded_decl (x, PUSH_GLOBAL);
+         if (t == x)
+           add_decl_to_level (x, NAMESPACE_LEVEL (CP_DECL_CONTEXT (t)));
+         return t;
+       }
 
       /* If declaring a type as a typedef, copy the type (unless we're
         at line 0), and install this TYPE_DECL as the new type's typedef
@@ -4099,7 +3879,13 @@ pushdecl (x)
            TREE_PUBLIC (name) = 1;
 
          if (!(TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x)
-               && t != NULL_TREE))
+               && t != NULL_TREE)
+             /* For an ordinary function, we create a binding from
+                the mangled name (i.e., NAME) to the DECL.  But, for
+                an `extern "C"' function, the mangled name and the
+                ordinary name are the same so we need not do this.  */
+             && !(TREE_CODE (x) == FUNCTION_DECL && 
+                  DECL_LANGUAGE (x) == lang_c))
            {
              if (TREE_CODE (x) == FUNCTION_DECL)
                my_friendly_assert 
@@ -4189,8 +3975,10 @@ pushdecl (x)
 
          /* Warn if shadowing an argument at the top level of the body.  */
          else if (oldlocal != NULL_TREE && !DECL_EXTERNAL (x)
-             && TREE_CODE (oldlocal) == PARM_DECL
-             && TREE_CODE (x) != PARM_DECL)
+                  && TREE_CODE (oldlocal) == PARM_DECL
+                  /* Don't complain if it's from an enclosing function.  */
+                  && DECL_CONTEXT (oldlocal) == current_function_decl
+                  && TREE_CODE (x) != PARM_DECL)
            {
              /* Go to where the parms should be and see if we
                 find them there.  */
@@ -4253,15 +4041,10 @@ pushdecl (x)
     }
 
   if (need_new_binding)
-    {
-      /* Put decls on list in reverse order.
-        We will reverse them later if necessary.  */
-      TREE_CHAIN (x) = current_binding_level->names;
-      current_binding_level->names = x;
-      if (current_binding_level == global_binding_level
-         && !TREE_PERMANENT (x))
-       my_friendly_abort (124);
-    }
+    add_decl_to_level (x, 
+                      DECL_NAMESPACE_SCOPE_P (x)
+                      ? NAMESPACE_LEVEL (CP_DECL_CONTEXT (x))
+                      : current_binding_level);
 
   return x;
 }
@@ -4349,10 +4132,9 @@ tree
 pushdecl_top_level (x)
      tree x;
 {
-  tree cur_namespace = current_namespace;
-  current_namespace = global_namespace;
+  push_to_top_level ();
   x = pushdecl_namespace_level (x);
-  current_namespace = cur_namespace;
+  pop_from_top_level ();
   return x;
 }
 
@@ -4387,6 +4169,35 @@ pushdecl_class_level (x)
     }
 }
 
+/* Enter DECL into the symbol table, if that's appropriate.  Returns
+   DECL, or a modified version thereof.  */
+
+tree
+maybe_push_decl (decl)
+     tree decl;
+{
+  tree type = TREE_TYPE (decl);
+
+  /* Add this decl to the current binding level, but not if it comes
+     from another scope, e.g. a static member variable.  TEM may equal
+     DECL or it may be a previous decl of the same name.  */
+  if ((TREE_CODE (decl) != PARM_DECL 
+       && DECL_CONTEXT (decl) != NULL_TREE 
+       /* Definitions of namespace members outside their namespace are
+         possible. */
+       && TREE_CODE (DECL_CONTEXT (decl)) != NAMESPACE_DECL)
+      || (TREE_CODE (decl) == TEMPLATE_DECL && !namespace_bindings_p ())
+      || TREE_CODE (type) == UNKNOWN_TYPE
+      /* The declaration of a template specialization does not affect
+        the functions available for overload resolution, so we do not
+        call pushdecl.  */
+      || (TREE_CODE (decl) == FUNCTION_DECL
+         && DECL_TEMPLATE_SPECIALIZATION (decl)))
+    return decl;
+  else
+    return pushdecl (decl);
+}
+
 #if 0
 /* This function is used to push the mangled decls for nested types into
    the appropriate scope.  Previously pushdecl_top_level was used, but that
@@ -4481,11 +4292,9 @@ push_class_level_binding (name, x)
      IDENTIFIER_CLASS_VALUE.  */
   if (push_class_binding (name, x))
     {
-      push_cache_obstack ();
       class_binding_level->class_shadowed
        = tree_cons (name, IDENTIFIER_CLASS_VALUE (name),
                     class_binding_level->class_shadowed);
-      pop_obstacks ();
       /* Record the value we are binding NAME to so that we can know
         what to pop later.  */
       TREE_TYPE (class_binding_level->class_shadowed) = x;
@@ -4538,7 +4347,7 @@ push_using_directive (used)
 
   ancestor = namespace_ancestor (current_decl_namespace (), used);
   ud = current_binding_level->using_directives;
-  ud = perm_tree_cons (used, ancestor, ud);
+  ud = tree_cons (used, ancestor, ud);
   current_binding_level->using_directives = ud;
   return ud;
 }
@@ -4573,17 +4382,7 @@ push_overloaded_decl (decl, flags)
   int doing_global = (namespace_bindings_p () || !(flags & PUSH_LOCAL));
 
   if (doing_global)
-    {
-      old = namespace_binding (name, DECL_CONTEXT (decl));
-      if (old && TREE_CODE (old) == FUNCTION_DECL
-         && DECL_ARTIFICIAL (old)
-         && (DECL_BUILT_IN (old) || DECL_BUILT_IN_NONANSI (old)))
-       {
-         if (duplicate_decls (decl, old))
-           return old;
-         old = NULL_TREE;
-       }
-    }
+    old = namespace_binding (name, DECL_CONTEXT (decl));
   else
     old = lookup_name_current_level (name);
 
@@ -4664,7 +4463,8 @@ push_overloaded_decl (decl, flags)
                  TREE_VALUE (*d) = new_binding;
                else
                  /* Build a TREE_LIST to wrap the OVERLOAD.  */
-                 *d = build_tree_list (NULL_TREE, new_binding);
+                 *d = tree_cons (NULL_TREE, new_binding, 
+                                 TREE_CHAIN (*d));
 
                /* And update the CPLUS_BINDING node.  */
                BINDING_VALUE (IDENTIFIER_BINDING (name))
@@ -4807,25 +4607,36 @@ redeclaration_error_message (newdecl, olddecl)
     }
 }
 \f
-/* Get the LABEL_DECL corresponding to identifier ID as a label.
-   Create one if none exists so far for the current function.
-   This function is called for both label definitions and label references.  */
+/* Create a new label, named ID.  */
 
-tree
-lookup_label (id)
+static tree
+make_label_decl (id, local_p)
      tree id;
+     int local_p;
 {
-  register tree decl = IDENTIFIER_LABEL_VALUE (id);
+  tree decl;
 
-  if (current_function_decl == NULL_TREE)
-    {
-      error ("label `%s' referenced outside of any function",
-            IDENTIFIER_POINTER (id));
-      return NULL_TREE;
-    }
+  decl = build_decl (LABEL_DECL, id, void_type_node);
+  if (expanding_p)
+    /* Make sure every label has an rtx.  */
+    label_rtx (decl);
+
+  DECL_CONTEXT (decl) = current_function_decl;
+  DECL_MODE (decl) = VOIDmode;
+  C_DECLARED_LABEL_FLAG (decl) = local_p;
+
+  /* Say where one reference is to the label, for the sake of the
+     error if it is not defined.  */
+  DECL_SOURCE_LINE (decl) = lineno;
+  DECL_SOURCE_FILE (decl) = input_filename;
 
-  if ((decl == NULL_TREE
-      || DECL_SOURCE_LINE (decl) == 0)
+  /* Record the fact that this identifier is bound to this label.  */
+  SET_IDENTIFIER_LABEL_VALUE (id, decl);
+
+  /* Record this label on the list of used labels so that we can check
+     at the end of the function to see whether or not the label was
+     actually defined.  */
+  if ((named_label_uses == NULL || named_label_uses->label_decl != decl)
       && (named_label_uses == NULL
          || named_label_uses->names_in_scope != current_binding_level->names
          || named_label_uses->label_decl != decl))
@@ -4842,60 +4653,65 @@ lookup_label (id)
       named_label_uses = new_ent;
     }
 
-  /* Use a label already defined or ref'd with this name.  */
-  if (decl != NULL_TREE)
-    {
-      /* But not if it is inherited and wasn't declared to be inheritable.  */
-      if (DECL_CONTEXT (decl) != current_function_decl
-         && ! C_DECLARED_LABEL_FLAG (decl))
-       return shadow_label (id);
-      return decl;
-    }
-
-  decl = build_decl (LABEL_DECL, id, void_type_node);
-
-  /* Make sure every label has an rtx.  */
-  label_rtx (decl);
-
-  /* A label not explicitly declared must be local to where it's ref'd.  */
-  DECL_CONTEXT (decl) = current_function_decl;
+  return decl;
+}
 
-  DECL_MODE (decl) = VOIDmode;
+/* Look for a label named ID in the current function.  If one cannot
+   be found, create one.  (We keep track of used, but undefined,
+   labels, and complain about them at the end of a function.)  */
 
-  /* Say where one reference is to the label,
-     for the sake of the error if it is not defined.  */
-  DECL_SOURCE_LINE (decl) = lineno;
-  DECL_SOURCE_FILE (decl) = input_filename;
+tree 
+lookup_label (id)
+     tree id;
+{
+  tree decl;
 
-  SET_IDENTIFIER_LABEL_VALUE (id, decl);
+  /* You can't use labels at global scope.  */
+  if (current_function_decl == NULL_TREE)
+    {
+      error ("label `%s' referenced outside of any function",
+            IDENTIFIER_POINTER (id));
+      return NULL_TREE;
+    }
+  
+  /* See if we've already got this label.  */
+  decl = IDENTIFIER_LABEL_VALUE (id);
+  if (decl != NULL_TREE && DECL_CONTEXT (decl) == current_function_decl)
+    return decl;
 
-  named_labels = tree_cons (NULL_TREE, decl, named_labels);
-  named_label_uses->label_decl = decl;
+  /* Record this label on the list of labels used in this function.
+     We do this before calling make_label_decl so that we get the
+     IDENTIFIER_LABEL_VALUE before the new label is declared.  */
+  named_labels = tree_cons (IDENTIFIER_LABEL_VALUE (id), NULL_TREE,
+                           named_labels);
+  /* We need a new label.  */
+  decl = make_label_decl (id, /*local_p=*/0);
+  /* Now fill in the information we didn't have before.  */
+  TREE_VALUE (named_labels) = decl;
 
   return decl;
 }
 
-/* Make a label named NAME in the current function,
-   shadowing silently any that may be inherited from containing functions
-   or containing scopes.
-
-   Note that valid use, if the label being shadowed
-   comes from another scope in the same function,
-   requires calling declare_nonlocal_label right away.  */
+/* Declare a local label named ID.  */
 
 tree
-shadow_label (name)
-     tree name;
+declare_local_label (id)
+     tree id;
 {
-  register tree decl = IDENTIFIER_LABEL_VALUE (name);
-
-  if (decl != NULL_TREE)
-    {
-      shadowed_labels = tree_cons (NULL_TREE, decl, shadowed_labels);
-      SET_IDENTIFIER_LABEL_VALUE (name, NULL_TREE);
-    }
+  tree decl;
 
-  return lookup_label (name);
+  /* Add a new entry to the SHADOWED_LABELS list so that when we leave
+     this scope we can restore the old value of
+     IDENTIFIER_TYPE_VALUE.  */
+  current_binding_level->shadowed_labels 
+    = tree_cons (IDENTIFIER_LABEL_VALUE (id), NULL_TREE,
+                current_binding_level->shadowed_labels);
+  /* Look for the label.  */
+  decl = make_label_decl (id, /*local_p=*/1);
+  /* Now fill in the information we didn't have before.  */
+  TREE_VALUE (current_binding_level->shadowed_labels) = decl;
+  
+  return decl;
 }
 
 /* Define a label, specifying the location in the source file.
@@ -4908,33 +4724,12 @@ define_label (filename, line, name)
      int line;
      tree name;
 {
-  tree decl;
-
-  if (minimal_parse_mode)
-    {
-      push_obstacks (&permanent_obstack, &permanent_obstack);
-      decl = build_decl (LABEL_DECL, name, void_type_node);
-      pop_obstacks ();
-      DECL_SOURCE_LINE (decl) = line;
-      DECL_SOURCE_FILE (decl) = filename;
-      add_tree (decl);
-      return decl;
-    }
-
-  decl = lookup_label (name);
+  tree decl = lookup_label (name);
 
   /* After labels, make any new cleanups go into their
      own new (temporary) binding contour.  */
   current_binding_level->more_cleanups_ok = 0;
 
-  /* If label with this name is known from an outer context, shadow it.  */
-  if (decl != NULL_TREE && DECL_CONTEXT (decl) != current_function_decl)
-    {
-      shadowed_labels = tree_cons (NULL_TREE, decl, shadowed_labels);
-      SET_IDENTIFIER_LABEL_VALUE (name, NULL_TREE);
-      decl = lookup_label (name);
-    }
-
   if (name == get_identifier ("wchar_t"))
     cp_pedwarn ("label named wchar_t");
 
@@ -4947,6 +4742,7 @@ define_label (filename, line, name)
     {
       struct named_label_list *uses, *prev;
       int identified = 0;
+      int saw_eh = 0;
 
       /* Mark label as having been defined.  */
       DECL_INITIAL (decl) = error_mark_node;
@@ -5001,7 +4797,7 @@ define_label (filename, line, name)
                                   uses->lineno_o_goto, "  from here");
                              }
                            identified = 1;
-                       }
+                         }
 
                        if (problem)
                          cp_error_at ("  crosses initialization of `%#D'",
@@ -5014,6 +4810,19 @@ define_label (filename, line, name)
                  }
                if (b == uses->binding_level)
                  break;
+               if (b->eh_region && ! saw_eh)
+                 {
+                   if (! identified)
+                     {
+                       cp_error ("jump to label `%D'", decl);
+                       error_with_file_and_line
+                         (uses->filename_o_goto,
+                          uses->lineno_o_goto, "  from here");
+                       identified = 1;
+                     }
+                   error ("  enters exception handling block");
+                   saw_eh = 1;
+                 }
                b = b->level_chain;
              }
 
@@ -5058,8 +4867,8 @@ pop_switch ()
   switch_stack = switch_stack->next;
 }
 
-/* Same, but for CASE labels.  If DECL is NULL_TREE, it's the default.  */
-/* XXX Note decl is never actually used. (bpk) */
+/* Note that we've seen a definition of a case label, and complain if this
+   is a bad place for one.  */
 
 void
 define_case_label ()
@@ -5068,6 +4877,10 @@ define_case_label ()
   struct binding_level *b = current_binding_level;
   int identified = 0;
 
+  if (! switch_stack)
+    /* Don't crash; we'll complain in do_case.  */
+    return;
+  
   if (cleanup)
     {
       static int explained = 0;
@@ -5300,55 +5113,12 @@ lookup_tag_reverse (type, name)
   return NULL_TREE;
 }
 \f
-/* Lookup TYPE in CONTEXT (a chain of nested types or a FUNCTION_DECL).
-   Return the type value, or NULL_TREE if not found.  */
-
-static tree
-lookup_nested_type (type, context)
-     tree type;
-     tree context;
-{
-  if (context == NULL_TREE)
-    return NULL_TREE;
-  while (context)
-    {
-      switch (TREE_CODE (context))
-       {
-       case TYPE_DECL:
-         {
-           tree ctype = TREE_TYPE (context);
-           tree match = value_member (type, CLASSTYPE_TAGS (ctype));
-           if (match)
-             return TREE_VALUE (match);
-           context = DECL_CONTEXT (context);
-
-           /* When we have a nested class whose member functions have
-              local types (e.g., a set of enums), we'll arrive here
-              with the DECL_CONTEXT as the actual RECORD_TYPE node for
-              the enclosing class.  Instead, we want to make sure we
-              come back in here with the TYPE_DECL, not the RECORD_TYPE.  */
-           if (context && TREE_CODE (context) == RECORD_TYPE)
-             context = TREE_CHAIN (context);
-         }
-         break;
-       case FUNCTION_DECL:
-         if (TYPE_NAME (type) && TYPE_IDENTIFIER (type))
-           return lookup_name (TYPE_IDENTIFIER (type), 1);
-         return NULL_TREE;
-       default:
-         my_friendly_abort (12);
-       }
-    }
-  return NULL_TREE;
-}
-
 /* Look up NAME in the NAMESPACE.  */
 
 tree
 lookup_namespace_name (namespace, name)
      tree namespace, name;
 {
-  struct tree_binding _b;
   tree val;
   tree template_id = NULL_TREE;
 
@@ -5379,7 +5149,7 @@ lookup_namespace_name (namespace, name)
 
   my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 373);
   
-  val = binding_init (&_b);
+  val = make_node (CPLUS_BINDING);
   if (!qualified_lookup_using_namespace (name, namespace, val, 0))
     return error_mark_node;
 
@@ -5481,15 +5251,14 @@ build_typename_type (context, name, fullname, base_type)
 
   push_obstacks (&permanent_obstack, &permanent_obstack);
 
-  if (!ht.table
-      && !hash_table_init (&ht, &hash_newfunc, &typename_hash, 
-                          &typename_compare))
-    fatal ("virtual memory exhausted");
-
-  /* The FULLNAME needs to exist for the life of the hash table, i.e.,
-     for the entire compilation.  */
-  if (!TREE_PERMANENT (fullname))
-    fullname = copy_to_permanent (fullname);
+  if (!ht.table)
+    {
+      static struct hash_table *h = &ht;
+      if (!hash_table_init (&ht, &hash_newfunc, &typename_hash, 
+                           &typename_compare))
+       fatal ("virtual memory exhausted");
+      ggc_add_tree_hash_table_root (&h, 1);
+    }
 
   /* Build the TYPENAME_TYPE.  */
   t = make_lang_type (TYPENAME_TYPE);
@@ -5507,12 +5276,7 @@ build_typename_type (context, name, fullname, base_type)
   /* See if we already have this type.  */
   e = hash_lookup (&ht, t, /*create=*/false, /*copy=*/0);
   if (e)
-    {
-      /* This will free not only TREE_TYPE, but the lang-specific data
-        and the TYPE_DECL as well.  */
-      obstack_free (&permanent_obstack, t);
-      t = (tree) e->key;
-    }
+    t = (tree) e->key;
   else
     /* Insert the type into the table.  */
     hash_lookup (&ht, t, /*create=*/true, /*copy=*/0);
@@ -5643,24 +5407,30 @@ select_decl (binding, flags)
   return val;
 }
 
-/* Unscoped lookup of a global, iterate over namespaces, considering
-   using namespace statements. */
+/* Unscoped lookup of a global: iterate over current namespaces,
+   considering using-directives.  If SPACESP is non-NULL, store a list
+   of the namespaces we've considered in it.  */
 
-static tree
-unqualified_namespace_lookup (name, flags)
+tree
+unqualified_namespace_lookup (name, flags, spacesp)
      tree name;
      int flags;
+     tree *spacesp;
 {
-  struct tree_binding _binding;
-  tree b = binding_init (&_binding);
+  tree b = make_node (CPLUS_BINDING);
   tree initial = current_decl_namespace();
   tree scope = initial;
   tree siter;
   struct binding_level *level;
   tree val = NULL_TREE;
 
-  while (!val)
+  if (spacesp)
+    *spacesp = NULL_TREE;
+
+  for (; !val; scope = CP_DECL_CONTEXT (scope))
     {
+      if (spacesp)
+       *spacesp = tree_cons (scope, NULL_TREE, *spacesp);
       val = binding_for_name (name, scope);
 
       /* Initialize binding for this context. */
@@ -5672,7 +5442,7 @@ unqualified_namespace_lookup (name, flags)
           !level->namespace_p;
           level = level->level_chain)
        if (!lookup_using_namespace (name, b, level->using_directives,
-                                     scope, flags))
+                                     scope, flags, spacesp))
          /* Give up because of error. */
          return error_mark_node;
 
@@ -5682,7 +5452,7 @@ unqualified_namespace_lookup (name, flags)
       while (1)
        {
          if (!lookup_using_namespace (name, b, DECL_NAMESPACE_USING (siter), 
-                                      scope, flags))
+                                      scope, flags, spacesp))
            /* Give up because of error. */
            return error_mark_node;
          if (siter == scope) break;
@@ -5692,7 +5462,6 @@ unqualified_namespace_lookup (name, flags)
       val = select_decl (b, flags);
       if (scope == global_namespace)
        break;
-      scope = CP_DECL_CONTEXT (scope);
     }
   return val;
 }
@@ -5826,8 +5595,8 @@ lookup_name_real (name, prefer_type, nonclass, namespaces_only)
            type = global_namespace;
          if (TREE_CODE (type) == NAMESPACE_DECL)
            {
-             struct tree_binding b;
-             val = binding_init (&b);
+             val = make_node (CPLUS_BINDING);
+             flags |= LOOKUP_COMPLAIN;
              if (!qualified_lookup_using_namespace (name, type, val, flags))
                return NULL_TREE;
              val = select_decl (val, flags);
@@ -5859,6 +5628,10 @@ lookup_name_real (name, prefer_type, nonclass, namespaces_only)
     }
 
   /* First, look in non-namespace scopes.  */
+
+  if (current_class_type == NULL_TREE)
+    nonclass = 1;
+
   for (t = IDENTIFIER_BINDING (name); t; t = TREE_CHAIN (t))
     {
       tree binding;
@@ -5877,15 +5650,13 @@ lookup_name_real (name, prefer_type, nonclass, namespaces_only)
        binding = NULL_TREE;
 
       if (binding
-         && (!val || !(TREE_CODE (binding) == TYPE_DECL
-                       && IMPLICIT_TYPENAME_P (TREE_TYPE (binding)))))
+         && (!val || !IMPLICIT_TYPENAME_TYPE_DECL_P (binding)))
        {
          if (val_is_implicit_typename && !yylex)
            warn_about_implicit_typename_lookup (val, binding);
          val = binding;
          val_is_implicit_typename 
-           = (TREE_CODE (val) == TYPE_DECL
-              && IMPLICIT_TYPENAME_P (TREE_TYPE (val)));
+           = IMPLICIT_TYPENAME_TYPE_DECL_P (val);
          if (!val_is_implicit_typename)
            break;
        }
@@ -5894,7 +5665,7 @@ lookup_name_real (name, prefer_type, nonclass, namespaces_only)
   /* Now lookup in namespace scopes.  */
   if (!val || val_is_implicit_typename)
     {
-      t = unqualified_namespace_lookup (name, flags);
+      t = unqualified_namespace_lookup (name, flags, 0);
       if (t)
        {
          if (val_is_implicit_typename && !yylex)
@@ -5983,7 +5754,7 @@ lookup_name_current_level (name)
 
   if (b->namespace_p)
     {
-      t =  IDENTIFIER_NAMESPACE_VALUE (name);
+      t = IDENTIFIER_NAMESPACE_VALUE (name);
 
       /* extern "C" function() */
       if (t != NULL_TREE && TREE_CODE (t) == TREE_LIST)
@@ -6074,14 +5845,6 @@ signal_catch (sig)
   my_friendly_abort (0);
 }
 
-#if 0
-/* Unused -- brendan 970107 */
-/* Array for holding types considered "built-in".  These types
-   are output in the module in which `main' is defined.  */
-static tree *builtin_type_tdescs_arr;
-static int builtin_type_tdescs_len, builtin_type_tdescs_max;
-#endif
-
 /* Push the declarations of builtin types into the namespace.
    RID_INDEX, if < RID_MAX is the index of the builtin type
    in the array RID_POINTERS.  NAME is the name used when looking
@@ -6192,12 +5955,11 @@ push_overloaded_decl_1 (x)
 __inline
 #endif
 tree
-auto_function (name, type, code)
+auto_function (name, type)
      tree name, type;
-     enum built_in_function code;
 {
   return define_function
-    (IDENTIFIER_POINTER (name), type, code, push_overloaded_decl_1,
+    (IDENTIFIER_POINTER (name), type, push_overloaded_decl_1,
      IDENTIFIER_POINTER (build_decl_overload (name, TYPE_ARG_TYPES (type),
                                              0)));
 }
@@ -6210,29 +5972,30 @@ auto_function (name, type, code)
 void
 init_decl_processing ()
 {
-  register tree endlink, int_endlink, double_endlink, unsigned_endlink;
   tree fields[20];
-  /* Data type of memcpy.  */
-  tree memcpy_ftype, strlen_ftype;
   int wchar_type_size;
-  tree temp;
   tree array_domain_type;
-  tree vb_off_identifier = NULL_TREE;
-  /* Function type `char *(char *, char *)' and similar ones */
-  tree string_ftype_ptr_ptr, int_ftype_string_string;
-  tree sizetype_endlink;
-  tree ptr_ftype, ptr_ftype_unsigned, ptr_ftype_sizetype;
-  tree void_ftype, void_ftype_int, void_ftype_ptr;
 
   /* Have to make these distinct before we try using them.  */
   lang_name_cplusplus = get_identifier ("C++");
   lang_name_c = get_identifier ("C");
   lang_name_java = get_identifier ("Java");
 
+  /* Let the back-end now how to save and restore language-specific
+     per-function globals.  */
+  init_lang_status = &push_cp_function_context;
+  free_lang_status = &pop_cp_function_context;
+  mark_lang_status = &mark_cp_function_context;
+
+  cp_parse_init ();
+  init_decl2 ();
+  init_pt ();
+
+  /* Create the global variables.  */
+  push_to_top_level ();
+
   /* Enter the global namespace. */
   my_friendly_assert (global_namespace == NULL_TREE, 375);
-  my_friendly_assert (current_lang_name == NULL_TREE, 375);
-  current_lang_name = lang_name_cplusplus;
   push_namespace (get_identifier ("::"));
   global_namespace = current_namespace;
   current_lang_name = NULL_TREE;
@@ -6248,8 +6011,6 @@ init_decl_processing ()
   current_lang_name = lang_name_c;
 
   current_function_decl = NULL_TREE;
-  named_labels = NULL_TREE;
-  named_label_uses = NULL;
   current_binding_level = NULL_BINDING_LEVEL;
   free_binding_level = NULL_BINDING_LEVEL;
 
@@ -6275,12 +6036,8 @@ init_decl_processing ()
   signal (SIGBUS, signal_catch);
 #endif
 
-  gcc_obstack_init (&decl_obstack);
+  build_common_tree_nodes (flag_signed_char);
 
-  /* Must lay these out before anything else gets laid out.  */
-  error_mark_node = make_node (ERROR_MARK);
-  TREE_PERMANENT (error_mark_node) = 1;
-  TREE_TYPE (error_mark_node) = error_mark_node;
   error_mark_list = build_tree_list (error_mark_node, error_mark_node);
   TREE_TYPE (error_mark_list) = error_mark_node;
 
@@ -6300,70 +6057,39 @@ init_decl_processing ()
   delta_identifier = get_identifier (VTABLE_DELTA_NAME);
   delta2_identifier = get_identifier (VTABLE_DELTA2_NAME);
   pfn_or_delta2_identifier = get_identifier ("__pfn_or_delta2");
-  if (flag_handle_signatures)
-    {
-      tag_identifier = get_identifier (SIGTABLE_TAG_NAME);
-      vb_off_identifier = get_identifier (SIGTABLE_VB_OFF_NAME);
-      vt_off_identifier = get_identifier (SIGTABLE_VT_OFF_NAME);
-    }
 
   /* Define `int' and `char' first so that dbx will output them first.  */
-
-  integer_type_node = make_signed_type (INT_TYPE_SIZE);
   record_builtin_type (RID_INT, NULL_PTR, integer_type_node);
-
-  /* Define `char', which is like either `signed char' or `unsigned char'
-     but not the same as either.  */
-
-  char_type_node
-    = (flag_signed_char
-       ? make_signed_type (CHAR_TYPE_SIZE)
-       : make_unsigned_type (CHAR_TYPE_SIZE));
   record_builtin_type (RID_CHAR, "char", char_type_node);
 
   /* `signed' is the same as `int' */
   record_builtin_type (RID_SIGNED, NULL_PTR, integer_type_node);
-  
-  long_integer_type_node = make_signed_type (LONG_TYPE_SIZE);
   record_builtin_type (RID_LONG, "long int", long_integer_type_node);
-
-  unsigned_type_node = make_unsigned_type (INT_TYPE_SIZE);
   record_builtin_type (RID_UNSIGNED, "unsigned int", unsigned_type_node);
-
-  long_unsigned_type_node = make_unsigned_type (LONG_TYPE_SIZE);
   record_builtin_type (RID_MAX, "long unsigned int", long_unsigned_type_node);
   record_builtin_type (RID_MAX, "unsigned long", long_unsigned_type_node);
-
-  long_long_integer_type_node = make_signed_type (LONG_LONG_TYPE_SIZE);
   record_builtin_type (RID_MAX, "long long int", long_long_integer_type_node);
-
-  long_long_unsigned_type_node = make_unsigned_type (LONG_LONG_TYPE_SIZE);
   record_builtin_type (RID_MAX, "long long unsigned int",
                       long_long_unsigned_type_node);
   record_builtin_type (RID_MAX, "long long unsigned",
                       long_long_unsigned_type_node);
-
-  short_integer_type_node = make_signed_type (SHORT_TYPE_SIZE);
   record_builtin_type (RID_SHORT, "short int", short_integer_type_node);
-  short_unsigned_type_node = make_unsigned_type (SHORT_TYPE_SIZE);
   record_builtin_type (RID_MAX, "short unsigned int", short_unsigned_type_node);
   record_builtin_type (RID_MAX, "unsigned short", short_unsigned_type_node);
 
-  /* `unsigned long' is the standard type for sizeof.
-     Note that stddef.h uses `unsigned long',
-     and this must agree, even if long and int are the same size.  */
-  set_sizetype
-    (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (SIZE_TYPE))));
-
   ptrdiff_type_node
     = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (PTRDIFF_TYPE)));
 
   /* Define both `signed char' and `unsigned char'.  */
-  signed_char_type_node = make_signed_type (CHAR_TYPE_SIZE);
   record_builtin_type (RID_MAX, "signed char", signed_char_type_node);
-  unsigned_char_type_node = make_unsigned_type (CHAR_TYPE_SIZE);
   record_builtin_type (RID_MAX, "unsigned char", unsigned_char_type_node);
 
+  /* `unsigned long' is the standard type for sizeof.
+     Note that stddef.h uses `unsigned long',
+     and this must agree, even if long and int are the same size.  */
+  set_sizetype
+    (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (SIZE_TYPE))));
+
   /* Create the widest literal types. */
   widest_integer_literal_type_node = make_signed_type (HOST_BITS_PER_WIDE_INT * 2);
   pushdecl (build_decl (TYPE_DECL, NULL_TREE, 
@@ -6374,72 +6100,22 @@ init_decl_processing ()
                        widest_unsigned_literal_type_node));
 
   /* These are types that type_for_size and type_for_mode use.  */
-  intQI_type_node = make_signed_type (GET_MODE_BITSIZE (QImode));
   pushdecl (build_decl (TYPE_DECL, NULL_TREE, intQI_type_node));
-  intHI_type_node = make_signed_type (GET_MODE_BITSIZE (HImode));
   pushdecl (build_decl (TYPE_DECL, NULL_TREE, intHI_type_node));
-  intSI_type_node = make_signed_type (GET_MODE_BITSIZE (SImode));
   pushdecl (build_decl (TYPE_DECL, NULL_TREE, intSI_type_node));
-  intDI_type_node = make_signed_type (GET_MODE_BITSIZE (DImode));
   pushdecl (build_decl (TYPE_DECL, NULL_TREE, intDI_type_node));
 #if HOST_BITS_PER_WIDE_INT >= 64
-  intTI_type_node = make_signed_type (GET_MODE_BITSIZE (TImode));
   pushdecl (build_decl (TYPE_DECL, get_identifier ("__int128_t"), intTI_type_node));
 #endif
-  unsigned_intQI_type_node = make_unsigned_type (GET_MODE_BITSIZE (QImode));
   pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intQI_type_node));
-  unsigned_intHI_type_node = make_unsigned_type (GET_MODE_BITSIZE (HImode));
   pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intHI_type_node));
-  unsigned_intSI_type_node = make_unsigned_type (GET_MODE_BITSIZE (SImode));
   pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intSI_type_node));
-  unsigned_intDI_type_node = make_unsigned_type (GET_MODE_BITSIZE (DImode));
   pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intDI_type_node));
 #if HOST_BITS_PER_WIDE_INT >= 64
-  unsigned_intTI_type_node = make_unsigned_type (GET_MODE_BITSIZE (TImode));
   pushdecl (build_decl (TYPE_DECL, get_identifier ("__uint128_t"), unsigned_intTI_type_node));
 #endif
 
-  float_type_node = make_node (REAL_TYPE);
-  TYPE_PRECISION (float_type_node) = FLOAT_TYPE_SIZE;
-  record_builtin_type (RID_FLOAT, NULL_PTR, float_type_node);
-  layout_type (float_type_node);
-
-  double_type_node = make_node (REAL_TYPE);
-  if (flag_short_double)
-    TYPE_PRECISION (double_type_node) = FLOAT_TYPE_SIZE;
-  else
-    TYPE_PRECISION (double_type_node) = DOUBLE_TYPE_SIZE;
-  record_builtin_type (RID_DOUBLE, NULL_PTR, double_type_node);
-  layout_type (double_type_node);
-
-  long_double_type_node = make_node (REAL_TYPE);
-  TYPE_PRECISION (long_double_type_node) = LONG_DOUBLE_TYPE_SIZE;
-  record_builtin_type (RID_MAX, "long double", long_double_type_node);
-  layout_type (long_double_type_node);
-
-  complex_integer_type_node = make_node (COMPLEX_TYPE);
-  pushdecl (build_decl (TYPE_DECL, get_identifier ("complex int"),
-                       complex_integer_type_node));
-  TREE_TYPE (complex_integer_type_node) = integer_type_node;
-  layout_type (complex_integer_type_node);
-
-  complex_float_type_node = make_node (COMPLEX_TYPE);
-  pushdecl (build_decl (TYPE_DECL, get_identifier ("complex float"),
-                       complex_float_type_node));
-  TREE_TYPE (complex_float_type_node) = float_type_node;
-  layout_type (complex_float_type_node);
-
-  complex_double_type_node = make_node (COMPLEX_TYPE);
-  pushdecl (build_decl (TYPE_DECL, get_identifier ("complex double"),
-                       complex_double_type_node));
-  TREE_TYPE (complex_double_type_node) = double_type_node;
-  layout_type (complex_double_type_node);
-
-  complex_long_double_type_node = make_node (COMPLEX_TYPE);
-  pushdecl (build_decl (TYPE_DECL, get_identifier ("complex long double"),
-                       complex_long_double_type_node));
-  TREE_TYPE (complex_long_double_type_node) = long_double_type_node;
-  layout_type (complex_long_double_type_node);
+  build_common_tree_nodes_2 (flag_short_double);
 
   java_byte_type_node = record_builtin_java_type ("__java_byte", 8);
   java_short_type_node = record_builtin_java_type ("__java_short", 16);
@@ -6450,10 +6126,6 @@ init_decl_processing ()
   java_char_type_node = record_builtin_java_type ("__java_char", -16);
   java_boolean_type_node = record_builtin_java_type ("__java_boolean", -1);
 
-  integer_zero_node = build_int_2 (0, 0);
-  TREE_TYPE (integer_zero_node) = integer_type_node;
-  integer_one_node = build_int_2 (1, 0);
-  TREE_TYPE (integer_one_node) = integer_type_node;
   integer_two_node = build_int_2 (2, 0);
   TREE_TYPE (integer_two_node) = integer_type_node;
   integer_three_node = build_int_2 (3, 0);
@@ -6470,23 +6142,25 @@ init_decl_processing ()
   boolean_true_node = build_int_2 (1, 0);
   TREE_TYPE (boolean_true_node) = boolean_type_node;
 
-  /* These are needed by stor-layout.c.  */
-  size_zero_node = size_int (0);
-  size_one_node = size_int (1);
+  signed_size_zero_node = build_int_2 (0, 0);  record_builtin_type (RID_FLOAT, NULL_PTR, float_type_node);
+  record_builtin_type (RID_DOUBLE, NULL_PTR, double_type_node);
+  record_builtin_type (RID_MAX, "long double", long_double_type_node);
+
+  pushdecl (build_decl (TYPE_DECL, get_identifier ("complex int"),
+                       complex_integer_type_node));
+  pushdecl (build_decl (TYPE_DECL, get_identifier ("complex float"),
+                       complex_float_type_node));
+  pushdecl (build_decl (TYPE_DECL, get_identifier ("complex double"),
+                       complex_double_type_node));
+  pushdecl (build_decl (TYPE_DECL, get_identifier ("complex long double"),
+                       complex_long_double_type_node));
 
-  signed_size_zero_node = build_int_2 (0, 0);
   TREE_TYPE (signed_size_zero_node) = make_signed_type (TYPE_PRECISION (sizetype));
 
-  void_type_node = make_node (VOID_TYPE);
   record_builtin_type (RID_VOID, NULL_PTR, void_type_node);
-  layout_type (void_type_node); /* Uses integer_zero_node.  */
   void_list_node = build_tree_list (NULL_TREE, void_type_node);
   TREE_PARMLIST (void_list_node) = 1;
 
-  null_pointer_node = build_int_2 (0, 0);
-  TREE_TYPE (null_pointer_node) = build_pointer_type (void_type_node);
-  layout_type (TREE_TYPE (null_pointer_node));
-     
   /* 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;
@@ -6495,6 +6169,7 @@ init_decl_processing ()
   const_string_type_node
     = build_pointer_type (build_qualified_type (char_type_node, 
                                                TYPE_QUAL_CONST));
+  empty_except_spec = build_tree_list (NULL_TREE, NULL_TREE);
 #if 0
   record_builtin_type (RID_MAX, NULL_PTR, string_type_node);
 #endif
@@ -6519,268 +6194,22 @@ init_decl_processing ()
      need to look inside this envelope.  */
   class_star_type_node = build_pointer_type (make_lang_type (RECORD_TYPE));
 
+  if (flag_huge_objects)
+    delta_type_node = long_integer_type_node;
+  else
+    delta_type_node = short_integer_type_node;
+
   default_function_type
     = build_function_type (integer_type_node, NULL_TREE);
 
   ptr_type_node = build_pointer_type (void_type_node);
   const_ptr_type_node
     = build_pointer_type (build_qualified_type (void_type_node,
-                                               TYPE_QUAL_CONST)); 
-#if 0
-  record_builtin_type (RID_MAX, NULL_PTR, ptr_type_node);
-#endif
-  endlink = void_list_node;
-  int_endlink = tree_cons (NULL_TREE, integer_type_node, endlink);
-  double_endlink = tree_cons (NULL_TREE, double_type_node, endlink);
-  unsigned_endlink = tree_cons (NULL_TREE, unsigned_type_node, endlink);
-
-  ptr_ftype = build_function_type (ptr_type_node, NULL_TREE);
-  ptr_ftype_unsigned = build_function_type (ptr_type_node, unsigned_endlink);
-  sizetype_endlink = tree_cons (NULL_TREE, sizetype, endlink);
-  /* We realloc here because sizetype could be int or unsigned.  S'ok.  */
-  ptr_ftype_sizetype = build_function_type (ptr_type_node, sizetype_endlink);
-
-  void_ftype = build_function_type (void_type_node, endlink);
-  void_ftype_int = build_function_type (void_type_node, int_endlink);
-  void_ftype_ptr
-    = build_function_type (void_type_node,
-                          tree_cons (NULL_TREE, ptr_type_node, endlink));
-  void_ftype_ptr
-    = build_exception_variant (void_ftype_ptr,
-                              tree_cons (NULL_TREE, NULL_TREE, NULL_TREE));
-
-  float_ftype_float
-    = build_function_type (float_type_node,
-                          tree_cons (NULL_TREE, float_type_node, endlink));
-
-  double_ftype_double
-    = build_function_type (double_type_node, double_endlink);
-
-  ldouble_ftype_ldouble
-    = build_function_type (long_double_type_node,
-                          tree_cons (NULL_TREE, long_double_type_node,
-                                     endlink));
-
-  double_ftype_double_double
-    = build_function_type (double_type_node,
-                          tree_cons (NULL_TREE, double_type_node,
-                                     double_endlink));
-
-  int_ftype_int
-    = build_function_type (integer_type_node, int_endlink);
-
-  long_ftype_long
-    = build_function_type (long_integer_type_node,
-                          tree_cons (NULL_TREE, long_integer_type_node,
-                                     endlink));
-
-  int_ftype_cptr_cptr_sizet
-    = build_function_type (integer_type_node,
-                          tree_cons (NULL_TREE, const_ptr_type_node,
-                                     tree_cons (NULL_TREE, const_ptr_type_node,
-                                                tree_cons (NULL_TREE,
-                                                           sizetype,
-                                                           endlink))));
-
-  string_ftype_ptr_ptr         /* strcpy prototype */
-    = build_function_type (string_type_node,
-                          tree_cons (NULL_TREE, string_type_node,
-                                     tree_cons (NULL_TREE,
-                                                const_string_type_node,
-                                                endlink)));
-
-  int_ftype_string_string      /* strcmp prototype */
-    = build_function_type (integer_type_node,
-                          tree_cons (NULL_TREE, const_string_type_node,
-                                     tree_cons (NULL_TREE,
-                                                const_string_type_node,
-                                                endlink)));
-
-  strlen_ftype         /* strlen prototype */
-    = build_function_type (sizetype,
-                          tree_cons (NULL_TREE, const_string_type_node,
-                                     endlink));
-
-  memcpy_ftype /* memcpy prototype */
-    = build_function_type (ptr_type_node,
-                          tree_cons (NULL_TREE, ptr_type_node,
-                                     tree_cons (NULL_TREE, const_ptr_type_node,
-                                                sizetype_endlink)));
-
-  if (flag_huge_objects)
-    delta_type_node = long_integer_type_node;
-  else
-    delta_type_node = short_integer_type_node;
-
-  builtin_function ("__builtin_constant_p", default_function_type,
-                   BUILT_IN_CONSTANT_P, NULL_PTR);
-
-  builtin_return_address_fndecl
-    = builtin_function ("__builtin_return_address", ptr_ftype_unsigned,
-                       BUILT_IN_RETURN_ADDRESS, NULL_PTR);
-
-  builtin_function ("__builtin_frame_address", ptr_ftype_unsigned,
-                   BUILT_IN_FRAME_ADDRESS, NULL_PTR);
-
-  builtin_function ("__builtin_alloca", ptr_ftype_sizetype,
-                   BUILT_IN_ALLOCA, "alloca");
-  builtin_function ("__builtin_ffs", int_ftype_int, BUILT_IN_FFS, NULL_PTR);
-  /* Define alloca, ffs as builtins.
-     Declare _exit just to mark it as volatile.  */
-  if (! flag_no_builtin && !flag_no_nonansi_builtin)
-    {
-      temp = builtin_function ("alloca", ptr_ftype_sizetype,
-                              BUILT_IN_ALLOCA, NULL_PTR);
-      /* Suppress error if redefined as a non-function.  */
-      DECL_BUILT_IN_NONANSI (temp) = 1;
-      temp = builtin_function ("ffs", int_ftype_int, BUILT_IN_FFS, NULL_PTR);
-      /* Suppress error if redefined as a non-function.  */
-      DECL_BUILT_IN_NONANSI (temp) = 1;
-      temp = builtin_function ("_exit", void_ftype_int,
-                              NOT_BUILT_IN, NULL_PTR);
-      TREE_THIS_VOLATILE (temp) = 1;
-      TREE_SIDE_EFFECTS (temp) = 1;
-      /* Suppress error if redefined as a non-function.  */
-      DECL_BUILT_IN_NONANSI (temp) = 1;
-    }
-
-  builtin_function ("__builtin_abs", int_ftype_int, BUILT_IN_ABS, NULL_PTR);
-  builtin_function ("__builtin_fabsf", float_ftype_float, BUILT_IN_FABS,
-                   NULL_PTR);
-  builtin_function ("__builtin_fabs", double_ftype_double, BUILT_IN_FABS,
-                   NULL_PTR);
-  builtin_function ("__builtin_fabsl", ldouble_ftype_ldouble, BUILT_IN_FABS,
-                   NULL_PTR);
-  builtin_function ("__builtin_labs", long_ftype_long,
-                   BUILT_IN_LABS, NULL_PTR);
-  builtin_function ("__builtin_saveregs", ptr_ftype,
-                   BUILT_IN_SAVEREGS, NULL_PTR);
-  builtin_function ("__builtin_classify_type", default_function_type,
-                   BUILT_IN_CLASSIFY_TYPE, NULL_PTR);
-  builtin_function ("__builtin_next_arg", ptr_ftype,
-                   BUILT_IN_NEXT_ARG, NULL_PTR);
-  builtin_function ("__builtin_args_info", int_ftype_int,
-                   BUILT_IN_ARGS_INFO, NULL_PTR);
-  builtin_function ("__builtin_setjmp",
-                   build_function_type (integer_type_node,
-                                        tree_cons (NULL_TREE, ptr_type_node,
-                                                   endlink)),
-                   BUILT_IN_SETJMP, NULL_PTR);
-  builtin_function ("__builtin_longjmp",
-                   build_function_type (integer_type_node,
-                                        tree_cons (NULL_TREE, ptr_type_node,
-                                                   tree_cons (NULL_TREE,
-                                                              integer_type_node,
-                                                              endlink))),
-                   BUILT_IN_LONGJMP, NULL_PTR);
-
-  /* Untyped call and return.  */
-  builtin_function ("__builtin_apply_args", ptr_ftype,
-                   BUILT_IN_APPLY_ARGS, NULL_PTR);
-
-  temp = tree_cons (NULL_TREE,
-                   build_pointer_type (build_function_type (void_type_node,
-                                                            NULL_TREE)),
-                   tree_cons (NULL_TREE, ptr_ftype_sizetype, NULL_TREE));
-  builtin_function ("__builtin_apply",
-                   build_function_type (ptr_type_node, temp),
-                   BUILT_IN_APPLY, NULL_PTR);
-  builtin_function ("__builtin_return", void_ftype_ptr,
-                   BUILT_IN_RETURN, NULL_PTR);
-
-  /* Currently under experimentation.  */
-  builtin_function ("__builtin_memcpy", memcpy_ftype,
-                   BUILT_IN_MEMCPY, "memcpy");
-  builtin_function ("__builtin_memcmp", int_ftype_cptr_cptr_sizet,
-                   BUILT_IN_MEMCMP, "memcmp");
-  builtin_function ("__builtin_strcmp", int_ftype_string_string,
-                   BUILT_IN_STRCMP, "strcmp");
-  builtin_function ("__builtin_strcpy", string_ftype_ptr_ptr,
-                   BUILT_IN_STRCPY, "strcpy");
-  builtin_function ("__builtin_strlen", strlen_ftype,
-                   BUILT_IN_STRLEN, "strlen");
-  builtin_function ("__builtin_sqrtf", float_ftype_float, 
-                   BUILT_IN_FSQRT, "sqrtf");
-  builtin_function ("__builtin_fsqrt", double_ftype_double,
-                   BUILT_IN_FSQRT, NULL_PTR);
-  builtin_function ("__builtin_sqrtl", ldouble_ftype_ldouble, 
-                   BUILT_IN_FSQRT, "sqrtl");
-  builtin_function ("__builtin_sinf", float_ftype_float, 
-                   BUILT_IN_SIN, "sinf");
-  builtin_function ("__builtin_sin", double_ftype_double, 
-                   BUILT_IN_SIN, "sin");
-  builtin_function ("__builtin_sinl", ldouble_ftype_ldouble, 
-                   BUILT_IN_SIN, "sinl");
-  builtin_function ("__builtin_cosf", float_ftype_float, 
-                   BUILT_IN_COS, "cosf");
-  builtin_function ("__builtin_cos", double_ftype_double, 
-                   BUILT_IN_COS, "cos");
-  builtin_function ("__builtin_cosl", ldouble_ftype_ldouble, 
-                   BUILT_IN_COS, "cosl");
-
-  if (!flag_no_builtin)
-    {
-      builtin_function ("abs", int_ftype_int, BUILT_IN_ABS, NULL_PTR);
-      builtin_function ("fabs", double_ftype_double, BUILT_IN_FABS, NULL_PTR);
-      builtin_function ("labs", long_ftype_long, BUILT_IN_LABS, NULL_PTR);
-      builtin_function ("fabsf", float_ftype_float, BUILT_IN_FABS, NULL_PTR);
-      builtin_function ("fabsl", ldouble_ftype_ldouble, BUILT_IN_FABS,
-                       NULL_PTR);
-      builtin_function ("memcpy", memcpy_ftype, BUILT_IN_MEMCPY, NULL_PTR);
-      builtin_function ("memcmp", int_ftype_cptr_cptr_sizet, BUILT_IN_MEMCMP,
-                       NULL_PTR);
-      builtin_function ("strcmp", int_ftype_string_string, BUILT_IN_STRCMP,
-                       NULL_PTR);
-      builtin_function ("strcpy", string_ftype_ptr_ptr, BUILT_IN_STRCPY,
-                       NULL_PTR);
-      builtin_function ("strlen", strlen_ftype, BUILT_IN_STRLEN, NULL_PTR);
-      builtin_function ("sqrtf", float_ftype_float, BUILT_IN_FSQRT, NULL_PTR);
-      builtin_function ("sqrt", double_ftype_double, BUILT_IN_FSQRT, NULL_PTR);
-      builtin_function ("sqrtl", ldouble_ftype_ldouble, BUILT_IN_FSQRT,
-                       NULL_PTR);
-      builtin_function ("sinf", float_ftype_float, BUILT_IN_SIN, NULL_PTR);
-      builtin_function ("sin", double_ftype_double, BUILT_IN_SIN, NULL_PTR);
-      builtin_function ("sinl", ldouble_ftype_ldouble, BUILT_IN_SIN, NULL_PTR);
-      builtin_function ("cosf", float_ftype_float, BUILT_IN_COS, NULL_PTR);
-      builtin_function ("cos", double_ftype_double, BUILT_IN_COS, NULL_PTR);
-      builtin_function ("cosl", ldouble_ftype_ldouble, BUILT_IN_COS, NULL_PTR);
-
-      /* Declare these functions volatile
-        to avoid spurious "control drops through" warnings.  */
-      temp = builtin_function ("abort", void_ftype,
-                              NOT_BUILT_IN, NULL_PTR);
-      TREE_THIS_VOLATILE (temp) = 1;
-      TREE_SIDE_EFFECTS (temp) = 1;
-      /* Well, these are actually ANSI, but we can't set DECL_BUILT_IN on
-         them...  */
-      DECL_BUILT_IN_NONANSI (temp) = 1;
-      temp = builtin_function ("exit", void_ftype_int,
-                              NOT_BUILT_IN, NULL_PTR);
-      TREE_THIS_VOLATILE (temp) = 1;
-      TREE_SIDE_EFFECTS (temp) = 1;
-      DECL_BUILT_IN_NONANSI (temp) = 1;
-    }
+                                               TYPE_QUAL_CONST));
+  c_common_nodes_and_builtins (1, flag_no_builtin, flag_no_nonansi_builtin);
 
-#if 0
-  /* Support for these has not been written in either expand_builtin
-     or build_function_call.  */
-  builtin_function ("__builtin_div", default_ftype, BUILT_IN_DIV, NULL_PTR);
-  builtin_function ("__builtin_ldiv", default_ftype, BUILT_IN_LDIV, NULL_PTR);
-  builtin_function ("__builtin_ffloor", double_ftype_double, BUILT_IN_FFLOOR,
-                   NULL_PTR);
-  builtin_function ("__builtin_fceil", double_ftype_double, BUILT_IN_FCEIL,
-                   NULL_PTR);
-  builtin_function ("__builtin_fmod", double_ftype_double_double,
-                   BUILT_IN_FMOD, NULL_PTR);
-  builtin_function ("__builtin_frem", double_ftype_double_double,
-                   BUILT_IN_FREM, NULL_PTR);
-  builtin_function ("__builtin_memset", ptr_ftype_ptr_int_int,
-                   BUILT_IN_MEMSET, NULL_PTR);
-  builtin_function ("__builtin_getexp", double_ftype_double, BUILT_IN_GETEXP,
-                   NULL_PTR);
-  builtin_function ("__builtin_getman", double_ftype_double, BUILT_IN_GETMAN,
-                   NULL_PTR);
-#endif
+  void_ftype_ptr
+    = build_exception_variant (void_ftype_ptr, empty_except_spec);
 
   /* C++ extensions */
 
@@ -6797,14 +6226,11 @@ init_decl_processing ()
   TYPE_POINTER_TO (unknown_type_node) = unknown_type_node;
   TYPE_REFERENCE_TO (unknown_type_node) = unknown_type_node;
 
-  /* This is for handling opaque types in signatures.  */
-  opaque_type_node = copy_node (ptr_type_node);
-  TYPE_MAIN_VARIANT (opaque_type_node) = opaque_type_node;
-  record_builtin_type (RID_MAX, 0, opaque_type_node);
-
   /* This is special for C++ so functions can be overloaded.  */
-  wchar_type_node
-    = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (WCHAR_TYPE)));
+  wchar_type_node = get_identifier (flag_short_wchar
+                                   ? "short unsigned int"
+                                   : WCHAR_TYPE);
+  wchar_type_node = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (wchar_type_node));
   wchar_type_size = TYPE_PRECISION (wchar_type_node);
   signed_wchar_type_node = make_signed_type (wchar_type_size);
   unsigned_wchar_type_node = make_unsigned_type (wchar_type_size);
@@ -6837,12 +6263,12 @@ init_decl_processing ()
   else
     {
       vtable_entry_type = make_lang_type (RECORD_TYPE);
-      fields[0] = build_lang_field_decl (FIELD_DECL, delta_identifier,
-                                        delta_type_node);
-      fields[1] = build_lang_field_decl (FIELD_DECL, index_identifier,
-                                        delta_type_node);
-      fields[2] = build_lang_field_decl (FIELD_DECL, pfn_identifier,
-                                        ptr_type_node);
+      fields[0] = build_lang_decl (FIELD_DECL, delta_identifier,
+                                  delta_type_node);
+      fields[1] = build_lang_decl (FIELD_DECL, index_identifier,
+                                  delta_type_node);
+      fields[2] = build_lang_decl (FIELD_DECL, pfn_identifier,
+                                  ptr_type_node);
       finish_builtin_type (vtable_entry_type, VTBL_PTR_TYPE, fields, 2,
                           double_type_node);
 
@@ -6868,44 +6294,6 @@ init_decl_processing ()
   layout_type (vtbl_ptr_type_node);
   record_builtin_type (RID_MAX, NULL_PTR, vtbl_ptr_type_node);
 
-  /* Simplify life by making a "sigtable_entry_type".  Give its
-     fields names so that the debugger can use them.  */
-
-  if (flag_handle_signatures)
-    {
-      sigtable_entry_type = make_lang_type (RECORD_TYPE);
-      fields[0] = build_lang_field_decl (FIELD_DECL, tag_identifier,
-                                        delta_type_node);
-      fields[1] = build_lang_field_decl (FIELD_DECL, vb_off_identifier,
-                                        delta_type_node);
-      fields[2] = build_lang_field_decl (FIELD_DECL, delta_identifier,
-                                        delta_type_node);
-      fields[3] = build_lang_field_decl (FIELD_DECL, index_identifier,
-                                        delta_type_node);
-      fields[4] = build_lang_field_decl (FIELD_DECL, pfn_identifier,
-                                        ptr_type_node);
-
-      /* Set the alignment to the max of the alignment of ptr_type_node and
-        delta_type_node.  Double alignment wastes a word on the Sparc.  */
-      finish_builtin_type (sigtable_entry_type, SIGTABLE_PTR_TYPE, fields, 4,
-                          (TYPE_ALIGN (ptr_type_node) > TYPE_ALIGN (delta_type_node))
-                          ? ptr_type_node
-                          : delta_type_node);
-
-      /* Make this part of an invisible union.  */
-      fields[5] = copy_node (fields[4]);
-      TREE_TYPE (fields[5]) = delta_type_node;
-      DECL_NAME (fields[5]) = vt_off_identifier;
-      DECL_MODE (fields[5]) = TYPE_MODE (delta_type_node);
-      DECL_SIZE (fields[5]) = TYPE_SIZE (delta_type_node);
-      TREE_UNSIGNED (fields[5]) = 0;
-      TREE_CHAIN (fields[4]) = fields[5];
-
-      sigtable_entry_type = build_qualified_type (sigtable_entry_type, 
-                                                 TYPE_QUAL_CONST);
-      record_builtin_type (RID_MAX, SIGTABLE_PTR_TYPE, sigtable_entry_type);
-    }
-
   std_node = build_decl (NAMESPACE_DECL, 
                         get_identifier (flag_honor_std ? "fake std":"std"),
                         void_type_node);
@@ -6926,26 +6314,23 @@ init_decl_processing ()
     if (flag_honor_std)
       pop_namespace ();
     newtype = build_exception_variant
-      (ptr_ftype_sizetype, build_tree_list (NULL_TREE, bad_alloc_type_node));
-    deltype = build_exception_variant
-      (void_ftype_ptr, build_tree_list (NULL_TREE, NULL_TREE));
-    auto_function (ansi_opname[(int) NEW_EXPR], newtype, NOT_BUILT_IN);
-    auto_function (ansi_opname[(int) VEC_NEW_EXPR], newtype, NOT_BUILT_IN);
-    global_delete_fndecl
-      = auto_function (ansi_opname[(int) DELETE_EXPR], deltype, NOT_BUILT_IN);
-    auto_function (ansi_opname[(int) VEC_DELETE_EXPR], deltype, NOT_BUILT_IN);
+      (ptr_ftype_sizetype, add_exception_specifier (NULL_TREE, bad_alloc_type_node, -1));
+    deltype = build_exception_variant (void_ftype_ptr, empty_except_spec);
+    auto_function (ansi_opname[(int) NEW_EXPR], newtype);
+    auto_function (ansi_opname[(int) VEC_NEW_EXPR], newtype);
+    global_delete_fndecl = auto_function (ansi_opname[(int) DELETE_EXPR],
+                                         deltype);
+    auto_function (ansi_opname[(int) VEC_DELETE_EXPR], deltype);
   }
 
   abort_fndecl
-    = define_function ("__pure_virtual", void_ftype,
-                      NOT_BUILT_IN, 0, 0);
+    = define_function ("__pure_virtual", void_ftype, 0, 0);
 
   /* Perform other language dependent initializations.  */
   init_class_processing ();
   init_init_processing ();
   init_search_processing ();
-  if (flag_rtti)
-    init_rtti_processing ();
+  init_rtti_processing ();
 
   if (flag_exceptions)
     init_exception_processing ();
@@ -6974,13 +6359,46 @@ init_decl_processing ()
      say -fwritable-strings?  */
   if (flag_writable_strings)
     flag_const_strings = 0;
+
+  /* Add GC roots for all of our global variables.  */
+  ggc_add_tree_root (c_global_trees, sizeof c_global_trees / sizeof(tree));
+  ggc_add_tree_root (cp_global_trees, sizeof cp_global_trees / sizeof(tree));
+  ggc_add_tree_root (&integer_three_node, 1);
+  ggc_add_tree_root (&integer_two_node, 1);
+  ggc_add_tree_root (&signed_size_zero_node, 1);
+  ggc_add_tree_root (&size_one_node, 1);
+  ggc_add_tree_root (&size_zero_node, 1);
+  ggc_add_root (&global_binding_level, 1, sizeof global_binding_level,
+               mark_binding_level);
+  ggc_add_root (&scope_chain, 1, sizeof scope_chain, &mark_saved_scope);
+  ggc_add_tree_root (&static_ctors, 1);
+  ggc_add_tree_root (&static_dtors, 1);
+  ggc_add_tree_root (&lastiddecl, 1);
+
+  ggc_add_tree_root (&enum_next_value, 1);
+  ggc_add_tree_root (&last_function_parm_tags, 1);
+  ggc_add_tree_root (&current_function_return_value, 1);
+  ggc_add_tree_root (&current_function_parms, 1);
+  ggc_add_tree_root (&current_function_parm_tags, 1);
+  ggc_add_tree_root (&last_function_parms, 1);
+  ggc_add_tree_root (&error_mark_list, 1);
+
+  ggc_add_tree_root (&global_namespace, 1);
+  ggc_add_tree_root (&global_type_node, 1);
+  ggc_add_tree_root (&anonymous_namespace_name, 1);
+
+  ggc_add_tree_root (&got_object, 1);
+  ggc_add_tree_root (&got_scope, 1);
+
+  ggc_add_tree_root (&current_lang_name, 1);
+  ggc_add_tree_root (&static_aggregates, 1);
 }
 
 /* Function to print any language-specific context for an error message.  */
 
 static void
 lang_print_error_function (file)
-     char *file;
+     const char *file;
 {
   default_print_error_function (file);
   maybe_print_template_context ();
@@ -6988,17 +6406,14 @@ lang_print_error_function (file)
 
 /* Make a definition for a builtin function named NAME and whose data type
    is TYPE.  TYPE should be a function type with argument types.
-   FUNCTION_CODE tells later passes how to compile calls to this function.
-   See tree.h for its possible values.
 
    If LIBRARY_NAME is nonzero, use that for DECL_ASSEMBLER_NAME,
    the name to be called if we can't opencode the function.  */
 
 tree
-define_function (name, type, function_code, pfn, library_name)
+define_function (name, type, pfn, library_name)
      const char *name;
      tree type;
-     enum built_in_function function_code;
      void (*pfn) PROTO((tree));
      const char *library_name;
 {
@@ -7017,11 +6432,27 @@ define_function (name, type, function_code, pfn, library_name)
   if (library_name)
     DECL_ASSEMBLER_NAME (decl) = get_identifier (library_name);
   make_function_rtl (decl);
-  if (function_code != NOT_BUILT_IN)
-    {
-      DECL_BUILT_IN (decl) = 1;
-      DECL_FUNCTION_CODE (decl) = function_code;
-    }
+  return decl;
+}
+
+
+/* Wrapper around define_function, for the benefit of 
+   c_common_nodes_and_builtins.
+   FUNCTION_CODE tells later passes how to compile calls to this function.
+   See tree.h for its possible values.  */
+
+tree
+builtin_function (name, type, code, class, libname)
+     const char *name;
+     tree type;
+     int code;
+     enum built_in_class class;
+     const char *libname;
+{
+  tree decl = define_function (name, type, (void (*) PROTO((tree)))pushdecl,
+                              libname);
+  DECL_BUILT_IN_CLASS (decl) = class;
+  DECL_FUNCTION_CODE (decl) = code;
   return decl;
 }
 \f
@@ -7264,26 +6695,6 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
   if (type == error_mark_node)
     return NULL_TREE;
 
-  /* Don't lose if destructors must be executed at file-level.  */
-  if (! processing_template_decl && TREE_STATIC (decl)
-      && TYPE_NEEDS_DESTRUCTOR (complete_type (type))
-      && !TREE_PERMANENT (decl))
-    {
-      push_obstacks (&permanent_obstack, &permanent_obstack);
-      decl = copy_node (decl);
-      if (TREE_CODE (type) == ARRAY_TYPE)
-       {
-         tree itype = TYPE_DOMAIN (type);
-         if (itype && ! TREE_PERMANENT (itype))
-           {
-             itype = build_index_type (copy_to_permanent (TYPE_MAX_VALUE (itype)));
-             type = build_cplus_array_type (TREE_TYPE (type), itype);
-             TREE_TYPE (decl) = type;
-           }
-       }
-      pop_obstacks ();
-    }
-
   context
     = (TREE_CODE (decl) == FUNCTION_DECL && DECL_VIRTUAL_P (decl))
       ? DECL_CLASS_CONTEXT (decl)
@@ -7343,6 +6754,13 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
       DECL_INITIAL (decl) = error_mark_node;
     }
 
+#ifdef SET_DEFAULT_DECL_ATTRIBUTES
+  SET_DEFAULT_DECL_ATTRIBUTES (decl, attributes);
+#endif
+  
+  /* Set attributes here so if duplicate decl, will have proper attributes.  */
+  cplus_decl_attributes (decl, attributes, prefix_attributes);
+
   if (context && TYPE_SIZE (complete_type (context)) != NULL_TREE)
     {
       push_nested_class (context, 2);
@@ -7400,41 +6818,16 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
                    decl);
     }
 
-#ifdef SET_DEFAULT_DECL_ATTRIBUTES
-  SET_DEFAULT_DECL_ATTRIBUTES (decl, attributes);
-#endif
-  
-  /* Set attributes here so if duplicate decl, will have proper attributes.  */
-  cplus_decl_attributes (decl, attributes, prefix_attributes);
-
-  /* Add this decl to the current binding level, but not if it
-     comes from another scope, e.g. a static member variable.
-     TEM may equal DECL or it may be a previous decl of the same name.  */
-  
-  if ((TREE_CODE (decl) != PARM_DECL && DECL_CONTEXT (decl) != NULL_TREE 
-       /* Definitions of namespace members outside their namespace are
-         possible. */
-       && TREE_CODE (DECL_CONTEXT (decl)) != NAMESPACE_DECL)
-      || (TREE_CODE (decl) == TEMPLATE_DECL && !namespace_bindings_p ())
-      || TREE_CODE (type) == LANG_TYPE
-      /* The declaration of template specializations does not affect
-        the functions available for overload resolution, so we do not
-        call pushdecl.  */
-      || (TREE_CODE (decl) == FUNCTION_DECL
-         && DECL_TEMPLATE_SPECIALIZATION (decl)))
-    tem = decl;
-  else
-    tem = pushdecl (decl);
+  /* Enter this declaration into the symbol table.  */
+  tem = maybe_push_decl (decl);
 
   if (processing_template_decl)
     {
-      if (! current_function_decl)
-       tem = push_template_decl (tem);
-      else if (minimal_parse_mode)
-       DECL_VINDEX (tem)
-           = build_min_nt (DECL_STMT, copy_to_permanent (declarator),
-                           copy_to_permanent (declspecs),
-                           NULL_TREE);
+      if (at_function_scope_p ())
+       push_permanent_obstack ();
+      tem = push_template_decl (tem);
+      if (at_function_scope_p ())
+       pop_obstacks ();
     }
 
 
@@ -7453,32 +6846,6 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
   /* Corresponding pop_obstacks is done in `cp_finish_decl'.  */
   push_obstacks_nochange ();
 
-#if 0
-  /* We have no way of knowing whether the initializer will need to be
-     evaluated at run-time or not until we've parsed it, so let's just put
-     it in the permanent obstack.  (jason) */
-  if (init_written
-      && ! (TREE_CODE (tem) == PARM_DECL
-           || (TREE_READONLY (tem)
-               && (TREE_CODE (tem) == VAR_DECL
-                   || TREE_CODE (tem) == FIELD_DECL))))
-    {
-      /* When parsing and digesting the initializer,
-        use temporary storage.  Do this even if we will ignore the value.  */
-      if (toplevel_bindings_p () && debug_temp_inits)
-       {
-         if (processing_template_decl
-             || TYPE_NEEDS_CONSTRUCTING (type)
-             || TREE_CODE (type) == REFERENCE_TYPE)
-           /* In this case, the initializer must lay down in permanent
-              storage, since it will be saved until `finish_file' is run.   */
-           ;
-         else
-           temporary_allocation ();
-       }
-    }
-#endif
-
   return tem;
 }
 
@@ -7550,23 +6917,6 @@ start_decl_1 (decl)
        }
     }
 
-#if 0
-  /* We don't do this yet for GNU C++.  */
-  /* For a local variable, define the RTL now.  */
-  if (! toplevel_bindings_p ()
-      /* But not if this is a duplicate decl
-        and we preserved the rtl from the previous one
-        (which may or may not happen).  */
-      && DECL_RTL (tem) == NULL_RTX)
-    {
-      if (TYPE_SIZE (TREE_TYPE (tem)) != NULL_TREE)
-       expand_decl (tem);
-      else if (TREE_CODE (TREE_TYPE (tem)) == ARRAY_TYPE
-              && DECL_INITIAL (tem) != NULL_TREE)
-       expand_decl (tem);
-    }
-#endif
-
   if (! initialized)
     DECL_INITIAL (decl) = NULL_TREE;
 }
@@ -7588,19 +6938,14 @@ grok_reference_init (decl, type, init)
       if ((DECL_LANG_SPECIFIC (decl) == 0
           || DECL_IN_AGGR_P (decl) == 0)
          && ! DECL_THIS_EXTERN (decl))
-       {
-         cp_error ("`%D' declared as reference but not initialized", decl);
-         if (TREE_CODE (decl) == VAR_DECL)
-           SET_DECL_REFERENCE_SLOT (decl, error_mark_node);
-       }
+       cp_error ("`%D' declared as reference but not initialized", decl);
       return;
     }
 
   if (init == error_mark_node)
     return;
 
-  if (TREE_CODE (type) == REFERENCE_TYPE
-      && TREE_CODE (init) == CONSTRUCTOR)
+  if (TREE_CODE (init) == CONSTRUCTOR)
     {
       cp_error ("ANSI C++ forbids use of initializer list to initialize reference `%D'", decl);
       return;
@@ -7618,32 +6963,40 @@ grok_reference_init (decl, type, init)
       /* Note: default conversion is only called in very special cases.  */
       init = default_conversion (init);
     }
-
+  
+  /* Convert INIT to the reference type TYPE.  This may involve the
+     creation of a temporary, whose lifetime must be the same as that
+     of the reference.  If so, a DECL_STMT for the temporary will be
+     added just after the DECL_STMT for DECL.  That's why we don't set
+     DECL_INITIAL for local references (instead assigning to them
+     explicitly); we need to allow the temporary to be initialized
+     first.  */
   tmp = convert_to_reference
     (type, init, CONV_IMPLICIT,
      LOOKUP_SPECULATIVELY|LOOKUP_NORMAL|DIRECT_BIND, decl);
 
   if (tmp == error_mark_node)
-    goto fail;
+    return;
   else if (tmp != NULL_TREE)
     {
       init = tmp;
-      DECL_INITIAL (decl) = save_expr (init);
+      tmp = save_expr (tmp);
+      if (building_stmt_tree ())
+       {
+         /* Initialize the declaration.  */
+         tmp = build (INIT_EXPR, TREE_TYPE (decl), decl, tmp);
+         /* Setting TREE_SIDE_EFFECTS prevents expand_expr from
+            omitting this expression entirely.  */
+         TREE_SIDE_EFFECTS (tmp) = 1;
+         finish_expr_stmt (tmp);
+       }
+      else
+       DECL_INITIAL (decl) = tmp;
     }
   else
     {
       cp_error ("cannot initialize `%T' from `%T'", type, TREE_TYPE (init));
-      goto fail;
-    }
-
-  /* ?? Can this be optimized in some cases to
-     hand back the DECL_INITIAL slot??  */
-  if (TYPE_SIZE (TREE_TYPE (type)))
-    {
-      init = convert_from_reference (decl);
-      if (TREE_PERMANENT (decl))
-       init = copy_to_permanent (init);
-      SET_DECL_REFERENCE_SLOT (decl, init);
+      return;
     }
 
   if (TREE_STATIC (decl) && ! TREE_CONSTANT (DECL_INITIAL (decl)))
@@ -7652,11 +7005,6 @@ grok_reference_init (decl, type, init)
       DECL_INITIAL (decl) = NULL_TREE;
     }
   return;
-
- fail:
-  if (TREE_CODE (decl) == VAR_DECL)
-    SET_DECL_REFERENCE_SLOT (decl, error_mark_node);
-  return;
 }
 
 /* Fill in DECL_INITIAL with some magical value to prevent expand_decl from
@@ -7686,6 +7034,160 @@ obscure_complex_init (decl, init)
   return init;
 }
 
+/* When parsing `int a[] = {1, 2};' we don't know the size of the
+   array until we finish parsing the initializer.  If that's the
+   situation we're in, update DECL accordingly.  */
+
+static void
+maybe_deduce_size_from_array_init (decl, init)
+     tree decl;
+     tree init;
+{
+  tree type = TREE_TYPE (decl);
+
+  if (TREE_CODE (type) == ARRAY_TYPE
+      && TYPE_DOMAIN (type) == NULL_TREE
+      && TREE_CODE (decl) != TYPE_DECL)
+    {
+      int do_default
+       = (TREE_STATIC (decl)
+          /* Even if pedantic, an external linkage array
+             may have incomplete type at first.  */
+          ? pedantic && ! DECL_EXTERNAL (decl)
+          : !DECL_EXTERNAL (decl));
+      tree initializer = init ? init : DECL_INITIAL (decl);
+      int failure = complete_array_type (type, initializer, do_default);
+
+      if (failure == 1)
+       cp_error ("initializer fails to determine size of `%D'", decl);
+
+      if (failure == 2)
+       {
+         if (do_default)
+           cp_error ("array size missing in `%D'", decl);
+         /* If a `static' var's size isn't known, make it extern as
+            well as static, so it does not get allocated.  If it's not
+            `static', then don't mark it extern; finish_incomplete_decl
+            will give it a default size and it will get allocated.  */
+         else if (!pedantic && TREE_STATIC (decl) && !TREE_PUBLIC (decl))
+           DECL_EXTERNAL (decl) = 1;
+       }
+
+      if (pedantic && TYPE_DOMAIN (type) != NULL_TREE
+         && tree_int_cst_lt (TYPE_MAX_VALUE (TYPE_DOMAIN (type)),
+                             integer_zero_node))
+       cp_error ("zero-size array `%D'", decl);
+
+      layout_decl (decl, 0);
+    }
+}
+
+/* Set DECL_SIZE, DECL_ALIGN, etc. for DECL (a VAR_DECL), and issue
+   any appropriate error messages regarding the layout.  */
+
+static void
+layout_var_decl (decl)
+     tree decl;
+{
+  tree type = TREE_TYPE (decl);
+  tree ttype = target_type (type);
+
+  /* If we haven't already layed out this declaration, do so now.
+     Note that we must not call complete type for an external object
+     because it's type might involve templates that we are not
+     supposed to isntantiate yet.  (And it's perfectly legal to say 
+     `extern X x' for some incomplete type `X'.)  */
+  if (!DECL_EXTERNAL (decl))
+    complete_type (type);
+  if (!DECL_SIZE (decl)&& TYPE_SIZE (type))
+    layout_decl (decl, 0);
+
+  if (!DECL_EXTERNAL (decl) && DECL_SIZE (decl) == NULL_TREE)
+    {
+      /* An automatic variable with an incomplete type: that is an error.
+        Don't talk about array types here, since we took care of that
+        message in grokdeclarator.  */
+      cp_error ("storage size of `%D' isn't known", decl);
+      TREE_TYPE (decl) = error_mark_node;
+    }
+  else if (!DECL_EXTERNAL (decl) && IS_AGGR_TYPE (ttype))
+    /* Let debugger know it should output info for this type.  */
+    note_debug_info_needed (ttype);
+
+  if (TREE_STATIC (decl) && DECL_CLASS_SCOPE_P (decl))
+    note_debug_info_needed (DECL_CONTEXT (decl));
+
+  if ((DECL_EXTERNAL (decl) || TREE_STATIC (decl))
+      && DECL_SIZE (decl) != NULL_TREE
+      && ! TREE_CONSTANT (DECL_SIZE (decl)))
+    {
+      if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST)
+       constant_expression_warning (DECL_SIZE (decl));
+      else
+       cp_error ("storage size of `%D' isn't constant", decl);
+    }
+}
+
+/* If a local static variable is declared in an inline function, or if
+   we have a weak definition, we must endeavor to create only one
+   instance of the variable at link-time.  */
+
+static void
+maybe_commonize_var (decl)
+     tree decl;
+{
+  /* Static data in a function with comdat linkage also has comdat
+     linkage.  */
+  if (TREE_STATIC (decl)
+      /* Don't mess with __FUNCTION__.  */
+      && ! TREE_ASM_WRITTEN (decl)
+      && current_function_decl
+      && DECL_CONTEXT (decl) == current_function_decl
+      && (DECL_THIS_INLINE (current_function_decl)
+         || DECL_TEMPLATE_INSTANTIATION (current_function_decl))
+      && TREE_PUBLIC (current_function_decl))
+    {
+      /* Rather than try to get this right with inlining, we suppress
+        inlining of such functions.  */
+      current_function_cannot_inline
+       = "function with static variable cannot be inline";
+
+      /* If flag_weak, we don't need to mess with this, as we can just
+        make the function weak, and let it refer to its unique local
+        copy.  This works because we don't allow the function to be
+        inlined.  */
+      if (! flag_weak)
+       {
+         if (DECL_INTERFACE_KNOWN (current_function_decl))
+           {
+             TREE_PUBLIC (decl) = 1;
+             DECL_EXTERNAL (decl) = DECL_EXTERNAL (current_function_decl);
+           }
+         else if (DECL_INITIAL (decl) == NULL_TREE
+                  || DECL_INITIAL (decl) == error_mark_node)
+           {
+             TREE_PUBLIC (decl) = 1;
+             DECL_COMMON (decl) = 1;
+           }
+         /* else we lose. We can only do this if we can use common,
+            which we can't if it has been initialized.  */
+
+         if (TREE_PUBLIC (decl))
+           DECL_ASSEMBLER_NAME (decl)
+             = build_static_name (current_function_decl, DECL_NAME (decl));
+         else if (! DECL_ARTIFICIAL (decl))
+           {
+             cp_warning_at ("sorry: semantics of inline function static data `%#D' are wrong (you'll wind up with multiple copies)", decl);
+             cp_warning_at ("  you can work around this by removing the initializer", decl);
+           }
+       }
+    }
+  else if (DECL_LANG_SPECIFIC (decl) && DECL_COMDAT (decl))
+    /* Set it up again; we might have set DECL_INITIAL since the last
+       time.  */
+    comdat_linkage (decl);
+}
+
 /* Issue an error message if DECL is an uninitialized const variable.  */
 
 static void
@@ -7705,230 +7207,73 @@ check_for_uninitialized_const_var (decl)
     cp_error ("uninitialized const `%D'", decl);
 }
 
-/* Finish processing of a declaration;
-   install its line number and initial value.
-   If the length of an array type is not known before,
-   it must be determined now, from the initial value, or it is an error.
+/* Verify INIT (the initializer for DECL), and record the
+   initialization in DECL_INITIAL, if appropriate.  Returns a new
+   value for INIT.  */
 
-   Call `pop_obstacks' iff NEED_POP is nonzero.
+static tree
+check_initializer (decl, init)
+     tree decl;
+     tree init;
+{
+  tree type;
 
-   For C++, `cp_finish_decl' must be fairly evasive:  it must keep initializers
-   for aggregates that have constructors alive on the permanent obstack,
-   so that the global initializing functions can be written at the end.
+  if (TREE_CODE (decl) == FIELD_DECL)
+    return init;
 
-   INIT0 holds the value of an initializer that should be allowed to escape
-   the normal rules.
+  type = TREE_TYPE (decl);
 
-   FLAGS is LOOKUP_ONLYCONVERTING is the = init syntax was used, else 0
-   if the (init) syntax was used.
+  /* If `start_decl' didn't like having an initialization, ignore it now.  */
+  if (init != NULL_TREE && DECL_INITIAL (decl) == NULL_TREE)
+    init = NULL_TREE;
 
-   For functions that take default parameters, DECL points to its
-   "maximal" instantiation.  `cp_finish_decl' must then also declared its
-   subsequently lower and lower forms of instantiation, checking for
-   ambiguity as it goes.  This can be sped up later.  */
+  /* Check the initializer.  */
+  if (init)
+    {
+      /* Things that are going to be initialized need to have complete
+        type.  */
+      TREE_TYPE (decl) = type = complete_type (TREE_TYPE (decl));
 
-void
-cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
-     tree decl, init;
-     tree asmspec_tree;
-     int need_pop;
-     int flags;
-{
-  register tree type;
-  tree cleanup = NULL_TREE, ttype = NULL_TREE;
-  int was_incomplete;
-  int temporary = allocation_temporary_p ();
-  char *asmspec = NULL;
-  int was_readonly = 0;
-  int already_used = 0;
-  tree core_type;
+      if (type == error_mark_node)
+       /* We will have already complained.  */
+       init = NULL_TREE;
+      else if (TYPE_SIZE (type) && !TREE_CONSTANT (TYPE_SIZE (type)))
+       {
+         cp_error ("variable-sized object `%D' may not be initialized", decl);
+         init = NULL_TREE;
+       }
+      else if (TREE_CODE (type) == ARRAY_TYPE
+              && !TYPE_SIZE (TREE_TYPE (type)))
+       {
+         cp_error ("elements of array `%#D' have incomplete type", decl);
+         init = NULL_TREE;
+       }
+      else if (!TYPE_SIZE (type))
+       {
+         cp_error ("`%D' has incomplete type", decl);
+         TREE_TYPE (decl) = error_mark_node;
+         init = NULL_TREE;
+       }
+    }
 
-  /* If this is 0, then we did not change obstacks.  */
-  if (! decl)
+  if (TREE_CODE (decl) == CONST_DECL)
     {
-      if (init)
-       error ("assignment (not initialization) in declaration");
-      return;
-    }
+      my_friendly_assert (TREE_CODE (decl) != REFERENCE_TYPE, 148);
 
-  /* If a name was specified, get the string.  */
-  if (asmspec_tree)
-      asmspec = TREE_STRING_POINTER (asmspec_tree);
+      DECL_INITIAL (decl) = init;
 
-  if (init && TREE_CODE (init) == NAMESPACE_DECL)
-    {
-      cp_error ("Cannot initialize `%D' to namespace `%D'",
-               decl, init);
+      /* This will keep us from needing to worry about our obstacks.  */
+      my_friendly_assert (init != NULL_TREE, 149);
       init = NULL_TREE;
     }
-
-  if (current_class_type
-      && DECL_REAL_CONTEXT (decl) == current_class_type
-      && TYPE_BEING_DEFINED (current_class_type)
-      && (DECL_INITIAL (decl) || init))
-    DECL_DEFINED_IN_CLASS_P (decl) = 1;
-
-  if (TREE_CODE (decl) == VAR_DECL 
-      && DECL_CONTEXT (decl)
-      && TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL
-      && DECL_CONTEXT (decl) != current_namespace
-      && init)
+  else if (!DECL_EXTERNAL (decl) && TREE_CODE (type) == REFERENCE_TYPE)
     {
-      /* Leave the namespace of the object. */
-      pop_decl_namespace ();
+      if (TREE_STATIC (decl))
+       make_decl_rtl (decl, NULL_PTR, toplevel_bindings_p ());
+      grok_reference_init (decl, type, init);
+      init = NULL_TREE;
     }
-
-  /* If the type of the thing we are declaring either has
-     a constructor, or has a virtual function table pointer,
-     AND its initialization was accepted by `start_decl',
-     then we stayed on the permanent obstack through the
-     declaration, otherwise, changed obstacks as GCC would.  */
-
-  type = TREE_TYPE (decl);
-
-  if (type == error_mark_node)
-    {
-      if (toplevel_bindings_p () && temporary)
-       end_temporary_allocation ();
-
-      return;
-    }
-
-  if (TYPE_HAS_MUTABLE_P (type))
-    TREE_READONLY (decl) = 0;
-  
-  if (processing_template_decl)
-    {
-      if (init && DECL_INITIAL (decl))
-       DECL_INITIAL (decl) = init;
-      if (minimal_parse_mode && ! DECL_ARTIFICIAL (decl))
-       {
-         tree stmt = DECL_VINDEX (decl);
-         /* If the decl is declaring a member of a local class (in a
-            template function), the DECL_VINDEX will either be NULL,
-            or it will be an actual virtual function index, not a
-            DECL_STMT.  */
-         if (stmt != NULL_TREE && TREE_CODE (stmt) == DECL_STMT)
-           {
-             DECL_VINDEX (decl) = NULL_TREE;
-             TREE_OPERAND (stmt, 2) = copy_to_permanent (init);
-             add_tree (stmt);
-           }
-       }
-
-      goto finish_end0;
-    }
-
-  /* Take care of TYPE_DECLs up front.  */
-  if (TREE_CODE (decl) == TYPE_DECL)
-    {
-      if (init && DECL_INITIAL (decl))
-       {
-         /* typedef foo = bar; store the type of bar as the type of foo.  */
-         TREE_TYPE (decl) = type = TREE_TYPE (init);
-         DECL_INITIAL (decl) = init = NULL_TREE;
-       }
-      if (type != error_mark_node
-         && IS_AGGR_TYPE (type) && DECL_NAME (decl))
-       {
-         if (TREE_TYPE (DECL_NAME (decl)) && TREE_TYPE (decl) != type)
-           cp_warning ("shadowing previous type declaration of `%#D'", decl);
-         set_identifier_type_value (DECL_NAME (decl), type);
-         CLASSTYPE_GOT_SEMICOLON (type) = 1;
-       }
-      GNU_xref_decl (current_function_decl, decl);
-
-      /* If we have installed this as the canonical typedef for this
-        type, and that type has not been defined yet, delay emitting
-        the debug information for it, as we will emit it later.  */
-      if (TYPE_MAIN_DECL (TREE_TYPE (decl)) == decl
-         && TYPE_SIZE (TREE_TYPE (decl)) == NULL_TREE)
-       TYPE_DECL_SUPPRESS_DEBUG (decl) = 1;
-
-      rest_of_decl_compilation (decl, NULL_PTR,
-                               DECL_CONTEXT (decl) == NULL_TREE, at_eof);
-      goto finish_end;
-    }
-
-  if (TREE_CODE (decl) != FUNCTION_DECL)
-    ttype = target_type (type);
-
-  if (! DECL_EXTERNAL (decl) && TREE_READONLY (decl)
-      && TYPE_NEEDS_CONSTRUCTING (type))
-    {
-      /* Currently, GNU C++ puts constants in text space, making them
-        impossible to initialize.  In the future, one would hope for
-        an operating system which understood the difference between
-        initialization and the running of a program.  */
-      was_readonly = 1;
-      TREE_READONLY (decl) = 0;
-    }
-
-  if (TREE_CODE (decl) == FIELD_DECL)
-    {
-      if (init && init != error_mark_node)
-       my_friendly_assert (TREE_PERMANENT (init), 147);
-
-      if (asmspec)
-       {
-         /* This must override the asm specifier which was placed
-            by grokclassfn.  Lay this out fresh.  */
-         DECL_RTL (TREE_TYPE (decl)) = NULL_RTX;
-         DECL_ASSEMBLER_NAME (decl) = get_identifier (asmspec);
-         make_decl_rtl (decl, asmspec, 0);
-       }
-    }
-  /* If `start_decl' didn't like having an initialization, ignore it now.  */
-  else if (init != NULL_TREE && DECL_INITIAL (decl) == NULL_TREE)
-    init = NULL_TREE;
-  else if (DECL_EXTERNAL (decl))
-    ;
-  else if (TREE_CODE (type) == REFERENCE_TYPE
-          || (TYPE_LANG_SPECIFIC (type) && IS_SIGNATURE_REFERENCE (type)))
-    {
-      if (TREE_STATIC (decl))
-       make_decl_rtl (decl, NULL_PTR,
-                      toplevel_bindings_p ()
-                      || pseudo_global_level_p ());
-      grok_reference_init (decl, type, init);
-      init = NULL_TREE;
-    }
-
-  /* Check for certain invalid initializations.  */
-  if (init)
-    {
-      if (TYPE_SIZE (type) && !TREE_CONSTANT (TYPE_SIZE (type)))
-       {
-         cp_error ("variable-sized object `%D' may not be initialized", decl);
-         init = NULL_TREE;
-       }
-      if (TREE_CODE (type) == ARRAY_TYPE
-         && !TYPE_SIZE (complete_type (TREE_TYPE (type))))
-       {
-         cp_error ("elements of array `%#D' have incomplete type", decl);
-         init = NULL_TREE;
-       }
-    }
-
-  GNU_xref_decl (current_function_decl, decl);
-
-  core_type = type;
-  while (TREE_CODE (core_type) == ARRAY_TYPE)
-    core_type = TREE_TYPE (core_type);
-  
-  if (TREE_CODE (decl) == FIELD_DECL)
-    ;
-  else if (TREE_CODE (decl) == CONST_DECL)
-    {
-      my_friendly_assert (TREE_CODE (decl) != REFERENCE_TYPE, 148);
-
-      DECL_INITIAL (decl) = init;
-
-      /* This will keep us from needing to worry about our obstacks.  */
-      my_friendly_assert (init != NULL_TREE, 149);
-      init = NULL_TREE;
-    }
-  else if (init)
+  else if (init)
     {
       if (TYPE_HAS_CONSTRUCTOR (type) || TYPE_NEEDS_CONSTRUCTING (type))
        {
@@ -7964,6 +7309,8 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
   else if (TREE_CODE_CLASS (TREE_CODE (type)) == 't'
           && (IS_AGGR_TYPE (type) || TYPE_NEEDS_CONSTRUCTING (type)))
     {
+      tree core_type = strip_array_types (type);
+
       if (! TYPE_NEEDS_CONSTRUCTING (core_type))
        {
          if (CLASSTYPE_READONLY_FIELDS_NEED_INIT (core_type))
@@ -7983,276 +7330,454 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
   else
     check_for_uninitialized_const_var (decl);
   
-  /* For top-level declaration, the initial value was read in
-     the temporary obstack.  MAXINDEX, rtl, etc. to be made below
-     must go in the permanent obstack; but don't discard the
-     temporary data yet.  */
+  return init;
+}
 
-  if (toplevel_bindings_p () && temporary)
-    end_temporary_allocation ();
+/* If DECL is not a local variable, give it RTL.  */
 
-  /* Deduce size of array from initialization, if not already known.  */
+static void
+make_rtl_for_nonlocal_decl (decl, init, asmspec)
+     tree decl;
+     tree init;
+     const char *asmspec;
+{
+  int toplev;
+  tree type;
 
-  if (TREE_CODE (type) == ARRAY_TYPE
-      && TYPE_DOMAIN (type) == NULL_TREE
-      && TREE_CODE (decl) != TYPE_DECL)
+  type = TREE_TYPE (decl);
+  toplev = toplevel_bindings_p ();
+
+  /* Handle non-variables up front.  */
+  if (TREE_CODE (decl) != VAR_DECL)
     {
-      int do_default
-       = (TREE_STATIC (decl)
-          /* Even if pedantic, an external linkage array
-             may have incomplete type at first.  */
-          ? pedantic && ! DECL_EXTERNAL (decl)
-          : !DECL_EXTERNAL (decl));
-      tree initializer = init ? init : DECL_INITIAL (decl);
-      int failure = complete_array_type (type, initializer, do_default);
+      rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
+      return;
+    }
 
-      if (failure == 1)
-       cp_error ("initializer fails to determine size of `%D'", decl);
+  /* Set the DECL_ASSEMBLER_NAME for the variable.  */
+  if (asmspec)
+    DECL_ASSEMBLER_NAME (decl) = get_identifier (asmspec);
 
-      if (failure == 2)
+  if (DECL_VIRTUAL_P (decl))
+    make_decl_rtl (decl, NULL_PTR, toplev);
+  else if (TREE_READONLY (decl)
+          && DECL_INITIAL (decl) != NULL_TREE
+          && DECL_INITIAL (decl) != error_mark_node
+          && ! EMPTY_CONSTRUCTOR_P (DECL_INITIAL (decl)))
+    {
+      DECL_INITIAL (decl) = save_expr (DECL_INITIAL (decl));
+
+      if (! toplev
+         && TREE_STATIC (decl)
+         && ! TREE_SIDE_EFFECTS (decl)
+         && ! TREE_PUBLIC (decl)
+         && ! DECL_EXTERNAL (decl)
+         && ! TYPE_NEEDS_DESTRUCTOR (type)
+         && DECL_MODE (decl) != BLKmode)
+       {
+         /* If this variable is really a constant, then fill its DECL_RTL
+            slot with something which won't take up storage.
+            If something later should take its address, we can always give
+            it legitimate RTL at that time.  */
+         DECL_RTL (decl) = gen_reg_rtx (DECL_MODE (decl));
+         store_expr (DECL_INITIAL (decl), DECL_RTL (decl), 0);
+         TREE_ASM_WRITTEN (decl) = 1;
+       }
+      else if (toplev && ! TREE_PUBLIC (decl))
        {
-         if (do_default)
-           cp_error ("array size missing in `%D'", decl);
-         /* If a `static' var's size isn't known, make it extern as
-            well as static, so it does not get allocated.  If it's not
-            `static', then don't mark it extern; finish_incomplete_decl
-            will give it a default size and it will get allocated.  */
-         else if (!pedantic && TREE_STATIC (decl) && !TREE_PUBLIC (decl))
-           DECL_EXTERNAL (decl) = 1;
+         /* If this is a static const, change its apparent linkage
+            if it belongs to a #pragma interface.  */
+         if (!interface_unknown)
+           {
+             TREE_PUBLIC (decl) = 1;
+             DECL_EXTERNAL (decl) = interface_only;
+           }
+         make_decl_rtl (decl, asmspec, toplev);
        }
-
-      if (pedantic && TYPE_DOMAIN (type) != NULL_TREE
-         && tree_int_cst_lt (TYPE_MAX_VALUE (TYPE_DOMAIN (type)),
-                             integer_zero_node))
-       cp_error ("zero-size array `%D'", decl);
-
-      layout_decl (decl, 0);
+      else if (toplev)
+       rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
     }
-
-  if (TREE_CODE (decl) == VAR_DECL)
+  else if (DECL_LANG_SPECIFIC (decl) && DECL_IN_AGGR_P (decl))
     {
-      if (DECL_SIZE (decl) == NULL_TREE
-         && TYPE_SIZE (complete_type (TREE_TYPE (decl))) != NULL_TREE)
-       layout_decl (decl, 0);
+      my_friendly_assert (TREE_STATIC (decl), 19990828);
 
-      if (TREE_STATIC (decl) && DECL_SIZE (decl) == NULL_TREE)
-       {
-         /* A static variable with an incomplete type:
-            that is an error if it is initialized.
-            Otherwise, let it through, but if it is not `extern'
-            then it may cause an error message later.  */
-         if (DECL_INITIAL (decl) != NULL_TREE)
-           cp_error ("storage size of `%D' isn't known", decl);
-         init = NULL_TREE;
-       }
-      else if (!DECL_EXTERNAL (decl) && DECL_SIZE (decl) == NULL_TREE)
+      if (init == NULL_TREE
+#ifdef DEFAULT_STATIC_DEFS
+         /* If this code is dead, then users must
+            explicitly declare static member variables
+            outside the class def'n as well.  */
+         && TYPE_NEEDS_CONSTRUCTING (type)
+#endif
+         )
        {
-         /* An automatic variable with an incomplete type: that is an error.
-            Don't talk about array types here, since we took care of that
-            message in grokdeclarator.  */
-         cp_error ("storage size of `%D' isn't known", decl);
-         TREE_TYPE (decl) = error_mark_node;
+         DECL_EXTERNAL (decl) = 1;
+         make_decl_rtl (decl, asmspec, 1);
        }
-      else if (!DECL_EXTERNAL (decl) && IS_AGGR_TYPE (ttype))
-       /* Let debugger know it should output info for this type.  */
-       note_debug_info_needed (ttype);
+      else
+       rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
+    }
+  else if (TREE_CODE (CP_DECL_CONTEXT (decl)) == NAMESPACE_DECL
+          || (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl)))
+    rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
+}
 
-      if (TREE_STATIC (decl) && DECL_CLASS_SCOPE_P (decl))
-       note_debug_info_needed (DECL_CONTEXT (decl));
+/* The old ARM scoping rules injected variables declared in the
+   initialization statement of a for-statement into the surrounding
+   scope.  We support this usage, in order to be backward-compatible.
+   DECL is a just-declared VAR_DECL; if necessary inject its
+   declaration into the surrounding scope.  */
 
-      if ((DECL_EXTERNAL (decl) || TREE_STATIC (decl))
-         && DECL_SIZE (decl) != NULL_TREE
-         && ! TREE_CONSTANT (DECL_SIZE (decl)))
+void
+maybe_inject_for_scope_var (decl)
+     tree decl;
+{
+  if (current_binding_level->is_for_scope)
+    {
+      struct binding_level *outer 
+       = current_binding_level->level_chain;
+
+      /* Check to see if the same name is already bound at the outer
+        level, either because it was directly declared, or because a
+        dead for-decl got preserved.  In either case, the code would
+        not have been valid under the ARM scope rules, so clear
+        is_for_scope for the current_binding_level.
+
+        Otherwise, we need to preserve the temp slot for decl to last
+        into the outer binding level.  */
+
+      tree outer_binding 
+       = TREE_CHAIN (IDENTIFIER_BINDING (DECL_NAME (decl)));
+             
+      if (outer_binding && BINDING_LEVEL (outer_binding) == outer
+         && (TREE_CODE (BINDING_VALUE (outer_binding)) 
+             == VAR_DECL)
+         && DECL_DEAD_FOR_LOCAL (BINDING_VALUE (outer_binding)))
        {
-         if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST)
-           constant_expression_warning (DECL_SIZE (decl));
-         else
-           cp_error ("storage size of `%D' isn't constant", decl);
+         BINDING_VALUE (outer_binding)
+           = DECL_SHADOWED_FOR_VAR (BINDING_VALUE (outer_binding));
+         current_binding_level->is_for_scope = 0;
        }
+      else if (DECL_IN_MEMORY_P (decl))
+       preserve_temp_slots (DECL_RTL (decl));
+    }
+}
 
-      if (! DECL_EXTERNAL (decl) && TYPE_NEEDS_DESTRUCTOR (type)
-         /* Cleanups for static variables are handled by `finish_file'.  */
-         && ! TREE_STATIC (decl))
+/* Generate code to initialize DECL (a local variable).  */
+
+void
+initialize_local_var (decl, init, flags)
+     tree decl;
+     tree init;
+     int flags;
+{
+  tree type = TREE_TYPE (decl);
+
+  /* If the type is bogus, don't bother initializing the variable.  */
+  if (type == error_mark_node)
+    return;
+
+  if (DECL_SIZE (decl) == NULL_TREE && !TREE_STATIC (decl))
+    {
+      /* If we used it already as memory, it must stay in memory.  */
+      DECL_INITIAL (decl) = NULL_TREE;
+      TREE_ADDRESSABLE (decl) = TREE_USED (decl);
+    }
+
+  /* Local statics are handled differently from ordinary automatic
+     variables.  */
+  if (TREE_STATIC (decl))
+    {
+      if (TYPE_NEEDS_CONSTRUCTING (type) || init != NULL_TREE
+         || TYPE_NEEDS_DESTRUCTOR (type))
+       expand_static_init (decl, init);
+      return;
+    }
+
+  if (DECL_SIZE (decl) && type != error_mark_node)
+    {
+      int already_used;
+  
+      /* Compute and store the initial value.  */
+      already_used = TREE_USED (decl) || TREE_USED (type);
+
+      if (init || TYPE_NEEDS_CONSTRUCTING (type))
        {
-         int yes = suspend_momentary ();
-         cleanup = maybe_build_cleanup (decl);
-         resume_momentary (yes);
+         int saved_stmts_are_full_exprs_p;
+
+         emit_line_note (DECL_SOURCE_FILE (decl),
+                         DECL_SOURCE_LINE (decl));
+         saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p;
+         stmts_are_full_exprs_p = 1;
+         finish_expr_stmt (build_aggr_init (decl, init, flags));
+         stmts_are_full_exprs_p = saved_stmts_are_full_exprs_p;
        }
+
+      /* Set this to 0 so we can tell whether an aggregate which was
+        initialized was ever used.  Don't do this if it has a
+        destructor, so we don't complain about the 'resource
+        allocation is initialization' idiom.  Now set
+        attribute((unused)) on types so decls of that type will be
+        marked used. (see TREE_USED, above.)  */
+      if (TYPE_NEEDS_CONSTRUCTING (type)
+         && ! already_used
+         && !TYPE_NEEDS_DESTRUCTOR (type) 
+         && DECL_NAME (decl))
+       TREE_USED (decl) = 0;
+      else if (already_used)
+       TREE_USED (decl) = 1;
     }
-  /* PARM_DECLs get cleanups, too.  */
-  else if (TREE_CODE (decl) == PARM_DECL && TYPE_NEEDS_DESTRUCTOR (type))
+}
+
+/* Generate code to destroy DECL (a local variable).  */
+
+void 
+destroy_local_var (decl)
+     tree decl;
+{
+  tree type = TREE_TYPE (decl);
+  tree cleanup;
+
+  /* Only variables get cleaned up.  */
+  if (TREE_CODE (decl) != VAR_DECL)
+    return;
+  
+  /* And only things with destructors need cleaning up.  */
+  if (!TYPE_NEEDS_DESTRUCTOR (type))
+    return;
+
+  if (TREE_CODE (decl) == VAR_DECL &&
+      (DECL_EXTERNAL (decl) || TREE_STATIC (decl)))
+    /* We don't clean up things that aren't defined in this
+       translation unit, or that need a static cleanup.  The latter
+       are handled by finish_file.  */
+    return;
+  
+  /* Compute the cleanup.  */
+  cleanup = maybe_build_cleanup (decl);
+
+  /* Record the cleanup required for this declaration.  */
+  if (DECL_SIZE (decl) && TREE_TYPE (decl) != error_mark_node
+      && cleanup)
+    finish_decl_cleanup (decl, cleanup);
+}
+
+/* Let the back-end know about DECL.  */
+
+void
+emit_local_var (decl)
+     tree decl;
+{
+  /* 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
     {
-      if (temporary)
-       end_temporary_allocation ();
-      cleanup = maybe_build_cleanup (decl);
-      if (temporary)
-       resume_temporary_allocation ();
+      if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl))
+       /* The user must have specified an assembler name for this
+          variable.  Set that up now.  */
+       rest_of_decl_compilation 
+         (decl, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
+          /*top_level=*/0, /*at_end=*/0);
+      else
+       expand_decl (decl);
     }
 
-  /* Output the assembler code and/or RTL code for variables and functions,
-     unless the type is an undefined structure or union.
-     If not, it will get done when the type is completed.  */
+  /* Actually do the initialization.  */
+  expand_start_target_temps ();
+  expand_decl_init (decl);
+  expand_end_target_temps ();
+}
 
-  was_incomplete = (DECL_SIZE (decl) == NULL_TREE);
+/* Finish processing of a declaration;
+   install its line number and initial value.
+   If the length of an array type is not known before,
+   it must be determined now, from the initial value, or it is an error.
 
-  if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL
-      || TREE_CODE (decl) == RESULT_DECL)
+   Call `pop_obstacks' iff NEED_POP is nonzero.
+
+   For C++, `cp_finish_decl' must be fairly evasive:  it must keep initializers
+   for aggregates that have constructors alive on the permanent obstack,
+   so that the global initializing functions can be written at the end.
+
+   INIT0 holds the value of an initializer that should be allowed to escape
+   the normal rules.
+
+   FLAGS is LOOKUP_ONLYCONVERTING is the = init syntax was used, else 0
+   if the (init) syntax was used.
+
+   For functions that take default parameters, DECL points to its
+   "maximal" instantiation.  `cp_finish_decl' must then also declared its
+   subsequently lower and lower forms of instantiation, checking for
+   ambiguity as it goes.  This can be sped up later.  */
+
+void
+cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
+     tree decl, init;
+     tree asmspec_tree;
+     int need_pop;
+     int flags;
+{
+  register tree type;
+  tree ttype = NULL_TREE;
+  int temporary = allocation_temporary_p ();
+  const char *asmspec = NULL;
+  int was_readonly = 0;
+
+  /* If this is 0, then we did not change obstacks.  */
+  if (! decl)
     {
-      /* ??? FIXME: What about nested classes?  */
-      int toplev = toplevel_bindings_p () || pseudo_global_level_p ();
-      int was_temp
-       = (TREE_STATIC (decl) && TYPE_NEEDS_DESTRUCTOR (type)
-          && allocation_temporary_p ());
+      if (init)
+       error ("assignment (not initialization) in declaration");
+      return;
+    }
+
+  /* If a name was specified, get the string.  */
+  if (asmspec_tree)
+      asmspec = TREE_STRING_POINTER (asmspec_tree);
 
-      if (was_temp)
+  if (init && TREE_CODE (init) == NAMESPACE_DECL)
+    {
+      cp_error ("Cannot initialize `%D' to namespace `%D'",
+               decl, init);
+      init = NULL_TREE;
+    }
+
+  if (current_class_type
+      && DECL_REAL_CONTEXT (decl) == current_class_type
+      && TYPE_BEING_DEFINED (current_class_type)
+      && (DECL_INITIAL (decl) || init))
+    DECL_DEFINED_IN_CLASS_P (decl) = 1;
+
+  if (TREE_CODE (decl) == VAR_DECL 
+      && DECL_CONTEXT (decl)
+      && TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL
+      && DECL_CONTEXT (decl) != current_namespace
+      && init)
+    {
+      /* Leave the namespace of the object. */
+      pop_decl_namespace ();
+    }
+
+  type = TREE_TYPE (decl);
+
+  if (type == error_mark_node)
+    {
+      if (toplevel_bindings_p () && temporary)
        end_temporary_allocation ();
 
-      /* Static data in a function with comdat linkage also has comdat
-         linkage.  */
-      if (TREE_CODE (decl) == VAR_DECL
-         && TREE_STATIC (decl)
-         /* Don't mess with __FUNCTION__.  */
-         && ! TREE_ASM_WRITTEN (decl)
-         && current_function_decl
-         && DECL_CONTEXT (decl) == current_function_decl
-         && (DECL_THIS_INLINE (current_function_decl)
-             || DECL_TEMPLATE_INSTANTIATION (current_function_decl))
-         && TREE_PUBLIC (current_function_decl))
-       {
-         /* Rather than try to get this right with inlining, we suppress
-            inlining of such functions.  */
-         current_function_cannot_inline
-           = "function with static variable cannot be inline";
-
-         /* If flag_weak, we don't need to mess with this, as we can just
-            make the function weak, and let it refer to its unique local
-            copy.  This works because we don't allow the function to be
-            inlined.  */
-         if (! flag_weak)
-           {
-             if (DECL_INTERFACE_KNOWN (current_function_decl))
-               {
-                 TREE_PUBLIC (decl) = 1;
-                 DECL_EXTERNAL (decl) = DECL_EXTERNAL (current_function_decl);
-               }
-             else if (DECL_INITIAL (decl) == NULL_TREE
-                      || DECL_INITIAL (decl) == error_mark_node)
-               {
-                 TREE_PUBLIC (decl) = 1;
-                 DECL_COMMON (decl) = 1;
-               }
-             /* else we lose. We can only do this if we can use common,
-                 which we can't if it has been initialized.  */
+      return;
+    }
 
-             if (TREE_PUBLIC (decl))
-               DECL_ASSEMBLER_NAME (decl)
-                 = build_static_name (current_function_decl, DECL_NAME (decl));
-             else if (! DECL_ARTIFICIAL (decl))
-               {
-                 cp_warning_at ("sorry: semantics of inline function static data `%#D' are wrong (you'll wind up with multiple copies)", decl);
-                 cp_warning_at ("  you can work around this by removing the initializer", decl);
-               }
-           }
-       }
+  /* Add this declaration to the statement-tree.  */
+  if (building_stmt_tree () 
+      && TREE_CODE (current_scope ()) == FUNCTION_DECL)
+    add_decl_stmt (decl);
 
-      else if (TREE_CODE (decl) == VAR_DECL
-              && DECL_LANG_SPECIFIC (decl)
-              && DECL_COMDAT (decl))
-       /* Set it up again; we might have set DECL_INITIAL since the
-          last time.  */
-       comdat_linkage (decl);
-
-      if (TREE_CODE (decl) == VAR_DECL && DECL_VIRTUAL_P (decl))
-       make_decl_rtl (decl, NULL_PTR, toplev);
-      else if (TREE_CODE (decl) == VAR_DECL
-              && TREE_READONLY (decl)
-              && DECL_INITIAL (decl) != NULL_TREE
-              && DECL_INITIAL (decl) != error_mark_node
-              && ! EMPTY_CONSTRUCTOR_P (DECL_INITIAL (decl)))
-       {
-         DECL_INITIAL (decl) = save_expr (DECL_INITIAL (decl));
-
-         if (asmspec)
-           DECL_ASSEMBLER_NAME (decl) = get_identifier (asmspec);
-
-         if (! toplev
-             && TREE_STATIC (decl)
-             && ! TREE_SIDE_EFFECTS (decl)
-             && ! TREE_PUBLIC (decl)
-             && ! DECL_EXTERNAL (decl)
-             && ! TYPE_NEEDS_DESTRUCTOR (type)
-             && DECL_MODE (decl) != BLKmode)
-           {
-             /* If this variable is really a constant, then fill its DECL_RTL
-                slot with something which won't take up storage.
-                If something later should take its address, we can always give
-                it legitimate RTL at that time.  */
-             DECL_RTL (decl) = gen_reg_rtx (DECL_MODE (decl));
-             store_expr (DECL_INITIAL (decl), DECL_RTL (decl), 0);
-             TREE_ASM_WRITTEN (decl) = 1;
-           }
-         else if (toplev && ! TREE_PUBLIC (decl))
-           {
-             /* If this is a static const, change its apparent linkage
-                if it belongs to a #pragma interface.  */
-             if (!interface_unknown)
-               {
-                 TREE_PUBLIC (decl) = 1;
-                 DECL_EXTERNAL (decl) = interface_only;
-               }
-             make_decl_rtl (decl, asmspec, toplev);
-           }
-         else
-           rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
+  if (TYPE_HAS_MUTABLE_P (type))
+    TREE_READONLY (decl) = 0;
+
+  if (processing_template_decl)
+    {
+      if (init && DECL_INITIAL (decl))
+       DECL_INITIAL (decl) = init;
+      goto finish_end0;
+    }
+
+  /* Parameters are handled by store_parm_decls, not cp_finish_decl.  */
+  my_friendly_assert (TREE_CODE (decl) != PARM_DECL, 19990828);
+
+  /* Take care of TYPE_DECLs up front.  */
+  if (TREE_CODE (decl) == TYPE_DECL)
+    {
+      if (init && DECL_INITIAL (decl))
+       {
+         /* typedef foo = bar; store the type of bar as the type of foo.  */
+         TREE_TYPE (decl) = type = TREE_TYPE (init);
+         DECL_INITIAL (decl) = init = NULL_TREE;
        }
-      else if (TREE_CODE (decl) == VAR_DECL
-              && DECL_LANG_SPECIFIC (decl)
-              && DECL_IN_AGGR_P (decl))
+      if (type != error_mark_node
+         && IS_AGGR_TYPE (type) && DECL_NAME (decl))
        {
-         if (TREE_STATIC (decl))
-           {
-             if (init == NULL_TREE
-#ifdef DEFAULT_STATIC_DEFS
-                 /* If this code is dead, then users must
-                    explicitly declare static member variables
-                    outside the class def'n as well.  */
-                 && TYPE_NEEDS_CONSTRUCTING (type)
-#endif
-                 )
-               {
-                 DECL_EXTERNAL (decl) = 1;
-                 make_decl_rtl (decl, asmspec, 1);
-               }
-             else
-               rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
-           }
-         else
-           /* Just a constant field.  Should not need any rtl.  */
-           goto finish_end0;
+         if (TREE_TYPE (DECL_NAME (decl)) && TREE_TYPE (decl) != type)
+           cp_warning ("shadowing previous type declaration of `%#D'", decl);
+         set_identifier_type_value (DECL_NAME (decl), type);
+         CLASSTYPE_GOT_SEMICOLON (type) = 1;
        }
-      else
-       rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
+      GNU_xref_decl (current_function_decl, decl);
 
-      if (was_temp)
-       resume_temporary_allocation ();
+      /* If we have installed this as the canonical typedef for this
+        type, and that type has not been defined yet, delay emitting
+        the debug information for it, as we will emit it later.  */
+      if (TYPE_MAIN_DECL (TREE_TYPE (decl)) == decl
+         && TYPE_SIZE (TREE_TYPE (decl)) == NULL_TREE)
+       TYPE_DECL_SUPPRESS_DEBUG (decl) = 1;
 
-      if (type != error_mark_node
-         && TYPE_LANG_SPECIFIC (core_type)
-         && CLASSTYPE_ABSTRACT_VIRTUALS (core_type))
-       abstract_virtuals_error (decl, core_type);
-      else if ((TREE_CODE (type) == FUNCTION_TYPE
-               || TREE_CODE (type) == METHOD_TYPE)
-              && TYPE_LANG_SPECIFIC (TREE_TYPE (type))
-              && CLASSTYPE_ABSTRACT_VIRTUALS (TREE_TYPE (type)))
-       abstract_virtuals_error (decl, TREE_TYPE (type));
-
-      if (TYPE_LANG_SPECIFIC (core_type) && IS_SIGNATURE (core_type))
-       signature_error (decl, core_type);
-      else if ((TREE_CODE (type) == FUNCTION_TYPE
-               || TREE_CODE (type) == METHOD_TYPE)
-              && TYPE_LANG_SPECIFIC (TREE_TYPE (type))
-              && IS_SIGNATURE (TREE_TYPE (type)))
-       signature_error (decl, TREE_TYPE (type));
+      rest_of_decl_compilation (decl, NULL_PTR,
+                               DECL_CONTEXT (decl) == NULL_TREE, at_eof);
+      goto finish_end;
+    }
+
+  if (TREE_CODE (decl) != FUNCTION_DECL)
+    ttype = target_type (type);
+
+  if (! DECL_EXTERNAL (decl) && TREE_READONLY (decl)
+      && TYPE_NEEDS_CONSTRUCTING (type))
+    {
+      /* Currently, GNU C++ puts constants in text space, making them
+        impossible to initialize.  In the future, one would hope for
+        an operating system which understood the difference between
+        initialization and the running of a program.  */
+      was_readonly = 1;
+      TREE_READONLY (decl) = 0;
+    }
+
+  if (TREE_CODE (decl) == FIELD_DECL && asmspec)
+    {
+      /* This must override the asm specifier which was placed by
+        grokclassfn.  Lay this out fresh.  */
+      DECL_RTL (TREE_TYPE (decl)) = NULL_RTX;
+      DECL_ASSEMBLER_NAME (decl) = get_identifier (asmspec);
+      make_decl_rtl (decl, asmspec, 0);
+    }
+
+  /* Deduce size of array from initialization, if not already known.  */
+  maybe_deduce_size_from_array_init (decl, init);
+  init = check_initializer (decl, init);
+
+  GNU_xref_decl (current_function_decl, decl);
+
+  /* For top-level declaration, the initial value was read in
+     the temporary obstack.  MAXINDEX, rtl, etc. to be made below
+     must go in the permanent obstack; but don't discard the
+     temporary data yet.  */
+
+  if (toplevel_bindings_p () && temporary)
+    end_temporary_allocation ();
+
+  if (TREE_CODE (decl) == VAR_DECL)
+    layout_var_decl (decl);
+
+  /* Output the assembler code and/or RTL code for variables and functions,
+     unless the type is an undefined structure or union.
+     If not, it will get done when the type is completed.  */
+  if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL
+      || TREE_CODE (decl) == RESULT_DECL)
+    {
+      if (TREE_CODE (decl) == VAR_DECL)
+       maybe_commonize_var (decl);
+
+      make_rtl_for_nonlocal_decl (decl, init, asmspec);
+
+      if (TREE_CODE (type) == FUNCTION_TYPE 
+         || TREE_CODE (type) == METHOD_TYPE)
+       abstract_virtuals_error (decl, 
+                                strip_array_types (TREE_TYPE (type)));
+      else 
+       abstract_virtuals_error (decl, strip_array_types (type));
 
       if (TREE_CODE (decl) == FUNCTION_DECL)
        ;
@@ -8263,6 +7788,31 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
          if (init)
            DECL_INITIAL (decl) = init;
        }
+      else if (TREE_CODE (CP_DECL_CONTEXT (decl)) == FUNCTION_DECL)
+       {
+         /* This is a local declaration.  */
+         if (doing_semantic_analysis_p ())
+           maybe_inject_for_scope_var (decl);
+         /* Initialize the local variable.  But, if we're building a
+            statement-tree, we'll do the initialization when we
+            expand the tree.  */
+         if (processing_template_decl)
+           {
+             if (init || DECL_INITIAL (decl) == error_mark_node)
+               DECL_INITIAL (decl) = init;
+           }
+         else
+           {
+             /* If we're not building RTL, then we need to do so
+                now.  */
+             if (!building_stmt_tree ())
+               emit_local_var (decl);
+             /* Initialize the variable.  */
+             initialize_local_var (decl, init, flags);
+             /* Clean up the variable.  */
+             destroy_local_var (decl);
+           }
+       }
       else if (TREE_STATIC (decl) && type != error_mark_node)
        {
          /* Cleanups for static variables are handled by `finish_file'.  */
@@ -8270,121 +7820,6 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
              || TYPE_NEEDS_DESTRUCTOR (type))
            expand_static_init (decl, init);
        }
-      else if (! toplev)
-       {
-         /* This is a declared decl which must live until the
-            end of the binding contour.  It may need a cleanup.  */
-
-         /* Recompute the RTL of a local array now
-            if it used to be an incomplete type.  */
-         if (was_incomplete && ! TREE_STATIC (decl))
-           {
-             /* If we used it already as memory, it must stay in memory.  */
-             TREE_ADDRESSABLE (decl) = TREE_USED (decl);
-             /* If it's still incomplete now, no init will save it.  */
-             if (DECL_SIZE (decl) == NULL_TREE)
-               DECL_INITIAL (decl) = NULL_TREE;
-             expand_decl (decl);
-           }
-         else if (! TREE_ASM_WRITTEN (decl)
-                  && (TYPE_SIZE (type) != NULL_TREE
-                      || TREE_CODE (type) == ARRAY_TYPE))
-           {
-             /* Do this here, because we did not expand this decl's
-                rtl in start_decl.  */
-             if (DECL_RTL (decl) == NULL_RTX)
-               expand_decl (decl);
-             else if (cleanup)
-               {
-                 /* XXX: Why don't we use decl here?  */
-                 /* Ans: Because it was already expanded? */
-                 if (! expand_decl_cleanup (NULL_TREE, cleanup))
-                   cp_error ("parser lost in parsing declaration of `%D'",
-                             decl);
-                 /* Cleanup used up here.  */
-                 cleanup = NULL_TREE;
-               }
-           }
-
-         if (current_binding_level->is_for_scope)
-           {
-             struct binding_level *outer 
-               = current_binding_level->level_chain;
-
-             /* Check to see if the same name is already bound at
-                the outer level, either because it was directly declared,
-                or because a dead for-decl got preserved.  In either case,
-                the code would not have been valid under the ARM
-                scope rules, so clear is_for_scope for the
-                current_binding_level.
-
-                Otherwise, we need to preserve the temp slot for decl
-                to last into the outer binding level.  */
-
-             tree outer_binding 
-               = TREE_CHAIN (IDENTIFIER_BINDING (DECL_NAME (decl)));
-             
-             if (outer_binding && BINDING_LEVEL (outer_binding) == outer
-                 && (TREE_CODE (BINDING_VALUE (outer_binding)) 
-                     == VAR_DECL)
-                 && DECL_DEAD_FOR_LOCAL (BINDING_VALUE (outer_binding)))
-               {
-                 BINDING_VALUE (outer_binding)
-                   = DECL_SHADOWED_FOR_VAR (BINDING_VALUE (outer_binding));
-                 current_binding_level->is_for_scope = 0;
-               }
-             else if (DECL_IN_MEMORY_P (decl))
-               preserve_temp_slots (DECL_RTL (decl));
-           }
-
-         expand_start_target_temps ();
-
-         if (DECL_SIZE (decl) && type != error_mark_node)
-           {
-             /* Compute and store the initial value.  */
-             expand_decl_init (decl);
-                     already_used = TREE_USED (decl) || TREE_USED (type);
-
-             if (init || TYPE_NEEDS_CONSTRUCTING (type))
-               {
-                 emit_line_note (DECL_SOURCE_FILE (decl),
-                                 DECL_SOURCE_LINE (decl));
-                 expand_aggr_init (decl, init, flags);
-               }
-
-             /* Set this to 0 so we can tell whether an aggregate which
-                was initialized was ever used.  Don't do this if it has a
-                destructor, so we don't complain about the 'resource
-                allocation is initialization' idiom.  */
-             /* Now set attribute((unused)) on types so decls of
-                that type will be marked used. (see TREE_USED, above.) 
-                This avoids the warning problems this particular code
-                tried to work around. */
-
-             if (TYPE_NEEDS_CONSTRUCTING (type)
-                 && ! already_used
-                 && cleanup == NULL_TREE
-                 && DECL_NAME (decl))
-               TREE_USED (decl) = 0;
-
-             if (already_used)
-               TREE_USED (decl) = 1;
-           }
-
-         /* Cleanup any temporaries needed for the initial value.  */
-         expand_end_target_temps ();
-
-         if (DECL_SIZE (decl) && type != error_mark_node)
-           {
-             /* Store the cleanup, if there was one.  */
-             if (cleanup)
-               {
-                 if (! expand_decl_cleanup (decl, cleanup))
-                   cp_error ("parser lost in parsing declaration of `%D'",
-                             decl);
-               }
-           }
-       }
     finish_end0:
 
       /* Undo call to `pushclass' that was done in `start_decl'
@@ -8428,12 +7863,10 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
     }
 
   if (need_pop)
-    {
-      /* Resume permanent allocation, if not within a function.  */
-      /* The corresponding push_obstacks_nochange is in start_decl,
-        start_method, groktypename, and in grokfield.  */
-      pop_obstacks ();
-    }
+    /* Resume permanent allocation, if not within a function.  The
+       corresponding push_obstacks_nochange is in start_decl,
+       start_method, groktypename, and in grokfield.  */
+    pop_obstacks ();
 
   if (was_readonly)
     TREE_READONLY (decl) = 1;
@@ -8449,6 +7882,75 @@ finish_decl (decl, init, asmspec_tree)
   cp_finish_decl (decl, init, asmspec_tree, 1, 0);
 }
 
+/* Generate code to handle the destruction of the function-scoped
+   static variable DECL.  */
+
+static void
+destroy_local_static (decl)
+     tree decl;
+{
+  tree cleanup, fcall;
+  tree compound_stmt;
+  int saved_flag_access_control;
+
+  if (atexit_node == 0)
+    {
+      tree atexit_fndecl, PFV, pfvlist;
+      /* Remember this information until end of file.  */
+      push_obstacks (&permanent_obstack, &permanent_obstack);
+      PFV = build_pointer_type (build_function_type
+                               (void_type_node, void_list_node));
+
+      pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
+
+      push_lang_context (lang_name_c);
+      /* Note that we do not call pushdecl for this function;
+        there's no reason that this declaration should be
+        accessible to anyone.  */
+      atexit_fndecl
+       = define_function ("atexit",
+                          build_function_type (void_type_node,
+                                               pfvlist),
+                          /*pfn=*/0, NULL_PTR);
+      mark_used (atexit_fndecl);
+      atexit_node = default_conversion (atexit_fndecl);
+      pop_lang_context ();
+      pop_obstacks ();
+    }
+             
+  /* Call build_cleanup before we enter the anonymous function so that
+     any access checks will be done relative to the current scope,
+     rather than the scope of the anonymous function.  */
+  build_cleanup (decl);
+
+  /* Now start the function.  */
+  cleanup = start_anon_func ();
+
+  /* Now, recompute the cleanup.  It may contain SAVE_EXPRs that refer
+     to the original function, rather than the anonymous one.  That
+     will make the back-end think that nested functions are in use,
+     which causes confusion.  */
+  saved_flag_access_control = flag_access_control;
+  flag_access_control = 0;
+  fcall = build_cleanup (decl);
+  flag_access_control = saved_flag_access_control;
+
+  /* Create the body of the anonymous function.  */
+  compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
+  finish_expr_stmt (fcall);
+  finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
+  end_anon_func ();
+
+  /* Call atexit with the cleanup function.  */
+  mark_addressable (cleanup);
+  cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
+  fcall = build_function_call (atexit_node,
+                              tree_cons (NULL_TREE, 
+                                         cleanup, 
+                                         NULL_TREE));
+  finish_expr_stmt (fcall);
+}
+
 void
 expand_static_init (decl, init)
      tree decl;
@@ -8465,6 +7967,10 @@ expand_static_init (decl, init)
     {
       /* Emit code to perform this initialization but once.  */
       tree temp;
+      tree if_stmt;
+      tree then_clause;
+      tree assignment;
+      tree temp_init;
 
       /* Remember this information until end of file.  */
       push_obstacks (&permanent_obstack, &permanent_obstack);
@@ -8497,97 +8003,55 @@ expand_static_init (decl, init)
       rest_of_decl_compilation (temp, NULL_PTR, 0, 0);
 
       /* Begin the conditional initialization.  */
-      expand_start_cond (build_binary_op (EQ_EXPR, temp,
-                                         integer_zero_node), 0);
-      expand_start_target_temps ();
+      if_stmt = begin_if_stmt ();
+      finish_if_stmt_cond (build_binary_op (EQ_EXPR, temp,
+                                           integer_zero_node), 
+                          if_stmt);
+      then_clause = begin_compound_stmt (/*has_no_scope=*/0);
 
       /* Do the initialization itself.  */
       if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))
          || (init && TREE_CODE (init) == TREE_LIST))
+       assignment = build_aggr_init (decl, init, 0);
+      else if (init)
        {
-         expand_aggr_init (decl, init, 0);
-         do_pending_stack_adjust ();
+         /* The initialization we're doing here is just a bitwise
+            copy.  */
+         assignment = build (INIT_EXPR, TREE_TYPE (decl), decl, init);
+         TREE_SIDE_EFFECTS (assignment) = 1;
        }
-      else if (init)
-       expand_assignment (decl, init, 0, 0);
-
-      /* Set TEMP to 1.  */
-      expand_assignment (temp, integer_one_node, 0, 0);
-
-      /* Cleanup any temporaries needed for the initial value.  If
-        destroying one of the temporaries causes an exception to be
-        thrown, then the object itself has still been fully
-        constructed.  */
-      expand_end_target_temps ();
+      else
+       assignment = NULL_TREE;
+
+      /* Once the assignment is complete, set TEMP to 1.  Since the
+        construction of the static object is complete at this point,
+        we want to make sure TEMP is set to 1 even if a temporary
+        constructed during the initialization throws an exception
+        when it is destroyed.  So, we combine the initialization and
+        the assignment to TEMP into a single expression, ensuring
+        that when we call finish_expr_stmt the cleanups will not be
+        run until after TEMP is set to 1.  */
+      temp_init = build_modify_expr (temp, NOP_EXPR, integer_one_node);
+      if (assignment)
+       {
+         assignment = tree_cons (NULL_TREE, assignment,
+                                 build_tree_list (NULL_TREE, 
+                                                  temp_init));
+         assignment = build_compound_expr (assignment);
+       }
+      else
+       assignment = temp_init;
+      finish_expr_stmt (assignment);
 
       /* Use atexit to register a function for destroying this static
         variable.  */
       if (TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (decl)))
-       {
-         tree cleanup, fcall;
-         static tree Atexit = 0;
-         int saved_flag_access_control;
+       destroy_local_static (decl);
+
+      finish_compound_stmt (/*has_no_scope=*/0, then_clause);
+      finish_then_clause (if_stmt);
+      finish_if_stmt ();
 
-         if (Atexit == 0)
-           {
-             tree atexit_fndecl, PFV, pfvlist;
-             /* Remember this information until end of file.  */
-             push_obstacks (&permanent_obstack, &permanent_obstack);
-             PFV = build_pointer_type (build_function_type
-                                       (void_type_node, void_list_node));
-
-             pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
-
-             push_lang_context (lang_name_c);
-             /* Note that we do not call pushdecl for this function;
-                there's no reason that this declaration should be
-                accessible to anyone.  */
-             atexit_fndecl
-               = define_function ("atexit",
-                                  build_function_type (void_type_node,
-                                                       pfvlist),
-                                  NOT_BUILT_IN, 
-                                  /*pfn=*/0,
-                                  NULL_PTR);
-             mark_used (atexit_fndecl);
-             Atexit = default_conversion (atexit_fndecl);
-             pop_lang_context ();
-             pop_obstacks ();
-           }
-             
-         /* Call build_cleanup before we enter the anonymous function
-            so that any access checks will be done relative to the
-            current scope, rather than the scope of the anonymous
-            function.  */
-         build_cleanup (decl);
-
-         /* Now start the function.  */
-         cleanup = start_anon_func ();
-
-         /* Now, recompute the cleanup.  It may contain SAVE_EXPRs
-            that refer to the original function, rather than the
-            anonymous one.  That will make the back-end think that
-            nested functions are in use, which causes confusion.  */
-         saved_flag_access_control = flag_access_control;
-         flag_access_control = 0;
-         fcall = build_cleanup (decl);
-         flag_access_control = saved_flag_access_control;
-
-         /* Finish off the function.  */
-         expand_expr_stmt (fcall);
-         end_anon_func ();
-
-         /* Call atexit with the cleanup function.  */
-         mark_addressable (cleanup);
-         cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
-         fcall = build_function_call (Atexit, 
-                                      expr_tree_cons (NULL_TREE, 
-                                                      cleanup, 
-                                                      NULL_TREE));
-         expand_expr_stmt (fcall);
-       }
-
-      expand_end_cond ();
       /* Resume old (possibly temporary) allocation.  */
       pop_obstacks ();
     }
@@ -8599,9 +8063,31 @@ expand_static_init (decl, init)
         currently in the temporary obstack.  */
       if (!TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
        preserve_initializer ();
-      static_aggregates = perm_tree_cons (init, decl, static_aggregates);
+      static_aggregates = tree_cons (init, decl, static_aggregates);
     }
 }
+
+/* Finish the declaration of a catch-parameter.  */
+
+tree
+start_handler_parms (declspecs, declarator)
+     tree declspecs;
+     tree declarator;
+{
+  tree decl;
+  if (declspecs)
+    {
+      decl = grokdeclarator (declarator, declspecs, CATCHPARM,
+                            1, NULL_TREE);
+      if (decl == NULL_TREE)
+       error ("invalid catch parameter");
+    }
+  else
+    decl = NULL_TREE;
+
+  return decl;
+}
+
 \f
 /* Make TYPE a complete type based on INITIAL_VALUE.
    Return 0 if successful, 1 if INITIAL_VALUE can't be deciphered,
@@ -8730,9 +8216,9 @@ bad_specifiers (object, type, virtualp, quals, inlinep, friendp, raises)
     cp_error ("`const' and `volatile' function specifiers on `%D' invalid in %s declaration",
              object, type);
   if (friendp)
-    cp_error_at ("invalid friend declaration", object);
+    cp_error_at ("`%D' declared as a friend", object);
   if (raises)
-    cp_error_at ("invalid exception specifications", object);
+    cp_error_at ("`%D' declared with an exception specification", object);
 }
 
 /* CTYPE is class type, or null if non-class.
@@ -8908,9 +8394,9 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
             the information in the TEMPLATE_ID_EXPR.  */
          SET_DECL_IMPLICIT_INSTANTIATION (decl);
          DECL_TEMPLATE_INFO (decl)
-           = perm_tree_cons (TREE_OPERAND (orig_declarator, 0),
-                             TREE_OPERAND (orig_declarator, 1),
-                             NULL_TREE);
+           = tree_cons (TREE_OPERAND (orig_declarator, 0),
+                        TREE_OPERAND (orig_declarator, 1),
+                        NULL_TREE);
 
          if (has_default_arg)
            {
@@ -9065,7 +8551,7 @@ grokvardecl (type, declarator, specbits_in, initialized, constp, in_namespace)
         can be initialized, the code will reach here.  */
       tree basetype = TYPE_OFFSET_BASETYPE (type);
       type = TREE_TYPE (type);
-      decl = build_lang_field_decl (VAR_DECL, declarator, type);
+      decl = build_lang_decl (VAR_DECL, declarator, type);
       DECL_CONTEXT (decl) = basetype;
       DECL_CLASS_CONTEXT (decl) = basetype;
       DECL_ASSEMBLER_NAME (decl) = build_static_name (basetype, declarator);
@@ -9081,7 +8567,16 @@ grokvardecl (type, declarator, specbits_in, initialized, constp, in_namespace)
       else
        context = NULL_TREE;
 
-      decl = build_decl (VAR_DECL, declarator, complete_type (type));
+      if (processing_template_decl) 
+       {
+         /* If we're in a template, we need DECL_LANG_SPECIFIC so that
+            we can call push_template_decl.  */
+         push_permanent_obstack ();
+         decl = build_lang_decl (VAR_DECL, declarator, type);
+         pop_obstacks ();
+       }
+      else
+       decl = build_decl (VAR_DECL, declarator, type);
 
       if (context)
        set_decl_namespace (decl, context, 0);
@@ -9154,6 +8649,7 @@ build_ptrmemfunc_type (type)
   tree fields[4];
   tree t;
   tree u;
+  tree unqualified_variant = NULL_TREE;
 
   /* If a canonical type already exists for this type, use it.  We use
      this method instead of type_hash_canon, because it only does a
@@ -9162,13 +8658,19 @@ build_ptrmemfunc_type (type)
   if ((t = TYPE_GET_PTRMEMFUNC_TYPE (type)))
     return t;
 
+  /* Make sure that we always have the unqualified pointer-to-member
+     type first.  */
+  if (CP_TYPE_QUALS (type) != TYPE_UNQUALIFIED)
+    unqualified_variant 
+      = build_ptrmemfunc_type (TYPE_MAIN_VARIANT (type));
+
   push_obstacks (TYPE_OBSTACK (type), TYPE_OBSTACK (type));
 
   u = make_lang_type (UNION_TYPE);
   SET_IS_AGGR_TYPE (u, 0);
-  fields[0] = build_lang_field_decl (FIELD_DECL, pfn_identifier, type);
-  fields[1] = build_lang_field_decl (FIELD_DECL, delta2_identifier,
-                                    delta_type_node);
+  fields[0] = build_lang_decl (FIELD_DECL, pfn_identifier, type);
+  fields[1] = build_lang_decl (FIELD_DECL, delta2_identifier,
+                              delta_type_node);
   finish_builtin_type (u, "__ptrmemfunc_type", fields, 1, ptr_type_node);
   TYPE_NAME (u) = NULL_TREE;
 
@@ -9179,11 +8681,11 @@ build_ptrmemfunc_type (type)
   /* ... and not really an aggregate.  */
   SET_IS_AGGR_TYPE (t, 0);
 
-  fields[0] = build_lang_field_decl (FIELD_DECL, delta_identifier,
-                                    delta_type_node);
-  fields[1] = build_lang_field_decl (FIELD_DECL, index_identifier,
-                                    delta_type_node);
-  fields[2] = build_lang_field_decl (FIELD_DECL, pfn_or_delta2_identifier, u);
+  fields[0] = build_lang_decl (FIELD_DECL, delta_identifier,
+                              delta_type_node);
+  fields[1] = build_lang_decl (FIELD_DECL, index_identifier,
+                              delta_type_node);
+  fields[2] = build_lang_decl (FIELD_DECL, pfn_or_delta2_identifier, u);
   finish_builtin_type (t, "__ptrmemfunc_type", fields, 2, ptr_type_node);
 
   pop_obstacks ();
@@ -9192,10 +8694,25 @@ build_ptrmemfunc_type (type)
      information for this anonymous RECORD_TYPE.  */
   TYPE_NAME (t) = NULL_TREE;
 
+  /* If this is not the unqualified form of this pointer-to-member
+     type, set the TYPE_MAIN_VARIANT for this type to be the
+     unqualified type.  Since they are actually RECORD_TYPEs that are
+     not variants of each other, we must do this manually.  */
+  if (CP_TYPE_QUALS (type) != TYPE_UNQUALIFIED)
+    {
+      t = build_qualified_type (t, CP_TYPE_QUALS (type));
+      TYPE_MAIN_VARIANT (t) = unqualified_variant;
+      TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (unqualified_variant);
+      TYPE_NEXT_VARIANT (unqualified_variant) = t;
+    }
+
+  /* Cache this pointer-to-member type so that we can find it again
+     later.  */
   TYPE_SET_PTRMEMFUNC_TYPE (type, t);
 
   /* Seems to be wanted.  */
   CLASSTYPE_GOT_SEMICOLON (t) = 1;
+
   return t;
 }
 
@@ -9316,9 +8833,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
   int explicit_int = 0;
   int explicit_char = 0;
   int defaulted_int = 0;
-  int opaque_typedef = 0;
   tree typedef_decl = NULL_TREE;
-  char *name;
+  const char *name;
   tree typedef_type = NULL_TREE;
   int funcdef_flag = 0;
   enum tree_code innermost_code = ERROR_MARK;
@@ -9429,7 +8945,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
            break;
 
          case CALL_EXPR:
-           if (parmlist_is_exprlist (TREE_OPERAND (decl, 1)))
+           if (parmlist_is_exprlist (CALL_DECLARATOR_PARMS (decl)))
              {
                /* This is actually a variable declaration using
                   constructor syntax.  We need to call start_decl and
@@ -9439,7 +8955,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                tree attributes, prefix_attributes;
 
                *next = TREE_OPERAND (decl, 0);
-               init = TREE_OPERAND (decl, 1);
+               init = CALL_DECLARATOR_PARMS (decl);
 
                if (attrlist)
                  {
@@ -9640,8 +9156,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
            return 0; /* We used to do a 155 abort here.  */
          }
       }
-    if (name == NULL)
-      name = "type name";
   }
 
   /* A function definition's declarator must have the form of
@@ -9672,8 +9186,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
 
      We also want to avoid calling this a PARM if it is in a namespace.  */
 
-  if (decl_context == NORMAL && ! namespace_bindings_p ()
-      && ! pseudo_global_level_p ())
+  if (decl_context == NORMAL && !toplevel_bindings_p ())
     {
       struct binding_level *b = current_binding_level;
       current_binding_level = b->level_chain;
@@ -9682,6 +9195,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
       current_binding_level = b;
     }
 
+  if (name == NULL)
+    name = decl_context == PARM ? "parameter" : "type name";
+  
   /* Look through the decl specs and record which ones appear.
      Some typespecs are defined as built-in typenames.
      Others, the ones that are modifiers of other types,
@@ -9806,10 +9322,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
   typedef_type = type;
 
   /* No type at all: default to `int', and set DEFAULTED_INT
-     because it was not a user-defined typedef.
-     Except when we have a `typedef' inside a signature, in
-     which case the type defaults to `unknown type' and is
-     instantiated when assigning to a signature pointer or ref.  */
+     because it was not a user-defined typedef.  */
 
   if (type == NULL_TREE
       && (RIDBIT_SETP (RID_SIGNED, specbits)
@@ -9831,15 +9344,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
        type = build_pointer_type (ctor_return_type);
       else if (return_type == return_conversion)
        type = ctor_return_type;
-      else if (current_class_type
-              && IS_SIGNATURE (current_class_type)
-              && RIDBIT_SETP (RID_TYPEDEF, specbits)
-              && (decl_context == FIELD || decl_context == NORMAL))
-       {
-         explicit_int = 0;
-         opaque_typedef = 1;
-         type = copy_node (opaque_type_node);
-       }
       else
        {
          /* We handle `main' specially here, because 'main () { }' is so
@@ -9851,14 +9355,14 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                         && in_namespace == NULL_TREE
                         && current_namespace == global_namespace);
 
-         if (in_system_header)
+         if (in_system_header || flag_ms_extensions)
            /* Allow it, sigh.  */;
          else if (pedantic || ! is_main)
-           cp_pedwarn ("ANSI C++ forbids declaration `%D' with no type",
-                       dname);
+           cp_pedwarn ("ANSI C++ forbids declaration of `%s' with no type",
+                       name);
          else if (warn_return_type)
-           cp_warning ("ANSI C++ forbids declaration `%D' with no type",
-                       dname);
+           cp_warning ("ANSI C++ forbids declaration of `%s' with no type",
+                       name);
 
          type = integer_type_node;
        }
@@ -10066,24 +9570,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
   friendp = RIDBIT_SETP (RID_FRIEND, specbits);
   RIDBIT_RESET (RID_FRIEND, specbits);
 
-  /* $7.1.2, Function specifiers */
-  if (friendp && explicitp)
-    error ("only declarations of constructors can be `explicit'");
-
-  if (RIDBIT_SETP (RID_MUTABLE, specbits))
-    {
-      if (decl_context == PARM)
-       {
-         error ("non-member `%s' cannot be declared `mutable'", name);
-         RIDBIT_RESET (RID_MUTABLE, specbits);
-       }
-      else if (friendp || decl_context == TYPENAME)
-       {
-         error ("non-object member `%s' cannot be declared `mutable'", name);
-         RIDBIT_RESET (RID_MUTABLE, specbits);
-       }
-    }
-
   /* Warn if two storage classes are given. Default to `auto'.  */
 
   if (RIDBIT_ANY_SET (specbits))
@@ -10109,11 +9595,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
       error ("virtual outside class declaration");
       virtualp = 0;
     }
-  if (current_class_name == NULL_TREE && RIDBIT_SETP (RID_MUTABLE, specbits))
-    {
-      error ("only members can be declared mutable");
-      RIDBIT_RESET (RID_MUTABLE, specbits);
-    }
 
   /* Static anonymous unions are dealt with here.  */
   if (staticp && decl_context == TYPENAME
@@ -10121,37 +9602,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
       && ANON_AGGR_TYPE_P (TREE_VALUE (declspecs)))
     decl_context = FIELD;
 
-  /* Give error if `const,' `volatile,' `inline,' `friend,' or `virtual'
-     is used in a signature member function declaration.  */
-  if (decl_context == FIELD
-      && IS_SIGNATURE (current_class_type)
-      && RIDBIT_NOTSETP (RID_TYPEDEF, specbits))
-    {
-      if (type_quals != TYPE_UNQUALIFIED)
-       {
-         error ("type qualifiers specified for signature member function `%s'", name);
-         type_quals = TYPE_UNQUALIFIED;
-       }
-      if (inlinep)
-       {
-         error ("`inline' specified for signature member function `%s'", name);
-         /* Later, we'll make signature member functions inline.  */
-         inlinep = 0;
-       }
-      if (friendp)
-       {
-         error ("`friend' declaration in signature definition");
-         friendp = 0;
-       }
-      if (virtualp)
-       {
-         error ("`virtual' specified for signature member function `%s'",
-                name);
-         /* Later, we'll make signature member functions virtual.  */
-         virtualp = 0;
-       }
-    }
-
   /* Warn about storage classes that are invalid for certain
      kinds of declarations (parameters, typenames, etc.).  */
 
@@ -10166,7 +9616,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
       else if (RIDBIT_SETP (RID_TYPEDEF, specbits))
        ;
       else if (decl_context == FIELD
-              && ! IS_SIGNATURE (current_class_type)
               /* C++ allows static class elements  */
               && RIDBIT_SETP (RID_STATIC, specbits))
        /* C++ also allows inlines and signed and unsigned elements,
@@ -10189,11 +9638,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                  op = IDENTIFIER_OPNAME_P (tmp);
                }
              error ("storage class specified for %s `%s'",
-                    IS_SIGNATURE (current_class_type)
-                    ? (op
-                       ? "signature member operator"
-                       : "signature member function")
-                    : (op ? "member operator" : "field"),
+                    op ? "member operator" : "field",
                     op ? operator_name_string (tmp) : name);
            }
          else
@@ -10203,12 +9648,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
          RIDBIT_RESET (RID_REGISTER, specbits);
          RIDBIT_RESET (RID_AUTO, specbits);
          RIDBIT_RESET (RID_EXTERN, specbits);
-
-         if (decl_context == FIELD && IS_SIGNATURE (current_class_type))
-           {
-             RIDBIT_RESET (RID_STATIC, specbits);
-             staticp = 0;
-           }
        }
     }
   else if (RIDBIT_SETP (RID_EXTERN, specbits) && initialized && !funcdef_flag)
@@ -10401,6 +9840,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                if (TREE_CODE (size) == NOP_EXPR
                    && TREE_TYPE (size) == TREE_TYPE (TREE_OPERAND (size, 0)))
                  size = TREE_OPERAND (size, 0);
+               if (TREE_READONLY_DECL_P (size))
+                 size = decl_constant_value (size);
 
                /* If this involves a template parameter, it will be a
                   constant at instantiation time, but we don't know
@@ -10421,10 +9862,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                          size = t;
                      }
 
-                   itype = make_node (INTEGER_TYPE);
-                   TYPE_MIN_VALUE (itype) = size_zero_node;
-                   TYPE_MAX_VALUE (itype) = build_min
-                     (MINUS_EXPR, sizetype, size, integer_one_node);
+                   itype = build_index_type (build_min
+                     (MINUS_EXPR, sizetype, size, integer_one_node));
                    goto dont_grok_size;
                  }
 
@@ -10436,8 +9875,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                              dname);
                    size = integer_one_node;
                  }
-               if (TREE_READONLY_DECL_P (size))
-                 size = decl_constant_value (size);
                if (pedantic && integer_zerop (size))
                  cp_pedwarn ("ANSI C++ forbids zero-size array `%D'", dname);
                if (TREE_CONSTANT (size))
@@ -10480,19 +9917,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                    TREE_OVERFLOW (itype) = 0;
                  }
 
-               /* If we're a parm, we need to have a permanent type so
-                   mangling checks for re-use will work right.  If both the
-                   element and index types are permanent, the array type
-                   will be, too.  */
-               if (decl_context == PARM
-                   && allocation_temporary_p () && TREE_PERMANENT (type))
-                 {
-                   push_obstacks (&permanent_obstack, &permanent_obstack);
-                   itype = build_index_type (itype);
-                   pop_obstacks ();
-                 }
-               else
-                 itype = build_index_type (itype);
+               itype = build_index_type (itype);
 
              dont_grok_size:
                resume_momentary (yes);
@@ -10507,7 +9932,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
          {
            tree arg_types;
            int funcdecl_p;
-           tree inner_parms = TREE_OPERAND (declarator, 1);
+           tree inner_parms = CALL_DECLARATOR_PARMS (declarator);
            tree inner_decl = TREE_OPERAND (declarator, 0);
 
            /* Declaring a function type.
@@ -10537,10 +9962,10 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
              inner_decl = dname;
 
            /* Pick up type qualifiers which should be applied to `this'.  */
-           quals = TREE_OPERAND (declarator, 2);
+           quals = CALL_DECLARATOR_QUALS (declarator);
 
            /* Pick up the exception specifications.  */
-           raises = TREE_TYPE (declarator);
+           raises = CALL_DECLARATOR_EXCEPTION_SPEC (declarator);
 
            /* Say it's a definition only for the CALL_EXPR
               closest to the identifier.  */
@@ -10614,13 +10039,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                        error ("return value type specifier for constructor ignored");
                    }
                    type = build_pointer_type (ctype);
-                   if (decl_context == FIELD
-                       && IS_SIGNATURE (current_class_type))
-                     {
-                       error ("constructor not allowed in signature");
-                       return void_type_node;
-                     }                   
-                   else if (decl_context == FIELD)
+                   if (decl_context == FIELD)
                      {
                        if (! member_function_or_else (ctype, current_class_type,
                                                       "constructor for alien class `%s' cannot be member"))
@@ -10727,31 +10146,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
             but to the target of the pointer.  */
          type_quals = TYPE_UNQUALIFIED;
 
-         if (IS_SIGNATURE (type))
-           {
-             if (TREE_CODE (declarator) == ADDR_EXPR)
-               {
-                 if (CLASSTYPE_METHOD_VEC (type) == NULL_TREE
-                     && TYPE_SIZE (type))
-                   cp_warning ("empty signature `%T' used in signature reference declaration",
-                               type);
-#if 0
-                 type = build_signature_reference_type (type);
-#else
-                 sorry ("signature reference");
-                 return NULL_TREE;
-#endif
-               }
-             else
-               {
-                 if (CLASSTYPE_METHOD_VEC (type) == NULL_TREE
-                     && TYPE_SIZE (type))
-                   cp_warning ("empty signature `%T' used in signature pointer declaration",
-                               type);
-                 type = build_signature_pointer_type (type);
-               }
-           }
-         else if (TREE_CODE (declarator) == ADDR_EXPR)
+         if (TREE_CODE (declarator) == ADDR_EXPR)
            {
              if (TREE_CODE (type) == VOID_TYPE)
                error ("invalid type: `void &'");
@@ -11008,24 +10403,42 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
 
   /* Now TYPE has the actual type.  */
 
-  if (explicitp == 1)
+  if (explicitp == 1 || (explicitp && friendp))
     {
-      error ("only constructors can be declared `explicit'");
+      /* [dcl.fct.spec] The explicit specifier shall only be used in
+         declarations of constructors within a class definition.  */
+      error ("only declarations of constructors can be `explicit'");
       explicitp = 0;
     }
 
   if (RIDBIT_SETP (RID_MUTABLE, specbits))
     {
-      if (type_quals & TYPE_QUAL_CONST)
+      if (current_class_name == NULL_TREE || decl_context == PARM || friendp)
+        {
+         error ("non-member `%s' cannot be declared `mutable'", name);
+          RIDBIT_RESET (RID_MUTABLE, specbits);
+        }
+      else if (decl_context == TYPENAME || RIDBIT_SETP (RID_TYPEDEF, specbits))
        {
-         error ("const `%s' cannot be declared `mutable'", name);
+         error ("non-object member `%s' cannot be declared `mutable'", name);
          RIDBIT_RESET (RID_MUTABLE, specbits);
        }
+      else if (TREE_CODE (type) == FUNCTION_TYPE
+               || TREE_CODE (type) == METHOD_TYPE)
+        {
+         error ("function `%s' cannot be declared `mutable'", name);
+         RIDBIT_RESET (RID_MUTABLE, specbits);
+        }
       else if (staticp)
        {
          error ("static `%s' cannot be declared `mutable'", name);
          RIDBIT_RESET (RID_MUTABLE, specbits);
        }
+      else if (type_quals & TYPE_QUAL_CONST)
+       {
+         error ("const `%s' cannot be declared `mutable'", name);
+         RIDBIT_RESET (RID_MUTABLE, specbits);
+       }
     }
 
   if (declarator == NULL_TREE
@@ -11060,8 +10473,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
            cp_pedwarn ("ANSI C++ forbids nested type `%D' with same name as enclosing class",
                        declarator);
          decl = build_lang_decl (TYPE_DECL, declarator, type);
-         if (IS_SIGNATURE (current_class_type) && opaque_typedef)
-           SIGNATURE_HAS_OPAQUE_TYPEDECLS (current_class_type) = 1;
        }
       else
        {
@@ -11069,15 +10480,18 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
             since it might be used as a template parameter. */
          if (type != error_mark_node)
            push_obstacks (TYPE_OBSTACK (type), TYPE_OBSTACK (type));
-         decl = build_decl (TYPE_DECL, declarator, type);
+         if (processing_template_decl)
+           decl = build_lang_decl (TYPE_DECL, declarator, type);
+         else
+           decl = build_decl (TYPE_DECL, declarator, type);
          if (type != error_mark_node)
            pop_obstacks ();
        }
 
-      /* If the user declares "struct {...} foo" then `foo' will have
-        an anonymous name.  Fill that name in now.  Nothing can
-        refer to it, so nothing needs know about the name change.
-        The TYPE_NAME field was filled in by build_struct_xref.  */
+      /* If the user declares "typedef struct {...} foo" then the
+        struct will have an anonymous name.  Fill that name in now.
+        Nothing can refer to it, so nothing needs know about the name
+        change.  */
       if (type != error_mark_node
          && TYPE_NAME (type)
          && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
@@ -11143,9 +10557,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
          || (typedef_decl && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl)))
        C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1;
 
-      if (RIDBIT_SETP (RID_MUTABLE, specbits))
-       error ("non-object member `%s' cannot be declared mutable", name);
-
       bad_specifiers (decl, "type", virtualp, quals != NULL_TREE,
                      inlinep, friendp, raises != NULL_TREE);
 
@@ -11175,11 +10586,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
       /* Note that the grammar rejects storage classes
         in typenames, fields or parameters.  */
       if (type_quals != TYPE_UNQUALIFIED)
-       {
-         if (IS_SIGNATURE (type))
-           error ("type qualifiers specified for signature type");
-         type_quals = TYPE_UNQUALIFIED;
-       }
+       type_quals = TYPE_UNQUALIFIED;
 
       /* Special case: "friend class foo" looks like a TYPENAME context.  */
       if (friendp)
@@ -11289,16 +10696,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
 
        bad_specifiers (decl, "parameter", virtualp, quals != NULL_TREE,
                        inlinep, friendp, raises != NULL_TREE);
-       if (current_class_type
-           && IS_SIGNATURE (current_class_type))
-         {
-           if (inlinep)
-             error ("parameter of signature member function declared `inline'");
-           if (RIDBIT_SETP (RID_AUTO, specbits))
-             error ("parameter of signature member function declared `auto'");
-           if (RIDBIT_SETP (RID_REGISTER, specbits))
-             error ("parameter of signature member function declared `register'");
-         }
 
        /* Compute the type actually passed in the parmlist,
           for the case where there is no prototype.
@@ -11552,18 +10949,16 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
 
            if (staticp)
              {
-               /* C++ allows static class members.
-                  All other work for this is done by grokfield.
-                  This VAR_DCL is built by build_lang_field_decl.
-                  All other VAR_DECLs are built by build_decl.  */
-               decl = build_lang_field_decl (VAR_DECL, declarator, type);
+               /* C++ allows static class members.  All other work
+                  for this is done by grokfield.  */
+               decl = build_lang_decl (VAR_DECL, declarator, type);
                TREE_STATIC (decl) = 1;
                /* In class context, 'static' means public access.  */
                TREE_PUBLIC (decl) = DECL_EXTERNAL (decl) = 1;
              }
            else
              {
-               decl = build_lang_field_decl (FIELD_DECL, declarator, type);
+               decl = build_lang_decl (FIELD_DECL, declarator, type);
                if (RIDBIT_SETP (RID_MUTABLE, specbits))
                  {
                    DECL_MUTABLE_P (decl) = 1;
@@ -11692,10 +11087,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
          }
       }
 
-    if (RIDBIT_SETP (RID_MUTABLE, specbits))
-      {
-       error ("`%s' cannot be declared mutable", name);
-      }
+    my_friendly_assert (!RIDBIT_SETP (RID_MUTABLE, specbits), 19990927);
 
     /* Record `register' declaration for warnings on &
        and in case doing stupid register allocation.  */
@@ -11773,13 +11165,15 @@ require_complete_types_for_parms (parms)
     }
 }
 
-/* Returns DECL if DECL is a local variable (or parameter).  Returns
+/* Returns *TP if *TP is a local variable (or parameter).  Returns
    NULL_TREE otherwise.  */
 
 static tree
-local_variable_p (t)
-     tree t;
+local_variable_p (tp)
+     tree *tp;
 {
+  tree t = *tp;
+
   if ((TREE_CODE (t) == VAR_DECL 
        /* A VAR_DECL with a context that is a _TYPE is a static data
          member.  */
@@ -11845,7 +11239,7 @@ check_default_argument (decl, arg)
        cp_error ("default argument for `%#D' has type `%T'", 
                  decl, TREE_TYPE (arg));
       else
-       cp_error ("default argument for paramter of type `%T' has type `%T'",
+       cp_error ("default argument for parameter of type `%T' has type `%T'",
                  decl_type, TREE_TYPE (arg));
 
       return error_mark_node;
@@ -11858,7 +11252,7 @@ check_default_argument (decl, arg)
 
      The keyword `this' shall not be used in a default argument of a
      member function.  */
-  var = search_tree (arg, local_variable_p);
+  var = search_tree (&arg, local_variable_p);
   if (var)
     {
       cp_error ("default argument `%E' uses local variable `%D'",
@@ -11993,20 +11387,8 @@ grokparms (first_parm, funcdef_flag)
                      type = build_pointer_type (type);
                      TREE_TYPE (decl) = type;
                    }
-                  else if (TREE_CODE (type) == RECORD_TYPE
-                           && TYPE_LANG_SPECIFIC (type)
-                           && CLASSTYPE_ABSTRACT_VIRTUALS (type))
-                    {
-                      abstract_virtuals_error (decl, type);
-                      any_error = 1;  /* Seems like a good idea. */
-                    }
-                  else if (TREE_CODE (type) == RECORD_TYPE
-                           && TYPE_LANG_SPECIFIC (type)
-                           && IS_SIGNATURE (type))
-                    {
-                      signature_error (decl, type);
-                      any_error = 1;  /* Seems like a good idea. */
-                    }
+                  else if (abstract_virtuals_error (decl, type))
+                   any_error = 1;  /* Seems like a good idea. */
                  else if (POINTER_TYPE_P (type))
                    {
                      tree t = type;
@@ -12041,12 +11423,11 @@ grokparms (first_parm, funcdef_flag)
 
              /* Since there is a prototype, args are passed in their own types.  */
              DECL_ARG_TYPE (decl) = TREE_TYPE (decl);
-#ifdef PROMOTE_PROTOTYPES
-             if ((TREE_CODE (type) == INTEGER_TYPE
-                  || TREE_CODE (type) == ENUMERAL_TYPE)
+             if (PROMOTE_PROTOTYPES
+                 && (TREE_CODE (type) == INTEGER_TYPE
+                     || TREE_CODE (type) == ENUMERAL_TYPE)
                  && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
                DECL_ARG_TYPE (decl) = integer_type_node;
-#endif
              if (!any_error && init)
                {
                  any_init++;
@@ -12065,14 +11446,7 @@ grokparms (first_parm, funcdef_flag)
                  TREE_CHAIN (last_decl) = decl;
                  last_decl = decl;
                }
-             if (! current_function_decl && TREE_PERMANENT (list_node))
-               {
-                 TREE_PURPOSE (list_node) = init;
-                 TREE_VALUE (list_node) = type;
-                 TREE_CHAIN (list_node) = NULL_TREE;
-               }
-             else
-               list_node = saveable_tree_cons (init, type, NULL_TREE);
+             list_node = tree_cons (init, type, NULL_TREE);
              if (result == NULL_TREE)
                {
                  result = list_node;
@@ -12412,9 +11786,7 @@ grok_op_properties (decl, virtualp, friendp)
       else if (name == ansi_opname[(int) COND_EXPR])
        {
          /* 13.4.0.3 */
-         pedwarn ("ANSI C++ prohibits overloading operator ?:");
-         if (list_length (argtypes) != 4)
-           cp_error ("`%D' must take exactly three arguments", decl);
+         cp_error ("ANSI C++ prohibits overloading operator ?:");
        }         
       else if (ambi_op_p (name))
        {
@@ -12540,8 +11912,6 @@ tag_name (code)
       return "union ";
     case enum_type:
       return "enum";
-    case signature_type:
-      return "signature";
     default:
       my_friendly_abort (981122);
     }
@@ -12587,7 +11957,6 @@ xref_tag (code_type_node, name, globalize)
     {
     case record_type:
     case class_type:
-    case signature_type:
       code = RECORD_TYPE;
       break;
     case union_type:
@@ -12752,17 +12121,6 @@ xref_tag (code_type_node, name, globalize)
          ref = make_lang_type (code);
          TYPE_CONTEXT (ref) = context;
 
-         if (tag_code == signature_type)
-           {
-             SET_SIGNATURE (ref);
-             /* Since a signature type will be turned into the type
-                of signature tables, it's not only an interface.  */
-             CLASSTYPE_INTERFACE_ONLY (ref) = 0;
-             SET_CLASSTYPE_INTERFACE_KNOWN (ref);
-             /* A signature doesn't have a vtable.  */
-             CLASSTYPE_VTABLE_NEEDS_WRITING (ref) = 0;
-           }
-
 #ifdef NONNESTED_CLASSES
          /* Class types don't nest the way enums do.  */
          class_binding_level = (struct binding_level *)0;
@@ -12777,11 +12135,9 @@ xref_tag (code_type_node, name, globalize)
         in global scope.  
          If it is not an IDENTIFIER, this is not a declaration */
       if (b->namespace_p && !class_binding_level
-         && TREE_CODE (name) == IDENTIFIER_NODE)
-       {
-         if (IDENTIFIER_NAMESPACE_VALUE (name) == NULL_TREE)
-           SET_IDENTIFIER_NAMESPACE_VALUE (name, TYPE_NAME (ref));
-       }
+         && TREE_CODE (name) == IDENTIFIER_NODE
+         && IDENTIFIER_NAMESPACE_VALUE (name) == NULL_TREE)
+       SET_IDENTIFIER_NAMESPACE_VALUE (name, TYPE_NAME (ref));
 
       if (!globalize && processing_template_decl && IS_AGGR_TYPE (ref))
        redeclare_class_template (ref, current_template_parms);
@@ -12796,7 +12152,7 @@ xref_tag (code_type_node, name, globalize)
     {
       if (tag_code == class_type)
        CLASSTYPE_DECLARED_CLASS (ref) = 1;
-      else if (tag_code == record_type || tag_code == signature_type)
+      else if (tag_code == record_type)
        CLASSTYPE_DECLARED_CLASS (ref) = 0;
     }
 
@@ -12920,7 +12276,8 @@ xref_basetypes (code_type_node, name, ref, binfo)
            }
 
          if (TYPE_FOR_JAVA (basetype)
-             && current_lang_stack == current_lang_base)
+             && (current_lang_stack 
+                 == &VARRAY_TREE (current_lang_base, 0)))
            TYPE_FOR_JAVA (ref) = 1;
 
          /* Note that the BINFO records which describe individual
@@ -13024,7 +12381,10 @@ start_enum (name)
     enumtype = lookup_tag (ENUMERAL_TYPE, name, b, 1);
 
   if (enumtype != NULL_TREE && TREE_CODE (enumtype) == ENUMERAL_TYPE)
-    cp_error ("multiple definition of `%#T'", enumtype);
+    {
+      cp_error ("multiple definition of `%#T'", enumtype);
+      cp_error_at ("previous definition here", enumtype);
+    }
   else
     {
       enumtype = make_node (ENUMERAL_TYPE);
@@ -13237,7 +12597,7 @@ build_enumerator (name, value, type)
  context = current_scope ();
  if (context && context == current_class_type)
    /* This enum declaration is local to the class.  */
-   decl = build_lang_field_decl (CONST_DECL, name, type);
+   decl = build_lang_decl (CONST_DECL, name, type);
  else
    /* It's a global enum, or it's local to a function.  (Note local to
       a function could mean local to a class method.  */
@@ -13266,26 +12626,61 @@ build_enumerator (name, value, type)
      enum_overflow = tree_int_cst_lt (enum_next_value, value);
    }
 
-  result = saveable_tree_cons (name, decl, NULL_TREE);
+  result = tree_cons (name, decl, NULL_TREE);
   return result;
 }
 
 \f
 static int function_depth;
 
+/* We're defining DECL.  Make sure that it's type is OK.  */
+
+static void
+check_function_type (decl)
+     tree decl;
+{
+  tree fntype = TREE_TYPE (decl);
+
+  /* In a function definition, arg types must be complete.  */
+  require_complete_types_for_parms (current_function_parms);
+
+  if (TYPE_SIZE (complete_type (TREE_TYPE (fntype))) == NULL_TREE)
+    {
+      cp_error ("return type `%#T' is incomplete", TREE_TYPE (fntype));
+
+      /* Make it return void instead, but don't change the
+        type of the DECL_RESULT, in case we have a named return value.  */
+      if (TREE_CODE (fntype) == METHOD_TYPE)
+       {
+         tree ctype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (fntype)));
+         TREE_TYPE (decl)
+           = build_cplus_method_type (ctype,
+                                      void_type_node,
+                                      FUNCTION_ARG_CHAIN (decl));
+       }
+      else
+       TREE_TYPE (decl)
+         = build_function_type (void_type_node,
+                                TYPE_ARG_TYPES (TREE_TYPE (decl)));
+      TREE_TYPE (decl) 
+       = build_exception_variant (fntype,
+                                  TYPE_RAISES_EXCEPTIONS (fntype));
+    }
+  else
+    abstract_virtuals_error (decl, TREE_TYPE (fntype));
+}
+
 /* Create the FUNCTION_DECL for a function definition.
    DECLSPECS and DECLARATOR are the parts of the declaration;
    they describe the function's name and the type it returns,
    but twisted together in a fashion that parallels the syntax of C.
 
-   If PRE_PARSED_P is non-zero then DECLARATOR is really the DECL for
-   the function we are about to process; DECLSPECS are ignored.  For
-   example, we set PRE_PARSED_P when processing the definition of
-   inline function that was defined in-class; the definition is
-   actually processed when the class is complete.  In this case,
-   PRE_PARSED_P is 2.  We also set PRE_PARSED_P when instanting the
-   body of a template function, and when constructing thunk functions
-   and such; in these cases PRE_PARSED_P is 1.
+   FLAGS is a bitwise or of SF_PRE_PARSED (indicating that the
+   DECLARATOR is really the DECL for the function we are about to
+   process and that DECLSPECS should be ignored), SF_INCLASS_INLINE
+   indicating that the function is an inline defined in-class, and
+   SF_EXPAND indicating that we should generate RTL for this
+   function.  
    
    This function creates a binding context for the function body
    as well as setting up the FUNCTION_DECL in current_function_decl.
@@ -13297,16 +12692,12 @@ static int function_depth;
    For C++, we must first check whether that datum makes any sense.
    For example, "class A local_a(1,2);" means that variable local_a
    is an aggregate of type A, which should have a constructor
-   applied to it with the argument list [1, 2].
-
-   @@ There is currently no way to retrieve the storage
-   @@ allocated to FUNCTION (or all of its parms) if we return
-   @@ something we had previously.  */
+   applied to it with the argument list [1, 2].  */
 
 int
-start_function (declspecs, declarator, attrs, pre_parsed_p)
+start_function (declspecs, declarator, attrs, flags)
      tree declspecs, declarator, attrs;
-     int pre_parsed_p;
+     int flags;
 {
   tree decl1;
   tree ctype = NULL_TREE;
@@ -13315,28 +12706,12 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
   extern int have_extern_spec;
   extern int used_extern_spec;
   int doing_friend = 0;
+  struct binding_level *bl;
 
   /* Sanity check.  */
   my_friendly_assert (TREE_CODE (TREE_VALUE (void_list_node)) == VOID_TYPE, 160);
   my_friendly_assert (TREE_CHAIN (void_list_node) == NULL_TREE, 161);
 
-  /* Assume, until we see it does.  */
-  current_function_returns_value = 0;
-  current_function_returns_null = 0;
-  named_labels = 0;
-  shadowed_labels = 0;
-  current_function_assigns_this = 0;
-  current_function_just_assigned_this = 0;
-  current_function_parms_stored = 0;
-  original_result_rtx = NULL_RTX;
-  base_init_expr = NULL_TREE;
-  current_base_init_list = NULL_TREE;
-  current_member_init_list = NULL_TREE;
-  ctor_label = dtor_label = NULL_TREE;
-  static_labelno = 0;
-
-  clear_temp_name ();
-
   /* This should only be done once on the top most decl.  */
   if (have_extern_spec && !used_extern_spec)
     {
@@ -13344,29 +12719,10 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
       used_extern_spec = 1;
     }
 
-  if (pre_parsed_p)
+  if (flags & SF_PRE_PARSED)
     {
       decl1 = declarator;
 
-#if 0
-      /* What was this testing for, exactly?  */
-      if (! DECL_ARGUMENTS (decl1)
-         && !DECL_STATIC_FUNCTION_P (decl1)
-         && !DECL_ARTIFICIAL (decl1)
-         && DECL_CLASS_SCOPE_P (decl1)
-         && TYPE_IDENTIFIER (DECL_CONTEXT (decl1))
-         && IDENTIFIER_TEMPLATE (TYPE_IDENTIFIER (DECL_CONTEXT (decl1))))
-       {
-         tree binding = binding_for_name (DECL_NAME (decl1), 
-                                          current_namespace);
-         cp_error ("redeclaration of `%#D'", decl1);
-         if (IDENTIFIER_CLASS_VALUE (DECL_NAME (decl1)))
-           cp_error_at ("previous declaration here", IDENTIFIER_CLASS_VALUE (DECL_NAME (decl1)));
-         else if (BINDING_VALUE (binding))
-           cp_error_at ("previous declaration here", BINDING_VALUE (binding));
-       }
-#endif
-
       fntype = TREE_TYPE (decl1);
       if (TREE_CODE (fntype) == METHOD_TYPE)
        ctype = TYPE_METHOD_BASETYPE (fntype);
@@ -13428,6 +12784,16 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
            }
        }
     }
+  
+  /* Sometimes we don't notice that a function is a static member, and
+     build a METHOD_TYPE for it.  Fix that up now.  */
+  if (ctype != NULL_TREE && DECL_STATIC_FUNCTION_P (decl1)
+      && TREE_CODE (TREE_TYPE (decl1)) == METHOD_TYPE)
+    {
+      revert_static_member_fn (&decl1, NULL, NULL);
+      last_function_parms = TREE_CHAIN (last_function_parms);
+      ctype = NULL_TREE;
+    }
 
   /* Warn if function was previously implicitly declared
      (but not if we warned then).  */
@@ -13435,8 +12801,6 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
       && IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1)) != NULL_TREE)
     cp_warning_at ("`%D' implicitly declared before its definition", IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1)));
 
-  announce_function (decl1);
-
   /* Set up current_class_type, and enter the scope of the class, if
      appropriate.  */
   if (ctype)
@@ -13450,53 +12814,9 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
      case where a template parameter has the same name as a field of
      the class.)  It is not until after this point that
      PROCESSING_TEMPLATE_DECL is guaranteed to be set up correctly.  */
-  if (pre_parsed_p == 2)
+  if (flags & SF_INCLASS_INLINE)
     maybe_begin_member_template_processing (decl1);
 
-  /* We are now in the scope of the function being defined.  */
-  current_function_decl = decl1;
-
-  /* Save the parm names or decls from this function's declarator
-     where store_parm_decls will find them.  */
-  current_function_parms = last_function_parms;
-  current_function_parm_tags = last_function_parm_tags;
-
-  if (! processing_template_decl)
-    {
-      /* In a function definition, arg types must be complete.  */
-      require_complete_types_for_parms (current_function_parms);
-
-      if (TYPE_SIZE (complete_type (TREE_TYPE (fntype))) == NULL_TREE)
-       {
-         cp_error ("return-type `%#T' is an incomplete type",
-                   TREE_TYPE (fntype));
-
-         /* Make it return void instead, but don't change the
-            type of the DECL_RESULT, in case we have a named return value.  */
-         if (ctype)
-           TREE_TYPE (decl1)
-             = build_cplus_method_type (build_type_variant (ctype,
-                                                            TREE_READONLY (decl1),
-                                                            TREE_SIDE_EFFECTS (decl1)),
-                                        void_type_node,
-                                        FUNCTION_ARG_CHAIN (decl1));
-         else
-           TREE_TYPE (decl1)
-             = build_function_type (void_type_node,
-                                    TYPE_ARG_TYPES (TREE_TYPE (decl1)));
-         DECL_RESULT (decl1)
-           = build_decl (RESULT_DECL, 0, TYPE_MAIN_VARIANT (TREE_TYPE (fntype)));
-         TREE_READONLY (DECL_RESULT (decl1))
-           = CP_TYPE_CONST_P (TREE_TYPE (fntype));
-         TREE_THIS_VOLATILE (DECL_RESULT (decl1))
-           = CP_TYPE_VOLATILE_P (TREE_TYPE (fntype));
-       }
-
-      if (TYPE_LANG_SPECIFIC (TREE_TYPE (fntype))
-         && CLASSTYPE_ABSTRACT_VIRTUALS (TREE_TYPE (fntype)))
-       abstract_virtuals_error (decl1, TREE_TYPE (fntype));
-    }
-
   /* Effective C++ rule 15.  See also c_expand_return.  */
   if (warn_ecpp
       && DECL_NAME (decl1) == ansi_opname[(int) MODIFY_EXPR]
@@ -13505,7 +12825,8 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
 
   /* Make the init_value nonzero so pushdecl knows this is not tentative.
      error_mark_node is replaced below (in poplevel) with the BLOCK.  */
-  DECL_INITIAL (decl1) = error_mark_node;
+  if (!DECL_INITIAL (decl1))
+    DECL_INITIAL (decl1) = error_mark_node;
 
 #ifdef SET_DEFAULT_DECL_ATTRIBUTES
   SET_DEFAULT_DECL_ATTRIBUTES (decl1, attrs);
@@ -13522,10 +12843,61 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
   if (processing_template_decl)
     decl1 = push_template_decl (decl1);
 
+  /* We are now in the scope of the function being defined.  */
+  current_function_decl = decl1;
+
+  /* Save the parm names or decls from this function's declarator
+     where store_parm_decls will find them.  */
+  current_function_parms = last_function_parms;
+  current_function_parm_tags = last_function_parm_tags;
+
+  /* Make sure the parameter and return types are reasonable.  When
+     you declare a function, these types can be incomplete, but they
+     must be complete when you define the function.  */
+  if (! processing_template_decl)
+    check_function_type (decl1);
+
+  /* Build the return declaration for the function.  */
+  restype = TREE_TYPE (fntype);
+  if (!processing_template_decl)
+    {
+      if (!DECL_RESULT (decl1))
+       {
+         DECL_RESULT (decl1)
+           = build_decl (RESULT_DECL, 0, TYPE_MAIN_VARIANT (restype));
+         c_apply_type_quals_to_decl (CP_TYPE_QUALS (restype), 
+                                     DECL_RESULT (decl1)); 
+       }
+    }
+  else
+    /* Just use `void'.  Nobody will ever look at this anyhow.  */
+    DECL_RESULT (decl1) = build_decl (RESULT_DECL, 0, void_type_node);
+
+  /* Initialize RTL machinery.  We cannot do this until
+     CURRENT_FUNCTION_DECL and DECL_RESULT are set up.  We do this
+     even when processing a template; this is how we get
+     CURRENT_FUNCTION set up, and our per-function variables
+     initialized.  */
+  bl = current_binding_level;
+  init_function_start (decl1, input_filename, lineno);
+  current_binding_level = bl;
+  expanding_p = (flags & SF_EXPAND) != 0;
+
+  /* Even though we're inside a function body, we still don't want to
+     call expand_expr to calculate the size of a variable-sized array.
+     We haven't necessarily assigned RTL to all variables yet, so it's
+     not safe to try to expand expressions involving them.  */
+  immediate_size_expand = 0;
+  current_function->x_dont_save_pending_sizes_p = 1;
+
+  /* Let the user know we're compiling this function.  */
+  if (processing_template_decl || !building_stmt_tree ())
+    announce_function (decl1);
+
   /* Record the decl so that the function name is defined.
      If we already have a decl for this name, and it is a FUNCTION_DECL,
      use the old decl.  */
-  if (!processing_template_decl && pre_parsed_p == 0)
+  if (!processing_template_decl && !(flags & SF_PRE_PARSED))
     {
       /* A specialization is not used to guide overload resolution.  */
       if ((flag_guiding_decls 
@@ -13544,7 +12916,52 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
       fntype = TREE_TYPE (decl1);
     }
 
+  /* Reset these in case the call to pushdecl changed them.  */
   current_function_decl = decl1;
+  current_function->decl = decl1;
+
+  /* Initialize the per-function data.  */
+  if (!DECL_PENDING_INLINE_P (decl1) && DECL_SAVED_FUNCTION_DATA (decl1))
+    {
+      /* If we already parsed this function, and we're just expanding it
+        now, restore saved state.  */
+      struct binding_level *bl = current_binding_level;
+      *cp_function_chain = *DECL_SAVED_FUNCTION_DATA (decl1);
+      current_binding_level = bl;
+
+      /* This function is being processed in whole-function mode; we
+        already did semantic analysis.  */
+      current_function->x_whole_function_mode_p = 1;
+
+      /* If we decided that we didn't want to inline this function,
+        make sure the back-end knows that.  */
+      if (!current_function_cannot_inline)
+       current_function_cannot_inline = cp_function_chain->cannot_inline;
+
+      /* We don't need the saved data anymore.  */
+      free (DECL_SAVED_FUNCTION_DATA (decl1));
+      DECL_SAVED_FUNCTION_DATA (decl1) = NULL;
+    }
+  else if (ctype && !doing_friend && !DECL_STATIC_FUNCTION_P (decl1))
+    {
+      /* We know that this was set up by `grokclassfn'.  We do not
+        wait until `store_parm_decls', since evil parse errors may
+        never get us to that point.  Here we keep the consistency
+        between `current_class_type' and `current_class_ptr'.  */
+      tree t = DECL_ARGUMENTS (decl1);
+             
+      my_friendly_assert (t != NULL_TREE && TREE_CODE (t) == PARM_DECL, 
+                         162);
+      my_friendly_assert (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE,
+                         19990811);
+         
+      cp_function_chain->x_current_class_ref 
+       = build_indirect_ref (t, NULL_PTR);
+      cp_function_chain->x_current_class_ptr = t;
+
+      if (DECL_DESTRUCTOR_P (decl1))
+       current_in_charge_parm = TREE_CHAIN (t);
+    }
 
   if (DECL_INTERFACE_KNOWN (decl1))
     {
@@ -13611,73 +13028,20 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
        DECL_INTERFACE_KNOWN (decl1) = 1;
     }
 
-  if (ctype != NULL_TREE && DECL_STATIC_FUNCTION_P (decl1))
-    {
-      if (TREE_CODE (fntype) == METHOD_TYPE)
-       TREE_TYPE (decl1) = fntype
-         = build_function_type (TREE_TYPE (fntype),
-                                TREE_CHAIN (TYPE_ARG_TYPES (fntype)));
-      current_function_parms = TREE_CHAIN (current_function_parms);
-      DECL_ARGUMENTS (decl1) = current_function_parms;
-      ctype = NULL_TREE;
-    }
-  restype = TREE_TYPE (fntype);
-
-  if (ctype)
+  if (doing_semantic_analysis_p ())
     {
-      /* If we're compiling a friend function, neither of the variables
-        current_class_ptr nor current_class_type will have values.  */
-      if (! doing_friend)
-       {
-         /* We know that this was set up by `grokclassfn'.
-            We do not wait until `store_parm_decls', since evil
-            parse errors may never get us to that point.  Here
-            we keep the consistency between `current_class_type'
-            and `current_class_ptr'.  */
-         tree t = current_function_parms;
-
-         my_friendly_assert (t != NULL_TREE
-                             && TREE_CODE (t) == PARM_DECL, 162);
-
-         if (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE)
-           {
-             int i;
-
-             if (! hack_decl_function_context (decl1))
-               temporary_allocation ();
-             i = suspend_momentary ();
-
-             /* Normally, build_indirect_ref returns
-                current_class_ref whenever current_class_ptr is
-                dereferenced.  This time, however, we want it to
-                *create* current_class_ref, so we temporarily clear
-                current_class_ptr to fool it.  */
-             current_class_ptr = NULL_TREE;
-             current_class_ref = build_indirect_ref (t, NULL_PTR);
-             current_class_ptr = t;
-
-             resume_momentary (i);
-             if (! hack_decl_function_context (decl1))
-               end_temporary_allocation ();
-           }
-         else
-           /* We're having a signature pointer here.  */
-           current_class_ref = current_class_ptr = t;
-
-       }
+      pushlevel (0);
+      current_binding_level->parm_flag = 1;
     }
-  else
-    current_class_ptr = current_class_ref = NULL_TREE;
-
-  pushlevel (0);
-  current_binding_level->parm_flag = 1;
-
-  GNU_xref_function (decl1, current_function_parms);
 
   if (attrs)
     cplus_decl_attributes (decl1, NULL_TREE, attrs);
   
-  make_function_rtl (decl1);
+  if (!building_stmt_tree ())
+    {
+      GNU_xref_function (decl1, current_function_parms);
+      make_function_rtl (decl1);
+    }
 
   /* Promote the value to int before returning it.  */
   if (C_PROMOTING_INTEGER_TYPE_P (restype))
@@ -13702,28 +13066,21 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
      on the permanent obstack in case we need to inline it later.  */
   if (! hack_decl_function_context (decl1))
     temporary_allocation ();
+  
+  /* Make sure that we always have a momntary obstack while we're in a
+     function body.  */
+  push_momentary ();
 
-  if (processing_template_decl)
-    {
-      ++minimal_parse_mode;
-      last_tree = DECL_SAVED_TREE (decl1)
-       = build_nt (EXPR_STMT, void_zero_node);
-    }
+  if (building_stmt_tree ())
+    begin_stmt_tree (decl1);
 
   ++function_depth;
 
   if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl1))
       && DECL_LANGUAGE (decl1) == lang_cplusplus)
-    {
-      dtor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
-      ctor_label = NULL_TREE;
-    }
-  else
-    {
-      dtor_label = NULL_TREE;
-      if (DECL_CONSTRUCTOR_P (decl1))
-       ctor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
-    }
+    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;
 }
@@ -13753,9 +13110,6 @@ store_parm_decls ()
   int parms_have_cleanups = 0;
   tree cleanups = NULL_TREE;
 
-  /* This is either a chain of PARM_DECLs (when a prototype is used).  */
-  tree specparms = current_function_parms;
-
   /* This is a list of types declared among parms in a prototype.  */
   tree parmtags = current_function_parm_tags;
 
@@ -13764,62 +13118,49 @@ store_parm_decls ()
      then CONST_DECLs for foo and bar are put here.  */
   tree nonparms = NULL_TREE;
 
-  if (toplevel_bindings_p ())
-    fatal ("parse errors have confused me too much");
-
-  /* Initialize RTL machinery.  */
-  init_function_start (fndecl, input_filename, lineno);
-
   /* Create a binding level for the parms.  */
-  expand_start_bindings (0);
+  if (!building_stmt_tree ())
+    expand_start_bindings (2);
 
-  if (specparms != NULL_TREE)
+  if (current_function_parms)
     {
       /* This case is when the function was defined with an ANSI prototype.
         The parms already have decls, so we need not do anything here
         except record them as in effect
         and complain if any redundant old-style parm decls were written.  */
 
-      register tree next;
+      tree specparms = current_function_parms;
+      tree next;
+
+      if (doing_semantic_analysis_p ())
+       {
+         /* Must clear this because it might contain TYPE_DECLs declared
+            at class level.  */
+         storedecls (NULL_TREE);
 
-      /* Must clear this because it might contain TYPE_DECLs declared
-        at class level.  */
-      storedecls (NULL_TREE);
+         /* If we're doing semantic analysis, then we'll call pushdecl
+            for each of these.  We must do them in reverse order so that
+            they end in the correct forward order.  */
+         specparms = nreverse (specparms);
+       }
 
-      for (parm = nreverse (specparms); parm; parm = next)
+      for (parm = specparms; parm; parm = next)
        {
          next = TREE_CHAIN (parm);
          if (TREE_CODE (parm) == PARM_DECL)
            {
              tree cleanup;
-             if (DECL_NAME (parm) == NULL_TREE)
-               {
-                 pushdecl (parm);
-               }
-             else if (TREE_CODE (TREE_TYPE (parm)) == VOID_TYPE)
-               cp_error ("parameter `%D' declared void", parm);
-             else
+             
+             if (doing_semantic_analysis_p ())
                {
-                 /* Now fill in DECL_REFERENCE_SLOT for any of the parm decls.
-                    A parameter is assumed not to have any side effects.
-                    If this should change for any reason, then this
-                    will have to wrap the bashed reference type in a save_expr.
-                    
-                    Also, if the parameter type is declared to be an X
-                    and there is an X(X&) constructor, we cannot lay it
-                    into the stack (any more), so we make this parameter
-                    look like it is really of reference type.  Functions
-                    which pass parameters to this function will know to
-                    create a temporary in their frame, and pass a reference
-                    to that.  */
-
-                 if (TREE_CODE (TREE_TYPE (parm)) == REFERENCE_TYPE
-                     && TYPE_SIZE (TREE_TYPE (TREE_TYPE (parm))))
-                   SET_DECL_REFERENCE_SLOT (parm, convert_from_reference (parm));
-
-                 pushdecl (parm);
+                 if (DECL_NAME (parm) == NULL_TREE
+                     || TREE_CODE (TREE_TYPE (parm)) != VOID_TYPE)
+                   pushdecl (parm);
+                 else
+                   cp_error ("parameter `%D' declared void", parm);
                }
-             if (! processing_template_decl
+
+             if (! building_stmt_tree ()
                  && (cleanup = maybe_build_cleanup (parm), cleanup))
                {
                  expand_decl (parm);
@@ -13838,12 +13179,17 @@ store_parm_decls ()
            }
        }
 
-      /* Get the decls in their original chain order
-        and record in the function.  This is all and only the
-        PARM_DECLs that were pushed into scope by the loop above.  */
-      DECL_ARGUMENTS (fndecl) = getdecls ();
+      if (doing_semantic_analysis_p ())
+       {
+         /* Get the decls in their original chain order
+            and record in the function.  This is all and only the
+            PARM_DECLs that were pushed into scope by the loop above.  */
+         DECL_ARGUMENTS (fndecl) = getdecls ();
+         storetags (chainon (parmtags, gettags ()));
 
-      storetags (chainon (parmtags, gettags ()));
+         /* We built up the cleanups in reversed order.  */
+         cleanups = nreverse (cleanups);
+       }
     }
   else
     DECL_ARGUMENTS (fndecl) = NULL_TREE;
@@ -13852,37 +13198,34 @@ store_parm_decls ()
      as the decl-chain of the current lexical scope.
      Put the enumerators in as well, at the front so that
      DECL_ARGUMENTS is not modified.  */
-
-  storedecls (chainon (nonparms, DECL_ARGUMENTS (fndecl)));
-
-  /* Declare __FUNCTION__ and __PRETTY_FUNCTION__ for this function.  */
-  declare_function_name ();
+  if (doing_semantic_analysis_p ())
+    storedecls (chainon (nonparms, DECL_ARGUMENTS (fndecl)));
 
   /* Initialize the RTL code for the function.  */
-  DECL_SAVED_INSNS (fndecl) = NULL_RTX;
-  if (! processing_template_decl)
+  DECL_SAVED_INSNS (fndecl) = 0;
+  if (! building_stmt_tree ())
     expand_function_start (fndecl, parms_have_cleanups);
 
   current_function_parms_stored = 1;
 
   /* If this function is `main', emit a call to `__main'
      to run global initializers, etc.  */
-  if (DECL_MAIN_P (fndecl))
+  if (DECL_MAIN_P (fndecl) && !building_stmt_tree ())
     expand_main_function ();
 
   /* Now that we have initialized the parms, we can start their
      cleanups.  We cannot do this before, since expand_decl_cleanup
      should not be called before the parm can be used.  */
-  if (cleanups
-      && ! processing_template_decl)      
-    {
-      for (cleanups = nreverse (cleanups); cleanups; cleanups = TREE_CHAIN (cleanups))
-       {
-         if (! expand_decl_cleanup (TREE_PURPOSE (cleanups), TREE_VALUE (cleanups)))
-           cp_error ("parser lost in parsing declaration of `%D'",
-                     TREE_PURPOSE (cleanups));
-       }
-    }
+  if (cleanups && !building_stmt_tree ())
+    while (cleanups)
+      {
+       if (! expand_decl_cleanup (TREE_PURPOSE (cleanups), 
+                                  TREE_VALUE (cleanups)))
+         cp_error ("parser lost in parsing declaration of `%D'",
+                   TREE_PURPOSE (cleanups));
+       
+       cleanups = TREE_CHAIN (cleanups);
+      }
 
   /* Create a binding contour which can be used to catch
      cleanup-generated temporaries.  Also, if the return value needs or
@@ -13890,77 +13233,213 @@ store_parm_decls ()
   if (parms_have_cleanups)
     {
       pushlevel (0);
-      expand_start_bindings (0);
+      if (!building_stmt_tree ())
+       expand_start_bindings (2);
+    }
+
+  /* Do the starting of the exception specifications, if we have any.  */
+  if (flag_exceptions && !processing_template_decl 
+      && building_stmt_tree () 
+      && TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
+    current_eh_spec_try_block = expand_start_eh_spec ();
+
+  last_parm_cleanup_insn = get_last_insn ();
+  last_dtor_insn = get_last_insn ();
+}
+
+/* Bind a name and initialization to the return value of
+   the current function.  */
+
+void
+store_return_init (decl)
+     tree decl;
+{
+  /* If this named return value comes in a register, put it in a
+     pseudo-register.  */
+  if (DECL_REGISTER (decl))
+    {
+      original_result_rtx = DECL_RTL (decl);
+      DECL_RTL (decl) = gen_reg_rtx (DECL_MODE (decl));
     }
+}
+
+\f
+/* We have finished doing semantic analysis on DECL, but have not yet
+   generated RTL for its body.  Save away our current state, so that
+   when we want to generate RTL later we know what to do.  */
 
-  if (! processing_template_decl && flag_exceptions)
-    {
-      /* Do the starting of the exception specifications, if we have any.  */
-      if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
-       expand_start_eh_spec ();
-    }
+static void
+save_function_data (decl)
+     tree decl;
+{
+  struct language_function *f;
 
-  last_parm_cleanup_insn = get_last_insn ();
-  last_dtor_insn = get_last_insn ();
+  /* Save the language-specific per-function data so that we can
+     get it back when we really expand this function.  */
+  my_friendly_assert (!DECL_PENDING_INLINE_P (decl),
+                     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_base_init_list = NULL_TREE;
+  f->x_member_init_list = NULL_TREE;
+  f->x_last_tree = NULL_TREE;
+  f->x_last_expr_type = NULL_TREE;
+  f->x_last_dtor_insn = NULL_RTX;
+  f->x_last_parm_cleanup_insn = NULL_RTX;
+  f->x_result_rtx = NULL_RTX;
+  f->x_named_label_uses = NULL;
+  f->bindings = NULL;
+
+  /* When we get back here again, we will be expanding.  */
+  f->x_expanding_p = 1;
+
+  /* If we've already decided that we cannot inline this function, we
+     must remember that fact when we actually go to expand the
+     function.  */
+  f->cannot_inline = current_function_cannot_inline;
+}
+
+/* At the end of every constructor we generate to code to return
+   `this'.  Do that now.  */
+
+static void
+finish_constructor_body ()
+{
+  /* Any return from a constructor will end up here.  */
+  add_tree (build_min_nt (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.  */
+  ctor_label = NULL_TREE;
+  /* In check_return_expr we translate an empty return from a
+     constructor to a return of `this'.  */
+  finish_return_stmt (NULL_TREE);
 }
 
-/* Bind a name and initialization to the return value of
-   the current function.  */
+/* At the end of every destructor we generate code to restore virtual
+   function tables to the values desired by base classes and to call
+   to base class destructors.  Do that now.  */
 
-void
-store_return_init (return_id, init)
-     tree return_id, init;
+static void
+finish_destructor_body ()
 {
-  tree decl = DECL_RESULT (current_function_decl);
+  tree compound_stmt;
+  tree in_charge;
+  tree virtual_size;
+  tree exprstmt;
 
-  if (pedantic)
-    /* Give this error as many times as there are occurrences,
-       so that users can use Emacs compilation buffers to find
-       and fix all such places.  */
-    pedwarn ("ANSI C++ does not permit named return values");
+  /* Create a block to contain all the extra code.  */
+  compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
 
-  if (return_id != NULL_TREE)
-    {
-      if (DECL_NAME (decl) == NULL_TREE)
-       {
-         DECL_NAME (decl) = return_id;
-         DECL_ASSEMBLER_NAME (decl) = return_id;
-       }
-      else
-       cp_error ("return identifier `%D' already in place", decl);
-    }
+  /* Any return from a destructor will end up here.  */
+  add_tree (build_min_nt (LABEL_STMT, dtor_label));
 
-  /* Can't let this happen for constructors.  */
-  if (DECL_CONSTRUCTOR_P (current_function_decl))
-    {
-      error ("can't redefine default return value for constructors");
-      return;
+  /* Generate the code to call destructor on base class.  If this
+     destructor belongs to a class with virtual functions, then set
+     the virtual function table pointer to represent the type of our
+     base class.  */
+
+  /* This side-effect makes call to `build_delete' generate the code
+     we have to have at the end of this destructor.  `build_delete'
+     will set the flag again.  */
+  TYPE_HAS_DESTRUCTOR (current_class_type) = 0;
+
+  /* These are two cases where we cannot delegate deletion.  */
+  if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)
+      || TYPE_GETS_REG_DELETE (current_class_type))
+    in_charge = integer_zero_node;
+  else
+    in_charge = current_in_charge_parm;
+
+  exprstmt = build_delete (current_class_type,
+                          current_class_ref, 
+                          in_charge,
+                          LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL, 
+                          0);
+
+  if (exprstmt != error_mark_node
+      && (TREE_CODE (exprstmt) != NOP_EXPR
+         || TREE_OPERAND (exprstmt, 0) != integer_zero_node
+         || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)))
+    {
+      if (exprstmt != void_zero_node)
+       /* Don't call `expand_expr_stmt' if we're not going to do
+          anything, since -Wall will give a diagnostic.  */
+       finish_expr_stmt (exprstmt);
+
+      /* Run destructors for all virtual baseclasses.  */
+      if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
+       {
+         tree vbases = nreverse (copy_list (CLASSTYPE_VBASECLASSES (current_class_type)));
+         tree if_stmt = begin_if_stmt ();
+         finish_if_stmt_cond (build (BIT_AND_EXPR, integer_type_node,
+                                     current_in_charge_parm, 
+                                     integer_two_node),
+                              if_stmt);
+
+         while (vbases)
+           {
+             if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (vbases)))
+               {
+                 tree vb = get_vbase
+                   (BINFO_TYPE (vbases),
+                    TYPE_BINFO (current_class_type));
+                 finish_expr_stmt
+                   (build_scoped_method_call
+                    (current_class_ref, vb, dtor_identifier,
+                     build_expr_list (NULL_TREE, integer_zero_node)));
+               }
+             vbases = TREE_CHAIN (vbases);
+           }
+
+         finish_then_clause (if_stmt);
+         finish_if_stmt ();
+       }
     }
+  
+  virtual_size = c_sizeof (current_class_type);
 
-  /* If we have a named return value, put that in our scope as well.  */
-  if (DECL_NAME (decl) != NULL_TREE)
+  /* At the end, call delete if that's what's requested.  */
+  
+  /* FDIS sez: At the point of definition of a virtual destructor
+     (including an implicit definition), non-placement operator delete
+     shall be looked up in the scope of the destructor's class and if
+     found shall be accessible and unambiguous.
+     
+     This is somewhat unclear, but I take it to mean that if the class
+     only defines placement deletes we don't do anything here.  So we
+     pass LOOKUP_SPECULATIVELY; delete_sanity will complain for us if
+     they ever try to delete one of these.  */
+  if (TYPE_GETS_REG_DELETE (current_class_type)
+      || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
     {
-      /* If this named return value comes in a register,
-        put it in a pseudo-register.  */
-      if (DECL_REGISTER (decl))
-       {
-         original_result_rtx = DECL_RTL (decl);
-         DECL_RTL (decl) = gen_reg_rtx (DECL_MODE (decl));
-       }
+      tree if_stmt;
 
-      /* Let `cp_finish_decl' know that this initializer is ok.  */
-      DECL_INITIAL (decl) = init;
-      pushdecl (decl);
+      exprstmt = build_op_delete_call
+       (DELETE_EXPR, current_class_ptr, virtual_size,
+        LOOKUP_NORMAL | LOOKUP_SPECULATIVELY, NULL_TREE);
 
-      if (minimal_parse_mode)
-       add_tree (build_min_nt (RETURN_INIT, return_id,
-                               copy_to_permanent (init)));
-      else
-       cp_finish_decl (decl, init, NULL_TREE, 0, 0);
+      if_stmt = begin_if_stmt ();
+      finish_if_stmt_cond (build (BIT_AND_EXPR, integer_type_node,
+                                 current_in_charge_parm,
+                                 integer_one_node),
+                          if_stmt);
+      finish_expr_stmt (exprstmt);
+      finish_then_clause (if_stmt);
+      finish_if_stmt ();
     }
+
+  /* Close the block we started above.  */
+  finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
 }
 
-\f
 /* Finish up a function declaration and compile that function
    all the way to assembler language output.  The free the storage
    for the function definition.
@@ -13976,40 +13455,33 @@ store_return_init (return_id, init)
      2 - INCLASS_INLINE
        We just finished processing the body of an in-class inline
        function definition.  (This processing will have taken place
-       after the class definition is complete.)
+       after the class definition is complete.)  */
 
-   NESTED is nonzero if we were in the middle of compiling another function
-   when we started on this one.  */
-
-void
-finish_function (lineno, flags, nested)
+tree
+finish_function (lineno, flags)
      int lineno;
      int flags;
-     int nested;
 {
   register tree fndecl = current_function_decl;
   tree fntype, ctype = NULL_TREE;
-  rtx last_parm_insn, insns;
   /* Label to use if this function is supposed to return a value.  */
   tree no_return_label = NULL_TREE;
-  tree decls = NULL_TREE;
   int call_poplevel = (flags & 1) != 0;
   int inclass_inline = (flags & 2) != 0;
-  int in_template;
+  int expand_p;
+  int nested;
 
   /* When we get some parse errors, we can end up without a
      current_function_decl, so cope.  */
   if (fndecl == NULL_TREE)
-    return;
-
-  if (function_depth > 1)
-    nested = 1;
+    return error_mark_node;
 
+  nested = function_depth > 1;
   fntype = TREE_TYPE (fndecl);
 
-/*  TREE_READONLY (fndecl) = 1;
-    This caused &foo to be of type ptr-to-const-function
-    which then got a warning when stored in a ptr-to-function variable.  */
+  /*  TREE_READONLY (fndecl) = 1;
+      This caused &foo to be of type ptr-to-const-function
+      which then got a warning when stored in a ptr-to-function variable.  */
 
   /* This happens on strange parse errors.  */
   if (! current_function_parms_stored)
@@ -14018,14 +13490,32 @@ finish_function (lineno, flags, nested)
       store_parm_decls ();
     }
 
-  if (processing_template_decl)
+  if (building_stmt_tree ())
     {
-      if (DECL_CONSTRUCTOR_P (fndecl) && call_poplevel)
+      if (DECL_CONSTRUCTOR_P (fndecl))
+       {
+         finish_constructor_body ();
+         if (call_poplevel)
+           do_poplevel ();
+       }
+      else if (DECL_DESTRUCTOR_P (fndecl) && !processing_template_decl)
+       finish_destructor_body ();
+      else if (DECL_MAIN_P (fndecl))
        {
-         decls = getdecls ();
-         expand_end_bindings (decls, decls != NULL_TREE, 0);
-         poplevel (decls != NULL_TREE, 0, 0);
+         /* Make it so that `main' always returns 0 by default.  */
+#ifdef VMS
+         finish_return_stmt (integer_one_node);
+#else
+         finish_return_stmt (integer_zero_node);
+#endif
        }
+
+      /* Finish dealing with exception specifiers.  */
+      if (flag_exceptions && !processing_template_decl
+         && TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
+       expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS 
+                           (TREE_TYPE (current_function_decl)),
+                           current_eh_spec_try_block);
     }
   else
     {
@@ -14051,291 +13541,17 @@ finish_function (lineno, flags, nested)
       do_pending_stack_adjust ();
 
       if (dtor_label)
-       {
-         tree binfo = TYPE_BINFO (current_class_type);
-         tree cond = integer_one_node;
-         tree exprstmt;
-         tree in_charge_node = lookup_name (in_charge_identifier, 0);
-         tree virtual_size;
-         int ok_to_optimize_dtor = 0;
-         int empty_dtor = get_last_insn () == last_dtor_insn;
-
-         if (current_function_assigns_this)
-           cond = build (NE_EXPR, boolean_type_node,
-                         current_class_ptr, integer_zero_node);
-         else
-           {
-             int n_baseclasses = CLASSTYPE_N_BASECLASSES (current_class_type);
-
-             /* If this destructor is empty, then we don't need to check
-                whether `this' is NULL in some cases.  */
-             if ((flag_this_is_variable & 1) == 0)
-               ok_to_optimize_dtor = 1;
-             else if (empty_dtor)
-               ok_to_optimize_dtor
-                 = (n_baseclasses == 0
-                    || (n_baseclasses == 1
-                        && TYPE_HAS_DESTRUCTOR (TYPE_BINFO_BASETYPE (current_class_type, 0))));
-           }
-
-         /* These initializations might go inline.  Protect
-            the binding level of the parms.  */
-         pushlevel (0);
-         expand_start_bindings (0);
-
-         if (current_function_assigns_this)
-           {
-             current_function_assigns_this = 0;
-             current_function_just_assigned_this = 0;
-           }
-
-         /* Generate the code to call destructor on base class.
-            If this destructor belongs to a class with virtual
-            functions, then set the virtual function table
-            pointer to represent the type of our base class.  */
-
-         /* This side-effect makes call to `build_delete' generate the
-            code we have to have at the end of this destructor.
-            `build_delete' will set the flag again.  */
-         TYPE_HAS_DESTRUCTOR (current_class_type) = 0;
-
-         /* These are two cases where we cannot delegate deletion.  */
-         if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)
-             || TYPE_GETS_REG_DELETE (current_class_type))
-           exprstmt = build_delete (current_class_type, current_class_ref, integer_zero_node,
-                                    LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL, 0);
-         else
-           exprstmt = build_delete (current_class_type, current_class_ref, in_charge_node,
-                                    LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL, 0);
-
-         /* If we did not assign to this, then `this' is non-zero at
-            the end of a destructor.  As a special optimization, don't
-            emit test if this is an empty destructor.  If it does nothing,
-            it does nothing.  If it calls a base destructor, the base
-            destructor will perform the test.  */
-
-         if (exprstmt != error_mark_node
-             && (TREE_CODE (exprstmt) != NOP_EXPR
-                 || TREE_OPERAND (exprstmt, 0) != integer_zero_node
-                 || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)))
-           {
-             expand_label (dtor_label);
-             if (cond != integer_one_node)
-               expand_start_cond (cond, 0);
-             if (exprstmt != void_zero_node)
-               /* Don't call `expand_expr_stmt' if we're not going to do
-                  anything, since -Wall will give a diagnostic.  */
-               expand_expr_stmt (exprstmt);
-
-             /* Run destructor on all virtual baseclasses.  */
-             if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
-               {
-                 tree vbases = nreverse (copy_list (CLASSTYPE_VBASECLASSES (current_class_type)));
-                 expand_start_cond (build (BIT_AND_EXPR, integer_type_node,
-                                           in_charge_node, integer_two_node), 0);
-                 while (vbases)
-                   {
-                     if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (vbases)))
-                       {
-                         tree vb = get_vbase
-                           (BINFO_TYPE (vbases),
-                            TYPE_BINFO (current_class_type));
-                         expand_expr_stmt
-                           (build_scoped_method_call
-                            (current_class_ref, vb, dtor_identifier,
-                             build_expr_list (NULL_TREE, integer_zero_node)));
-                       }
-                     vbases = TREE_CHAIN (vbases);
-                   }
-                 expand_end_cond ();
-               }
-
-             do_pending_stack_adjust ();
-             if (cond != integer_one_node)
-               expand_end_cond ();
-           }
-
-         virtual_size = c_sizeof (current_class_type);
-
-         /* At the end, call delete if that's what's requested.  */
-
-         /* FDIS sez: At the point of definition of a virtual destructor
-              (including an implicit definition), non-placement operator
-              delete shall be looked up in the scope of the destructor's
-              class and if found shall be accessible and unambiguous.
-
-            This is somewhat unclear, but I take it to mean that if the
-            class only defines placement deletes we don't do anything here.
-            So we pass LOOKUP_SPECULATIVELY; delete_sanity will complain
-            for us if they ever try to delete one of these.  */
-
-         if (TYPE_GETS_REG_DELETE (current_class_type)
-             || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
-           exprstmt = build_op_delete_call
-             (DELETE_EXPR, current_class_ptr, virtual_size,
-              LOOKUP_NORMAL | LOOKUP_SPECULATIVELY, NULL_TREE);
-         else
-           exprstmt = NULL_TREE;
-
-         if (exprstmt)
-           {
-             cond = build (BIT_AND_EXPR, integer_type_node,
-                           in_charge_node, integer_one_node);
-             expand_start_cond (cond, 0);
-             expand_expr_stmt (exprstmt);
-             expand_end_cond ();
-           }
-
-         /* End of destructor.  */
-         expand_end_bindings (NULL_TREE, getdecls () != NULL_TREE, 0);
-         poplevel (getdecls () != NULL_TREE, 0, 0);
-
-         /* Back to the top of destructor.  */
-         /* Don't execute destructor code if `this' is NULL.  */
-
-         start_sequence ();
-
-         /* If the dtor is empty, and we know there is not possible way we
-            could use any vtable entries, before they are possibly set by
-            a base class dtor, we don't have to setup the vtables, as we
-            know that any base class dtoring will set up any vtables it
-            needs.  We avoid MI, because one base class dtor can do a
-            virtual dispatch to an overridden function that would need to
-            have a non-related vtable set up, we cannot avoid setting up
-            vtables in that case.  We could change this to see if there is
-            just one vtable.  */
-         if (! empty_dtor || TYPE_USES_COMPLEX_INHERITANCE (current_class_type))
-           {
-             /* Make all virtual function table pointers in non-virtual base
-                classes point to CURRENT_CLASS_TYPE's virtual function
-                tables.  */
-             expand_direct_vtbls_init (binfo, binfo, 1, 0, current_class_ptr);
-
-             if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
-               expand_indirect_vtbls_init (binfo, current_class_ref, current_class_ptr);
-           }
-         
-         if (! ok_to_optimize_dtor)
-           {
-             cond = build_binary_op (NE_EXPR,
-                                     current_class_ptr, integer_zero_node);
-             expand_start_cond (cond, 0);
-           }
-
-         insns = get_insns ();
-         end_sequence ();
-
-         last_parm_insn = get_first_nonparm_insn ();
-         if (last_parm_insn == NULL_RTX)
-           last_parm_insn = get_last_insn ();
-         else
-           last_parm_insn = previous_insn (last_parm_insn);
-
-         emit_insns_after (insns, last_parm_insn);
-
-         if (! ok_to_optimize_dtor)
-           expand_end_cond ();
-       }
-      else if (current_function_assigns_this)
-       {
-         /* Does not need to call emit_base_init, because
-            that is done (if needed) just after assignment to this
-            is seen.  */
-
-         if (DECL_CONSTRUCTOR_P (current_function_decl))
-           {
-             end_protect_partials ();
-             expand_label (ctor_label);
-             ctor_label = NULL_TREE;
-
-             if (call_poplevel)
-               {
-                 decls = getdecls ();
-                 expand_end_bindings (decls, decls != NULL_TREE, 0);
-                 poplevel (decls != NULL_TREE, 0, 0);
-               }
-             /* c_expand_return knows to return 'this' from a constructor.  */
-             c_expand_return (NULL_TREE);
-           }
-         else if (TREE_CODE (TREE_TYPE (DECL_RESULT (current_function_decl))) != VOID_TYPE
-                  && return_label != NULL_RTX)
-           no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
-
-         current_function_assigns_this = 0;
-         current_function_just_assigned_this = 0;
-         base_init_expr = NULL_TREE;
-       }
+       ;
       else if (DECL_CONSTRUCTOR_P (fndecl))
        {
-         tree cond = NULL_TREE, thenclause = NULL_TREE;
-         /* Allow constructor for a type to get a new instance of the object
-            using `build_new'.  */
-         tree abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type);
-         CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = NULL_TREE;
-
-         if (flag_this_is_variable > 0)
-           {
-             cond = build_binary_op (EQ_EXPR,
-                                     current_class_ptr, integer_zero_node);
-             thenclause = build_modify_expr (current_class_ptr, NOP_EXPR,
-                                             build_new (NULL_TREE, current_class_type, void_type_node, 0));
-           }
-
-         CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = abstract_virtuals;
-
-         start_sequence ();
-
-         if (flag_this_is_variable > 0)
-           {
-             expand_start_cond (cond, 0);
-             expand_expr_stmt (thenclause);
-             expand_end_cond ();
-           }
-
-         /* Emit insns from `emit_base_init' which sets up virtual
-            function table pointer(s).  */
-         if (base_init_expr)
-           {
-             expand_expr_stmt (base_init_expr);
-             base_init_expr = NULL_TREE;
-           }
-
-         insns = get_insns ();
-         end_sequence ();
-
-         /* This is where the body of the constructor begins.  */
-
-         emit_insns_after (insns, last_parm_cleanup_insn);
-
+         /* All subobjects have been fully constructed at this point.  */
          end_protect_partials ();
 
-         /* This is where the body of the constructor ends.  */
-         expand_label (ctor_label);
-         ctor_label = NULL_TREE;
-
          if (call_poplevel)
-           {
-             decls = getdecls ();
-             expand_end_bindings (decls, decls != NULL_TREE, 0);
-             poplevel (decls != NULL_TREE, 1, 0);
-           }
-
-         /* c_expand_return knows to return 'this' from a constructor.  */
-         c_expand_return (NULL_TREE);
-
-         current_function_assigns_this = 0;
-         current_function_just_assigned_this = 0;
-       }
-      else if (DECL_MAIN_P (fndecl))
-       {
-         /* Make it so that `main' always returns 0 by default.  */
-#ifdef VMS
-         c_expand_return (integer_one_node);
-#else
-         c_expand_return (integer_zero_node);
-#endif
+           do_poplevel ();
        }
       else if (return_label != NULL_RTX
+              && flag_this_is_variable <= 0
               && current_function_return_value == NULL_TREE
               && ! DECL_NAME (DECL_RESULT (current_function_decl)))
        no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
@@ -14380,7 +13596,8 @@ finish_function (lineno, flags, nested)
          emit_label (cleanup_label);
        }
 
-      /* Get return value into register if that's where it's supposed to be.  */
+      /* Get return value into register if that's where it's supposed
+        to be.  */
       if (original_result_rtx)
        fixup_result_decl (DECL_RESULT (fndecl), original_result_rtx);
 
@@ -14396,49 +13613,39 @@ finish_function (lineno, flags, nested)
          expand_label (no_return_label);
        }
 
+      /* We hard-wired immediate_size_expand to zero in
+        start_function.  Expand_function_end will decrement this
+        variable.  So, we set the variable to one here, so that after
+        the decrement it will remain zero.  */
+      immediate_size_expand = 1;
+
       /* Generate rtl for function exit.  */
       expand_function_end (input_filename, lineno, 1);
     }
+
+  /* We have to save this value here in case
+     maybe_end_member_template_processing decides to pop all the
+     template parameters.  */
+  expand_p = !building_stmt_tree ();
   
-  /* If we're processing a template, squirrel away the definition
-     until we do an instantiation.  */
-  if (processing_template_decl)
-    {
-      --minimal_parse_mode;
-      DECL_SAVED_TREE (fndecl) = TREE_CHAIN (DECL_SAVED_TREE (fndecl));
-      /* We have to save this value here in case
-        maybe_end_member_template_processing decides to pop all the
-        template parameters.  */
-      in_template = 1;
-    }
-  else
-    in_template = 0;
+  /* If we're saving up tree structure, tie off the function now.  */
+  if (!expand_p)
+    finish_stmt_tree (fndecl);
 
   /* This must come after expand_function_end because cleanups might
      have declarations (from inline functions) that need to go into
      this function's blocks.  */
-  if (current_binding_level->parm_flag != 1)
-    my_friendly_abort (122);
-  poplevel (1, 0, 1);
-
-  /* If this is a in-class inline definition, we may have to pop the
-     bindings for the template parameters that we added in
-     maybe_begin_member_template_processing when start_function was
-     called.  */
-  if (inclass_inline)
-    maybe_end_member_template_processing ();
-
-  /* Reset scope for C++: if we were in the scope of a class,
-     then when we finish this function, we are not longer so.
-     This cannot be done until we know for sure that no more
-     class members will ever be referenced in this function
-     (i.e., calls to destructors).  */
-  if (current_class_name)
+  if (doing_semantic_analysis_p ())
     {
-      ctype = current_class_type;
-      pop_nested_class ();
+      if (current_binding_level->parm_flag != 1)
+       my_friendly_abort (122);
+      poplevel (1, 0, 1);
     }
 
+  /* Remember that we were in class scope.  */
+  if (current_class_name)
+    ctype = current_class_type;
+
   /* Must mark the RESULT_DECL as being in this function.  */
   DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl;
 
@@ -14446,8 +13653,17 @@ finish_function (lineno, flags, nested)
      to the FUNCTION_DECL node itself.  */
   BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl;
 
-  if (!in_template)
+  /* Undo the call to push_momentary in start_function.  */
+  pop_momentary ();
+
+  /* Save away current state, if appropriate.  */
+  if (!expanding_p && !processing_template_decl)
+    save_function_data (fndecl);
+
+  if (expand_p)
     {
+      int returns_null;
+      int returns_value;
       int saved_flag_keep_inline_functions =
        flag_keep_inline_functions;
 
@@ -14463,9 +13679,21 @@ finish_function (lineno, flags, nested)
           function is gone.  See save_tree_status.  */
        flag_keep_inline_functions = 1;
 
+      /* Before we call rest_of_compilation (which will pop the
+        CURRENT_FUNCTION), we must save these values.  */
+      returns_null = current_function_returns_null;
+      returns_value = current_function_returns_value;
+
+      /* If this is a nested function (like a template instantiation
+        that we're compiling in the midst of compiling something
+        else), push a new GC context.  That will keep local variables
+        on the stack from being collected while we're doing the
+        compilation of this function.  */
+      if (function_depth > 1)
+       ggc_push_context ();
+
       /* Run the optimizers and output the assembler code for this
          function.  */
-
       if (DECL_ARTIFICIAL (fndecl))
        {
          /* Do we really *want* to inline this synthesized method?  */
@@ -14483,6 +13711,10 @@ finish_function (lineno, flags, nested)
       else
        rest_of_compilation (fndecl);
 
+      /* Undo the call to ggc_push_context above.  */
+      if (function_depth > 1)
+       ggc_pop_context ();
+
       flag_keep_inline_functions = saved_flag_keep_inline_functions;
 
       if (DECL_SAVED_INSNS (fndecl) && ! TREE_ASM_WRITTEN (fndecl))
@@ -14498,7 +13730,7 @@ finish_function (lineno, flags, nested)
       if (ctype && TREE_ASM_WRITTEN (fndecl))
        note_debug_info_needed (ctype);
 
-      current_function_returns_null |= can_reach_end;
+      returns_null |= can_reach_end;
 
       /* Since we don't normally go through c_expand_return for constructors,
         this normally gets the wrong value.
@@ -14506,12 +13738,12 @@ finish_function (lineno, flags, nested)
         NOTE_INSN_FUNCTION_END, confusing jump.c.  */
       if (DECL_CONSTRUCTOR_P (fndecl)
          || DECL_NAME (DECL_RESULT (fndecl)) != NULL_TREE)
-       current_function_returns_null = 0;
+       returns_null = 0;
 
-      if (TREE_THIS_VOLATILE (fndecl) && current_function_returns_null)
+      if (TREE_THIS_VOLATILE (fndecl) && returns_null)
        cp_warning ("`noreturn' function `%D' does return", fndecl);
       else if ((warn_return_type || pedantic)
-              && current_function_returns_null
+              && returns_null
               && TREE_CODE (TREE_TYPE (fntype)) != VOID_TYPE)
        {
          /* If this function returns non-void and control can drop through,
@@ -14520,10 +13752,27 @@ finish_function (lineno, flags, nested)
        }
       /* With just -W, complain only if function returns both with
         and without a value.  */
-      else if (extra_warnings
-              && current_function_returns_value && current_function_returns_null)
+      else if (extra_warnings && returns_value && returns_null)
        warning ("this function may return with or without a value");
     }
+  else
+    {
+      /* Since we never call rest_of_compilation, we never clear
+        CURRENT_FUNCTION.  Do so explicitly.  */
+      free_after_compilation (current_function);
+      current_function = NULL;
+    }
+
+  /* If this is a in-class inline definition, we may have to pop the
+     bindings for the template parameters that we added in
+     maybe_begin_member_template_processing when start_function was
+     called.  */
+  if (inclass_inline)
+    maybe_end_member_template_processing ();
+
+  /* Leave the scope of the class.  */
+  if (ctype)
+    pop_nested_class ();
 
   --function_depth;
 
@@ -14533,7 +13782,7 @@ finish_function (lineno, flags, nested)
   if (! nested)
     permanent_allocation (1);
 
-  if (DECL_SAVED_INSNS (fndecl) == NULL_RTX)
+  if (!DECL_SAVED_INSNS (fndecl) && !DECL_SAVED_FUNCTION_DATA (fndecl))
     {
       tree t;
 
@@ -14546,10 +13795,11 @@ finish_function (lineno, flags, nested)
     }
 
   if (DECL_STATIC_CONSTRUCTOR (fndecl))
-    static_ctors = perm_tree_cons (NULL_TREE, fndecl, static_ctors);
+    static_ctors = tree_cons (NULL_TREE, fndecl, static_ctors);
   if (DECL_STATIC_DESTRUCTOR (fndecl))
-    static_dtors = perm_tree_cons (NULL_TREE, fndecl, static_dtors);
+    static_dtors = tree_cons (NULL_TREE, fndecl, static_dtors);
 
+  /* Clean up.  */
   if (! nested)
     {
       /* Let the error reporting routines know that we're outside a
@@ -14558,9 +13808,7 @@ finish_function (lineno, flags, nested)
       current_function_decl = NULL_TREE;
     }
 
-  named_label_uses = NULL;
-  current_class_ptr = NULL_TREE;
-  current_class_ref = NULL_TREE;
+  return fndecl;
 }
 \f
 /* Create the FUNCTION_DECL for a function definition.
@@ -14603,9 +13851,6 @@ start_method (declspecs, declarator, attrlist)
     /* Not a function, tell parser to report parse error.  */
     return NULL_TREE;
 
-  if (IS_SIGNATURE (current_class_type))
-    IS_DEFAULT_IMPLEMENTATION (fndecl) = 1;
-
   if (DECL_IN_AGGR_P (fndecl))
     {
       if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (fndecl)) != current_class_type)
@@ -14811,7 +14056,7 @@ maybe_build_cleanup_1 (decl, auto_delete)
 
       if (TYPE_USES_VIRTUAL_BASECLASSES (type)
          && ! TYPE_HAS_DESTRUCTOR (type))
-       rval = build_compound_expr (expr_tree_cons (NULL_TREE, rval,
+       rval = build_compound_expr (tree_cons (NULL_TREE, rval,
                                               build_expr_list (NULL_TREE, build_vbase_delete (type, decl))));
 
       if (TREE_CODE (decl) != PARM_DECL)
@@ -14822,6 +14067,26 @@ maybe_build_cleanup_1 (decl, auto_delete)
   return 0;
 }
 
+/* Build a TARGET_EXPR, initializing the DECL with the VALUE.  */
+
+tree
+build_target_expr (decl, value)
+     tree decl;
+     tree value;
+{
+  tree t;
+
+  t = build (TARGET_EXPR, TREE_TYPE (decl), decl, value, 
+            maybe_build_cleanup (decl), NULL_TREE);
+  /* We always set TREE_SIDE_EFFECTS so that expand_expr does not
+     ignore the TARGET_EXPR.  If there really turn out to be no
+     side-effects, then the optimizer should be able to get rid of
+     whatever code is generated anyhow.  */
+  TREE_SIDE_EFFECTS (t) = 1;
+
+  return t;
+}
+
 /* If DECL is of a type which needs a cleanup, build that cleanup
    here.  The cleanup does free the storage with a call to delete.  */
 
@@ -14854,70 +14119,31 @@ void
 cplus_expand_expr_stmt (exp)
      tree exp;
 {
-  if (processing_template_decl)
-    {
-      add_tree (build_min_nt (EXPR_STMT, exp));
-      return;
-    }
-
-  /* Arrange for all temps to disappear.  */
-  expand_start_target_temps ();
-
-  exp = require_complete_type_in_void (exp);
+  if (stmts_are_full_exprs_p)
+    exp = convert_to_void (exp, "statement");
   
-  if (TREE_CODE (exp) == FUNCTION_DECL)
-    {
-      cp_warning ("reference, not call, to function `%D'", exp);
-      warning ("at this point in file");
-    }
-
 #if 0
   /* We should do this eventually, but right now this causes regex.o from
      libg++ to miscompile, and tString to core dump.  */
   exp = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp);
 #endif
 
-  /* Strip unused implicit INDIRECT_REFs of references.  */
-  if (TREE_CODE (exp) == INDIRECT_REF
-      && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == REFERENCE_TYPE)
-    exp = TREE_OPERAND (exp, 0);
-
   /* If we don't do this, we end up down inside expand_expr
      trying to do TYPE_MODE on the ERROR_MARK, and really
      go outside the bounds of the type.  */
   if (exp != error_mark_node)
     expand_expr_stmt (break_out_cleanups (exp));
-
-  /* Clean up any pending cleanups.  This happens when a function call
-     returns a cleanup-needing value that nobody uses.  */
-  expand_end_target_temps ();
 }
 
-/* When a stmt has been parsed, this function is called.
-
-   Currently, this function only does something within a
-   constructor's scope: if a stmt has just assigned to this,
-   and we are in a derived class, we call `emit_base_init'.  */
+/* When a stmt has been parsed, this function is called.  */
 
 void
 finish_stmt ()
 {
-  extern struct nesting *cond_stack, *loop_stack, *case_stack;
-
-  
-  if (current_function_assigns_this
-      || ! current_function_just_assigned_this)
-    return;
-  if (DECL_CONSTRUCTOR_P (current_function_decl))
-    {
-      /* Constructors must wait until we are out of control
-        zones before calling base constructors.  */
-      if (cond_stack || loop_stack || case_stack)
-       return;
-      expand_expr_stmt (base_init_expr);
-      check_base_init (current_class_type);
-    }
-  current_function_assigns_this = 1;
+  /* Always assume this statement was not an expression statement.  If
+     it actually was an expression statement, its our callers
+     responsibility to fix this up.  */
+  last_expr_type = NULL_TREE;
 }
 
 /* Change a static member function definition into a FUNCTION_TYPE, instead
@@ -14955,116 +14181,73 @@ revert_static_member_fn (decl, fn, argtypes)
     *argtypes = args;
 }
 
-struct cp_function
-{
-  int returns_value;
-  int returns_null;
-  int assigns_this;
-  int just_assigned_this;
-  int parms_stored;
-  int temp_name_counter;
-  tree named_labels;
-  struct named_label_list *named_label_uses;
-  tree shadowed_labels;
-  tree ctor_label;
-  tree dtor_label;
-  rtx last_dtor_insn;
-  rtx last_parm_cleanup_insn;
-  tree base_init_list;
-  tree member_init_list;
-  tree base_init_expr;
-  tree current_class_ptr;
-  tree current_class_ref;
-  rtx result_rtx;
-  struct cp_function *next;
-  struct binding_level *binding_level;
-  int static_labelno;
-};
+/* Initialize the variables used during compilation of a C++ 
+   function.  */ 
+
+static void
+push_cp_function_context (f)
+     struct function *f;
+{
+  struct language_function *p 
+    = ((struct language_function *) 
+       xcalloc (1, sizeof (struct language_function)));
+  f->language = p;
 
-static struct cp_function *cp_function_chain;
+  /* It takes an explicit call to expand_body to generate RTL for a
+     function.  */
+  expanding_p = 0;
 
-extern int temp_name_counter;
+  /* Whenever we start a new function, we destroy temporaries in the
+     usual way.  */
+  stmts_are_full_exprs_p = 1;
+}
 
-/* Save and reinitialize the variables
-   used during compilation of a C++ function.  */
+/* Free the language-specific parts of F, now that we've finished
+   compiling the function.  */
 
-void
-push_cp_function_context (context)
-     tree context;
+static void
+pop_cp_function_context (f)
+     struct function *f;
 {
-  struct cp_function *p
-    = (struct cp_function *) xmalloc (sizeof (struct cp_function));
-
-  push_function_context_to (context);
-
-  p->next = cp_function_chain;
-  cp_function_chain = p;
-
-  p->named_labels = named_labels;
-  p->named_label_uses = named_label_uses;
-  p->shadowed_labels = shadowed_labels;
-  p->returns_value = current_function_returns_value;
-  p->returns_null = current_function_returns_null;
-  p->binding_level = current_binding_level;
-  p->ctor_label = ctor_label;
-  p->dtor_label = dtor_label;
-  p->last_dtor_insn = last_dtor_insn;
-  p->last_parm_cleanup_insn = last_parm_cleanup_insn;
-  p->assigns_this = current_function_assigns_this;
-  p->just_assigned_this = current_function_just_assigned_this;
-  p->parms_stored = current_function_parms_stored;
-  p->result_rtx = original_result_rtx;
-  p->base_init_expr = base_init_expr;
-  p->temp_name_counter = temp_name_counter;
-  p->base_init_list = current_base_init_list;
-  p->member_init_list = current_member_init_list;
-  p->current_class_ptr = current_class_ptr;
-  p->current_class_ref = current_class_ref;
-  p->static_labelno = static_labelno;
-}
-
-/* Restore the variables used during compilation of a C++ function.  */
+  free (f->language);
+  f->language = 0;
+}
 
-void
-pop_cp_function_context (context)
-     tree context;
+/* Mark P for GC.  */
+
+static void
+mark_lang_function (p)
+     struct language_function *p;
 {
-  struct cp_function *p = cp_function_chain;
-  tree link;
+  if (!p)
+    return;
+
+  ggc_mark_tree (p->x_named_labels);
+  ggc_mark_tree (p->x_ctor_label);
+  ggc_mark_tree (p->x_dtor_label);
+  ggc_mark_tree (p->x_base_init_list);
+  ggc_mark_tree (p->x_member_init_list);
+  ggc_mark_tree (p->x_current_class_ptr);
+  ggc_mark_tree (p->x_current_class_ref);
+  ggc_mark_tree (p->x_last_tree);
+  ggc_mark_tree (p->x_last_expr_type);
+  ggc_mark_tree (p->x_eh_spec_try_block);
+  ggc_mark_tree (p->x_scope_stmt_stack);
+
+  ggc_mark_rtx (p->x_last_dtor_insn);
+  ggc_mark_rtx (p->x_last_parm_cleanup_insn);
+  ggc_mark_rtx (p->x_result_rtx);
+
+  mark_binding_level (&p->bindings);
+}
+
+/* Mark the language-specific data in F for GC.  */
 
-  /* Bring back all the labels that were shadowed.  */
-  for (link = shadowed_labels; link; link = TREE_CHAIN (link))
-    if (DECL_NAME (TREE_VALUE (link)) != 0)
-      SET_IDENTIFIER_LABEL_VALUE (DECL_NAME (TREE_VALUE (link)),
-                                 TREE_VALUE (link));
-
-  pop_function_context_from (context);
-
-  cp_function_chain = p->next;
-
-  named_labels = p->named_labels;
-  named_label_uses = p->named_label_uses;
-  shadowed_labels = p->shadowed_labels;
-  current_function_returns_value = p->returns_value;
-  current_function_returns_null = p->returns_null;
-  current_binding_level = p->binding_level;
-  ctor_label = p->ctor_label;
-  dtor_label = p->dtor_label;
-  last_dtor_insn = p->last_dtor_insn;
-  last_parm_cleanup_insn = p->last_parm_cleanup_insn;
-  current_function_assigns_this = p->assigns_this;
-  current_function_just_assigned_this = p->just_assigned_this;
-  current_function_parms_stored = p->parms_stored;
-  original_result_rtx = p->result_rtx;
-  base_init_expr = p->base_init_expr;
-  temp_name_counter = p->temp_name_counter;
-  current_base_init_list = p->base_init_list;
-  current_member_init_list = p->member_init_list;
-  current_class_ptr = p->current_class_ptr;
-  current_class_ref = p->current_class_ref;
-  static_labelno = p->static_labelno;
-
-  free (p);
+void
+mark_cp_function_context (f)
+     struct function *f;
+{
+  mark_lang_function (f->language);
 }
 
 int
@@ -15072,3 +14255,98 @@ in_function_p ()
 {
   return function_depth != 0;
 }
+
+
+void
+lang_mark_false_label_stack (l)
+     struct label_node *l;
+{
+  /* C++ doesn't use false_label_stack.  It better be NULL.  */
+  my_friendly_assert (l == NULL, 19990904);
+}
+
+void
+lang_mark_tree (t)
+     tree t;
+{
+  enum tree_code code = TREE_CODE (t);
+  if (code == IDENTIFIER_NODE)
+    {
+      struct lang_identifier *li = (struct lang_identifier *) t;
+      struct lang_id2 *li2 = li->x;
+      ggc_mark_tree (li->namespace_bindings);
+      ggc_mark_tree (li->bindings);
+      ggc_mark_tree (li->class_value);
+      ggc_mark_tree (li->class_template_info);
+
+      if (li2)
+       {
+         ggc_mark_tree (li2->label_value);
+         ggc_mark_tree (li2->implicit_decl);
+         ggc_mark_tree (li2->error_locus);
+       }
+    }
+  else if (code == CPLUS_BINDING)
+    {
+      if (BINDING_HAS_LEVEL_P (t))
+       mark_binding_level (&BINDING_LEVEL (t));
+      else
+       ggc_mark_tree (BINDING_SCOPE (t));
+      ggc_mark_tree (BINDING_VALUE (t));
+    }
+  else if (code == OVERLOAD)
+    ggc_mark_tree (OVL_FUNCTION (t));
+  else if (code == TEMPLATE_PARM_INDEX)
+    ggc_mark_tree (TEMPLATE_PARM_DECL (t));
+  else if (TREE_CODE_CLASS (code) == 'd')
+    {
+      struct lang_decl *ld = DECL_LANG_SPECIFIC (t);
+
+      if (ld)
+       {
+         ggc_mark (ld);
+         if (!DECL_GLOBAL_CTOR_P (t) && !DECL_GLOBAL_DTOR_P (t))
+           ggc_mark_tree (ld->decl_flags.u2.access);
+         ggc_mark_tree (ld->decl_flags.context);
+         if (TREE_CODE (t) != NAMESPACE_DECL)
+           ggc_mark_tree (ld->decl_flags.u.template_info);
+         if (CAN_HAVE_FULL_LANG_DECL_P (t))
+           {
+             ggc_mark_tree (ld->main_decl_variant);
+             ggc_mark_tree (ld->befriending_classes);
+             ggc_mark_tree (ld->saved_tree);
+             if (TREE_CODE (t) == TYPE_DECL)
+               ggc_mark_tree (ld->u.sorted_fields);
+             else if (TREE_CODE (t) == FUNCTION_DECL
+                      && !DECL_PENDING_INLINE_P (t))
+               mark_lang_function (DECL_SAVED_FUNCTION_DATA (t));
+           }
+       }
+    }
+  else if (TREE_CODE_CLASS (code) == 't')
+    {
+      struct lang_type *lt = TYPE_LANG_SPECIFIC (t);
+
+      if (lt && !(TREE_CODE (t) == POINTER_TYPE 
+                 && TREE_CODE (TREE_TYPE (t)) == METHOD_TYPE))
+       {
+         ggc_mark (lt);
+         ggc_mark_tree (lt->vfields);
+         ggc_mark_tree (lt->vbases);
+         ggc_mark_tree (lt->tags);
+         ggc_mark_tree (lt->search_slot);
+         ggc_mark_tree (lt->size);
+         ggc_mark_tree (lt->abstract_virtuals);
+         ggc_mark_tree (lt->friend_classes);
+         ggc_mark_tree (lt->rtti);
+         ggc_mark_tree (lt->methods);
+         ggc_mark_tree (lt->template_info);
+         ggc_mark_tree (lt->befriending_classes);
+       }
+      else if (lt)
+       /* In the case of pointer-to-member function types, the
+          TYPE_LANG_SPECIFIC is really just a tree.  */
+       ggc_mark_tree ((tree) lt);
+    }
+}
+