OSDN Git Service

* cp/cp-tree.h (struct cp_language_function): Remove x_result_rtx.
[pf3gnuchains/gcc-fork.git] / gcc / cp / semantics.c
index 028279f..28c0f35 100644 (file)
@@ -3,7 +3,7 @@
    building RTL.  These routines are used both during actual parsing
    and during the instantiation of template functions. 
 
-   Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
    Written by Mark Mitchell (mmitchell@usa.net) based on code found
    formerly in parse.y and pt.c.  
 
@@ -34,6 +34,8 @@
 #include "flags.h"
 #include "ggc.h"
 #include "rtl.h"
+#include "output.h"
+#include "timevar.h"
 
 /* There routines provide a modular interface to perform many parsing
    operations.  They may therefore be used during actual parsing, or
    parsing into this file; that will make implementing the new parser
    much easier since it will be able to make use of these routines.  */
 
-static tree expand_cond PROTO((tree));
-static tree maybe_convert_cond PROTO((tree));
-
-/* Record the fact that STMT was the last statement added to the
-   statement tree.  */
-
-#define SET_LAST_STMT(stmt) \
-  (current_stmt_tree->x_last_stmt = (stmt))
-
-/* When parsing a template, LAST_TREE contains the last statement
-   parsed.  These are chained together through the TREE_CHAIN field,
-   but often need to be re-organized since the parse is performed
-   bottom-up.  This macro makes LAST_TREE the indicated SUBSTMT of
-   STMT.  */
-
-#define RECHAIN_STMTS(stmt, substmt)   \
-  do {                                 \
-    substmt = TREE_CHAIN (stmt);       \
-    TREE_CHAIN (stmt) = NULL_TREE;     \
-    SET_LAST_STMT (stmt);              \
-  } while (0)
+static tree maybe_convert_cond PARAMS ((tree));
+static tree simplify_aggr_init_exprs_r PARAMS ((tree *, int *, void *));
+static void deferred_type_access_control PARAMS ((void));
+static void emit_associated_thunks PARAMS ((tree));
+static void genrtl_try_block PARAMS ((tree));
+static void genrtl_handler PARAMS ((tree));
+static void genrtl_catch_block PARAMS ((tree));
+static void genrtl_ctor_stmt PARAMS ((tree));
+static void genrtl_subobject PARAMS ((tree));
+static void genrtl_named_return_value PARAMS ((void));
+static void cp_expand_stmt PARAMS ((tree));
+static void genrtl_start_function PARAMS ((tree));
+static void genrtl_finish_function PARAMS ((tree));
 
 /* Finish processing the COND, the SUBSTMT condition for STMT.  */
 
@@ -82,27 +76,108 @@ static tree maybe_convert_cond PROTO((tree));
     else                                               \
       substmt = cond;                                  \
   } while (0)
-  
-/* T is a statement.  Add it to the statement-tree.  */
+
+/* Returns non-zero if the current statement is a full expression,
+   i.e. temporaries created during that statement should be destroyed
+   at the end of the statement.  */
+
+int
+stmts_are_full_exprs_p ()
+{
+  return current_stmt_tree ()->stmts_are_full_exprs_p;
+}
+
+/* Returns the stmt_tree (if any) to which statements are currently
+   being added.  If there is no active statement-tree, NULL is
+   returned.  */
+
+stmt_tree
+current_stmt_tree ()
+{
+  return (cfun 
+         ? &cfun->language->x_stmt_tree 
+         : &scope_chain->x_stmt_tree);
+}
+
+/* Nonzero if TYPE is an anonymous union or struct type.  We have to use a
+   flag for this because "A union for which objects or pointers are
+   declared is not an anonymous union" [class.union].  */
+
+int
+anon_aggr_type_p (node)
+     tree node;
+{
+  return (CLASS_TYPE_P (node) && TYPE_LANG_SPECIFIC(node)->anon_aggr);
+}
+
+/* Finish a scope.  */
+
+tree
+do_poplevel ()
+{
+  tree block = NULL_TREE;
+
+  if (stmts_are_full_exprs_p ())
+    {
+      tree scope_stmts = NULL_TREE;
+
+      if (!processing_template_decl)
+       scope_stmts = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0);
+
+      block = poplevel (kept_level_p (), 1, 0);
+      if (block && !processing_template_decl)
+       {
+         SCOPE_STMT_BLOCK (TREE_PURPOSE (scope_stmts)) = block;
+         SCOPE_STMT_BLOCK (TREE_VALUE (scope_stmts)) = block;
+       }
+    }
+
+  return block;
+}
+
+/* Begin a new scope.  */ 
 
 void
-add_tree (t)
-     tree t;
+do_pushlevel ()
+{
+  if (stmts_are_full_exprs_p ())
+    {
+      pushlevel (0);
+      if (!processing_template_decl)
+       add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0);
+    }
+}
+
+/* Finish a goto-statement.  */
+
+void
+finish_goto_stmt (destination)
+     tree destination;
 {
-  /* Add T to the statement-tree.  */
-  TREE_CHAIN (last_tree) = t;
-  SET_LAST_STMT (t);
+  if (TREE_CODE (destination) == IDENTIFIER_NODE)
+    destination = lookup_label (destination);
+
+  /* We warn about unused labels with -Wunused.  That means we have to
+     mark the used labels as used.  */
+  if (TREE_CODE (destination) == LABEL_DECL)
+    TREE_USED (destination) = 1;
+    
+  if (TREE_CODE (destination) != LABEL_DECL)
+    /* We don't inline calls to functions with computed gotos.
+       Those functions are typically up to some funny business,
+       and may be depending on the labels being at particular
+       addresses, or some such.  */
+    DECL_UNINLINABLE (current_function_decl) = 1;
+  
+  check_goto (destination);
 
-  /* When we expand a statement-tree, we must know whether or not the
-     statements are full-expresions.  We record that fact here.  */
-  if (building_stmt_tree ())
-    STMT_IS_FULL_EXPR_P (last_tree) = stmts_are_full_exprs_p;
+  add_stmt (build_stmt (GOTO_STMT, destination));
 }
 
 /* COND is the condition-expression for an if, while, etc.,
    statement.  Convert it to a boolean value, if appropriate.  */
 
-static tree
+tree
 maybe_convert_cond (cond)
      tree cond;
 {
@@ -127,34 +202,20 @@ finish_expr_stmt (expr)
 {
   if (expr != NULL_TREE)
     {
-      if (building_stmt_tree ())
-       {
-         /* Do default conversion if safe and possibly important,
-            in case within ({...}).  */
-         if (!processing_template_decl
-             && !stmts_are_full_exprs_p
-             && ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
-                  && lvalue_p (expr))
-                 || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE))
-           expr = default_conversion (expr);
-
-         if (!processing_template_decl)
-           expr = break_out_cleanups (expr);
-
-         add_tree (build_min_nt (EXPR_STMT, expr));
-       }
-      else
-       {
-         emit_line_note (input_filename, lineno);
-
-         if (stmts_are_full_exprs_p)
-           expand_start_target_temps ();
-           
-         cplus_expand_expr_stmt (expr);
-
-         if (stmts_are_full_exprs_p)
-           expand_end_target_temps ();
-       }
+      if (!processing_template_decl
+         && !(stmts_are_full_exprs_p ())
+         && ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
+              && lvalue_p (expr))
+             || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE))
+       expr = default_conversion (expr);
+      
+      if (stmts_are_full_exprs_p ())
+       expr = convert_to_void (expr, "statement");
+      
+      if (!processing_template_decl)
+       expr = break_out_cleanups (expr);
+      
+      add_stmt (build_stmt (EXPR_STMT, expr));
     }
 
   finish_stmt ();
@@ -164,6 +225,7 @@ finish_expr_stmt (expr)
   last_expr_type = expr ? TREE_TYPE (expr) : NULL_TREE;
 }
 
+
 /* Begin an if-statement.  Returns a newly created IF_STMT if
    appropriate.  */
 
@@ -171,17 +233,9 @@ tree
 begin_if_stmt ()
 {
   tree r;
-
   do_pushlevel ();
-
-  if (building_stmt_tree ())
-    {
-      r = build_min_nt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
-      add_tree (r);
-    }
-  else
-    r = NULL_TREE;
-
+  r = build_stmt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
+  add_stmt (r);
   return r;
 }
 
@@ -194,14 +248,7 @@ finish_if_stmt_cond (cond, if_stmt)
      tree if_stmt;
 {
   cond = maybe_convert_cond (cond);
-
-  if (building_stmt_tree ())
-    FINISH_COND (cond, if_stmt, IF_COND (if_stmt));
-  else
-    {
-      emit_line_note (input_filename, lineno);
-      expand_start_cond (cond, 0);
-    }
+  FINISH_COND (cond, if_stmt, IF_COND (if_stmt));
 }
 
 /* Finish the then-clause of an if-statement, which may be given by
@@ -211,14 +258,9 @@ tree
 finish_then_clause (if_stmt)
      tree if_stmt;
 {
-  if (building_stmt_tree ())
-    {
-      RECHAIN_STMTS (if_stmt, THEN_CLAUSE (if_stmt));
-      SET_LAST_STMT (if_stmt);
-      return if_stmt;
-    }
-  else
-    return NULL_TREE;
+  RECHAIN_STMTS (if_stmt, THEN_CLAUSE (if_stmt));
+  last_tree = if_stmt;
+  return if_stmt;
 }
 
 /* Begin the else-clause of an if-statement.  */
@@ -226,8 +268,6 @@ finish_then_clause (if_stmt)
 void 
 begin_else_clause ()
 {
-  if (!building_stmt_tree ())
-    expand_start_else ();
 }
 
 /* Finish the else-clause of an if-statement, which may be given by
@@ -237,8 +277,7 @@ void
 finish_else_clause (if_stmt)
      tree if_stmt;
 {
-  if (building_stmt_tree ())
-    RECHAIN_STMTS (if_stmt, ELSE_CLAUSE (if_stmt));
+  RECHAIN_STMTS (if_stmt, ELSE_CLAUSE (if_stmt));
 }
 
 /* Finsh an if-statement.  */
@@ -246,13 +285,23 @@ finish_else_clause (if_stmt)
 void 
 finish_if_stmt ()
 {
-  if (!building_stmt_tree ())
-    expand_end_cond ();
-
   do_poplevel ();
   finish_stmt ();
 }
 
+void
+clear_out_block ()
+{
+  /* If COND wasn't a declaration, clear out the
+     block we made for it and start a new one here so the
+     optimization in expand_end_loop will work.  */
+  if (getdecls () == NULL_TREE)
+    {
+      do_poplevel ();
+      do_pushlevel ();
+    }
+}
+
 /* Begin a while-statement.  Returns a newly created WHILE_STMT if
    appropriate.  */
 
@@ -260,26 +309,13 @@ tree
 begin_while_stmt ()
 {
   tree r;
-
-  if (building_stmt_tree ())
-    {
-      r = build_min_nt (WHILE_STMT, NULL_TREE, NULL_TREE);
-      add_tree (r);
-    }
-  else
-    {
-      emit_nop ();
-      emit_line_note (input_filename, lineno);
-      expand_start_loop (1); 
-      r = NULL_TREE;
-    }
-
+  r = build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE);
+  add_stmt (r);
   do_pushlevel ();
-
   return r;
 }
 
-/* Process the COND of an if-statement, which may be given by
+/* Process the COND of a while-statement, which may be given by
    WHILE_STMT.  */
 
 void 
@@ -288,23 +324,8 @@ finish_while_stmt_cond (cond, while_stmt)
      tree while_stmt;
 {
   cond = maybe_convert_cond (cond);
-
-  if (building_stmt_tree ())
-    FINISH_COND (cond, while_stmt, WHILE_COND (while_stmt));
-  else
-    {
-      emit_line_note (input_filename, lineno);
-      expand_exit_loop_if_false (0, cond);
-    }
-
-  /* If COND wasn't a declaration, clear out the
-     block we made for it and start a new one here so the
-     optimization in expand_end_loop will work.  */
-  if (getdecls () == NULL_TREE)
-    {
-      do_poplevel ();
-      do_pushlevel ();
-    }
+  FINISH_COND (cond, while_stmt, WHILE_COND (while_stmt));
+  clear_out_block ();
 }
 
 /* Finish a while-statement, which may be given by WHILE_STMT.  */
@@ -314,11 +335,7 @@ finish_while_stmt (while_stmt)
      tree while_stmt;
 {
   do_poplevel ();
-
-  if (building_stmt_tree ())
-    RECHAIN_STMTS (while_stmt, WHILE_BODY (while_stmt));
-  else
-    expand_end_loop ();
+  RECHAIN_STMTS (while_stmt, WHILE_BODY (while_stmt));
   finish_stmt ();
 }
 
@@ -328,19 +345,9 @@ finish_while_stmt (while_stmt)
 tree
 begin_do_stmt ()
 {
-  if (building_stmt_tree ())
-    {
-      tree r = build_min_nt (DO_STMT, NULL_TREE, NULL_TREE);
-      add_tree (r);
-      return r;
-    }
-  else
-    {
-      emit_nop ();
-      emit_line_note (input_filename, lineno);
-      expand_start_loop_continue_elsewhere (1);
-      return NULL_TREE;
-    }
+  tree r = build_stmt (DO_STMT, NULL_TREE, NULL_TREE);
+  add_stmt (r);
+  return r;
 }
 
 /* Finish the body of a do-statement, which may be given by DO_STMT.  */
@@ -349,10 +356,7 @@ void
 finish_do_body (do_stmt)
      tree do_stmt;
 {
-  if (building_stmt_tree ())
-    RECHAIN_STMTS (do_stmt, DO_BODY (do_stmt));
-  else
-    expand_loop_continue_here ();
+  RECHAIN_STMTS (do_stmt, DO_BODY (do_stmt));
 }
 
 /* Finish a do-statement, which may be given by DO_STMT, and whose
@@ -364,16 +368,7 @@ finish_do_stmt (cond, do_stmt)
      tree do_stmt;
 {
   cond = maybe_convert_cond (cond);
-
-  if (building_stmt_tree ())
-    DO_COND (do_stmt) = cond;
-  else
-    {
-      emit_line_note (input_filename, lineno);
-      expand_exit_loop_if_false (0, cond);
-      expand_end_loop ();
-    }
-
+  DO_COND (do_stmt) = cond;
   finish_stmt ();
 }
 
@@ -384,10 +379,9 @@ void
 finish_return_stmt (expr)
      tree expr;
 {
-  if (doing_semantic_analysis_p () && !processing_template_decl)
+  if (!processing_template_decl)
     expr = check_return_expr (expr);
-
-  if (doing_semantic_analysis_p () && !processing_template_decl)
+  if (!processing_template_decl)
     {
       if (DECL_CONSTRUCTOR_P (current_function_decl) && ctor_label)
        {
@@ -410,15 +404,7 @@ finish_return_stmt (expr)
          return;
        }
     }
-
-  if (building_stmt_tree ())
-    add_tree (build_min_nt (RETURN_STMT, expr));
-  else
-    {
-      emit_line_note (input_filename, lineno);
-      c_expand_return (expr);
-    }
-
+  add_stmt (build_stmt (RETURN_STMT, expr));
   finish_stmt ();
 }
 
@@ -429,16 +415,11 @@ begin_for_stmt ()
 {
   tree r;
 
-  if (building_stmt_tree ())
-    {
-      r = build_min_nt (FOR_STMT, NULL_TREE, NULL_TREE, 
-                       NULL_TREE, NULL_TREE);
-      add_tree (r);
-    }
-  else
-    r = NULL_TREE;
-
-  if (flag_new_for_scope > 0)
+  r = build_stmt (FOR_STMT, NULL_TREE, NULL_TREE, 
+                 NULL_TREE, NULL_TREE);
+  NEW_FOR_SCOPE_P (r) = flag_new_for_scope > 0;
+  add_stmt (r);
+  if (NEW_FOR_SCOPE_P (r))
     {
       do_pushlevel ();
       note_level_for_for ();
@@ -454,18 +435,8 @@ void
 finish_for_init_stmt (for_stmt)
      tree for_stmt;
 {
-  if (building_stmt_tree ())
-    {
-      if (last_tree != for_stmt)
-       RECHAIN_STMTS (for_stmt, FOR_INIT_STMT (for_stmt));
-    }
-  else
-    {
-      emit_nop ();
-      emit_line_note (input_filename, lineno);
-      expand_start_loop_continue_elsewhere (1); 
-    }
-
+  if (last_tree != for_stmt)
+    RECHAIN_STMTS (for_stmt, FOR_INIT_STMT (for_stmt));
   do_pushlevel ();
 }
 
@@ -478,24 +449,8 @@ finish_for_cond (cond, for_stmt)
      tree for_stmt;
 {
   cond = maybe_convert_cond (cond);
-
-  if (building_stmt_tree ())
-    FINISH_COND (cond, for_stmt, FOR_COND (for_stmt));
-  else
-    {
-      emit_line_note (input_filename, lineno);
-      if (cond)
-       expand_exit_loop_if_false (0, cond);
-    }
-  
-  /* If the cond wasn't a declaration, clear out the
-     block we made for it and start a new one here so the
-     optimization in expand_end_loop will work.  */
-  if (getdecls () == NULL_TREE)
-    {
-      do_poplevel ();
-      do_pushlevel ();
-    }  
+  FINISH_COND (cond, for_stmt, FOR_COND (for_stmt));
+  clear_out_block ();
 }
 
 /* Finish the increment-EXPRESSION in a for-statement, which may be
@@ -506,8 +461,7 @@ finish_for_expr (expr, for_stmt)
      tree expr;
      tree for_stmt;
 {
-  if (building_stmt_tree ())
-    FOR_EXPR (for_stmt) = expr;
+  FOR_EXPR (for_stmt) = expr;
 }
 
 /* Finish the body of a for-statement, which may be given by
@@ -515,27 +469,14 @@ finish_for_expr (expr, for_stmt)
    provided.  */
 
 void
-finish_for_stmt (expr, for_stmt)
-     tree expr;
+finish_for_stmt (for_stmt)
      tree for_stmt;
 {
   /* Pop the scope for the body of the loop.  */
   do_poplevel ();
-
-  if (building_stmt_tree ())
-    RECHAIN_STMTS (for_stmt, FOR_BODY (for_stmt));
-  else
-    {
-      emit_line_note (input_filename, lineno);
-      expand_loop_continue_here ();
-      if (expr) 
-       finish_expr_stmt (expr);
-      expand_end_loop ();
-    }
-
-  if (flag_new_for_scope > 0)
+  RECHAIN_STMTS (for_stmt, FOR_BODY (for_stmt));
+  if (NEW_FOR_SCOPE_P (for_stmt))
     do_poplevel ();
-
   finish_stmt (); 
 }
 
@@ -544,11 +485,7 @@ finish_for_stmt (expr, for_stmt)
 void
 finish_break_stmt ()
 {
-  emit_line_note (input_filename, lineno);
-  if (building_stmt_tree ())
-    add_tree (build_min_nt (BREAK_STMT));
-  else if ( ! expand_exit_something ())
-    cp_error ("break statement not within loop or switch");
+  add_stmt (build_break_stmt ());
 }
 
 /* Finish a continue-statement.  */
@@ -556,11 +493,7 @@ finish_break_stmt ()
 void
 finish_continue_stmt ()
 {
-  emit_line_note (input_filename, lineno);
-  if (building_stmt_tree ())
-    add_tree (build_min_nt (CONTINUE_STMT));
-  else if (! expand_continue_loop (0))
-    cp_error ("continue statement not within a loop");   
+  add_stmt (build_continue_stmt ());
 }
 
 /* Begin a switch-statement.  Returns a new SWITCH_STMT if
@@ -570,17 +503,9 @@ tree
 begin_switch_stmt ()
 {
   tree r;
-
-  if (building_stmt_tree ())
-    {
-      r = build_min_nt (SWITCH_STMT, NULL_TREE, NULL_TREE);
-      add_tree (r);
-    }
-  else
-    r = NULL_TREE;
-
+  r = build_stmt (SWITCH_STMT, NULL_TREE, NULL_TREE);
+  add_stmt (r);
   do_pushlevel ();
-
   return r;
 }
 
@@ -591,95 +516,86 @@ finish_switch_cond (cond, switch_stmt)
      tree cond;
      tree switch_stmt;
 {
-  if (building_stmt_tree ())
-    FINISH_COND (cond, switch_stmt, SWITCH_COND (switch_stmt));
-  else if (cond != error_mark_node)
+  if (!processing_template_decl)
     {
-      emit_line_note (input_filename, lineno);
-      c_expand_start_case (cond);
-    }
-  else
-    /* The code is in error, but we don't want expand_end_case to
-       crash. */
-    c_expand_start_case (boolean_false_node);
+      tree type;
+      tree index;
+
+      /* Convert the condition to an integer or enumeration type.  */
+      cond = build_expr_type_conversion (WANT_INT | WANT_ENUM, cond, 1);
+      if (cond == NULL_TREE)
+       {
+         error ("switch quantity not an integer");
+         cond = error_mark_node;
+       }
+      if (cond != error_mark_node)
+       {
+         cond = default_conversion (cond);
+         cond = fold (build1 (CLEANUP_POINT_EXPR, TREE_TYPE (cond), cond));
+       }
 
-  push_switch ();
+      type = TREE_TYPE (cond);
+      index = get_unwidened (cond, NULL_TREE);
+      /* We can't strip a conversion from a signed type to an unsigned,
+        because if we did, int_fits_type_p would do the wrong thing
+        when checking case values for being in range,
+        and it's too hard to do the right thing.  */
+      if (TREE_UNSIGNED (TREE_TYPE (cond))
+         == TREE_UNSIGNED (TREE_TYPE (index)))
+       cond = index;
+    }
+  FINISH_COND (cond, switch_stmt, SWITCH_COND (switch_stmt));
+  push_switch (switch_stmt);
 }
 
 /* Finish the body of a switch-statement, which may be given by
    SWITCH_STMT.  The COND to switch on is indicated.  */
 
 void
-finish_switch_stmt (cond, switch_stmt)
-     tree cond;
+finish_switch_stmt (switch_stmt)
      tree switch_stmt;
 {
-  if (building_stmt_tree ())
-    RECHAIN_STMTS (switch_stmt, SWITCH_BODY (switch_stmt));
-  else
-    expand_end_case (cond);
+  RECHAIN_STMTS (switch_stmt, SWITCH_BODY (switch_stmt));
   pop_switch (); 
   do_poplevel ();
   finish_stmt ();
 }
 
-/* Finish a case-label.  */
-
-void 
-finish_case_label (low_value, high_value)
-     tree low_value;
-     tree high_value;
-{
-  if (building_stmt_tree ())
-    {
-      /* Add a representation for the case label to the statement
-        tree.  */
-      add_tree (build_min_nt (CASE_LABEL, low_value, high_value));
-      /* And warn about crossing initializations, etc.  */
-      if (!processing_template_decl)
-       define_case_label ();
-      return;
-    }
-
-  do_case (low_value, high_value);
-}
-
-/* Finish a goto-statement.  */
+/* Generate the RTL for T, which is a TRY_BLOCK. */
 
-void
-finish_goto_stmt (destination)
-     tree destination;
+static void 
+genrtl_try_block (t)
+     tree t;
 {
-  if (TREE_CODE (destination) == IDENTIFIER_NODE)
-    destination = lookup_label (destination);
-
-  /* We warn about unused labels with -Wunused.  That means we have to
-     mark the used labels as used.  */
-  if (TREE_CODE (destination) == LABEL_DECL)
-    TREE_USED (destination) = 1;
-    
-  if (building_stmt_tree ())
+  if (CLEANUP_P (t))
     {
-      if (TREE_CODE (destination) != LABEL_DECL)
-       /* We don't inline calls to functions with computed gotos.
-          Those functions are typically up to some funny business,
-          and may be depending on the labels being at particular
-          addresses, or some such.  */
-       DECL_UNINLINABLE (current_function_decl) = 1;
-
-      add_tree (build_min_nt (GOTO_STMT, destination));
+      expand_eh_region_start ();
+      expand_stmt (TRY_STMTS (t));
+      expand_eh_region_end (protect_with_terminate (TRY_HANDLERS (t)));
     }
   else
     {
-      emit_line_note (input_filename, lineno);
+      if (!FN_TRY_BLOCK_P (t)) 
+       emit_line_note (input_filename, lineno);
+      expand_start_try_stmts ();
 
-      if (TREE_CODE (destination) == LABEL_DECL)
+      expand_stmt (TRY_STMTS (t));
+
+      if (FN_TRY_BLOCK_P (t))
        {
-         label_rtx (destination);
-         expand_goto (destination); 
+         end_protect_partials ();
+         expand_start_all_catch ();
+         in_function_try_handler = 1;
+         expand_stmt (TRY_HANDLERS (t));
+         in_function_try_handler = 0;
+         expand_end_all_catch ();
+       }
+      else 
+       {
+         expand_start_all_catch ();  
+         expand_stmt (TRY_HANDLERS (t));
+         expand_end_all_catch ();
        }
-      else
-       expand_computed_goto (destination);
     }
 }
 
@@ -689,19 +605,9 @@ finish_goto_stmt (destination)
 tree
 begin_try_block ()
 {
-  if (building_stmt_tree ())
-    {
-      tree r = build_min_nt (TRY_BLOCK, NULL_TREE,
-                            NULL_TREE);
-      add_tree (r);
-      return r;
-    }
-  else
-    {
-      emit_line_note (input_filename, lineno);
-      expand_start_try_stmts ();
-      return NULL_TREE;
-    }
+  tree r = build_stmt (TRY_BLOCK, NULL_TREE, NULL_TREE);
+  add_stmt (r);
+  return r;
 }
 
 /* Likewise, for a function-try-block.  */
@@ -709,21 +615,10 @@ begin_try_block ()
 tree
 begin_function_try_block ()
 {
-  if (building_stmt_tree ())
-    {
-      tree r = build_min_nt (TRY_BLOCK, NULL_TREE,
-                            NULL_TREE);
-      FN_TRY_BLOCK_P (r) = 1;
-      add_tree (r);
-      return r;
-    }
-  else
-    {
-      if (! current_function_parms_stored)
-       store_parm_decls ();
-      expand_start_early_try_stmts ();
-      return NULL_TREE;
-    }
+  tree r = build_stmt (TRY_BLOCK, NULL_TREE, NULL_TREE);
+  FN_TRY_BLOCK_P (r) = 1;
+  add_stmt (r);
+  return r;
 }
 
 /* Finish a try-block, which may be given by TRY_BLOCK.  */
@@ -732,10 +627,7 @@ void
 finish_try_block (try_block)
      tree try_block;
 {
-  if (building_stmt_tree ())
-    RECHAIN_STMTS (try_block, TRY_STMTS (try_block));
-  else
-    expand_start_all_catch ();  
+  RECHAIN_STMTS (try_block, TRY_STMTS (try_block));
 }
 
 /* Finish the body of a cleanup try-block, which may be given by
@@ -745,8 +637,7 @@ void
 finish_cleanup_try_block (try_block)
      tree try_block;
 {
-  if (building_stmt_tree ())
-    RECHAIN_STMTS (try_block, TRY_STMTS (try_block));
+  RECHAIN_STMTS (try_block, TRY_STMTS (try_block));
 }
 
 /* Finish an implicitly generated try-block, with a cleanup is given
@@ -757,13 +648,8 @@ finish_cleanup (cleanup, try_block)
      tree cleanup;
      tree try_block;
 {
-  if (building_stmt_tree ()) 
-    {
-      TRY_HANDLERS (try_block) = cleanup;
-      CLEANUP_P (try_block) = 1;
-    }
-  else
-    expand_eh_region_end (protect_with_terminate (cleanup));
+  TRY_HANDLERS (try_block) = cleanup;
+  CLEANUP_P (try_block) = 1;
 }
 
 /* Likewise, for a function-try-block.  */
@@ -772,25 +658,16 @@ void
 finish_function_try_block (try_block)
      tree try_block; 
 {
-  if (building_stmt_tree ())
+  if (TREE_CHAIN (try_block) 
+      && TREE_CODE (TREE_CHAIN (try_block)) == CTOR_INITIALIZER)
     {
-      if (TREE_CHAIN (try_block) 
-         && TREE_CODE (TREE_CHAIN (try_block)) == CTOR_INITIALIZER)
-       {
-         /* Chain the compound statement after the CTOR_INITIALIZER.  */
-         TREE_CHAIN (TREE_CHAIN (try_block)) = last_tree;
-         /* And make the CTOR_INITIALIZER the body of the try-block.  */
-         RECHAIN_STMTS (try_block, TRY_STMTS (try_block));
-       }
-      else
-       RECHAIN_STMTS (try_block, TRY_STMTS (try_block));
+      /* Chain the compound statement after the CTOR_INITIALIZER.  */
+      TREE_CHAIN (TREE_CHAIN (try_block)) = last_tree;
+      /* And make the CTOR_INITIALIZER the body of the try-block.  */
+      RECHAIN_STMTS (try_block, TRY_STMTS (try_block));
     }
   else
-    {
-      end_protect_partials ();
-      expand_start_all_catch ();
-    }
-
+    RECHAIN_STMTS (try_block, TRY_STMTS (try_block));
   in_function_try_handler = 1;
 }
 
@@ -801,10 +678,8 @@ void
 finish_handler_sequence (try_block)
      tree try_block;
 {
-  if (building_stmt_tree ())
-    RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block));
-  else
-    expand_end_all_catch ();
+  RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block));
+  check_handlers (TRY_HANDLERS (try_block));
 }
 
 /* Likewise, for a function-try-block.  */
@@ -814,11 +689,26 @@ finish_function_handler_sequence (try_block)
      tree try_block;
 {
   in_function_try_handler = 0;
+  RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block));
+  check_handlers (TRY_HANDLERS (try_block));
+}
 
-  if (building_stmt_tree ())
-    RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block));
-  else
-    expand_end_all_catch ();
+/* Generate the RTL for T, which is a HANDLER. */
+
+static void
+genrtl_handler (t)
+     tree t;
+{
+  genrtl_do_pushlevel ();
+  expand_stmt (HANDLER_BODY (t));
+  if (!processing_template_decl)
+    {
+      /* Fall to outside the try statement when done executing
+        handler and we fall off end of handler.  This is jump
+        Lresume in the documentation.  */
+      expand_goto (top_label_entry (&caught_return_label_stack));
+      end_catch_handler ();
+    }
 }
 
 /* Begin a handler.  Returns a HANDLER if appropriate.  */
@@ -827,17 +717,9 @@ tree
 begin_handler ()
 {
   tree r;
-
-  if (building_stmt_tree ())
-    {
-      r = build_min_nt (HANDLER, NULL_TREE, NULL_TREE);
-      add_tree (r);
-    }
-  else
-    r = NULL_TREE;
-
+  r = build_stmt (HANDLER, NULL_TREE, NULL_TREE);
+  add_stmt (r);
   do_pushlevel ();
-
   return r;
 }
 
@@ -862,12 +744,24 @@ finish_handler_parms (decl, handler)
          RECHAIN_STMTS (handler, HANDLER_PARMS (handler));
        }
     }
-  else if (building_stmt_tree ())
+  else
     blocks = expand_start_catch_block (decl);
 
+  if (decl)
+    TREE_TYPE (handler) = TREE_TYPE (decl);
+
   return blocks;
 }
 
+/* Generate the RTL for a CATCH_BLOCK. */
+
+static void
+genrtl_catch_block (type)
+     tree type;
+{
+  start_catch_handler (type);
+}
+
 /* Note the beginning of a handler for TYPE.  This function is called
    at the point to which control should be transferred when an
    appropriately-typed exception is thrown.  */
@@ -876,10 +770,7 @@ void
 begin_catch_block (type)
      tree type;
 {
-  if (building_stmt_tree ())
-    add_tree (build (START_CATCH_STMT, type));
-  else
-    start_catch_handler (type);
+  add_stmt (build (START_CATCH_STMT, type));
 }
 
 /* Finish a handler, which may be given by HANDLER.  The BLOCKs are
@@ -891,24 +782,24 @@ finish_handler (blocks, handler)
      tree handler;
 {
   if (!processing_template_decl)
-    {
-      if (building_stmt_tree ())
-       expand_end_catch_block (blocks);
-
-      if (!building_stmt_tree ())
-       {
-         /* Fall to outside the try statement when done executing
-            handler and we fall off end of handler.  This is jump
-            Lresume in the documentation.  */
-         expand_goto (top_label_entry (&caught_return_label_stack));
-         end_catch_handler ();
-       }
-    }
-
+      expand_end_catch_block (blocks);
   do_poplevel ();
+  RECHAIN_STMTS (handler, HANDLER_BODY (handler));
+}
 
-  if (building_stmt_tree ())
-    RECHAIN_STMTS (handler, HANDLER_BODY (handler));
+/* Generate the RTL for T, which is a CTOR_STMT. */
+
+static void
+genrtl_ctor_stmt (t)
+     tree t;
+{
+  if (CTOR_BEGIN_P (t))
+    begin_protect_partials ();
+  else
+    /* After this point, any exceptions will cause the
+       destructor to be executed, so we no longer need to worry
+       about destroying the various subobjects ourselves.  */
+    end_protect_partials ();
 }
 
 /* Begin a compound-statement.  If HAS_NO_SCOPE is non-zero, the
@@ -920,21 +811,25 @@ begin_compound_stmt (has_no_scope)
      int has_no_scope;
 {
   tree r; 
+  int is_try = 0;
 
-  if (building_stmt_tree ())
-    {
-      r = build_min_nt (COMPOUND_STMT, NULL_TREE);
-      add_tree (r);
-      if (has_no_scope)
-       COMPOUND_STMT_NO_SCOPE (r) = 1;
-    }
-  else
-    r = NULL_TREE;
+  r = build_stmt (COMPOUND_STMT, NULL_TREE);
+
+  if (last_tree && TREE_CODE (last_tree) == TRY_BLOCK)
+    is_try = 1;
+
+  add_stmt (r);
+  if (has_no_scope)
+    COMPOUND_STMT_NO_SCOPE (r) = 1;
 
   last_expr_type = NULL_TREE;
 
   if (!has_no_scope)
-    do_pushlevel ();
+    {
+      do_pushlevel ();
+      if (is_try)
+       note_level_for_eh ();
+    }
   else
     /* Normally, we try hard to keep the BLOCK for a
        statement-expression.  But, if it's a statement-expression with
@@ -944,23 +839,17 @@ begin_compound_stmt (has_no_scope)
 
   /* If this is the outermost block of the function, declare the
      variables __FUNCTION__, __PRETTY_FUNCTION__, and so forth.  */
-  if (current_function
-      && !current_function_name_declared 
+  if (cfun
+      && !function_name_declared_p
       && !has_no_scope)
     {
-      /* When we get callbacks from the middle-end, we need to know
-        we're in the midst of declaring these variables.  */
-      current_function_name_declared = 2;
-      /* Actually insert the declarations.  */
+      function_name_declared_p = 1;
       declare_function_name ();
-      /* And now just remember that we're all done.  */
-      current_function_name_declared = 1;
     }
 
   return r;
 }
 
-
 /* Finish a compound-statement, which may be given by COMPOUND_STMT.
    If HAS_NO_SCOPE is non-zero, the compound statement does not define
    a scope.  */
@@ -978,8 +867,7 @@ finish_compound_stmt (has_no_scope, compound_stmt)
   else
     r = NULL_TREE;
 
-  if (building_stmt_tree ())
-    RECHAIN_STMTS (compound_stmt, COMPOUND_BODY (compound_stmt));
+  RECHAIN_STMTS (compound_stmt, COMPOUND_BODY (compound_stmt));
 
   /* When we call finish_stmt we will lose LAST_EXPR_TYPE.  But, since
      the precise purpose of that variable is store the type of the
@@ -1005,6 +893,9 @@ finish_asm_stmt (cv_qualifier, string, output_operands,
      tree input_operands;
      tree clobbers;
 {
+  tree r;
+  tree t;
+
   if (TREE_CHAIN (string))
     string = combine_strings (string);
 
@@ -1016,35 +907,14 @@ finish_asm_stmt (cv_qualifier, string, output_operands,
       cv_qualifier = NULL_TREE;
     }
 
-  if (building_stmt_tree ())
-    {
-      tree r = build_min_nt (ASM_STMT, cv_qualifier, string,
-                            output_operands, input_operands,
-                            clobbers);
-      add_tree (r);
-    }
-  else
-    {
-      emit_line_note (input_filename, lineno);
-      if (output_operands != NULL_TREE || input_operands != NULL_TREE
-           || clobbers != NULL_TREE)
-       {
-         tree t;
-
-         for (t = input_operands; t; t = TREE_CHAIN (t))
-           TREE_VALUE (t) = decay_conversion (TREE_VALUE (t));
+  if (!processing_template_decl)
+    for (t = input_operands; t; t = TREE_CHAIN (t))
+      TREE_VALUE (t) = decay_conversion (TREE_VALUE (t));
 
-         c_expand_asm_operands (string, output_operands,
-                                input_operands, 
-                                clobbers,
-                                cv_qualifier != NULL_TREE,
-                                input_filename, lineno);
-       }
-      else
-       expand_asm (string);
-      
-      finish_stmt ();
-    }
+  r = build_stmt (ASM_STMT, cv_qualifier, string,
+                 output_operands, input_operands,
+                 clobbers);
+  add_stmt (r);
 }
 
 /* Finish a label with the indicated NAME.  */
@@ -1054,11 +924,7 @@ finish_label_stmt (name)
      tree name;
 {
   tree decl = define_label (input_filename, lineno, name);
-
-  if (building_stmt_tree ())
-    add_tree (build_min_nt (LABEL_STMT, decl));
-  else if (decl)
-    expand_label (decl);
+  add_stmt (build_stmt (LABEL_STMT, decl));
 }
 
 /* Finish a series of declarations for local labels.  G++ allows users
@@ -1070,22 +936,16 @@ finish_label_decl (name)
      tree name;
 {
   tree decl = declare_local_label (name);
-  if (building_stmt_tree ())
-    add_decl_stmt (decl);
+  add_decl_stmt (decl);
 }
 
-/* Create a declaration statement for the declaration given by the
-   DECL.  */
+/* Generate the RTL for a SUBOBJECT. */
 
-void
-add_decl_stmt (decl)
-     tree decl;
+static void 
+genrtl_subobject (cleanup)
+     tree cleanup;
 {
-  tree decl_stmt;
-
-  /* We need the type to last until instantiation time.  */
-  decl_stmt = build_min_nt (DECL_STMT, decl);
-  add_tree (decl_stmt);
+  add_partial_entry (cleanup);
 }
 
 /* We're in a constructor, and have just constructed a a subobject of
@@ -1096,13 +956,8 @@ void
 finish_subobject (cleanup)
      tree cleanup;
 {
-  if (building_stmt_tree ())
-    {
-      tree r = build_min_nt (SUBOBJECT, cleanup);
-      add_tree (r);
-    }
-  else
-    add_partial_entry (cleanup);
+  tree r = build_stmt (SUBOBJECT, cleanup);
+  add_stmt (r);
 }
 
 /* When DECL goes out of scope, make sure that CLEANUP is executed.  */
@@ -1112,11 +967,33 @@ finish_decl_cleanup (decl, cleanup)
      tree decl;
      tree cleanup;
 {
-  if (building_stmt_tree ())
-    add_tree (build_min_nt (CLEANUP_STMT, decl, cleanup));
-  else if (!decl 
-          || (DECL_SIZE (decl) && TREE_TYPE (decl) != error_mark_node))
-    expand_decl_cleanup (decl, cleanup);
+  add_stmt (build_stmt (CLEANUP_STMT, decl, cleanup));
+}
+
+/* Generate the RTL for a RETURN_INIT. */
+
+static void
+genrtl_named_return_value ()
+{
+  tree decl = DECL_RESULT (current_function_decl);
+
+  /* If this named return value comes in a register, put it in a
+     pseudo-register.  */
+  if (DECL_REGISTER (decl))
+    {
+      /* Note that the mode of the old DECL_RTL may be wider than the
+        mode of DECL_RESULT, depending on the calling conventions for
+        the processor.  For example, on the Alpha, a 32-bit integer
+        is returned in a DImode register -- the DECL_RESULT has
+        SImode but the DECL_RTL for the DECL_RESULT has DImode.  So,
+        here, we use the mode the back-end has already assigned for
+        the return value.  */
+      DECL_RTL (decl) = gen_reg_rtx (GET_MODE (DECL_RTL (decl)));
+      if (TREE_ADDRESSABLE (decl))
+       put_var_into_stack (decl);
+    }
+
+  emit_local_var (decl);
 }
 
 /* Bind a name and initialization to the return value of
@@ -1128,11 +1005,12 @@ finish_named_return_value (return_id, init)
 {
   tree decl = DECL_RESULT (current_function_decl);
 
+  /* 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.  */
   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");
+    pedwarn ("ISO C++ does not permit named return values");
+  cp_deprecated ("the named return value extension");
 
   if (return_id != NULL_TREE)
     {
@@ -1158,19 +1036,82 @@ finish_named_return_value (return_id, init)
   /* If we have a named return value, put that in our scope as well.  */
   if (DECL_NAME (decl) != NULL_TREE)
     {
-      /* Let `cp_finish_decl' know that this initializer is ok.  */
-      DECL_INITIAL (decl) = init;
-      if (doing_semantic_analysis_p ())
-       pushdecl (decl);
+      /* Let `cp_finish_decl' know that this initializer is ok.  */
+      DECL_INITIAL (decl) = init;
+      if (doing_semantic_analysis_p ())
+       pushdecl (decl);
+      if (!processing_template_decl) 
+       {
+         cp_finish_decl (decl, init, NULL_TREE, 0);
+         add_stmt (build_stmt (RETURN_INIT, NULL_TREE, NULL_TREE));
+       }
+      else
+       add_stmt (build_stmt (RETURN_INIT, return_id, init));
+    }
+
+  /* Don't use tree-inlining for functions with named return values.
+     That doesn't work properly because we don't do any translation of
+     the RETURN_INITs when they are copied.  */
+  DECL_UNINLINABLE (current_function_decl) = 1;
+}
+
+/* The INIT_LIST is a list of mem-initializers, in the order they were
+   written by the user.  The TREE_VALUE of each node is a list of
+   initializers for a particular subobject.  The TREE_PURPOSE is a
+   FIELD_DECL is the initializer is for a non-static data member, and
+   a class type if the initializer is for a base class.  */
+
+void
+finish_mem_initializers (init_list)
+     tree init_list;
+{
+  tree member_init_list;
+  tree base_init_list;
+  tree last_base_warned_about;
+  tree next; 
+  tree init;
+
+  member_init_list = NULL_TREE;
+  base_init_list = NULL_TREE;
+  last_base_warned_about = NULL_TREE;
+
+  for (init = init_list; init; init = next)
+    {
+      next = TREE_CHAIN (init);
+      if (TREE_CODE (TREE_PURPOSE (init)) == FIELD_DECL)
+       {
+         TREE_CHAIN (init) = member_init_list;
+         member_init_list = init;
+
+         /* We're running through the initializers from right to left
+            as we process them here.  So, if we see a data member
+            initializer after we see a base initializer, that
+            actually means that the base initializer preceeded the
+            data member initializer.  */
+         if (warn_reorder && last_base_warned_about != base_init_list)
+           {
+             tree base;
+
+             for (base = base_init_list; 
+                  base != last_base_warned_about; 
+                  base = TREE_CHAIN (base))
+               {
+                 cp_warning ("base initializer for `%T'",
+                             TREE_PURPOSE (base));
+                 warning ("   will be re-ordered to precede member initializations");
+               }
 
-      if (building_stmt_tree ())
-       add_tree (build_min_nt (RETURN_INIT, return_id, init));
+             last_base_warned_about = base_init_list;
+           }
+       }
       else
        {
-         cp_finish_decl (decl, init, NULL_TREE, 0);
-         store_return_init (decl);
+         TREE_CHAIN (init) = base_init_list;
+         base_init_list = init;
        }
     }
+
+  setup_vtbl_ptr (member_init_list, base_init_list);
 }
 
 /* Cache the value of this class's main virtual function table pointer
@@ -1178,7 +1119,9 @@ finish_named_return_value (return_id, init)
    more than one virtual function call is made this function.  */
 
 void
-setup_vtbl_ptr ()
+setup_vtbl_ptr (member_init_list, base_init_list)
+     tree member_init_list;
+     tree base_init_list;
 {
   my_friendly_assert (doing_semantic_analysis_p (), 19990919);
 
@@ -1189,39 +1132,38 @@ setup_vtbl_ptr ()
   if (DECL_CONSTRUCTOR_P (current_function_decl))
     {
       if (processing_template_decl)
-       add_tree (build_min_nt
+       add_stmt (build_min_nt
                  (CTOR_INITIALIZER,
-                  current_member_init_list, current_base_init_list));
+                  member_init_list, base_init_list));
       else
        {
          tree ctor_stmt;
 
          /* Mark the beginning of the constructor.  */
-         ctor_stmt = build_min_nt (CTOR_STMT);
+         ctor_stmt = build_stmt (CTOR_STMT);
          CTOR_BEGIN_P (ctor_stmt) = 1;
-         add_tree (ctor_stmt);
+         add_stmt (ctor_stmt);
          
          /* And actually initialize the base-classes and members.  */
-         finish_expr_stmt (emit_base_init (current_class_type));
+         emit_base_init (member_init_list, base_init_list);
        }
     }
   else if (DECL_DESTRUCTOR_P (current_function_decl)
           && !processing_template_decl)
     {
-      tree binfo = TYPE_BINFO (current_class_type);
       tree if_stmt;
       tree compound_stmt;
       int saved_cfnd;
 
-      /* 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
+      /* If the dtor is empty, and we know there is not any 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 dtor 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.  */
+        vtables in that case.  We could change this to see if there
+        is just one vtable.  */
       if_stmt = begin_if_stmt ();
 
       /* If it is not safe to avoid setting up the vtables, then
@@ -1234,19 +1176,15 @@ setup_vtbl_ptr ()
 
       /* Don't declare __PRETTY_FUNCTION__ and friends here when we
         open the block for the if-body.  */
-      saved_cfnd = current_function_name_declared;
-      current_function_name_declared = 1;
+      saved_cfnd = function_name_declared_p;
+      function_name_declared_p = 1;
       compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
-      current_function_name_declared = saved_cfnd;
+      function_name_declared_p = saved_cfnd;
 
       /* 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);
+      initialize_vtbl_ptrs (current_class_ptr);
 
       finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
       finish_then_clause (if_stmt);
@@ -1262,97 +1200,12 @@ setup_vtbl_ptr ()
   vtbls_set_up_p = 1;
 }
 
-/* Add a scope-statement to the statement-tree.  BEGIN_P indicates
-   whether this statements opens or closes a scope.  PARTIAL_P is true
-   for a partial scope, i.e, the scope that begins after a label when
-   an object that needs a cleanup is created.  If BEGIN_P is nonzero,
-   returns a new TREE_LIST representing the top of the SCOPE_STMT
-   stack.  The TREE_PURPOSE is the new SCOPE_STMT.  If BEGIN_P is
-   zero, returns a TREE_LIST whose TREE_VALUE is the new SCOPE_STMT,
-   and whose TREE_PURPOSE is the matching SCOPE_STMT iwth
-   SCOPE_BEGIN_P set.  */
-
-tree
-add_scope_stmt (begin_p, partial_p)
-     int begin_p;
-     int partial_p;
-{
-  tree ss;
-  tree top;
-
-  /* Build the statement.  */
-  ss = build_min_nt (SCOPE_STMT, NULL_TREE);
-  SCOPE_BEGIN_P (ss) = begin_p;
-  SCOPE_PARTIAL_P (ss) = partial_p;
-
-  /* Keep the scope stack up to date.  */
-  if (begin_p)
-    {
-      current_scope_stmt_stack 
-       = tree_cons (ss, NULL_TREE, current_scope_stmt_stack);
-      top = current_scope_stmt_stack;
-    }
-  else
-    {
-      top = current_scope_stmt_stack;
-      TREE_VALUE (top) = ss;
-      current_scope_stmt_stack = TREE_CHAIN (top);
-    }
-
-  /* Add the new statement to the statement-tree.  */
-  add_tree (ss);
-
-  return top;
-}
-
-/* Begin a new scope.  */
-
-void
-do_pushlevel ()
-{
-  if (!building_stmt_tree ())
-    {
-      emit_line_note (input_filename, lineno);
-      clear_last_expr ();
-    }
-  if (stmts_are_full_exprs_p)
-    {
-      pushlevel (0);
-      if (!building_stmt_tree ()
-         && !current_function->x_whole_function_mode_p)
-       my_friendly_abort (19991129);
-
-      if (building_stmt_tree () && !processing_template_decl)
-       add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0);
-    }
-}
-
-/* Finish a scope.  */
+/* Returns the stack of SCOPE_STMTs for the current function.  */
 
-tree
-do_poplevel ()
+tree *
+current_scope_stmt_stack ()
 {
-  tree block = NULL_TREE;
-
-  if (stmts_are_full_exprs_p)
-    {
-      tree scope_stmts;
-      int keep = kept_level_p ();
-
-      if (building_stmt_tree () && !processing_template_decl)
-       scope_stmts = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0);
-      else
-       scope_stmts = NULL_TREE;
-
-      block = poplevel (kept_level_p (), 1, 0);
-      if (block && !processing_template_decl)
-       {
-         SCOPE_STMT_BLOCK (TREE_PURPOSE (scope_stmts)) = block;
-         SCOPE_STMT_BLOCK (TREE_VALUE (scope_stmts)) = block;
-       }
-    }
-
-  return block;
+  return &cfun->language->x_scope_stmt_stack;
 }
 
 /* Finish a parenthesized expression EXPR.  */
@@ -1365,6 +1218,10 @@ finish_parenthesized_expr (expr)
     /* This inhibits warnings in truthvalue_conversion.  */
     C_SET_EXP_ORIGINAL_CODE (expr, ERROR_MARK); 
 
+  if (TREE_CODE (expr) == OFFSET_REF)
+    /* [expr.unary.op]/3 The qualified id of a pointer-to-member must not be
+       enclosed in parentheses.  */
+    PTRMEM_OK_P (expr) = 0;
   return expr;
 }
 
@@ -1377,7 +1234,7 @@ begin_stmt_expr ()
   /* If we're outside a function, we won't have a statement-tree to
      work with.  But, if we see a statement-expression we need to
      create one.  */
-  if (!current_function && !last_tree)
+  if (! cfun && !last_tree)
     begin_stmt_tree (&scope_chain->x_saved_tree);
 
   keep_next_level (1);
@@ -1385,7 +1242,37 @@ begin_stmt_expr ()
      statement will be chained onto the tree structure, starting at
      last_tree.  We return last_tree so that we can later unhook the
      compound statement.  */
-  return building_stmt_tree () ? last_tree : expand_start_stmt_expr(); 
+  return last_tree; 
+}
+
+/* Used when beginning a statement-expression outside function scope.
+   For example, when handling a file-scope initializer, we use this
+   function.  */
+
+tree
+begin_global_stmt_expr ()
+{
+  if (! cfun && !last_tree)
+    begin_stmt_tree (&scope_chain->x_saved_tree);
+
+  keep_next_level (1);
+  
+  return (last_tree != NULL_TREE) ? last_tree : expand_start_stmt_expr(); 
+}
+
+/* Finish the STMT_EXPR last begun with begin_global_stmt_expr.  */
+
+tree 
+finish_global_stmt_expr (stmt_expr)
+     tree stmt_expr;
+{
+  stmt_expr = expand_end_stmt_expr (stmt_expr);
+  
+  if (! cfun
+      && TREE_CHAIN (scope_chain->x_saved_tree) == NULL_TREE)
+    finish_stmt_tree (&scope_chain->x_saved_tree);
+
+  return stmt_expr;
 }
 
 /* Finish a statement-expression.  RTL_EXPR should be the value
@@ -1399,29 +1286,21 @@ finish_stmt_expr (rtl_expr)
 {
   tree result;
 
-  if (!building_stmt_tree ())
-    rtl_expr = expand_end_stmt_expr (rtl_expr);
-
-  if (building_stmt_tree ())
-    {
-      /* If the last thing in the statement-expression was not an
-        expression-statement, then it has type `void'.  */
-      if (!last_expr_type)
-       last_expr_type = void_type_node;
-      result = build_min (STMT_EXPR, last_expr_type, last_tree);
-      TREE_SIDE_EFFECTS (result) = 1;
-      
-      /* Remove the compound statement from the tree structure; it is
-        now saved in the STMT_EXPR.  */
-      SET_LAST_STMT (rtl_expr);
-      TREE_CHAIN (last_tree) = NULL_TREE;
-    }
-  else 
-    result = rtl_expr;
+  /* If the last thing in the statement-expression was not an
+     expression-statement, then it has type `void'.  */
+  if (!last_expr_type)
+    last_expr_type = void_type_node;
+  result = build_min (STMT_EXPR, last_expr_type, last_tree);
+  TREE_SIDE_EFFECTS (result) = 1;
+  
+  /* Remove the compound statement from the tree structure; it is
+     now saved in the STMT_EXPR.  */
+  last_tree = rtl_expr;
+  TREE_CHAIN (last_tree) = NULL_TREE;
 
   /* If we created a statement-tree for this statement-expression,
      remove it now.  */ 
-  if (!current_function 
+  if (! cfun
       && TREE_CHAIN (scope_chain->x_saved_tree) == NULL_TREE)
     finish_stmt_tree (&scope_chain->x_saved_tree);
 
@@ -1548,7 +1427,7 @@ finish_object_call_expr (fn, object, args)
 }
 
 /* Finish a qualified member function call using OBJECT and ARGS as
-   arguments to FN.  Returns an expressino for the call.  */
+   arguments to FN.  Returns an expression for the call.  */
 
 tree 
 finish_qualified_object_call_expr (fn, object, args)
@@ -1658,7 +1537,55 @@ finish_id_expr (expr)
   return expr;
 }
 
-/* Begin a function defniition declared with DECL_SPECS and
+static tree current_type_lookups;
+
+/* Perform deferred access control for types used in the type of a
+   declaration.  */
+
+static void
+deferred_type_access_control ()
+{
+  tree lookup = type_lookups;
+
+  if (lookup == error_mark_node)
+    return;
+
+  for (; lookup; lookup = TREE_CHAIN (lookup))
+    enforce_access (TREE_PURPOSE (lookup), TREE_VALUE (lookup));
+}
+
+void
+decl_type_access_control (decl)
+     tree decl;
+{
+  tree save_fn;
+
+  if (type_lookups == error_mark_node)
+    return;
+
+  save_fn = current_function_decl;
+
+  if (decl && TREE_CODE (decl) == FUNCTION_DECL)
+    current_function_decl = decl;
+
+  deferred_type_access_control ();
+
+  current_function_decl = save_fn;
+  
+  /* Now strip away the checks for the current declarator; they were
+     added to type_lookups after typed_declspecs saved the copy that
+     ended up in current_type_lookups.  */
+  type_lookups = current_type_lookups;
+}
+
+void
+save_type_access_control (lookups)
+     tree lookups;
+{
+  current_type_lookups = lookups;
+}
+
+/* Begin a function definition declared with DECL_SPECS and
    DECLARATOR.  Returns non-zero if the function-declaration is
    legal.  */
 
@@ -1669,11 +1596,14 @@ begin_function_definition (decl_specs, declarator)
 {
   tree specs;
   tree attrs;
+
   split_specs_attrs (decl_specs, &specs, &attrs);
   if (!start_function (specs, declarator, attrs, SF_DEFAULT))
     return 0;
-  
-  reinit_parse_for_function ();
+
+  deferred_type_access_control ();
+  type_lookups = error_mark_node;
+
   /* The things we're about to see are not directly qualified by any
      template headers we've seen thus far.  */
   reset_specialization ();
@@ -1751,7 +1681,7 @@ finish_template_template_parm (aggr, identifier)
   tree tmpl = build_lang_decl (TEMPLATE_DECL, identifier, NULL_TREE);
   DECL_TEMPLATE_PARMS (tmpl) = current_template_parms;
   DECL_TEMPLATE_RESULT (tmpl) = decl;
-  SET_DECL_ARTIFICIAL (decl);
+  DECL_ARTIFICIAL (decl) = 1;
   end_template_decl ();
 
   return finish_template_type_parm (aggr, tmpl);
@@ -1784,7 +1714,7 @@ begin_class_definition (t)
   if (t == error_mark_node
       || ! IS_AGGR_TYPE (t))
     {
-      t = make_lang_type (RECORD_TYPE);
+      t = make_aggr_type (RECORD_TYPE);
       pushtag (make_anon_name (), t, 0);
     }
 
@@ -1832,6 +1762,7 @@ begin_class_definition (t)
          TYPE_FIELDS (t) = NULL_TREE;
          TYPE_METHODS (t) = NULL_TREE;
          CLASSTYPE_TAGS (t) = NULL_TREE;
+         CLASSTYPE_VBASECLASSES (t) = NULL_TREE;
          TYPE_SIZE (t) = NULL_TREE;
        }
 
@@ -1840,7 +1771,7 @@ begin_class_definition (t)
     }
   /* If this type was already complete, and we see another definition,
      that's an error.  */
-  else if (TYPE_SIZE (t))
+  else if (COMPLETE_TYPE_P (t))
     duplicate_tag_error (t);
 
   /* Update the location of the decl.  */
@@ -1849,12 +1780,13 @@ begin_class_definition (t)
   
   if (TYPE_BEING_DEFINED (t))
     {
-      t = make_lang_type (TREE_CODE (t));
+      t = make_aggr_type (TREE_CODE (t));
       pushtag (TYPE_IDENTIFIER (t), t, 0);
     }
   maybe_process_partial_specialization (t);
   pushclass (t, 1);
   TYPE_BEING_DEFINED (t) = 1;
+  TYPE_PACKED (t) = flag_pack_struct;
   /* Reset the interface data, at the earliest possible
      moment, as it might have been set via a class foo;
      before.  */
@@ -1874,11 +1806,6 @@ begin_class_definition (t)
        || ! CLASSTYPE_INTERFACE_ONLY (t))
       CLASSTYPE_VTABLE_NEEDS_WRITING (t) = 1;
   }
-#if 0
-  tmp = TYPE_IDENTIFIER ($<ttype>0);
-  if (tmp && IDENTIFIER_TEMPLATE (tmp))
-    overload_template_name (tmp, 1);
-#endif
   reset_specialization();
   
   /* Make a declaration for this class in its own scope.  */
@@ -1911,19 +1838,19 @@ finish_member_declaration (decl)
     = (current_access_specifier == access_protected_node);
   if (TREE_CODE (decl) == TEMPLATE_DECL)
     {
-      TREE_PRIVATE (DECL_RESULT (decl)) = TREE_PRIVATE (decl);
-      TREE_PROTECTED (DECL_RESULT (decl)) = TREE_PROTECTED (decl);
+      TREE_PRIVATE (DECL_TEMPLATE_RESULT (decl)) = TREE_PRIVATE (decl);
+      TREE_PROTECTED (DECL_TEMPLATE_RESULT (decl)) = TREE_PROTECTED (decl);
     }
 
   /* Mark the DECL as a member of the current class.  */
-  if (TREE_CODE (decl) == FUNCTION_DECL 
-      || DECL_FUNCTION_TEMPLATE_P (decl))
-    /* Historically, DECL_CONTEXT was not set for a FUNCTION_DECL in
-       finish_struct.  Presumably it is already set as the function is
-       parsed.  Perhaps DECL_CLASS_CONTEXT is already set, too?  */
-    DECL_CLASS_CONTEXT (decl) = current_class_type;
-  else
-    DECL_CONTEXT (decl) = current_class_type;
+  DECL_CONTEXT (decl) = current_class_type;
+
+  /* [dcl.link]
+
+     A C language linkage is ignored for the names of class members
+     and the member function type of class member functions.  */
+  if (DECL_LANG_SPECIFIC (decl) && DECL_LANGUAGE (decl) == lang_c)
+    DECL_LANGUAGE (decl) = lang_cplusplus;
 
   /* Put functions on the TYPE_METHODS list and everything else on the
      TYPE_FIELDS list.  Note that these are built up in reverse order.
@@ -1933,7 +1860,7 @@ finish_member_declaration (decl)
     {
       /* We also need to add this function to the
         CLASSTYPE_METHOD_VEC.  */
-      add_method (current_class_type, 0, decl);
+      add_method (current_class_type, decl, /*error_p=*/0);
 
       TREE_CHAIN (decl) = TYPE_METHODS (current_class_type);
       TYPE_METHODS (current_class_type) = decl;
@@ -2018,8 +1945,7 @@ finish_class_definition (t, attributes, semi, pop_scope_p)
 void
 begin_inline_definitions ()
 {
-  if (pending_inlines 
-      && current_scope () == current_function_decl)
+  if (current_scope () == current_function_decl)
     do_pending_inlines ();
 }
 
@@ -2078,7 +2004,7 @@ finish_template_decl (parms)
     end_specialization ();
 }
 
-/* Finish processing a template-id (which names a type) of the form
+/* Finish processing a template-id (which names a type) of the form
    NAME < ARGS >.  Return the TYPE_DECL for the type named by the
    template-id.  If ENTERING_SCOPE is non-zero we are about to enter
    the scope of template-id indicated.  */
@@ -2192,7 +2118,7 @@ finish_typeof (expr)
     {
       tree t;
 
-      t = make_lang_type (TYPEOF_TYPE);
+      t = make_aggr_type (TYPEOF_TYPE);
       TYPE_FIELDS (t) = expr;
 
       return t;
@@ -2201,321 +2127,178 @@ finish_typeof (expr)
   return TREE_TYPE (expr);
 }
 
-/* Create an empty statement tree rooted at T.  */
+/* Generate RTL for the statement T, and its substatements, and any
+   other statements at its nesting level.  */
 
-void
-begin_stmt_tree (t)
-     tree *t;
-{
-  /* We create a trivial EXPR_STMT so that last_tree is never NULL in
-     what follows.  We remove the extraneous statement in
-     finish_stmt_tree.  */
-  *t = build_nt (EXPR_STMT, void_zero_node);
-  SET_LAST_STMT (*t);
-  last_expr_type = NULL_TREE;
-}
+static void
+cp_expand_stmt (t)
+     tree t;
+{
+  switch (TREE_CODE (t))
+    {
+    case CLEANUP_STMT:
+      genrtl_decl_cleanup (CLEANUP_DECL (t), CLEANUP_EXPR (t));
+      break;
 
-/* Finish the statement tree rooted at T.  */
+    case START_CATCH_STMT:
+      genrtl_catch_block (TREE_TYPE (t));
+      break;
 
-void
-finish_stmt_tree (t)
-     tree *t;
-{
-  tree stmt;
-  
-  /* Remove the fake extra statement added in begin_stmt_tree.  */
-  stmt = TREE_CHAIN (*t);
-  *t = stmt;
-  SET_LAST_STMT (NULL_TREE);
+    case CTOR_STMT:
+      genrtl_ctor_stmt (t);
+      break;
 
-  if (current_function)
-    {
-      /* The line-number recorded in the outermost statement in a function
-        is the line number of the end of the function.  */
-      STMT_LINENO (stmt) = lineno;
-      STMT_LINENO_FOR_FN_P (stmt) = 1;
-    }
-}
+    case TRY_BLOCK:
+      genrtl_try_block (t);
+      break;
 
-/* We're about to expand T, a statement.  Set up appropriate context
-   for the substitution.  */
+    case HANDLER:
+      genrtl_handler (t);
+      break;
 
-void
-prep_stmt (t)
-     tree t;
-{
-  if (!STMT_LINENO_FOR_FN_P (t))
-    lineno = STMT_LINENO (t);
-  stmts_are_full_exprs_p = STMT_IS_FULL_EXPR_P (t);
-}
+    case SUBOBJECT:
+      genrtl_subobject (SUBOBJECT_CLEANUP (t));
+      break;
 
-/* Some statements, like for-statements or if-statements, require a
-   condition.  This condition can be a declaration.  If T is such a
-   declaration it is processed, and an expression appropriate to use
-   as the condition is returned.  Otherwise, T itself is returned.  */
+    case RETURN_INIT:
+      genrtl_named_return_value ();
+      break;
 
-static tree
-expand_cond (t)
-     tree t;
-{
-  if (t && TREE_CODE (t) == TREE_LIST)
-    {
-      expand_stmt (TREE_PURPOSE (t));
-      return TREE_VALUE (t);
+    default:
+      my_friendly_abort (19990810);
+      break;
     }
-  else 
-    return t;
 }
 
-/* Generate RTL for the statement T, and its substatements, and any
-   other statements at its nesting level.  */
+/* Called from expand_body via walk_tree.  Replace all AGGR_INIT_EXPRs
+   will equivalent CALL_EXPRs.  */
 
-tree
-expand_stmt (t)
-     tree t;
-{
-  tree rval = NULL_TREE;
+static tree
+simplify_aggr_init_exprs_r (tp, walk_subtrees, data)
+     tree *tp;
+     int *walk_subtrees ATTRIBUTE_UNUSED;
+     void *data ATTRIBUTE_UNUSED;
+{
+  tree aggr_init_expr;
+  tree call_expr;
+  tree fn;
+  tree args;
+  tree slot;
+  tree type;
+  tree call_type;
+  int copy_from_buffer_p;
+
+  aggr_init_expr = *tp;
+  /* We don't need to walk into types; there's nothing in a type that
+     needs simplification.  (And, furthermore, there are places we
+     actively don't want to go.  For example, we don't want to wander
+     into the default arguments for a FUNCTION_DECL that appears in a
+     CALL_EXPR.)  */
+  if (TYPE_P (aggr_init_expr))
+    {
+      *walk_subtrees = 0;
+      return NULL_TREE;
+    }
+  /* Only AGGR_INIT_EXPRs are interesting.  */
+  else if (TREE_CODE (aggr_init_expr) != AGGR_INIT_EXPR)
+    return NULL_TREE;
+
+  /* Form an appropriate CALL_EXPR.  */
+  fn = TREE_OPERAND (aggr_init_expr, 0);
+  args = TREE_OPERAND (aggr_init_expr, 1);
+  slot = TREE_OPERAND (aggr_init_expr, 2);
+  type = TREE_TYPE (aggr_init_expr);
+  call_type = type;
+  if (AGGR_INIT_VIA_CTOR_P (aggr_init_expr))
+    {
+      /* Replace the first argument with the address of the third
+        argument to the AGGR_INIT_EXPR.  */
+      call_type = build_pointer_type (type);
+      mark_addressable (slot);
+      args = tree_cons (NULL_TREE, build1 (ADDR_EXPR, call_type, slot),
+                       TREE_CHAIN (args));
+    }
+  call_expr = build (CALL_EXPR, call_type, fn, args, NULL_TREE);
+  TREE_SIDE_EFFECTS (call_expr) = 1;
+
+  /* If we're using the non-reentrant PCC calling convention, then we
+     need to copy the returned value out of the static buffer into the
+     SLOT.  */
+  copy_from_buffer_p = 0;
+#ifdef PCC_STATIC_STRUCT_RETURN  
+  if (!AGGR_INIT_VIA_CTOR_P (aggr_init_expr) && aggregate_value_p (type))
+    {
+      int old_ac;
+
+      flag_access_control = 0;
+      call_expr = build_aggr_init (slot, call_expr, LOOKUP_ONLYCONVERTING);
+      flag_access_control = old_ac;
+      copy_from_buffer_p = 1;
+    }
+#endif
 
-  while (t && t != error_mark_node)
+  /* If this AGGR_INIT_EXPR indicates the value returned by a
+     function, then we want to use the value of the initialized
+     location as the result.  */
+  if (AGGR_INIT_VIA_CTOR_P (aggr_init_expr) || copy_from_buffer_p)
     {
-      int saved_stmts_are_full_exprs_p;
+      call_expr = build (COMPOUND_EXPR, type,
+                        call_expr, slot);
+      TREE_SIDE_EFFECTS (call_expr) = 1;
+    }
 
-      /* Assume we'll have nothing to return.  */
-      rval = NULL_TREE;
+  /* Replace the AGGR_INIT_EXPR with the CALL_EXPR.  */
+  TREE_CHAIN (call_expr) = TREE_CHAIN (aggr_init_expr);
+  *tp = call_expr;
 
-      /* Set up context appropriately for handling this statement.  */
-      saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p;
-      prep_stmt (t);
+  /* Keep iterating.  */
+  return NULL_TREE;
+}
 
-      switch (TREE_CODE (t))
-       {
-       case RETURN_STMT:
-         finish_return_stmt (RETURN_EXPR (t));
-         break;
-
-       case EXPR_STMT:
-         finish_expr_stmt (EXPR_STMT_EXPR (t));
-         break;
-
-       case DECL_STMT:
-         {
-           tree decl;
-
-           emit_line_note (input_filename, lineno);
-           decl = DECL_STMT_DECL (t);
-           /* If this is a declaration for an automatic local
-              variable, initialize it.  Note that we might also see a
-              declaration for a namespace-scope object (declared with
-              `extern').  We don't have to handle the initialization
-              of those objects here; they can only be declarations,
-              rather than definitions.  */
-           if (TREE_CODE (decl) == VAR_DECL 
-               && !TREE_STATIC (decl)
-               && !DECL_EXTERNAL (decl))
-             {
-               /* Let the back-end know about this variable.  */
-               if (!ANON_AGGR_TYPE_P (TREE_TYPE (decl)))
-                 emit_local_var (decl);
-               else
-                 expand_anon_union_decl (decl, NULL_TREE, 
-                                         DECL_ANON_UNION_ELEMS (decl));
-             }
-           else if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl))
-             make_rtl_for_local_static (decl);
-         }
-         break;
-
-       case CLEANUP_STMT:
-         finish_decl_cleanup (CLEANUP_DECL (t), CLEANUP_EXPR (t));
-         break;
-
-       case START_CATCH_STMT:
-         begin_catch_block (TREE_TYPE (t));
-         break;
-
-       case CTOR_STMT:
-         if (CTOR_BEGIN_P (t))
-           begin_protect_partials ();
-         else
-           /* After this point, any exceptions will cause the
-              destructor to be executed, so we no longer need to worry
-              about destroying the various subobjects ourselves.  */
-           end_protect_partials ();
-         break;
-
-       case FOR_STMT:
-         {
-           tree tmp;
-
-           begin_for_stmt ();
-           expand_stmt (FOR_INIT_STMT (t));
-           finish_for_init_stmt (NULL_TREE);
-           finish_for_cond (expand_cond (FOR_COND (t)), NULL_TREE);
-           tmp = FOR_EXPR (t);
-           finish_for_expr (tmp, NULL_TREE);
-           expand_stmt (FOR_BODY (t));
-           finish_for_stmt (tmp, NULL_TREE);
-         }
-         break;
-
-       case WHILE_STMT:
-         {
-           begin_while_stmt ();
-           finish_while_stmt_cond (expand_cond (WHILE_COND (t)), NULL_TREE);
-           expand_stmt (WHILE_BODY (t));
-           finish_while_stmt (NULL_TREE);
-         }
-         break;
-
-       case DO_STMT:
-         {
-           begin_do_stmt ();
-           expand_stmt (DO_BODY (t));
-           finish_do_body (NULL_TREE);
-           finish_do_stmt (DO_COND (t), NULL_TREE);
-         }
-         break;
-
-       case IF_STMT:
-         begin_if_stmt ();
-         finish_if_stmt_cond (expand_cond (IF_COND (t)), NULL_TREE);
-         if (THEN_CLAUSE (t))
-           {
-             expand_stmt (THEN_CLAUSE (t));
-             finish_then_clause (NULL_TREE);
-           }
-         if (ELSE_CLAUSE (t))
-           {
-             begin_else_clause ();
-             expand_stmt (ELSE_CLAUSE (t));
-             finish_else_clause (NULL_TREE);
-           }
-         finish_if_stmt ();
-         break;
-
-       case COMPOUND_STMT:
-         begin_compound_stmt (COMPOUND_STMT_NO_SCOPE (t));
-         expand_stmt (COMPOUND_BODY (t));
-         rval = finish_compound_stmt (COMPOUND_STMT_NO_SCOPE (t), 
-                                      NULL_TREE);
-         break;
-
-       case BREAK_STMT:
-         finish_break_stmt ();
-         break;
-
-       case CONTINUE_STMT:
-         finish_continue_stmt ();
-         break;
-
-       case SWITCH_STMT:
-         {
-           tree cond;
-
-           begin_switch_stmt ();
-           cond = expand_cond (SWITCH_COND (t));
-           finish_switch_cond (cond, NULL_TREE);
-           expand_stmt (SWITCH_BODY (t));
-           finish_switch_stmt (cond, NULL_TREE);
-         }
-         break;
-
-       case CASE_LABEL:
-         finish_case_label (CASE_LOW (t), CASE_HIGH (t));
-         break;
-
-       case LABEL_STMT:
-         expand_label (LABEL_STMT_LABEL (t));
-         break;
-
-       case GOTO_STMT:
-         finish_goto_stmt (GOTO_DESTINATION (t));
-         break;
-
-       case ASM_STMT:
-         finish_asm_stmt (ASM_CV_QUAL (t), ASM_STRING (t), ASM_OUTPUTS
-                          (t), ASM_INPUTS (t), ASM_CLOBBERS (t));
-         break;
-
-       case TRY_BLOCK:
-         if (CLEANUP_P (t))
-           {
-             expand_eh_region_start ();
-             expand_stmt (TRY_STMTS (t));
-             finish_cleanup_try_block (NULL_TREE);
-             finish_cleanup (TRY_HANDLERS (t), NULL_TREE);
-           }
-         else
-           {
-             if (FN_TRY_BLOCK_P (t))
-               begin_function_try_block ();
-             else
-               begin_try_block ();
+/* Emit all thunks to FN that should be emitted when FN is emitted.  */
 
-             expand_stmt (TRY_STMTS (t));
+static void
+emit_associated_thunks (fn)
+     tree fn;
+{
+  /* When we use vcall offsets, we emit thunks with the virtual
+     functions to which they thunk. The whole point of vcall offsets
+     is so that you can know statically the entire set of thunks that
+     will ever be needed for a given virtual function, thereby
+     enabling you to output all the thunks with the function itself.  */
+  if (vcall_offsets_in_vtable_p () && DECL_VIRTUAL_P (fn))
+    {
+      tree binfo;
+      tree v;
+
+      for (binfo = TYPE_BINFO (DECL_CONTEXT (fn));
+          binfo;
+          binfo = TREE_CHAIN (binfo))
+       for (v = BINFO_VIRTUALS (binfo); v; v = TREE_CHAIN (v))
+         if (BV_FN (v) == fn
+             && (!integer_zerop (BV_DELTA (v))
+                 || BV_VCALL_INDEX (v)))
+           {
+             tree thunk;
+             tree vcall_index;
 
-             if (FN_TRY_BLOCK_P (t))
+             if (BV_USE_VCALL_INDEX_P (v))
                {
-                 finish_function_try_block (NULL_TREE);
-                 expand_stmt (TRY_HANDLERS (t));
-                 finish_function_handler_sequence (NULL_TREE);
+                 vcall_index = BV_VCALL_INDEX (v);
+                 my_friendly_assert (vcall_index != NULL_TREE, 20000621);
                }
              else
-               {
-                 finish_try_block (NULL_TREE);
-                 expand_stmt (TRY_HANDLERS (t));
-                 finish_handler_sequence (NULL_TREE);
-               }
-           }
-         break;
-
-       case HANDLER:
-         begin_handler ();
-         expand_stmt (HANDLER_BODY (t));
-         finish_handler (NULL_TREE, NULL_TREE);
-         break;
-
-       case SUBOBJECT:
-         finish_subobject (SUBOBJECT_CLEANUP (t));
-         break;
-
-       case SCOPE_STMT:
-         if (!SCOPE_NO_CLEANUPS_P (t))
-           {
-             if (SCOPE_BEGIN_P (t))
-               expand_start_bindings (2 * SCOPE_NULLIFIED_P (t));
-             else if (SCOPE_END_P (t))
-               expand_end_bindings (NULL_TREE, !SCOPE_NULLIFIED_P (t), 
-                                    SCOPE_PARTIAL_P (t));
+               vcall_index = NULL_TREE;
+
+             thunk = make_thunk (build1 (ADDR_EXPR,
+                                         vfunc_ptr_type_node,
+                                         fn),
+                                 BV_DELTA (v),
+                                 vcall_index,
+                                 /*generate_with_vtable_p=*/0);
+             use_thunk (thunk, /*emit_p=*/1);
            }
-         else if (!SCOPE_NULLIFIED_P (t))
-           emit_note (NULL,
-                      (SCOPE_BEGIN_P (t) 
-                       ? NOTE_INSN_BLOCK_BEG
-                       : NOTE_INSN_BLOCK_END));
-         break;
-
-       case RETURN_INIT:
-         /* Clear this out so that finish_named_return_value can set it
-            again.  */
-         DECL_NAME (DECL_RESULT (current_function_decl)) = NULL_TREE;
-         finish_named_return_value (TREE_OPERAND (t, 0), 
-                                    TREE_OPERAND (t, 1));
-         break;
-
-       default:
-         my_friendly_abort (19990810);
-         break;
-       }
-
-      /* Restore saved state.  */
-      stmts_are_full_exprs_p = saved_stmts_are_full_exprs_p;
-
-      /* Go on to the next statement in this scope.  */
-      t = TREE_CHAIN (t);
     }
-
-  return rval;
 }
 
 /* Generate RTL for FN.  */
@@ -2525,7 +2308,7 @@ expand_body (fn)
      tree fn;
 {
   int saved_lineno;
-  char *saved_input_filename;
+  const char *saved_input_filename;
 
   /* When the parser calls us after finishing the body of a template
      function, we don't really want to expand the body.  When we're
@@ -2545,6 +2328,21 @@ expand_body (fn)
       return;
     }
 
+  /* Replace AGGR_INIT_EXPRs with appropriate CALL_EXPRs.  */
+  walk_tree_without_duplicates (&DECL_SAVED_TREE (fn),
+                               simplify_aggr_init_exprs_r,
+                               NULL);
+
+  /* If this is a constructor or destructor body, we have to clone it
+     under the new ABI.  */
+  if (maybe_clone_body (fn))
+    {
+      /* We don't want to process FN again, so pretend we've written
+        it out, even though we haven't.  */
+      TREE_ASM_WRITTEN (fn) = 1;
+      return;
+    }
+
   /* There's no reason to do any of the work here if we're only doing
      semantic analysis; this code just generates RTL.  */
   if (flag_syntax_only)
@@ -2553,19 +2351,14 @@ expand_body (fn)
   /* If possible, avoid generating RTL for this function.  Instead,
      just record it as an inline function, and wait until end-of-file
      to decide whether to write it out or not.  */
-  if (/* We have to generate RTL if we can't inline trees.  */
-      flag_inline_trees
-      /* Or if it's not an inline function.  */
-      && DECL_INLINE (fn)
+  if (/* We have to generate RTL if it's not an inline function.  */
+      (DECL_INLINE (fn) || DECL_COMDAT (fn))
       /* Or if we have to keep all inline functions anyhow.  */
       && !flag_keep_inline_functions
       /* Or if we actually have a reference to the function.  */
       && !DECL_NEEDED_P (fn)
-      /* Or if we're at the end-of-file, and this function is not
-        DECL_COMDAT.  */
-      && (!at_eof || DECL_COMDAT (fn))
       /* Or if this is a nested function.  */
-      && !hack_decl_function_context (fn))
+      && !decl_function_context (fn))
     {
       /* Give the function RTL now so that we can assign it to a
         function pointer, etc.  */
@@ -2579,13 +2372,23 @@ expand_body (fn)
        }
       /* Remember this function.  In finish_file we'll decide if
         we actually need to write this function out.  */
-      mark_inline_for_output (fn);
+      defer_fn (fn);
+      /* Let the back-end know that this funtion exists.  */
+      note_deferral_of_defined_inline_function (fn);
       return;
     }
 
+  /* Emit any thunks that should be emitted at the same time as FN.  */
+  emit_associated_thunks (fn);
+
+  timevar_push (TV_INTEGRATION);
+
   /* Optimize the body of the function before expanding it.  */
   optimize_function (fn);
 
+  timevar_pop (TV_INTEGRATION);
+  timevar_push (TV_EXPAND);
+
   /* Save the current file name and line number.  When we expand the
      body of the function, we'll set LINENO and INPUT_FILENAME so that
      error-mesages come out in the right places.  */
@@ -2594,27 +2397,27 @@ expand_body (fn)
   lineno = DECL_SOURCE_LINE (fn);
   input_filename = DECL_SOURCE_FILE (fn);
 
-  start_function (NULL_TREE, fn, NULL_TREE, SF_PRE_PARSED | SF_EXPAND);
-  store_parm_decls ();
+  genrtl_start_function (fn);
+  current_function_is_thunk = DECL_THUNK_P (fn);
 
   /* We don't need to redeclare __FUNCTION__, __PRETTY_FUNCTION__, or
      any of the other magic variables we set up when starting a
      function body.  */
-  current_function_name_declared = 1;
+  function_name_declared_p = 1;
 
   /* Expand the body.  */
   expand_stmt (DECL_SAVED_TREE (fn));
 
   /* Statements should always be full-expressions at the outermost set
      of curly braces for a function.  */
-  my_friendly_assert (stmts_are_full_exprs_p, 19990831);
+  my_friendly_assert (stmts_are_full_exprs_p (), 19990831);
 
   /* The outermost statement for a function contains the line number
      recorded when we finished processing the function.  */
   lineno = STMT_LINENO (DECL_SAVED_TREE (fn));
 
   /* Generate code for the function.  */
-  finish_function (lineno, 0);
+  genrtl_finish_function (fn);
 
   /* If possible, obliterate the body of the function so that it can
      be garbage collected.  */
@@ -2632,4 +2435,261 @@ expand_body (fn)
   /* And restore the current source position.  */
   lineno = saved_lineno;
   input_filename = saved_input_filename;
+  extract_interface_info ();
+
+  timevar_pop (TV_EXPAND);
+}
+
+/* Start generating the RTL for FN.  */
+
+static void
+genrtl_start_function (fn)
+     tree fn;
+{
+  tree parm;
+
+  /* Tell everybody what function we're processing.  */
+  current_function_decl = fn;
+  /* Get the RTL machinery going for this function.  */
+  init_function_start (fn, DECL_SOURCE_FILE (fn), DECL_SOURCE_LINE (fn));
+  /* Let everybody know that we're expanding this function, not doing
+     semantic analysis.  */
+  expanding_p = 1;
+
+  /* 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;
+  cfun->x_dont_save_pending_sizes_p = 1;
+
+  /* Let the user know we're compiling this function.  */
+  announce_function (fn);
+
+  /* Initialize the per-function data.  */
+  my_friendly_assert (!DECL_PENDING_INLINE_P (fn), 20000911);
+  if (DECL_SAVED_FUNCTION_DATA (fn))
+    {
+      /* If we already parsed this function, and we're just expanding it
+        now, restore saved state.  */
+      *cp_function_chain = *DECL_SAVED_FUNCTION_DATA (fn);
+
+      /* This function is being processed in whole-function mode; we
+        already did semantic analysis.  */
+      cfun->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 (fn));
+      DECL_SAVED_FUNCTION_DATA (fn) = NULL;
+    }
+
+  /* Tell the cross-reference machinery that we're defining this
+     function.  */
+  GNU_xref_function (fn, DECL_ARGUMENTS (fn));
+
+  /* Keep track of how many functions we're presently expanding.  */
+  ++function_depth;
+
+  /* Create a binding level for the parameters.  */
+  expand_start_bindings (2);
+  /* Clear out any previously saved instructions for this function, in
+     case it was defined more than once.  */
+  DECL_SAVED_INSNS (fn) = NULL;
+  /* Go through the PARM_DECLs for this function to see if any need
+     cleanups.  */
+  for (parm = DECL_ARGUMENTS (fn); parm; parm = TREE_CHAIN (parm))
+    if (TREE_TYPE (parm) != error_mark_node
+       && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (parm)))
+      {
+       expand_function_start (fn, /*parms_have_cleanups=*/1);
+       break;
+      }
+  if (!parm)
+    expand_function_start (fn, /*parms_have_cleanups=*/0);
+  /* If this function is `main'.  */
+  if (DECL_MAIN_P (fn))
+    expand_main_function ();
+  /* Create a binding contour which can be used to catch
+     cleanup-generated temporaries.  */
+  expand_start_bindings (2);
+}
+
+/* Finish generating the RTL for FN.  */
+
+static void
+genrtl_finish_function (fn)
+     tree fn;
+{
+  tree no_return_label = NULL_TREE;
+
+#if 0
+  if (write_symbols != NO_DEBUG)
+    {
+      /* Keep this code around in case we later want to control debug info
+        based on whether a type is "used".  (jason 1999-11-11) */
+
+      tree ttype = target_type (fntype);
+      tree parmdecl;
+
+      if (IS_AGGR_TYPE (ttype))
+       /* Let debugger know it should output info for this type.  */
+       note_debug_info_needed (ttype);
+
+      for (parmdecl = DECL_ARGUMENTS (fndecl); parmdecl; parmdecl = TREE_CHAIN (parmdecl))
+       {
+         ttype = target_type (TREE_TYPE (parmdecl));
+         if (IS_AGGR_TYPE (ttype))
+           /* Let debugger know it should output info for this type.  */
+           note_debug_info_needed (ttype);
+       }
+    }
+#endif
+
+  /* Clean house because we will need to reorder insns here.  */
+  do_pending_stack_adjust ();
+
+  if (!dtor_label && !DECL_CONSTRUCTOR_P (fn)
+      && return_label != NULL_RTX
+      && current_function_return_value == NULL_TREE
+      && ! DECL_NAME (DECL_RESULT (current_function_decl)))
+    no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+
+  if (flag_exceptions)
+    expand_exception_blocks ();
+
+  /* If this function is supposed to return a value, ensure that
+     we do not fall into the cleanups by mistake.  The end of our
+     function will look like this:
+
+     user code (may have return stmt somewhere)
+     goto no_return_label
+     cleanup_label:
+     cleanups
+     goto return_label
+     no_return_label:
+     NOTE_INSN_FUNCTION_END
+     return_label:
+     things for return
+
+     If the user omits a return stmt in the USER CODE section, we
+     will have a control path which reaches NOTE_INSN_FUNCTION_END.
+     Otherwise, we won't.  */
+  if (no_return_label)
+    {
+      DECL_CONTEXT (no_return_label) = fn;
+      DECL_INITIAL (no_return_label) = error_mark_node;
+      DECL_SOURCE_FILE (no_return_label) = input_filename;
+      DECL_SOURCE_LINE (no_return_label) = lineno;
+      expand_goto (no_return_label);
+    }
+
+  if (cleanup_label)
+    {
+      /* Remove the binding contour which is used to catch
+        cleanup-generated temporaries.  */
+      expand_end_bindings (0, 0, 0);
+      poplevel (0, 0, 0);
+
+      /* Emit label at beginning of cleanup code for parameters.  */
+      emit_label (cleanup_label);
+    }
+
+  /* Finish building code that will trigger warnings if users forget
+     to make their functions return values.  */
+  emit_jump (return_label);
+  if (no_return_label)
+    {
+      /* We don't need to call `expand_*_return' here because we don't
+        need any cleanups here--this path of code is only for error
+        checking purposes.  */
+      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);
+
+  /* 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.  */
+  rest_of_compilation (fn);
+
+  /* Undo the call to ggc_push_context above.  */
+  if (function_depth > 1)
+    ggc_pop_context ();
+
+  if (DECL_SAVED_INSNS (fn) && ! TREE_ASM_WRITTEN (fn))
+    {
+      /* Set DECL_EXTERNAL so that assemble_external will be called as
+        necessary.  We'll clear it again in finish_file.  */
+      if (! DECL_EXTERNAL (fn))
+       DECL_NOT_REALLY_EXTERN (fn) = 1;
+      DECL_EXTERNAL (fn) = 1;
+      defer_fn (fn);
+    }
+
+#if 0
+  /* Keep this code around in case we later want to control debug info
+     based on whether a type is "used".  (jason 1999-11-11) */
+
+  if (ctype && TREE_ASM_WRITTEN (fn))
+    note_debug_info_needed (ctype);
+#endif
+
+  /* If this function is marked with the constructor attribute, add it
+     to the list of functions to be called along with constructors
+     from static duration objects.  */
+  if (DECL_STATIC_CONSTRUCTOR (fn))
+    static_ctors = tree_cons (NULL_TREE, fn, static_ctors);
+
+  /* If this function is marked with the destructor attribute, add it
+     to the list of functions to be called along with destructors from
+     static duration objects.  */
+  if (DECL_STATIC_DESTRUCTOR (fn))
+    static_dtors = tree_cons (NULL_TREE, fn, static_dtors);
+
+  --function_depth;
+
+  if (!DECL_SAVED_INSNS (fn)
+      && !(flag_inline_trees && DECL_INLINE (fn)))
+    {
+      tree t;
+
+      /* Stop pointing to the local nodes about to be freed.  */
+      /* But DECL_INITIAL must remain nonzero so we know this
+        was an actual function definition.  */
+      DECL_INITIAL (fn) = error_mark_node;
+      for (t = DECL_ARGUMENTS (fn); t; t = TREE_CHAIN (t))
+       DECL_RTL (t) = DECL_INCOMING_RTL (t) = NULL_RTX;
+    }
+
+  /* Let the error reporting routines know that we're outside a
+     function.  For a nested function, this value is used in
+     pop_cp_function_context and then reset via pop_function_context.  */
+  current_function_decl = NULL_TREE;
+}
+
+/* Perform initialization related to this module.  */
+
+void
+init_cp_semantics ()
+{
+  lang_expand_stmt = cp_expand_stmt;
 }