c-common.h (flag_dump_translation_unit): Remove.
[gcc.git] / gcc / cp / semantics.c
index 7c46d1da5f658f03e9c99fc5a35f6f128f6a0271..b30c80e8c3d687a92b60ab16b7b42213f6c0c73a 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, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2000, 2001 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,7 @@
 #include "flags.h"
 #include "ggc.h"
 #include "rtl.h"
+#include "expr.h"
 #include "output.h"
 #include "timevar.h"
 
 
 static tree maybe_convert_cond PARAMS ((tree));
 static tree simplify_aggr_init_exprs_r PARAMS ((tree *, int *, void *));
-static tree prune_unused_decls PARAMS ((tree *, int *, void *));
 static void deferred_type_access_control PARAMS ((void));
 static void emit_associated_thunks PARAMS ((tree));
-
-/* Record the fact that STMT was the last statement added to the
-   statement tree.  */
-
-#define SET_LAST_STMT(stmt) \
-  (current_stmt_tree->x_last_stmt = (stmt))
-
-/* When parsing a template, LAST_TREE contains the last statement
-   parsed.  These are chained together through the TREE_CHAIN field,
-   but often need to be re-organized since the parse is performed
-   bottom-up.  This macro makes LAST_TREE the indicated SUBSTMT of
-   STMT.  */
-
-#define RECHAIN_STMTS(stmt, substmt)   \
-  do {                                 \
-    substmt = TREE_CHAIN (stmt);       \
-    TREE_CHAIN (stmt) = NULL_TREE;     \
-    SET_LAST_STMT (stmt);              \
-  } while (0)
+static void genrtl_try_block PARAMS ((tree));
+static void genrtl_eh_spec_block PARAMS ((tree));
+static void genrtl_handler 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));
+static tree clear_decl_rtl PARAMS ((tree *, int *, void *));
 
 /* Finish processing the COND, the SUBSTMT condition for STMT.  */
 
@@ -88,19 +79,6 @@ static void emit_associated_thunks PARAMS ((tree));
       substmt = cond;                                  \
   } while (0)
 
-/* Wrapper since C and C++ expand_expr_stmt are different. */
-
-expand_expr_stmt_fn lang_expand_expr_stmt = cplus_expand_expr_stmt;
-
-/* Wrapper function instead of #define for use with c-common code. */
-
-void
-set_current_function_name_declared (i)
-     int i;
-{
-  cp_function_chain->name_declared = i;
-}
-
 /* 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.  */
@@ -108,17 +86,19 @@ set_current_function_name_declared (i)
 int
 stmts_are_full_exprs_p ()
 {
-  return current_stmt_tree->stmts_are_full_exprs_p;
+  return current_stmt_tree ()->stmts_are_full_exprs_p;
 }
 
-/* One if we have already declared __FUNCTION__ (and related
-   variables) in the current function.  Two if we are in the process
-   of doing so.  */
+/* Returns the stmt_tree (if any) to which statements are currently
+   being added.  If there is no active statement-tree, NULL is
+   returned.  */
 
-int
-current_function_name_declared ()
+stmt_tree
+current_stmt_tree ()
 {
-  return cp_function_chain->name_declared;
+  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
@@ -170,23 +150,9 @@ do_pushlevel ()
     }
 }
 
-/* T is a statement.  Add it to the statement-tree.  */
-
-void
-add_tree (t)
-     tree t;
-{
-  /* Add T to the statement-tree.  */
-  TREE_CHAIN (last_tree) = t;
-  SET_LAST_STMT (t);
-  /* When we expand a statement-tree, we must know whether or not the
-     statements are full-expresions.  We record that fact here.  */
-  STMT_IS_FULL_EXPR_P (last_tree) = stmts_are_full_exprs_p ();
-}
-
 /* Finish a goto-statement.  */
 
-void
+tree
 finish_goto_stmt (destination)
      tree destination;
 {
@@ -207,7 +173,7 @@ finish_goto_stmt (destination)
   
   check_goto (destination);
 
-  add_tree (build_stmt (GOTO_STMT, destination));
+  return add_stmt (build_stmt (GOTO_STMT, destination));
 }
 
 /* COND is the condition-expression for an if, while, etc.,
@@ -232,10 +198,12 @@ maybe_convert_cond (cond)
 
 /* Finish an expression-statement, whose EXPRESSION is as indicated.  */
 
-void 
+tree
 finish_expr_stmt (expr)
      tree expr;
 {
+  tree r = NULL_TREE;
+
   if (expr != NULL_TREE)
     {
       if (!processing_template_decl
@@ -248,10 +216,7 @@ finish_expr_stmt (expr)
       if (stmts_are_full_exprs_p ())
        expr = convert_to_void (expr, "statement");
       
-      if (!processing_template_decl)
-       expr = break_out_cleanups (expr);
-      
-      add_tree (build_stmt (EXPR_STMT, expr));
+      r = add_stmt (build_stmt (EXPR_STMT, expr));
     }
 
   finish_stmt ();
@@ -259,6 +224,8 @@ finish_expr_stmt (expr)
   /* This was an expression-statement, so we save the type of the
      expression.  */
   last_expr_type = expr ? TREE_TYPE (expr) : NULL_TREE;
+
+  return r;
 }
 
 
@@ -271,7 +238,7 @@ begin_if_stmt ()
   tree r;
   do_pushlevel ();
   r = build_stmt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
-  add_tree (r);
+  add_stmt (r);
   return r;
 }
 
@@ -295,7 +262,7 @@ finish_then_clause (if_stmt)
      tree if_stmt;
 {
   RECHAIN_STMTS (if_stmt, THEN_CLAUSE (if_stmt));
-  SET_LAST_STMT (if_stmt);
+  last_tree = if_stmt;
   return if_stmt;
 }
 
@@ -316,7 +283,7 @@ finish_else_clause (if_stmt)
   RECHAIN_STMTS (if_stmt, ELSE_CLAUSE (if_stmt));
 }
 
-/* Finsh an if-statement.  */
+/* Finish an if-statement.  */
 
 void 
 finish_if_stmt ()
@@ -346,7 +313,7 @@ begin_while_stmt ()
 {
   tree r;
   r = build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE);
-  add_tree (r);
+  add_stmt (r);
   do_pushlevel ();
   return r;
 }
@@ -382,7 +349,7 @@ tree
 begin_do_stmt ()
 {
   tree r = build_stmt (DO_STMT, NULL_TREE, NULL_TREE);
-  add_tree (r);
+  add_stmt (r);
   return r;
 }
 
@@ -411,10 +378,12 @@ finish_do_stmt (cond, do_stmt)
 /* Finish a return-statement.  The EXPRESSION returned, if any, is as
    indicated.  */
 
-void
+tree
 finish_return_stmt (expr)
      tree expr;
 {
+  tree r;
+
   if (!processing_template_decl)
     expr = check_return_expr (expr);
   if (!processing_template_decl)
@@ -427,21 +396,21 @@ finish_return_stmt (expr)
             return a value there.  When we finally generate the real
             return statement, CTOR_LABEL is no longer set, and we fall
             through into the normal return-processing code below.  */
-         finish_goto_stmt (ctor_label);
-         return;
+         return finish_goto_stmt (ctor_label);
        }
       else if (DECL_DESTRUCTOR_P (current_function_decl))
        {
          /* Similarly, all destructors must run destructors for
             base-classes before returning.  So, all returns in a
-            destructor get sent to the DTOR_LABEL; finsh_function emits
+            destructor get sent to the DTOR_LABEL; finish_function emits
             code to return a value there.  */
-         finish_goto_stmt (dtor_label);
-         return;
+         return finish_goto_stmt (dtor_label);
        }
     }
-  add_tree (build_stmt (RETURN_STMT, expr));
+  r = add_stmt (build_stmt (RETURN_STMT, expr));
   finish_stmt ();
+
+  return r;
 }
 
 /* Begin a for-statement.  Returns a new FOR_STMT if appropriate.  */
@@ -454,7 +423,7 @@ begin_for_stmt ()
   r = build_stmt (FOR_STMT, NULL_TREE, NULL_TREE, 
                  NULL_TREE, NULL_TREE);
   NEW_FOR_SCOPE_P (r) = flag_new_for_scope > 0;
-  add_tree (r);
+  add_stmt (r);
   if (NEW_FOR_SCOPE_P (r))
     {
       do_pushlevel ();
@@ -518,18 +487,18 @@ finish_for_stmt (for_stmt)
 
 /* Finish a break-statement.  */
 
-void
+tree
 finish_break_stmt ()
 {
-  add_tree (build_stmt (BREAK_STMT));
+  return add_stmt (build_break_stmt ());
 }
 
 /* Finish a continue-statement.  */
 
-void
+tree
 finish_continue_stmt ()
 {
-  add_tree (build_stmt (CONTINUE_STMT));
+  return add_stmt (build_continue_stmt ());
 }
 
 /* Begin a switch-statement.  Returns a new SWITCH_STMT if
@@ -540,7 +509,7 @@ begin_switch_stmt ()
 {
   tree r;
   r = build_stmt (SWITCH_STMT, NULL_TREE, NULL_TREE);
-  add_tree (r);
+  add_stmt (r);
   do_pushlevel ();
   return r;
 }
@@ -554,6 +523,9 @@ finish_switch_cond (cond, switch_stmt)
 {
   if (!processing_template_decl)
     {
+      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)
@@ -566,9 +538,19 @@ finish_switch_cond (cond, switch_stmt)
          cond = default_conversion (cond);
          cond = fold (build1 (CLEANUP_POINT_EXPR, TREE_TYPE (cond), cond));
        }
+
+      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 ();
+  push_switch (switch_stmt);
 }
 
 /* Finish the body of a switch-statement, which may be given by
@@ -584,44 +566,24 @@ finish_switch_stmt (switch_stmt)
   finish_stmt ();
 }
 
-/* Finish a case-label.  */
-
-void 
-finish_case_label (low_value, high_value)
-     tree low_value;
-     tree high_value;
-{
-  /* Add a representation for the case label to the statement
-     tree.  */
-  add_tree (build_stmt (CASE_LABEL, low_value, high_value));
-  /* And warn about crossing initializations, etc.  */
-  if (!processing_template_decl)
-    define_case_label ();
-}
-
 /* Generate the RTL for T, which is a TRY_BLOCK. */
 
-void genrtl_try_block (t)
+static void 
+genrtl_try_block (t)
      tree t;
 {
   if (CLEANUP_P (t))
     {
       expand_eh_region_start ();
       expand_stmt (TRY_STMTS (t));
-      expand_eh_region_end (protect_with_terminate (TRY_HANDLERS (t)));
+      expand_eh_region_end_cleanup (TRY_HANDLERS (t));
     }
   else
     {
-      if (FN_TRY_BLOCK_P (t)) {
-       if (! current_function_parms_stored)
-         store_parm_decls ();
-       expand_start_early_try_stmts ();
-      }
-      else {
+      if (!FN_TRY_BLOCK_P (t)) 
        emit_line_note (input_filename, lineno);
-       expand_start_try_stmts ();
-      }
 
+      expand_eh_region_start ();
       expand_stmt (TRY_STMTS (t));
 
       if (FN_TRY_BLOCK_P (t))
@@ -642,6 +604,21 @@ void genrtl_try_block (t)
     }
 }
 
+/* Generate the RTL for T, which is an EH_SPEC_BLOCK. */
+
+static void 
+genrtl_eh_spec_block (t)
+     tree t;
+{
+  expand_eh_region_start ();
+  expand_stmt (EH_SPEC_STMTS (t));
+  expand_eh_region_end_allowed (EH_SPEC_RAISES (t),
+                               build_call (call_unexpected_node,
+                                           tree_cons (NULL_TREE,
+                                                      build_exc_ptr (),
+                                                      NULL_TREE)));
+}
+
 /* Begin a try-block.  Returns a newly-created TRY_BLOCK if
    appropriate.  */
 
@@ -649,7 +626,7 @@ tree
 begin_try_block ()
 {
   tree r = build_stmt (TRY_BLOCK, NULL_TREE, NULL_TREE);
-  add_tree (r);
+  add_stmt (r);
   return r;
 }
 
@@ -660,7 +637,7 @@ begin_function_try_block ()
 {
   tree r = build_stmt (TRY_BLOCK, NULL_TREE, NULL_TREE);
   FN_TRY_BLOCK_P (r) = 1;
-  add_tree (r);
+  add_stmt (r);
   return r;
 }
 
@@ -738,20 +715,16 @@ finish_function_handler_sequence (try_block)
 
 /* Generate the RTL for T, which is a HANDLER. */
 
-void
+static void
 genrtl_handler (t)
      tree t;
 {
   genrtl_do_pushlevel ();
+  if (!processing_template_decl)
+    expand_start_catch (HANDLER_TYPE (t));
   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 ();
-    }
+    expand_end_catch ();
 }
 
 /* Begin a handler.  Returns a HANDLER if appropriate.  */
@@ -761,8 +734,11 @@ begin_handler ()
 {
   tree r;
   r = build_stmt (HANDLER, NULL_TREE, NULL_TREE);
-  add_tree (r);
+  add_stmt (r);
+  /* Create a binding level for the eh_info and the exception object
+     cleanup.  */
   do_pushlevel ();
+  note_level_for_catch ();
   return r;
 }
 
@@ -770,13 +746,12 @@ begin_handler ()
    HANDLER.  DECL is the declaration for the catch parameter, or NULL
    if this is a `catch (...)' clause.  */
 
-tree
+void
 finish_handler_parms (decl, handler)
      tree decl;
      tree handler;
 {
-  tree blocks = NULL_TREE;
-
+  tree type = NULL_TREE;
   if (processing_template_decl)
     {
       if (decl)
@@ -785,54 +760,31 @@ finish_handler_parms (decl, handler)
          decl = push_template_decl (decl);
          add_decl_stmt (decl);
          RECHAIN_STMTS (handler, HANDLER_PARMS (handler));
+         type = TREE_TYPE (decl);
        }
     }
   else
-    blocks = expand_start_catch_block (decl);
+    type = expand_start_catch_block (decl);
 
-  if (decl)
-    TREE_TYPE (handler) = TREE_TYPE (decl);
-
-  return blocks;
-}
-
-/* Generate the RTL for a CATCH_BLOCK. */
-
-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.  */
-
-void
-begin_catch_block (type)
-     tree type;
-{
-  add_tree (build (START_CATCH_STMT, type));
+  HANDLER_TYPE (handler) = type;
 }
 
 /* Finish a handler, which may be given by HANDLER.  The BLOCKs are
    the return value from the matching call to finish_handler_parms.  */
 
 void
-finish_handler (blocks, handler)
-     tree blocks;
+finish_handler (handler)
      tree handler;
 {
   if (!processing_template_decl)
-      expand_end_catch_block (blocks);
+    expand_end_catch_block ();
   do_poplevel ();
   RECHAIN_STMTS (handler, HANDLER_BODY (handler));
 }
 
 /* Generate the RTL for T, which is a CTOR_STMT. */
 
-void
+static void
 genrtl_ctor_stmt (t)
      tree t;
 {
@@ -861,7 +813,7 @@ begin_compound_stmt (has_no_scope)
   if (last_tree && TREE_CODE (last_tree) == TRY_BLOCK)
     is_try = 1;
 
-  add_tree (r);
+  add_stmt (r);
   if (has_no_scope)
     COMPOUND_STMT_NO_SCOPE (r) = 1;
 
@@ -871,7 +823,7 @@ begin_compound_stmt (has_no_scope)
     {
       do_pushlevel ();
       if (is_try)
-       note_level_for_eh ();
+       note_level_for_try ();
     }
   else
     /* Normally, we try hard to keep the BLOCK for a
@@ -880,16 +832,6 @@ begin_compound_stmt (has_no_scope)
        to accidentally keep a block *inside* the scopeless block.  */ 
     keep_next_level (0);
 
-  /* If this is the outermost block of the function, declare the
-     variables __FUNCTION__, __PRETTY_FUNCTION__, and so forth.  */
-  if (cfun
-      && !(current_function_name_declared () )
-      && !has_no_scope)
-    {
-      cp_function_chain->name_declared = 1;
-      declare_function_name ();
-    }
-
   return r;
 }
 
@@ -927,7 +869,7 @@ finish_compound_stmt (has_no_scope, compound_stmt)
    STRING, some OUTPUT_OPERANDS, some INPUT_OPERANDS, and some
    CLOBBERS.  */
 
-void
+tree
 finish_asm_stmt (cv_qualifier, string, output_operands,
                 input_operands, clobbers)
      tree cv_qualifier;
@@ -952,12 +894,27 @@ finish_asm_stmt (cv_qualifier, string, output_operands,
 
   if (!processing_template_decl)
     for (t = input_operands; t; t = TREE_CHAIN (t))
-      TREE_VALUE (t) = decay_conversion (TREE_VALUE (t));
+      {
+       tree converted_operand 
+         = decay_conversion (TREE_VALUE (t)); 
+
+       /* If the type of the operand hasn't been determined (e.g.,
+          because it involves an overloaded function), then issue an
+          error message.  There's no context available to resolve the
+          overloading.  */
+       if (TREE_TYPE (converted_operand) == unknown_type_node)
+         {
+           cp_error ("type of asm operand `%E' could not be determined", 
+                     TREE_VALUE (t));
+           converted_operand = error_mark_node;
+         }
+       TREE_VALUE (t) = converted_operand;
+      }
 
   r = build_stmt (ASM_STMT, cv_qualifier, string,
                  output_operands, input_operands,
                  clobbers);
-  add_tree (r);
+  return add_stmt (r);
 }
 
 /* Finish a label with the indicated NAME.  */
@@ -967,7 +924,7 @@ finish_label_stmt (name)
      tree name;
 {
   tree decl = define_label (input_filename, lineno, name);
-  add_tree (build_stmt (LABEL_STMT, decl));
+  add_stmt (build_stmt (LABEL_STMT, decl));
 }
 
 /* Finish a series of declarations for local labels.  G++ allows users
@@ -982,23 +939,9 @@ finish_label_decl (name)
   add_decl_stmt (decl);
 }
 
-/* Create a declaration statement for the declaration given by the
-   DECL.  */
-
-void
-add_decl_stmt (decl)
-     tree decl;
-{
-  tree decl_stmt;
-
-  /* We need the type to last until instantiation time.  */
-  decl_stmt = build_stmt (DECL_STMT, decl);
-  add_tree (decl_stmt); 
-}
-
 /* Generate the RTL for a SUBOBJECT. */
 
-void 
+static void 
 genrtl_subobject (cleanup)
      tree cleanup;
 {
@@ -1014,7 +957,7 @@ finish_subobject (cleanup)
      tree cleanup;
 {
   tree r = build_stmt (SUBOBJECT, cleanup);
-  add_tree (r);
+  add_stmt (r);
 }
 
 /* When DECL goes out of scope, make sure that CLEANUP is executed.  */
@@ -1024,61 +967,33 @@ finish_decl_cleanup (decl, cleanup)
      tree decl;
      tree cleanup;
 {
-  add_tree (build_stmt (CLEANUP_STMT, decl, cleanup));
+  add_stmt (build_stmt (CLEANUP_STMT, decl, cleanup));
 }
 
 /* Generate the RTL for a RETURN_INIT. */
 
-void
-genrtl_named_return_value (return_id, init)
-     tree return_id, init;
+static void
+genrtl_named_return_value ()
 {
-  tree decl;
-  /* Clear this out so that finish_named_return_value can set it
-     again.  */
-  DECL_NAME (DECL_RESULT (current_function_decl)) = NULL_TREE;
-
-  decl = DECL_RESULT (current_function_decl);
-  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 ("ISO C++ does not permit named return values");
-
-  if (return_id != NULL_TREE)
-    {
-      if (DECL_NAME (decl) == NULL_TREE)
-       {
-         DECL_NAME (decl) = return_id;
-         DECL_ASSEMBLER_NAME (decl) = return_id;
-       }
-      else
-       {
-         cp_error ("return identifier `%D' already in place", return_id);
-         return;
-       }
-    }
-
-  /* Can't let this happen for constructors.  */
-  if (DECL_CONSTRUCTOR_P (current_function_decl))
-    {
-      error ("can't redefine default return value for constructors");
-      return;
-    }
+  tree decl = DECL_RESULT (current_function_decl);
 
-  /* If we have a named return value, put that in our scope as well.  */
-  if (DECL_NAME (decl) != NULL_TREE)
+  /* If this named return value comes in a register, put it in a
+     pseudo-register.  */
+  if (DECL_REGISTER (decl))
     {
-      /* Let `cp_finish_decl' know that this initializer is ok.  */
-      DECL_INITIAL (decl) = init;
-      cp_finish_decl (decl, init, NULL_TREE, 0);
-      store_return_init (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.  */
+      SET_DECL_RTL (decl, gen_reg_rtx (GET_MODE (DECL_RTL (decl))));
+      if (TREE_ADDRESSABLE (decl))
+       put_var_into_stack (decl);
     }
 
-  /* 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;
+  emit_local_var (decl);
 }
 
 /* Bind a name and initialization to the return value of
@@ -1090,19 +1005,17 @@ 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 ("ISO C++ does not permit named return values");
+  cp_deprecated ("the named return value extension");
 
   if (return_id != NULL_TREE)
     {
       if (DECL_NAME (decl) == NULL_TREE)
-       {
-         DECL_NAME (decl) = return_id;
-         DECL_ASSEMBLER_NAME (decl) = return_id;
-       }
+       DECL_NAME (decl) = return_id;
       else
        {
          cp_error ("return identifier `%D' already in place", return_id);
@@ -1124,7 +1037,13 @@ finish_named_return_value (return_id, init)
       DECL_INITIAL (decl) = init;
       if (doing_semantic_analysis_p ())
        pushdecl (decl);
-      add_tree (build_stmt (RETURN_INIT, return_id, init));
+      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.
@@ -1210,7 +1129,7 @@ setup_vtbl_ptr (member_init_list, base_init_list)
   if (DECL_CONSTRUCTOR_P (current_function_decl))
     {
       if (processing_template_decl)
-       add_tree (build_min_nt
+       add_stmt (build_min_nt
                  (CTOR_INITIALIZER,
                   member_init_list, base_init_list));
       else
@@ -1220,7 +1139,7 @@ setup_vtbl_ptr (member_init_list, base_init_list)
          /* Mark the beginning of the constructor.  */
          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.  */
          emit_base_init (member_init_list, base_init_list);
@@ -1231,7 +1150,6 @@ setup_vtbl_ptr (member_init_list, base_init_list)
     {
       tree if_stmt;
       tree compound_stmt;
-      int saved_cfnd;
 
       /* If the dtor is empty, and we know there is not any possible
         way we could use any vtable entries, before they are possibly
@@ -1252,12 +1170,7 @@ setup_vtbl_ptr (member_init_list, base_init_list)
       finish_if_stmt_cond (boolean_true_node, if_stmt);
       current_vcalls_possible_p = &IF_COND (if_stmt);
 
-      /* Don't declare __PRETTY_FUNCTION__ and friends here when we
-        open the block for the if-body.  */
-      saved_cfnd = current_function_name_declared ();
-      cp_function_chain->name_declared = 1;
       compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
-      cp_function_chain->name_declared = saved_cfnd;
 
       /* Make all virtual function table pointers in non-virtual base
         classes point to CURRENT_CLASS_TYPE's virtual function
@@ -1278,48 +1191,12 @@ setup_vtbl_ptr (member_init_list, base_init_list)
   vtbls_set_up_p = 1;
 }
 
+/* Returns the stack of SCOPE_STMTs for the current function.  */
 
-/* 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 *
+current_scope_stmt_stack ()
 {
-  tree ss;
-  tree top;
-
-  /* Build the statement.  */
-  ss = build_stmt (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;
+  return &cfun->language->x_scope_stmt_stack;
 }
 
 /* Finish a parenthesized expression EXPR.  */
@@ -1409,7 +1286,7 @@ finish_stmt_expr (rtl_expr)
   
   /* Remove the compound statement from the tree structure; it is
      now saved in the STMT_EXPR.  */
-  SET_LAST_STMT (rtl_expr);
+  last_tree = rtl_expr;
   TREE_CHAIN (last_tree) = NULL_TREE;
 
   /* If we created a statement-tree for this statement-expression,
@@ -1541,7 +1418,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)
@@ -1594,31 +1471,6 @@ finish_qualified_call_expr (fn, args)
                              args);
 }
 
-/* Finish an expression taking the address of LABEL.  Returns an
-   expression for the address.  */
-
-tree 
-finish_label_address_expr (label)
-     tree label;
-{
-  tree result;
-
-  label = lookup_label (label);
-  if (label == NULL_TREE)
-    result = null_pointer_node;
-  else
-    {
-      TREE_USED (label) = 1;
-      result = build1 (ADDR_EXPR, ptr_type_node, label);
-      TREE_CONSTANT (result) = 1;
-      /* This function cannot be inlined.  All jumps to the addressed
-        label should wind up at the same point.  */
-      DECL_UNINLINABLE (current_function_decl) = 1;
-    }
-
-  return result;
-}
-
 /* Finish an expression of the form CODE EXPR.  */
 
 tree
@@ -1648,6 +1500,8 @@ finish_id_expr (expr)
   if (TREE_CODE (expr) == IDENTIFIER_NODE)
     expr = do_identifier (expr, 1, NULL_TREE);
 
+  if (TREE_TYPE (expr) == error_mark_node)
+    expr = error_mark_node;
   return expr;
 }
 
@@ -1690,13 +1544,41 @@ decl_type_access_control (decl)
      added to type_lookups after typed_declspecs saved the copy that
      ended up in current_type_lookups.  */
   type_lookups = current_type_lookups;
+  
+  current_type_lookups = NULL_TREE;
 }
 
+/* Record the lookups, if we're doing deferred access control.  */
+
 void
 save_type_access_control (lookups)
      tree lookups;
 {
-  current_type_lookups = lookups;
+  if (type_lookups != error_mark_node)
+    {
+      my_friendly_assert (!current_type_lookups, 20010301);
+      current_type_lookups = lookups;
+    }
+  else
+    my_friendly_assert (!lookups || lookups == error_mark_node, 20010301);
+}
+
+/* Set things up so that the next deferred access control will succeed.
+   This is needed for friend declarations see grokdeclarator for details.  */
+
+void
+skip_type_access_control ()
+{
+  type_lookups = NULL_TREE;
+}
+
+/* Reset the deferred access control.  */
+
+void
+reset_type_access_control ()
+{
+  type_lookups = NULL_TREE;
+  current_type_lookups = NULL_TREE;
 }
 
 /* Begin a function definition declared with DECL_SPECS and
@@ -1733,7 +1615,7 @@ begin_constructor_declarator (scope, name)
      tree scope;
      tree name;
 {
-  tree result = build_parse_node (SCOPE_REF, scope, name);
+  tree result = build_nt (SCOPE_REF, scope, name);
   enter_scope_of (result);
   return result;
 }
@@ -1763,6 +1645,10 @@ finish_translation_unit ()
   pop_everything ();
   while (current_namespace != global_namespace)
     pop_namespace ();
+
+  /* Do file scope __FUNCTION__ et al. */
+  finish_fname_decls ();
+  
   finish_file ();
 }
 
@@ -1798,6 +1684,8 @@ finish_template_template_parm (aggr, identifier)
   DECL_ARTIFICIAL (decl) = 1;
   end_template_decl ();
 
+  my_friendly_assert (DECL_TEMPLATE_PARMS (tmpl), 20010110);
+
   return finish_template_type_parm (aggr, tmpl);
 }
 
@@ -1809,13 +1697,15 @@ finish_parmlist (parms, ellipsis)
      tree parms;
      int ellipsis;
 {
-  if (!ellipsis)
-    chainon (parms, void_list_node);
-  /* We mark the PARMS as a parmlist so that declarator processing can
-     disambiguate certain constructs.  */
-  if (parms != NULL_TREE)
-    TREE_PARMLIST (parms) = 1;
-
+  if (parms)
+    {
+      /* We mark the PARMS as a parmlist so that declarator processing can
+         disambiguate certain constructs.  */
+      TREE_PARMLIST (parms) = 1;
+      /* We do not append void_list_node here, but leave it to grokparms
+         to do that.  */
+      PARMLIST_ELLIPSIS_P (parms) = ellipsis;
+    }
   return parms;
 }
 
@@ -1825,6 +1715,15 @@ tree
 begin_class_definition (t)
      tree t;
 {
+  /* Check the bases are accessible. */
+  decl_type_access_control (TYPE_NAME (t));
+  reset_type_access_control ();
+  
+  if (processing_template_parmlist)
+    {
+      cp_error ("definition of `%#T' inside template parameter list", t);
+      return error_mark_node;
+    }
   if (t == error_mark_node
       || ! IS_AGGR_TYPE (t))
     {
@@ -1904,22 +1803,12 @@ begin_class_definition (t)
   /* Reset the interface data, at the earliest possible
      moment, as it might have been set via a class foo;
      before.  */
-  {
-    tree name = TYPE_IDENTIFIER (t);
-    
-    if (! ANON_AGGRNAME_P (name))
-      {
-       CLASSTYPE_INTERFACE_ONLY (t) = interface_only;
-       SET_CLASSTYPE_INTERFACE_UNKNOWN_X
-         (t, interface_unknown);
-      }
-    
-    /* Only leave this bit clear if we know this
-       class is part of an interface-only specification.  */
-    if (! CLASSTYPE_INTERFACE_KNOWN (t)
-       || ! CLASSTYPE_INTERFACE_ONLY (t))
-      CLASSTYPE_VTABLE_NEEDS_WRITING (t) = 1;
-  }
+  if (! TYPE_ANONYMOUS_P (t))
+    {
+      CLASSTYPE_INTERFACE_ONLY (t) = interface_only;
+      SET_CLASSTYPE_INTERFACE_UNKNOWN_X
+       (t, interface_unknown);
+    }
   reset_specialization();
   
   /* Make a declaration for this class in its own scope.  */
@@ -1964,7 +1853,7 @@ finish_member_declaration (decl)
      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;
+    SET_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.
@@ -2047,6 +1936,8 @@ finish_class_definition (t, attributes, semi, pop_scope_p)
     check_for_missing_semicolon (t); 
   if (pop_scope_p)
     pop_scope (CP_DECL_CONTEXT (TYPE_MAIN_DECL (t)));
+  if (current_function_decl)
+    type_lookups = error_mark_node;
   if (current_scope () == current_function_decl)
     do_pending_defargs ();
 
@@ -2059,8 +1950,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 ();
 }
 
@@ -2119,7 +2009,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.  */
@@ -2133,7 +2023,8 @@ finish_template_type (name, args, entering_scope)
   tree decl;
 
   decl = lookup_template_class (name, args,
-                               NULL_TREE, NULL_TREE, entering_scope);
+                               NULL_TREE, NULL_TREE,
+                               entering_scope, /*complain=*/1);
   if (decl != error_mark_node)
     decl = TYPE_STUB_DECL (decl);
 
@@ -2179,21 +2070,19 @@ finish_base_specifier (access_specifier, base_class)
      tree access_specifier;
      tree base_class;
 {
-  tree type;
   tree result;
 
-  if (base_class == NULL_TREE)
-    {
-      error ("invalid base class");
-      type = error_mark_node;
-    }
-  else
-    type = TREE_TYPE (base_class);
-
-  if (! is_aggr_type (type, 1))
+  if (! is_aggr_type (base_class, 1))
     result = NULL_TREE;
   else
-    result = build_tree_list (access_specifier, type);
+    {
+      if (CP_TYPE_QUALS (base_class) != 0)
+        {
+          cp_error ("base class `%T' has cv qualifiers", base_class);
+          base_class = TYPE_MAIN_VARIANT (base_class);
+        }
+      result = build_tree_list (access_specifier, base_class);
+    }
 
   return result;
 }
@@ -2239,244 +2128,56 @@ finish_typeof (expr)
       return t;
     }
 
-  return TREE_TYPE (expr);
-}
-
-/* Remove declarations of internal variables that are not used from a
-   stmt tree.  To qualify, the variable must have a name and must have
-   a zero DECL_SOURCE_LINE.  We tried to remove all variables for
-   which TREE_USED was false, but it turns out that there's tons of
-   variables for which TREE_USED is false but that are still in fact
-   used.  */
-
-static tree
-prune_unused_decls (tp, walk_subtrees, data)
-     tree *tp;
-     int *walk_subtrees ATTRIBUTE_UNUSED;
-     void *data ATTRIBUTE_UNUSED;
-{
-  tree t = *tp;
-
-  if (t == NULL_TREE)
-    {
-      *walk_subtrees = 0;
-      return NULL_TREE;
-    }
-
-  if (TREE_CODE (t) == DECL_STMT)
-    {
-      tree d = DECL_STMT_DECL (t);
-      if (!TREE_USED (d) && DECL_NAME (d) && DECL_SOURCE_LINE (d) == 0)
-       {
-         *tp = TREE_CHAIN (t);
-         /* Recurse on the new value of tp, otherwise we will skip
-            the next statement.  */
-         return prune_unused_decls (tp, walk_subtrees, data);
-       }
-    }
-  else if (TREE_CODE (t) == BLOCK)
-    {
-      /* walk_tree doesn't inspect BLOCK_VARS, so we must do it by hand.  */
-      tree *vp;
-
-      for (vp = &BLOCK_VARS (t); *vp; )
-       {
-         tree v = *vp;
-         if (! TREE_USED (v) && DECL_NAME (v) && DECL_SOURCE_LINE (v) == 0)
-           *vp = TREE_CHAIN (v);  /* drop */
-         else
-           vp = &TREE_CHAIN (v);  /* advance */
-       }
-      if (BLOCK_VARS (t) == NULL_TREE)
-       TREE_USED (t) = 0;
-    }
-  return NULL_TREE;
-}
-
-/* Create an empty statement tree rooted at T.  */
-
-void
-begin_stmt_tree (t)
-     tree *t;
-{
-  /* We create a trivial EXPR_STMT so that last_tree is never NULL in
-     what follows.  We remove the extraneous statement in
-     finish_stmt_tree.  */
-  *t = build_nt (EXPR_STMT, void_zero_node);
-  SET_LAST_STMT (*t);
-  last_expr_type = NULL_TREE;
-}
-
-/* Finish the statement tree rooted at T.  */
-
-void
-finish_stmt_tree (t)
-     tree *t;
-{
-  tree stmt;
-  int old_lineno;
-  
-  /* Remove the fake extra statement added in begin_stmt_tree.  */
-  stmt = TREE_CHAIN (*t);
-  *t = stmt;
-  SET_LAST_STMT (NULL_TREE);
-
-  /* Remove unused decls from the stmt tree.  walk_tree messes with
-     the line number, so save/restore it.  */
-  old_lineno = lineno;
-  walk_tree_without_duplicates (t, prune_unused_decls, NULL);
-  lineno = old_lineno;
-
-  if (cfun)
-    {
-      /* The line-number recorded in the outermost statement in a function
-        is the line number of the end of the function.  */
-      STMT_LINENO (stmt) = lineno;
-      STMT_LINENO_FOR_FN_P (stmt) = 1;
-    }
-}
-
-/* We're about to expand T, a statement.  Set up appropriate context
-   for the substitution.  */
+  if (TREE_CODE (expr) == OFFSET_REF)
+    expr = resolve_offset_ref (expr);
 
-void
-prep_stmt (t)
-     tree t;
-{
-  if (!STMT_LINENO_FOR_FN_P (t))
-    lineno = STMT_LINENO (t);
-  current_stmt_tree->stmts_are_full_exprs_p = STMT_IS_FULL_EXPR_P (t);
+  return TREE_TYPE (expr);
 }
 
 /* Generate RTL for the statement T, and its substatements, and any
    other statements at its nesting level.  */
 
-tree
-lang_expand_stmt (t)
+static void
+cp_expand_stmt (t)
      tree t;
 {
-  tree rval = NULL_TREE;
-
-  while (t && t != error_mark_node)
+  switch (TREE_CODE (t))
     {
-      int saved_stmts_are_full_exprs_p;
+    case CLEANUP_STMT:
+      genrtl_decl_cleanup (CLEANUP_DECL (t), CLEANUP_EXPR (t));
+      break;
 
-      /* Assume we'll have nothing to return.  */
-      rval = NULL_TREE;
+    case CTOR_STMT:
+      genrtl_ctor_stmt (t);
+      break;
 
-      /* Set up context appropriately for handling this statement.  */
-      saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p ();
-      prep_stmt (t);
+    case TRY_BLOCK:
+      genrtl_try_block (t);
+      break;
 
-      switch (TREE_CODE (t))
-       {
-       case RETURN_STMT:
-         genrtl_return_stmt (RETURN_EXPR (t));
-         break;
-
-       case EXPR_STMT:
-         genrtl_expr_stmt (EXPR_STMT_EXPR (t));
-         break;
-
-       case DECL_STMT:
-         genrtl_decl_stmt (t);
-         break;
-
-       case CLEANUP_STMT:
-         genrtl_decl_cleanup (CLEANUP_DECL (t), CLEANUP_EXPR (t));
-         break;
-
-       case START_CATCH_STMT:
-         genrtl_catch_block (TREE_TYPE (t));
-         break;
-
-       case CTOR_STMT:
-         genrtl_ctor_stmt (t);
-         break;
-
-       case FOR_STMT:
-         genrtl_for_stmt (t);
-         break;
-
-       case WHILE_STMT:
-         genrtl_while_stmt (t);
-         break;
-
-       case DO_STMT:
-         genrtl_do_stmt (t);
-         break;
-
-       case IF_STMT:
-         genrtl_if_stmt (t);
-         break;
-
-       case COMPOUND_STMT:
-         genrtl_compound_stmt (t);
-         break;
-
-       case BREAK_STMT:
-         genrtl_break_stmt ();
-         break;
-
-       case CONTINUE_STMT:
-         genrtl_continue_stmt ();
-         break;
-
-       case SWITCH_STMT:
-         genrtl_switch_stmt (t);
-         break;
-
-       case CASE_LABEL:
-         genrtl_case_label (CASE_LOW (t), CASE_HIGH (t));
-         break;
-
-       case LABEL_STMT:
-         expand_label (LABEL_STMT_LABEL (t));
-         break;
-
-       case GOTO_STMT:
-         genrtl_goto_stmt (GOTO_DESTINATION (t));
-         break;
-
-       case ASM_STMT:
-         genrtl_asm_stmt (ASM_CV_QUAL (t), ASM_STRING (t),
-                          ASM_OUTPUTS (t), ASM_INPUTS (t), ASM_CLOBBERS (t));
-         break;
-
-       case TRY_BLOCK:
-         genrtl_try_block (t);
-         break;
-
-       case HANDLER:
-         genrtl_handler (t);
-         break;
-
-       case SUBOBJECT:
-         genrtl_subobject (SUBOBJECT_CLEANUP (t));
-         break;
-
-       case SCOPE_STMT:
-         genrtl_scope_stmt (t);
-         break;
-
-       case RETURN_INIT:
-         genrtl_named_return_value (TREE_OPERAND (t, 0), 
-                                    TREE_OPERAND (t, 1));
-         break;
-
-       default:
-         my_friendly_abort (19990810);
-         break;
-       }
+    case EH_SPEC_BLOCK:
+      genrtl_eh_spec_block (t);
+      break;
 
-      /* Restore saved state.  */
-      current_stmt_tree->stmts_are_full_exprs_p = saved_stmts_are_full_exprs_p;
+    case HANDLER:
+      genrtl_handler (t);
+      break;
 
-      /* Go on to the next statement in this scope.  */
-      t = TREE_CHAIN (t);
-    }
+    case SUBOBJECT:
+      genrtl_subobject (SUBOBJECT_CLEANUP (t));
+      break;
 
-  return rval;
+    case RETURN_INIT:
+      genrtl_named_return_value ();
+      break;
+
+    case USING_STMT:
+      break;
+    
+    default:
+      my_friendly_abort (19990810);
+      break;
+    }
 }
 
 /* Called from expand_body via walk_tree.  Replace all AGGR_INIT_EXPRs
@@ -2494,7 +2195,6 @@ simplify_aggr_init_exprs_r (tp, walk_subtrees, data)
   tree args;
   tree slot;
   tree type;
-  tree call_type;
   int copy_from_buffer_p;
 
   aggr_init_expr = *tp;
@@ -2517,17 +2217,20 @@ simplify_aggr_init_exprs_r (tp, walk_subtrees, data)
   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),
+      args = tree_cons (NULL_TREE, 
+                       build1 (ADDR_EXPR, 
+                               build_pointer_type (TREE_TYPE (slot)),
+                               slot),
                        TREE_CHAIN (args));
     }
-  call_expr = build (CALL_EXPR, call_type, fn, args, NULL_TREE);
+  call_expr = build (CALL_EXPR, 
+                    TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))),
+                    fn, args, NULL_TREE);
   TREE_SIDE_EFFECTS (call_expr) = 1;
 
   /* If we're using the non-reentrant PCC calling convention, then we
@@ -2537,7 +2240,7 @@ simplify_aggr_init_exprs_r (tp, walk_subtrees, data)
 #ifdef PCC_STATIC_STRUCT_RETURN  
   if (!AGGR_INIT_VIA_CTOR_P (aggr_init_expr) && aggregate_value_p (type))
     {
-      int old_ac;
+      int old_ac = flag_access_control;
 
       flag_access_control = 0;
       call_expr = build_aggr_init (slot, call_expr, LOOKUP_ONLYCONVERTING);
@@ -2610,7 +2313,6 @@ emit_associated_thunks (fn)
     }
 }
 
-
 /* Generate RTL for FN.  */
 
 void
@@ -2670,9 +2372,6 @@ expand_body (fn)
       /* Or if this is a nested function.  */
       && !decl_function_context (fn))
     {
-      /* Give the function RTL now so that we can assign it to a
-        function pointer, etc.  */
-      make_function_rtl (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))
@@ -2688,13 +2387,23 @@ expand_body (fn)
       return;
     }
 
+  /* Compute the appropriate object-file linkage for inline
+     functions.  */
+  if (DECL_DECLARED_INLINE_P (fn))
+    import_export_decl (fn);
+
   /* 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);
+  /* Optimize the body of the function before expanding it.  We do not
+     optimize thunks, as (1) the backend tries to optimize the call to
+     the thunkee, (b) the tree based inliner breaks that optimization,
+     (c) virtual functions are rarely inlineable, and (d)
+     ASM_OUTPUT_MI_THUNK is there to DTRT anyway.  */
+  if (!DECL_THUNK_P (fn))
+    optimize_function (fn);
 
   timevar_pop (TV_INTEGRATION);
   timevar_push (TV_EXPAND);
@@ -2707,15 +2416,9 @@ 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.  */
-  cp_function_chain->name_declared = 1;
-
   /* Expand the body.  */
   expand_stmt (DECL_SAVED_TREE (fn));
 
@@ -2728,11 +2431,11 @@ expand_body (fn)
   lineno = STMT_LINENO (DECL_SAVED_TREE (fn));
 
   /* Generate code for the function.  */
-  finish_function (0);
+  genrtl_finish_function (fn);
 
   /* If possible, obliterate the body of the function so that it can
      be garbage collected.  */
-  if (flag_dump_translation_unit)
+  if (dump_enabled_p (TDI_all))
     /* Keep the body; we're going to dump it.  */
     ;
   else if (DECL_INLINE (fn) && flag_inline_trees)
@@ -2750,3 +2453,288 @@ expand_body (fn)
 
   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 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.  */
+  if (return_label)
+    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 ();
+
+  /* There's no need to defer outputting this function any more; we
+     know we want to output it.  */
+  DECL_DEFER_OUTPUT (fn) = 0;
+
+  /* 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 we don't need the RTL for this function anymore, stop pointing
+     to it.  That's especially important for LABEL_DECLs, since you
+     can reach all the instructions in the function from the
+     CODE_LABEL stored in the DECL_RTL for the LABEL_DECL.  */
+  if (!DECL_SAVED_INSNS (fn))
+    {
+      tree t;
+
+      /* Walk the BLOCK-tree, clearing DECL_RTL for LABEL_DECLs and
+        non-static local variables.  */
+      walk_tree_without_duplicates (&DECL_SAVED_TREE (fn),
+                                   clear_decl_rtl,
+                                   NULL);
+
+      /* Clear out the RTL for the arguments.  */
+      for (t = DECL_ARGUMENTS (fn); t; t = TREE_CHAIN (t))
+       {
+         SET_DECL_RTL (t, NULL_RTX);
+         DECL_INCOMING_RTL (t) = NULL_RTX;
+       }
+
+      if (!(flag_inline_trees && DECL_INLINE (fn)))
+       /* DECL_INITIAL must remain nonzero so we know this was an
+          actual function definition.  */
+       DECL_INITIAL (fn) = error_mark_node;
+    }
+  
+  /* 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;
+}
+
+/* Clear out the DECL_RTL for the non-static variables in BLOCK and
+   its sub-blocks.  */
+
+static tree
+clear_decl_rtl (tp, walk_subtrees, data)
+     tree *tp;
+     int *walk_subtrees ATTRIBUTE_UNUSED;
+     void *data ATTRIBUTE_UNUSED;
+{
+  if (nonstatic_local_decl_p (*tp)) 
+    SET_DECL_RTL (*tp, NULL_RTX);
+    
+  return NULL_TREE;
+}
+
+/* Perform initialization related to this module.  */
+
+void
+init_cp_semantics ()
+{
+  lang_expand_stmt = cp_expand_stmt;
+}