OSDN Git Service

* decl.c (initialize_local_var): Handle static variables here.
[pf3gnuchains/gcc-fork.git] / gcc / cp / decl.c
index cd42511..00043d6 100644 (file)
@@ -63,12 +63,6 @@ extern int (*valid_lang_attribute) PROTO ((tree, tree, tree, tree));
 
 int ggc_p = 1;
 
-/* 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 WCHAR_UNSIGNED
 #define WCHAR_UNSIGNED 0
 #endif
@@ -106,8 +100,6 @@ static struct stack_level *decl_stack;
 static tree grokparms                          PROTO((tree, int));
 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));
@@ -149,7 +141,7 @@ 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 int lookup_flags PROTO((int, int));
@@ -158,7 +150,6 @@ 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 *));
@@ -167,7 +158,7 @@ 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 tree layout_var_decl 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 *));
@@ -176,9 +167,13 @@ 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));
@@ -370,13 +365,6 @@ extern int flag_conserve_space;
 \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.  */
-#define current_function_assigns_this cp_function_chain->assigns_this
-#define current_function_just_assigned_this \
-  cp_function_chain->just_assigned_this
-
 /* Flag used when debugging spew.c */
 
 extern int spew_debug;
@@ -390,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:
@@ -788,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 ()
 {
@@ -829,10 +795,12 @@ void
 pushlevel (tag_transparent)
      int tag_transparent;
 {
-  register struct binding_level *newlevel = NULL_BINDING_LEVEL;
+  struct binding_level *newlevel;
 
-  /* Reuse or create a struct for this binding level.  */
+  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) */
@@ -1130,14 +1098,17 @@ pop_label (link)
 {
   tree label = TREE_VALUE (link);
 
-  if (DECL_INITIAL (label) == NULL_TREE)
+  if (!processing_template_decl && doing_semantic_analysis_p ())
     {
-      cp_error_at ("label `%D' used but not defined", label);
-      /* Avoid crashing later.  */
-      define_label (input_filename, 1, DECL_NAME (label));
+      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);
     }
-  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));
 }
@@ -1192,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);
@@ -1569,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;
@@ -1584,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,
@@ -1652,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
@@ -2942,6 +2916,12 @@ warn_extern_redeclared_static (newdecl, olddecl)
 
   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.  */
@@ -3051,6 +3031,15 @@ duplicate_decls (newdecl, olddecl)
             the declarations, but make the original one static.  */
          DECL_THIS_STATIC (olddecl) = 1;
          TREE_PUBLIC (olddecl) = 0;
+
+         /* 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))
@@ -3287,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
@@ -3526,7 +3516,7 @@ duplicate_decls (newdecl, olddecl)
             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.  */
@@ -3633,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
@@ -3645,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))
@@ -3785,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;
@@ -3877,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 
@@ -4033,7 +4041,10 @@ pushdecl (x)
     }
 
   if (need_new_binding)
-    add_decl_to_level (x, current_binding_level);
+    add_decl_to_level (x, 
+                      DECL_NAMESPACE_SCOPE_P (x)
+                      ? NAMESPACE_LEVEL (CP_DECL_CONTEXT (x))
+                      : current_binding_level);
 
   return x;
 }
@@ -4121,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;
 }
 
@@ -4282,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;
@@ -4608,12 +4616,8 @@ make_label_decl (id, local_p)
 {
   tree decl;
 
-  if (building_stmt_tree ())
-    push_permanent_obstack ();
   decl = build_decl (LABEL_DECL, id, void_type_node);
-  if (building_stmt_tree ())
-    pop_obstacks ();
-  else
+  if (expanding_p)
     /* Make sure every label has an rtx.  */
     label_rtx (decl);
 
@@ -4863,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 ()
@@ -4873,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;
@@ -5746,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)
@@ -6028,8 +6036,6 @@ init_decl_processing ()
   signal (SIGBUS, signal_catch);
 #endif
 
-  gcc_obstack_init (&decl_obstack);
-
   build_common_tree_nodes (flag_signed_char);
 
   error_mark_list = build_tree_list (error_mark_node, error_mark_node);
@@ -6221,8 +6227,10 @@ init_decl_processing ()
   TYPE_REFERENCE_TO (unknown_type_node) = unknown_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);
@@ -6322,8 +6330,7 @@ init_decl_processing ()
   init_class_processing ();
   init_init_processing ();
   init_search_processing ();
-  if (flag_rtti)
-    init_rtti_processing ();
+  init_rtti_processing ();
 
   if (flag_exceptions)
     init_exception_processing ();
@@ -6435,19 +6442,17 @@ define_function (name, type, pfn, library_name)
    See tree.h for its possible values.  */
 
 tree
-builtin_function (name, type, code, libname)
+builtin_function (name, type, code, class, libname)
      const char *name;
      tree type;
-     enum built_in_function code;
+     int code;
+     enum built_in_class class;
      const char *libname;
 {
   tree decl = define_function (name, type, (void (*) PROTO((tree)))pushdecl,
                               libname);
-  if (code != NOT_BUILT_IN)
-    {
-      DECL_BUILT_IN (decl) = 1;
-      DECL_FUNCTION_CODE (decl) = code;
-    }
+  DECL_BUILT_IN_CLASS (decl) = class;
+  DECL_FUNCTION_CODE (decl) = code;
   return decl;
 }
 \f
@@ -7078,23 +7083,23 @@ maybe_deduce_size_from_array_init (decl, init)
 }
 
 /* Set DECL_SIZE, DECL_ALIGN, etc. for DECL (a VAR_DECL), and issue
-   any appropriate error messages regarding the layout.  INIT is a
-   the initializer for DECL; returns a modified version.  */
+   any appropriate error messages regarding the layout.  */
 
-static tree
-layout_var_decl (decl, init)
+static void
+layout_var_decl (decl)
      tree decl;
-     tree init;
 {
-  tree ttype = target_type (TREE_TYPE (decl));
-
-  /* If we haven't already layed out this declaration, and we know its
-     type, 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.  */
-  if (!DECL_EXTERNAL (decl)  
-      && DECL_SIZE (decl) == NULL_TREE
-      && TYPE_SIZE (complete_type (TREE_TYPE (decl))) != NULL_TREE)
+  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)
@@ -7121,8 +7126,6 @@ layout_var_decl (decl, init)
       else
        cp_error ("storage size of `%D' isn't constant", decl);
     }
-
-  return init;
 }
 
 /* If a local static variable is declared in an inline function, or if
@@ -7343,25 +7346,27 @@ make_rtl_for_nonlocal_decl (decl, init, asmspec)
 
   type = TREE_TYPE (decl);
   toplev = toplevel_bindings_p ();
-  push_obstacks_nochange ();
-  if (TREE_STATIC (decl) 
-      && TYPE_NEEDS_DESTRUCTOR (type)
-      && allocation_temporary_p ())
-    end_temporary_allocation  ();
 
-  if (TREE_CODE (decl) == VAR_DECL && DECL_VIRTUAL_P (decl))
+  /* Handle non-variables up front.  */
+  if (TREE_CODE (decl) != VAR_DECL)
+    {
+      rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
+      return;
+    }
+
+  /* Set the DECL_ASSEMBLER_NAME for the variable.  */
+  if (asmspec)
+    DECL_ASSEMBLER_NAME (decl) = get_identifier (asmspec);
+
+  if (DECL_VIRTUAL_P (decl))
     make_decl_rtl (decl, NULL_PTR, toplev);
-  else if (TREE_CODE (decl) == VAR_DECL
-          && TREE_READONLY (decl)
+  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 (asmspec)
-       DECL_ASSEMBLER_NAME (decl) = get_identifier (asmspec);
-
       if (! toplev
          && TREE_STATIC (decl)
          && ! TREE_SIDE_EFFECTS (decl)
@@ -7389,12 +7394,10 @@ make_rtl_for_nonlocal_decl (decl, init, asmspec)
            }
          make_decl_rtl (decl, asmspec, toplev);
        }
-      else
+      else if (toplev)
        rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
     }
-  else if (TREE_CODE (decl) == VAR_DECL
-          && DECL_LANG_SPECIFIC (decl)
-          && DECL_IN_AGGR_P (decl))
+  else if (DECL_LANG_SPECIFIC (decl) && DECL_IN_AGGR_P (decl))
     {
       my_friendly_assert (TREE_STATIC (decl), 19990828);
 
@@ -7413,10 +7416,9 @@ make_rtl_for_nonlocal_decl (decl, init, asmspec)
       else
        rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
     }
-  else
+  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);
-
-  pop_obstacks ();
 }
 
 /* The old ARM scoping rules injected variables declared in the
@@ -7468,9 +7470,11 @@ initialize_local_var (decl, init, flags)
      tree init;
      int flags;
 {
-  tree type;
+  tree type = TREE_TYPE (decl);
 
-  type = complete_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))
     {
@@ -7479,6 +7483,16 @@ initialize_local_var (decl, init, flags)
       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;
@@ -7561,7 +7575,16 @@ emit_local_var (decl)
     my_friendly_assert (TREE_CODE (decl) == RESULT_DECL, 
                        19990828);
   else
-    expand_decl (decl);
+    {
+      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);
+    }
 
   /* Actually do the initialization.  */
   expand_start_target_temps ();
@@ -7736,7 +7759,7 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
     end_temporary_allocation ();
 
   if (TREE_CODE (decl) == VAR_DECL)
-    init = layout_var_decl (decl, init);
+    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.
@@ -7744,9 +7767,6 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
   if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL
       || TREE_CODE (decl) == RESULT_DECL)
     {
-      /* ??? FIXME: What about nested classes?  */
-      int toplev = toplevel_bindings_p ();
-
       if (TREE_CODE (decl) == VAR_DECL)
        maybe_commonize_var (decl);
 
@@ -7768,17 +7788,11 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
          if (init)
            DECL_INITIAL (decl) = init;
        }
-      else if (TREE_STATIC (decl) && type != error_mark_node)
-       {
-         /* Cleanups for static variables are handled by `finish_file'.  */
-         if (TYPE_NEEDS_CONSTRUCTING (type) || init != NULL_TREE
-             || TYPE_NEEDS_DESTRUCTOR (type))
-           expand_static_init (decl, init);
-       }
-      else if (! toplev)
+      else if (TREE_CODE (CP_DECL_CONTEXT (decl)) == FUNCTION_DECL)
        {
          /* This is a local declaration.  */
-         maybe_inject_for_scope_var (decl);
+         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.  */
@@ -7789,13 +7803,23 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
            }
          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'.  */
+         if (TYPE_NEEDS_CONSTRUCTING (type) || init != NULL_TREE
+             || TYPE_NEEDS_DESTRUCTOR (type))
+           expand_static_init (decl, init);
+       }
     finish_end0:
 
       /* Undo call to `pushclass' that was done in `start_decl'
@@ -7990,9 +8014,12 @@ expand_static_init (decl, init)
          || (init && TREE_CODE (init) == TREE_LIST))
        assignment = build_aggr_init (decl, init, 0);
       else if (init)
-       /* The initialization we're doing here is just a bitwise
-          copy.  */
-       assignment = build (INIT_EXPR, TREE_TYPE (decl), decl, init);
+       {
+         /* 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
        assignment = NULL_TREE;
 
@@ -8042,7 +8069,7 @@ expand_static_init (decl, init)
 
 /* Finish the declaration of a catch-parameter.  */
 
-void
+tree
 start_handler_parms (declspecs, declarator)
      tree declspecs;
      tree declarator;
@@ -8057,7 +8084,8 @@ start_handler_parms (declspecs, declarator)
     }
   else
     decl = NULL_TREE;
-  expand_start_catch_block (decl);
+
+  return decl;
 }
 
 \f
@@ -9128,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
@@ -9169,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,
@@ -9329,11 +9358,11 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
          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;
        }
@@ -9541,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))
@@ -9584,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
@@ -10397,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
@@ -10533,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);
 
@@ -11066,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.  */
@@ -11147,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.  */
@@ -11232,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'",
@@ -12115,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);
@@ -12766,6 +12784,16 @@ start_function (declspecs, declarator, attrs, flags)
            }
        }
     }
+  
+  /* 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).  */
@@ -12797,7 +12825,8 @@ start_function (declspecs, declarator, attrs, flags)
 
   /* 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);
@@ -12859,7 +12888,7 @@ start_function (declspecs, declarator, attrs, flags)
      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;
-  get_pending_sizes ();
+  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 ())
@@ -12891,6 +12920,49 @@ start_function (declspecs, declarator, attrs, flags)
   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))
     {
       tree ctx = hack_decl_function_context (decl1);
@@ -12956,59 +13028,12 @@ start_function (declspecs, declarator, attrs, flags)
        DECL_INTERFACE_KNOWN (decl1) = 1;
     }
 
-  if (ctype != NULL_TREE && DECL_STATIC_FUNCTION_P (decl1))
+  if (doing_semantic_analysis_p ())
     {
-      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;
-    }
-
-  my_friendly_assert (current_class_ptr == NULL_TREE, 19990908);
-  my_friendly_assert (current_class_ref == NULL_TREE, 19990908);
-  if (ctype)
-    {
-      /* 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;
-         int i;
-             
-         my_friendly_assert (t != NULL_TREE
-                             && TREE_CODE (t) == PARM_DECL, 162);
-         my_friendly_assert (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE,
-                             19990811);
-         
-         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.  */
-         cp_function_chain->x_current_class_ref 
-           = build_indirect_ref (t, NULL_PTR);
-         cp_function_chain->x_current_class_ptr = t;
-         
-         resume_momentary (i);
-         if (! hack_decl_function_context (decl1))
-           end_temporary_allocation ();
-       }
+      pushlevel (0);
+      current_binding_level->parm_flag = 1;
     }
 
-  pushlevel (0);
-  current_binding_level->parm_flag = 1;
-
   if (attrs)
     cplus_decl_attributes (decl1, NULL_TREE, attrs);
   
@@ -13053,16 +13078,9 @@ start_function (declspecs, declarator, attrs, flags)
 
   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;
 }
@@ -13092,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;
 
@@ -13103,39 +13118,48 @@ 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");
-
   /* 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;
 
-      /* Must clear this because it might contain TYPE_DECLs declared
-        at class level.  */
-      storedecls (NULL_TREE);
+      if (doing_semantic_analysis_p ())
+       {
+         /* 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)
+             
+             if (doing_semantic_analysis_p ())
                {
-                 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);
                }
-             else if (TREE_CODE (TREE_TYPE (parm)) == VOID_TYPE)
-               cp_error ("parameter `%D' declared void", parm);
-             else
-               pushdecl (parm);
+
              if (! building_stmt_tree ()
                  && (cleanup = maybe_build_cleanup (parm), cleanup))
                {
@@ -13155,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;
@@ -13169,8 +13198,8 @@ 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)));
+  if (doing_semantic_analysis_p ())
+    storedecls (chainon (nonparms, DECL_ARGUMENTS (fndecl)));
 
   /* Initialize the RTL code for the function.  */
   DECL_SAVED_INSNS (fndecl) = 0;
@@ -13188,17 +13217,15 @@ store_parm_decls ()
      cleanups.  We cannot do this before, since expand_decl_cleanup
      should not be called before the parm can be used.  */
   if (cleanups && !building_stmt_tree ())
-    {
-      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));
-       }
-    }
+    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
@@ -13207,15 +13234,14 @@ store_parm_decls ()
     {
       pushlevel (0);
       if (!building_stmt_tree ())
-       expand_start_bindings (0);
+       expand_start_bindings (2);
     }
 
-  if (! building_stmt_tree () && 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 ();
-    }
+  /* 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 ();
@@ -13238,6 +13264,182 @@ store_return_init (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.  */
+
+static void
+save_function_data (decl)
+     tree decl;
+{
+  struct language_function *f;
+
+  /* Save the language-specific per-function data so that we can
+     get it back when we really expand this function.  */
+  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);
+}
+
+/* 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.  */
+
+static void
+finish_destructor_body ()
+{
+  tree compound_stmt;
+  tree in_charge;
+  tree virtual_size;
+  tree exprstmt;
+
+  /* Create a block to contain all the extra code.  */
+  compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
+
+  /* Any return from a destructor will end up here.  */
+  add_tree (build_min_nt (LABEL_STMT, dtor_label));
+
+  /* Generate the code to call destructor on base class.  If this
+     destructor belongs to a class with virtual functions, then set
+     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);
+
+  /* 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))
+    {
+      tree if_stmt;
+
+      exprstmt = build_op_delete_call
+       (DELETE_EXPR, current_class_ptr, virtual_size,
+        LOOKUP_NORMAL | LOOKUP_SPECULATIVELY, NULL_TREE);
+
+      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);
+}
+
 /* Finish up a function declaration and compile that function
    all the way to assembler language output.  The free the storage
    for the function definition.
@@ -13262,10 +13464,8 @@ finish_function (lineno, flags)
 {
   register tree fndecl = current_function_decl;
   tree fntype, ctype = NULL_TREE;
-  rtx fn_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 expand_p;
@@ -13279,9 +13479,9 @@ finish_function (lineno, flags)
   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)
@@ -13292,21 +13492,30 @@ finish_function (lineno, flags)
 
   if (building_stmt_tree ())
     {
-      if (DECL_CONSTRUCTOR_P (fndecl) && call_poplevel)
+      if (DECL_CONSTRUCTOR_P (fndecl))
        {
-         decls = getdecls ();
-         expand_end_bindings (decls, decls != NULL_TREE, 0);
-         poplevel (decls != NULL_TREE, 0, 0);
+         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))
+       {
+         /* 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
        }
 
-      /* Because we do not call expand_function_end, we won't call
-        expand_end_bindings to match the call to
-        expand_start_bindings we did in store_parm_decls.  Therefore,
-        we explicitly call expand_end_bindings here.  However, we
-        really shouldn't be calling expand_start_bindings at all when
-        building_stmt_tree; it's conceptually an RTL-generation
-        function, rather than a front-end function.  */
-      expand_end_bindings (0, 0, 0);
+      /* 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
     {
@@ -13332,291 +13541,17 @@ finish_function (lineno, flags)
       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 ();
-
-         fn_last_parm_insn = get_first_nonparm_insn ();
-         if (fn_last_parm_insn == NULL_RTX)
-           fn_last_parm_insn = get_last_insn ();
-         else
-           fn_last_parm_insn = previous_insn (fn_last_parm_insn);
-
-         emit_insns_after (insns, fn_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);
@@ -13700,9 +13635,12 @@ finish_function (lineno, flags)
   /* 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 (doing_semantic_analysis_p ())
+    {
+      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)
@@ -13718,6 +13656,10 @@ finish_function (lineno, flags)
   /* 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;
@@ -13840,7 +13782,7 @@ finish_function (lineno, flags)
   if (! nested)
     permanent_allocation (1);
 
-  if (DECL_SAVED_INSNS (fndecl) == 0)
+  if (!DECL_SAVED_INSNS (fndecl) && !DECL_SAVED_FUNCTION_DATA (fndecl))
     {
       tree t;
 
@@ -14198,22 +14140,6 @@ cplus_expand_expr_stmt (exp)
 void
 finish_stmt ()
 {
-  if (!current_function_assigns_this
-      && current_function_just_assigned_this)
-    {
-      if (DECL_CONSTRUCTOR_P (current_function_decl) 
-         && !building_stmt_tree ())
-       {
-         /* Constructors must wait until we are out of control
-            zones before calling base constructors.  */
-         if (in_control_zone_p ())
-           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.  */
@@ -14267,9 +14193,9 @@ push_cp_function_context (f)
        xcalloc (1, sizeof (struct language_function)));
   f->language = p;
 
-  /* For now, we always assume we're expanding all the way to RTL
-     unless we're explicitly doing otherwise.  */
-  expanding_p = 1;
+  /* It takes an explicit call to expand_body to generate RTL for a
+     function.  */
+  expanding_p = 0;
 
   /* Whenever we start a new function, we destroy temporaries in the
      usual way.  */
@@ -14287,12 +14213,12 @@ pop_cp_function_context (f)
   f->language = 0;
 }
 
-void
-mark_cp_function_context (f)
-     struct function *f;
-{
-  struct language_function *p = f->language;
+/* Mark P for GC.  */
 
+static void
+mark_lang_function (p)
+     struct language_function *p;
+{
   if (!p)
     return;
 
@@ -14301,11 +14227,12 @@ mark_cp_function_context (f)
   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_base_init_expr);
   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);
@@ -14314,6 +14241,14 @@ mark_cp_function_context (f)
   mark_binding_level (&p->bindings);
 }
 
+/* Mark the language-specific data in F for GC.  */
+
+void
+mark_cp_function_context (f)
+     struct function *f;
+{
+  mark_lang_function (f->language);
+}
 
 int
 in_function_p ()
@@ -14370,7 +14305,8 @@ lang_mark_tree (t)
       if (ld)
        {
          ggc_mark (ld);
-         ggc_mark_tree (ld->decl_flags.access);
+         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);
@@ -14381,6 +14317,9 @@ lang_mark_tree (t)
              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));
            }
        }
     }