OSDN Git Service

2002-08-24 Matt Austern <austern@apple.com>
[pf3gnuchains/gcc-fork.git] / gcc / cp / semantics.c
index 66f36ab..2737bbe 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, 2001 Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
    Written by Mark Mitchell (mmitchell@usa.net) based on code found
    formerly in parse.y and pt.c.  
 
@@ -28,6 +28,7 @@
 #include "system.h"
 #include "tree.h"
 #include "cp-tree.h"
+#include "tree-inline.h"
 #include "except.h"
 #include "lex.h"
 #include "toplev.h"
@@ -37,6 +38,7 @@
 #include "expr.h"
 #include "output.h"
 #include "timevar.h"
+#include "debug.h"
 
 /* There routines provide a modular interface to perform many parsing
    operations.  They may therefore be used during actual parsing, or
 
 static tree maybe_convert_cond PARAMS ((tree));
 static tree simplify_aggr_init_exprs_r PARAMS ((tree *, int *, void *));
-static tree nullify_returns_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_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));
@@ -65,19 +64,19 @@ static tree clear_decl_rtl PARAMS ((tree *, int *, void *));
 
 /* Finish processing the COND, the SUBSTMT condition for STMT.  */
 
-#define FINISH_COND(cond, stmt, substmt)               \
+#define FINISH_COND(COND, STMT, SUBSTMT)               \
   do {                                                 \
-    if (last_tree != stmt)                             \
+    if (last_tree != (STMT))                           \
       {                                                        \
-        RECHAIN_STMTS (stmt, substmt);                 \
-        if (!processing_template_decl)                  \
-          {                                             \
-           cond = build_tree_list (substmt, cond);     \
-           substmt = cond;                             \
-          }                                             \
+        RECHAIN_STMTS (STMT, SUBSTMT);                 \
+        if (!processing_template_decl)                 \
+          {                                            \
+           (COND) = build_tree_list (SUBSTMT, COND);   \
+           (SUBSTMT) = (COND);                         \
+          }                                            \
       }                                                        \
     else                                               \
-      substmt = cond;                                  \
+      (SUBSTMT) = (COND);                              \
   } while (0)
 
 /* Returns non-zero if the current statement is a full expression,
@@ -98,7 +97,7 @@ stmt_tree
 current_stmt_tree ()
 {
   return (cfun 
-         ? &cfun->language->x_stmt_tree 
+         ? &cfun->language->base.x_stmt_tree 
          : &scope_chain->x_stmt_tree);
 }
 
@@ -110,7 +109,7 @@ int
 anon_aggr_type_p (node)
      tree node;
 {
-  return (CLASS_TYPE_P (node) && TYPE_LANG_SPECIFIC(node)->anon_aggr);
+  return ANON_AGGR_TYPE_P (node);
 }
 
 /* Finish a scope.  */
@@ -204,6 +203,7 @@ finish_expr_stmt (expr)
      tree expr;
 {
   tree r = NULL_TREE;
+  tree expr_type = NULL_TREE;;
 
   if (expr != NULL_TREE)
     {
@@ -214,6 +214,9 @@ finish_expr_stmt (expr)
              || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE))
        expr = default_conversion (expr);
       
+      /* Remember the type of the expression.  */
+      expr_type = TREE_TYPE (expr);
+
       if (stmts_are_full_exprs_p ())
        expr = convert_to_void (expr, "statement");
       
@@ -224,7 +227,7 @@ 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;
+  last_expr_type = expr_type;
 
   return r;
 }
@@ -263,7 +266,6 @@ finish_then_clause (if_stmt)
      tree if_stmt;
 {
   RECHAIN_STMTS (if_stmt, THEN_CLAUSE (if_stmt));
-  last_tree = if_stmt;
   return if_stmt;
 }
 
@@ -289,21 +291,8 @@ finish_else_clause (if_stmt)
 void 
 finish_if_stmt ()
 {
-  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 ();
-    }
+  do_poplevel ();
 }
 
 /* Begin a while-statement.  Returns a newly created WHILE_STMT if
@@ -328,8 +317,26 @@ finish_while_stmt_cond (cond, while_stmt)
      tree while_stmt;
 {
   cond = maybe_convert_cond (cond);
-  FINISH_COND (cond, while_stmt, WHILE_COND (while_stmt));
-  clear_out_block ();
+  if (getdecls () == NULL_TREE)
+    /* It was a simple condition; install it.  */
+    WHILE_COND (while_stmt) = cond;
+  else
+    {
+      /* If there was a declaration in the condition, we can't leave it
+        there; transform
+           while (A x = 42) { }
+        to
+           while (true) { A x = 42; if (!x) break; }  */
+      tree if_stmt;
+      WHILE_COND (while_stmt) = boolean_true_node;
+
+      if_stmt = begin_if_stmt ();
+      cond = build_unary_op (TRUTH_NOT_EXPR, cond, 0);
+      finish_if_stmt_cond (cond, if_stmt);
+      finish_break_stmt ();
+      finish_then_clause (if_stmt);
+      finish_if_stmt ();
+    }
 }
 
 /* Finish a while-statement, which may be given by WHILE_STMT.  */
@@ -389,17 +396,7 @@ finish_return_stmt (expr)
     expr = check_return_expr (expr);
   if (!processing_template_decl)
     {
-      if (DECL_CONSTRUCTOR_P (current_function_decl) && ctor_label)
-       {
-         /* Even returns without a value in a constructor must return
-            `this'.  We accomplish this by sending all returns in a
-            constructor to the CTOR_LABEL; finish_function emits code to
-            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.  */
-         return finish_goto_stmt (ctor_label);
-       }
-      else if (DECL_DESTRUCTOR_P (current_function_decl))
+      if (DECL_DESTRUCTOR_P (current_function_decl))
        {
          /* Similarly, all destructors must run destructors for
             base-classes before returning.  So, all returns in a
@@ -424,12 +421,12 @@ 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_stmt (r);
   if (NEW_FOR_SCOPE_P (r))
     {
       do_pushlevel ();
       note_level_for_for ();
     }
+  add_stmt (r);
 
   return r;
 }
@@ -455,8 +452,26 @@ finish_for_cond (cond, for_stmt)
      tree for_stmt;
 {
   cond = maybe_convert_cond (cond);
-  FINISH_COND (cond, for_stmt, FOR_COND (for_stmt));
-  clear_out_block ();
+  if (getdecls () == NULL_TREE)
+    /* It was a simple condition; install it.  */
+    FOR_COND (for_stmt) = cond;
+  else
+    {
+      /* If there was a declaration in the condition, we can't leave it
+        there; transform
+           for (; A x = 42;) { }
+        to
+           for (;;) { A x = 42; if (!x) break; }  */
+      tree if_stmt;
+      FOR_COND (for_stmt) = NULL_TREE;
+
+      if_stmt = begin_if_stmt ();
+      cond = build_unary_op (TRUTH_NOT_EXPR, cond, 0);
+      finish_if_stmt_cond (cond, if_stmt);
+      finish_break_stmt ();
+      finish_then_clause (if_stmt);
+      finish_if_stmt ();
+    }
 }
 
 /* Finish the increment-EXPRESSION in a for-statement, which may be
@@ -509,9 +524,9 @@ tree
 begin_switch_stmt ()
 {
   tree r;
-  r = build_stmt (SWITCH_STMT, NULL_TREE, NULL_TREE);
-  add_stmt (r);
   do_pushlevel ();
+  r = build_stmt (SWITCH_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
+  add_stmt (r);
   return r;
 }
 
@@ -522,9 +537,9 @@ finish_switch_cond (cond, switch_stmt)
      tree cond;
      tree switch_stmt;
 {
+  tree orig_type = NULL;
   if (!processing_template_decl)
     {
-      tree type;
       tree index;
 
       /* Convert the condition to an integer or enumeration type.  */
@@ -534,23 +549,27 @@ finish_switch_cond (cond, switch_stmt)
          error ("switch quantity not an integer");
          cond = error_mark_node;
        }
+      orig_type = TREE_TYPE (cond);
       if (cond != error_mark_node)
        {
          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;
+      if (cond != error_mark_node)
+       {
+         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));
+  SWITCH_TYPE (switch_stmt) = orig_type;
   push_switch (switch_stmt);
 }
 
@@ -563,8 +582,8 @@ finish_switch_stmt (switch_stmt)
 {
   RECHAIN_STMTS (switch_stmt, SWITCH_BODY (switch_stmt));
   pop_switch (); 
-  do_poplevel ();
   finish_stmt ();
+  do_poplevel ();
 }
 
 /* Generate the RTL for T, which is a TRY_BLOCK. */
@@ -589,7 +608,6 @@ genrtl_try_block (t)
 
       if (FN_TRY_BLOCK_P (t))
        {
-         end_protect_partials ();
          expand_start_all_catch ();
          in_function_try_handler = 1;
          expand_stmt (TRY_HANDLERS (t));
@@ -677,7 +695,7 @@ finish_cleanup (cleanup, try_block)
 
 void
 finish_function_try_block (try_block)
-     tree try_block; 
+     tree try_block;
 {
   if (TREE_CHAIN (try_block) 
       && TREE_CODE (TREE_CHAIN (try_block)) == CTOR_INITIALIZER)
@@ -783,21 +801,6 @@ finish_handler (handler)
   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
    compound-statement does not define a scope.  Returns a new
    COMPOUND_STMT if appropriate.  */
@@ -882,35 +885,74 @@ finish_asm_stmt (cv_qualifier, string, output_operands,
   tree r;
   tree t;
 
-  if (TREE_CHAIN (string))
-    string = combine_strings (string);
-
   if (cv_qualifier != NULL_TREE
       && cv_qualifier != ridpointers[(int) RID_VOLATILE])
     {
-      cp_warning ("%s qualifier ignored on asm",
+      warning ("%s qualifier ignored on asm",
                  IDENTIFIER_POINTER (cv_qualifier));
       cv_qualifier = NULL_TREE;
     }
 
   if (!processing_template_decl)
-    for (t = input_operands; t; t = TREE_CHAIN (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;
-      }
+    {
+      int i;
+      int ninputs;
+      int noutputs;
+
+      for (t = input_operands; t; t = TREE_CHAIN (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)
+           {
+             error ("type of asm operand `%E' could not be determined", 
+                       TREE_VALUE (t));
+             converted_operand = error_mark_node;
+           }
+         TREE_VALUE (t) = converted_operand;
+       }
+
+      ninputs = list_length (input_operands);
+      noutputs = list_length (output_operands);
+
+      for (i = 0, t = output_operands; t; t = TREE_CHAIN (t), ++i)
+       {
+         bool allows_mem;
+         bool allows_reg;
+         bool is_inout;
+         const char *constraint;
+         tree operand;
+
+         constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
+         operand = TREE_VALUE (output_operands);
+
+         if (!parse_output_constraint (&constraint,
+                                       i, ninputs, noutputs,
+                                       &allows_mem,
+                                       &allows_reg,
+                                       &is_inout))
+           {
+             /* By marking the type as erroneous, we will not try to
+                process this operand again in expand_asm_operands.  */
+             TREE_TYPE (operand) = error_mark_node;
+             continue;
+           }
+
+         /* If the operand is a DECL that is going to end up in
+            memory, assume it is addressable.  This is a bit more
+            conservative than it would ideally be; the exact test is
+            buried deep in expand_asm_operands and depends on the
+            DECL_RTL for the OPERAND -- which we don't have at this
+            point.  */
+         if (!allows_reg && DECL_P (operand))
+           cxx_mark_addressable (operand);
+       }
+    }
 
   r = build_stmt (ASM_STMT, cv_qualifier, string,
                  output_operands, input_operands,
@@ -940,35 +982,25 @@ finish_label_decl (name)
   add_decl_stmt (decl);
 }
 
-/* Generate the RTL for a SUBOBJECT. */
-
-static void 
-genrtl_subobject (cleanup)
-     tree cleanup;
-{
-  add_partial_entry (cleanup);
-}
-
-/* We're in a constructor, and have just constructed a a subobject of
-   *THIS.  CLEANUP is code to run if an exception is thrown before the
-   end of the current function is reached.   */
+/* When DECL goes out of scope, make sure that CLEANUP is executed.  */
 
 void 
-finish_subobject (cleanup)
+finish_decl_cleanup (decl, cleanup)
+     tree decl;
      tree cleanup;
 {
-  tree r = build_stmt (SUBOBJECT, cleanup);
-  add_stmt (r);
+  add_stmt (build_stmt (CLEANUP_STMT, decl, cleanup));
 }
 
-/* When DECL goes out of scope, make sure that CLEANUP is executed.  */
+/* If the current scope exits with an exception, run CLEANUP.  */
 
-void 
-finish_decl_cleanup (decl, cleanup)
-     tree decl;
+void
+finish_eh_cleanup (cleanup)
      tree cleanup;
 {
-  add_stmt (build_stmt (CLEANUP_STMT, decl, cleanup));
+  tree r = build_stmt (CLEANUP_STMT, NULL_TREE, cleanup);
+  CLEANUP_EH_ONLY (r) = 1;
+  add_stmt (r);
 }
 
 /* Generate the RTL for a RETURN_INIT. */
@@ -1019,7 +1051,7 @@ finish_named_return_value (return_id, init)
        DECL_NAME (decl) = return_id;
       else
        {
-         cp_error ("return identifier `%D' already in place", return_id);
+         error ("return identifier `%D' already in place", return_id);
          return;
        }
     }
@@ -1053,6 +1085,15 @@ finish_named_return_value (return_id, init)
   DECL_UNINLINABLE (current_function_decl) = 1;
 }
 
+/* Begin processing a mem-initializer-list.  */
+
+void
+begin_mem_initializers ()
+{
+  if (! DECL_CONSTRUCTOR_P (current_function_decl))
+    error ("only constructors take base initializers");
+}
+
 /* 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
@@ -1084,7 +1125,7 @@ finish_mem_initializers (init_list)
          /* 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
+            actually means that the base initializer preceded the
             data member initializer.  */
          if (warn_reorder && last_base_warned_about != base_init_list)
            {
@@ -1094,7 +1135,7 @@ finish_mem_initializers (init_list)
                   base != last_base_warned_about; 
                   base = TREE_CHAIN (base))
                {
-                 cp_warning ("base initializer for `%T'",
+                 warning ("base initializer for `%T'",
                              TREE_PURPOSE (base));
                  warning ("   will be re-ordered to precede member initializations");
                }
@@ -1109,87 +1150,11 @@ finish_mem_initializers (init_list)
        }
     }
 
-  setup_vtbl_ptr (member_init_list, base_init_list);
-}
-
-/* Cache the value of this class's main virtual function table pointer
-   in a register variable.  This will save one indirection if a
-   more than one virtual function call is made this function.  */
-
-void
-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);
-
-  /* If we've already done this, there's no need to do it again.  */
-  if (vtbls_set_up_p)
-    return;
-
-  if (DECL_CONSTRUCTOR_P (current_function_decl))
-    {
-      if (processing_template_decl)
-       add_stmt (build_min_nt
-                 (CTOR_INITIALIZER,
-                  member_init_list, base_init_list));
-      else
-       {
-         tree ctor_stmt;
-
-         /* Mark the beginning of the constructor.  */
-         ctor_stmt = build_stmt (CTOR_STMT);
-         CTOR_BEGIN_P (ctor_stmt) = 1;
-         add_stmt (ctor_stmt);
-         
-         /* And actually initialize the base-classes and members.  */
-         emit_base_init (member_init_list, base_init_list);
-       }
-    }
-  else if (DECL_DESTRUCTOR_P (current_function_decl)
-          && !processing_template_decl)
-    {
-      tree if_stmt;
-      tree compound_stmt;
-
-      /* 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.  */
-      if_stmt = begin_if_stmt ();
-
-      /* If it is not safe to avoid setting up the vtables, then
-        someone will change the condition to be boolean_true_node.  
-         (Actually, for now, we do not have code to set the condition
-        appropriately, so we just assume that we always need to
-        initialize the vtables.)  */
-      finish_if_stmt_cond (boolean_true_node, if_stmt);
-      current_vcalls_possible_p = &IF_COND (if_stmt);
-
-      compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
-
-      /* Make all virtual function table pointers in non-virtual base
-        classes point to CURRENT_CLASS_TYPE's virtual function
-        tables.  */
-      initialize_vtbl_ptrs (current_class_ptr);
-
-      finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
-      finish_then_clause (if_stmt);
-      finish_if_stmt ();
-    }
-
-  /* Always keep the BLOCK node associated with the outermost pair of
-     curly braces of a function.  These are needed for correct
-     operation of dwarfout.c.  */
-  keep_next_level (1);
-
-  /* The virtual function tables are set up now.  */
-  vtbls_set_up_p = 1;
+  if (processing_template_decl)
+    add_stmt (build_min_nt (CTOR_INITIALIZER,
+                           member_init_list, base_init_list));
+  else
+    emit_base_init (member_init_list, base_init_list);
 }
 
 /* Returns the stack of SCOPE_STMTs for the current function.  */
@@ -1197,7 +1162,7 @@ setup_vtbl_ptr (member_init_list, base_init_list)
 tree *
 current_scope_stmt_stack ()
 {
-  return &cfun->language->x_scope_stmt_stack;
+  return &cfun->language->base.x_scope_stmt_stack;
 }
 
 /* Finish a parenthesized expression EXPR.  */
@@ -1207,7 +1172,7 @@ finish_parenthesized_expr (expr)
      tree expr;
 {
   if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (expr))))
-    /* This inhibits warnings in truthvalue_conversion.  */
+    /* This inhibits warnings in c_common_truthvalue_conversion.  */
     C_SET_EXP_ORIGINAL_CODE (expr, ERROR_MARK); 
 
   if (TREE_CODE (expr) == OFFSET_REF)
@@ -1249,7 +1214,7 @@ begin_global_stmt_expr ()
 
   keep_next_level (1);
   
-  return (last_tree != NULL_TREE) ? last_tree : expand_start_stmt_expr(); 
+  return last_tree ? last_tree : expand_start_stmt_expr(/*has_scope=*/1); 
 }
 
 /* Finish the STMT_EXPR last begun with begin_global_stmt_expr.  */
@@ -1299,32 +1264,86 @@ finish_stmt_expr (rtl_expr)
   return result;
 }
 
-/* Finish a call to FN with ARGS.  Returns a representation of the
-   call.  */
+/* Generate an expression for `FN (ARGS)'.
+
+   If DISALLOW_VIRTUAL is true, the call to FN will be not generated
+   as a virtual call, even if FN is virtual.  (This flag is set when
+   encountering an expression where the function name is explicitly
+   qualified.  For example a call to `X::f' never generates a virtual
+   call.)
+
+   Returns code for the call.  */
 
 tree 
-finish_call_expr (fn, args, koenig)
-     tree fn;
-     tree args;
-     int koenig;
+finish_call_expr (tree fn, tree args, bool disallow_virtual)
 {
-  tree result;
+  if (fn == error_mark_node || args == error_mark_node)
+    return error_mark_node;
+
+  if (processing_template_decl)
+    return build_nt (CALL_EXPR, fn, args, NULL_TREE);
 
-  if (koenig)
+  /* ARGS should be a list of arguments.  */
+  my_friendly_assert (!args || TREE_CODE (args) == TREE_LIST,
+                     20020712);
+
+  if (BASELINK_P (fn))
     {
-      if (TREE_CODE (fn) == BIT_NOT_EXPR)
-       fn = build_x_unary_op (BIT_NOT_EXPR, TREE_OPERAND (fn, 0));
-      else if (TREE_CODE (fn) != TEMPLATE_ID_EXPR)
-       fn = do_identifier (fn, 2, args);
-    }
-  result = build_x_function_call (fn, args, current_class_ref);
+      tree object;
+
+      /* A call to a member function.  From [over.call.func]:
+
+          If the keyword this is in scope and refers to the class of
+          that member function, or a derived class thereof, then the
+          function call is transformed into a qualified function call
+          using (*this) as the postfix-expression to the left of the
+          . operator.... [Otherwise] a contrived object of type T
+          becomes the implied object argument.  
+
+        This paragraph is unclear about this situation:
+
+         struct A { void f(); };
+         struct B : public A {};
+         struct C : public A { void g() { B::f(); }};
+
+       In particular, for `B::f', this paragraph does not make clear
+       whether "the class of that member function" refers to `A' or 
+       to `B'.  We believe it refers to `B'.  */
+      if (current_class_type 
+         && DERIVED_FROM_P (BINFO_TYPE (BASELINK_ACCESS_BINFO (fn)),
+                            current_class_type)
+         && current_class_ref)
+       object = current_class_ref;
+      else
+       {
+         tree representative_fn;
 
-  if (TREE_CODE (result) == CALL_EXPR
-      && (! TREE_TYPE (result)
-          || TREE_CODE (TREE_TYPE (result)) != VOID_TYPE))
-    result = require_complete_type (result);
+         representative_fn = BASELINK_FUNCTIONS (fn);
+         if (TREE_CODE (representative_fn) == TEMPLATE_ID_EXPR)
+           representative_fn = TREE_OPERAND (representative_fn, 0);
+         representative_fn = get_first_fn (representative_fn);
+         object = build_dummy_object (DECL_CONTEXT (representative_fn));
+       }
 
-  return result;
+      return build_new_method_call (object, fn, args, NULL_TREE,
+                                   (disallow_virtual 
+                                    ? LOOKUP_NONVIRTUAL : 0));
+    }
+  else if (is_overloaded_fn (fn))
+    /* A call to a namespace-scope function.  */
+    return build_new_function_call (fn, args);
+  else if (CLASS_TYPE_P (TREE_TYPE (fn)))
+    {
+      /* If the "function" is really an object of class type, it might
+        have an overloaded `operator ()'.  */
+      tree result;
+      result = build_opfncall (CALL_EXPR, LOOKUP_NORMAL, fn, args, NULL_TREE);
+      if (result)
+       return result;
+    }
+
+  /* A call where the function is unknown.  */
+  return build_function_call (fn, args);
 }
 
 /* Finish a call to a postfix increment or decrement or EXPR.  (Which
@@ -1355,9 +1374,6 @@ finish_this_expr ()
 
   if (current_class_ptr)
     {
-#ifdef WARNING_ABOUT_CCD
-      TREE_USED (current_class_ptr) = 1;
-#endif
       result = current_class_ptr;
     }
   else if (current_function_decl
@@ -1387,14 +1403,6 @@ finish_object_call_expr (fn, object, args)
      tree object;
      tree args;
 {
-#if 0
-  /* This is a future direction of this code, but because
-     build_x_function_call cannot always undo what is done in
-     build_component_ref entirely yet, we cannot do this.  */
-
-  tree real_fn = build_component_ref (object, fn, NULL_TREE, 1);
-  return finish_call_expr (real_fn, args);
-#else
   if (DECL_DECLARES_TYPE_P (fn))
     {
       if (processing_template_decl)
@@ -1409,13 +1417,15 @@ finish_object_call_expr (fn, object, args)
        fn = DECL_NAME (fn);
       else
        {
-         cp_error ("calling type `%T' like a method", fn);
+         error ("calling type `%T' like a method", fn);
          return error_mark_node;
        }
     }
-
-  return build_method_call (object, fn, args, NULL_TREE, LOOKUP_NORMAL);
-#endif
+  
+  if (name_p (fn))
+    return build_method_call (object, fn, args, NULL_TREE, LOOKUP_NORMAL);
+  else
+    return build_new_method_call (object, fn, args, NULL_TREE, LOOKUP_NORMAL);
 }
 
 /* Finish a qualified member function call using OBJECT and ARGS as
@@ -1445,33 +1455,17 @@ finish_pseudo_destructor_call_expr (object, scope, destructor)
     return build_min_nt (PSEUDO_DTOR_EXPR, object, scope, destructor);
 
   if (scope && scope != destructor)
-    cp_error ("destructor specifier `%T::~%T()' must have matching names", 
+    error ("destructor specifier `%T::~%T()' must have matching names", 
              scope, destructor);
 
   if ((scope == NULL_TREE || IDENTIFIER_GLOBAL_VALUE (destructor))
       && (TREE_CODE (TREE_TYPE (object)) !=
          TREE_CODE (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (destructor)))))
-    cp_error ("`%E' is not of type `%T'", object, destructor);
+    error ("`%E' is not of type `%T'", object, destructor);
 
   return cp_convert (void_type_node, object);
 }
 
-/* Finish a call to a globally qualified member function FN using
-   ARGS.  Returns an expression for the call.  */
-
-tree 
-finish_qualified_call_expr (fn, args)
-     tree fn;
-     tree args;
-{
-  if (processing_template_decl)
-    return build_min_nt (CALL_EXPR, fn, args, NULL_TREE);
-  else
-    return build_member_call (TREE_OPERAND (fn, 0),
-                             TREE_OPERAND (fn, 1),
-                             args);
-}
-
 /* Finish an expression of the form CODE EXPR.  */
 
 tree
@@ -1506,6 +1500,20 @@ finish_id_expr (expr)
   return expr;
 }
 
+/* Return the declaration for the function-name variable indicated by
+   ID.  */
+
+tree
+finish_fname (tree id)
+{
+  tree decl;
+  
+  decl = fname_decl (C_RID_CODE (id), id);
+  if (processing_template_decl)
+    decl = build_min_nt (LOOKUP_EXPR, DECL_NAME (decl));
+  return decl;
+}
+
 static tree current_type_lookups;
 
 /* Perform deferred access control for types used in the type of a
@@ -1545,32 +1553,13 @@ 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;
 {
-  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;
+  current_type_lookups = lookups;
 }
 
 /* Reset the deferred access control.  */
@@ -1582,20 +1571,17 @@ reset_type_access_control ()
   current_type_lookups = NULL_TREE;
 }
 
-/* Begin a function definition declared with DECL_SPECS and
-   DECLARATOR.  Returns non-zero if the function-declaration is
-   legal.  */
+/* Begin a function definition declared with DECL_SPECS, ATTRIBUTES,
+   and DECLARATOR.  Returns non-zero if the function-declaration is
+   valid.  */
 
 int
-begin_function_definition (decl_specs, declarator)
+begin_function_definition (decl_specs, attributes, declarator)
      tree decl_specs;
+     tree attributes;
      tree declarator;
 {
-  tree specs;
-  tree attrs;
-
-  split_specs_attrs (decl_specs, &specs, &attrs);
-  if (!start_function (specs, declarator, attrs, SF_DEFAULT))
+  if (!start_function (decl_specs, declarator, attributes, SF_DEFAULT))
     return 0;
 
   deferred_type_access_control ();
@@ -1690,6 +1676,25 @@ finish_template_template_parm (aggr, identifier)
   return finish_template_type_parm (aggr, tmpl);
 }
 
+/* ARGUMENT is the default-argument value for a template template
+   parameter.  If ARGUMENT is invalid, issue error messages and return
+   the ERROR_MARK_NODE.  Otherwise, ARGUMENT itself is returned.  */
+
+tree
+check_template_template_default_arg (tree argument)
+{
+  if (TREE_CODE (argument) != TEMPLATE_DECL
+      && TREE_CODE (argument) != TEMPLATE_TEMPLATE_PARM
+      && TREE_CODE (argument) != TYPE_DECL
+      && TREE_CODE (argument) != UNBOUND_CLASS_TEMPLATE)
+    {
+      error ("invalid default template argument");
+      return error_mark_node;
+    }
+
+  return argument;
+}
+
 /* Finish a parameter list, indicated by PARMS.  If ELLIPSIS is
    non-zero, the parameter list was terminated by a `...'.  */
 
@@ -1716,13 +1721,16 @@ tree
 begin_class_definition (t)
      tree t;
 {
+  if (t == error_mark_node)
+    return error_mark_node;
+
   /* 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);
+      error ("definition of `%#T' inside template parameter list", t);
       return error_mark_node;
     }
 
@@ -1738,7 +1746,7 @@ begin_class_definition (t)
      This is erroneous.  */
   else if (TREE_CODE (t) == TYPENAME_TYPE)
     {
-      cp_error ("invalid definition of qualified type `%T'", t);
+      error ("invalid definition of qualified type `%T'", t);
       t = error_mark_node;
     }
 
@@ -1891,7 +1899,7 @@ finish_member_declaration (decl)
           struct S { enum E { }; int E } s;
           s.E = 3;
 
-        is legal.  In addition, the FIELD_DECLs must be maintained in
+        is valid.  In addition, the FIELD_DECLs must be maintained in
         declaration order so that class layout works as expected.
         However, we don't need that order until class layout, so we
         save a little time by putting FIELD_DECLs on in reverse order
@@ -1925,6 +1933,9 @@ finish_class_definition (t, attributes, semi, pop_scope_p)
      int semi;
      int pop_scope_p;
 {
+  if (t == error_mark_node)
+    return error_mark_node;
+
   /* finish_struct nukes this anyway; if finish_exception does too,
      then it can go.  */
   if (semi)
@@ -1932,8 +1943,8 @@ finish_class_definition (t, attributes, semi, pop_scope_p)
 
   /* If we got any attributes in class_head, xref_tag will stick them in
      TREE_TYPE of the type.  Grab them now.  */
-  attributes = chainon (TREE_TYPE (t), attributes);
-  TREE_TYPE (t) = NULL_TREE;
+  attributes = chainon (TYPE_ATTRIBUTES (t), attributes);
+  TYPE_ATTRIBUTES (t) = NULL_TREE;
 
   if (TREE_CODE (t) == ENUMERAL_TYPE)
     ;
@@ -1948,8 +1959,6 @@ 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 ();
 
@@ -1966,16 +1975,6 @@ begin_inline_definitions ()
     do_pending_inlines ();
 }
 
-/* Finish processing the inline function definitions cached during the
-   processing of a class definition.  */
-
-void
-finish_inline_definitions ()
-{
-  if (current_class_type == NULL_TREE)
-    clear_inline_text_obstack (); 
-}
-
 /* Finish processing the declaration of a member class template
    TYPES whose template parameters are given by PARMS.  */
 
@@ -2008,7 +2007,7 @@ finish_member_class_template (types)
   return NULL_TREE;
 }
 
-/* Finish processsing a complete template declaration.  The PARMS are
+/* Finish processing a complete template declaration.  The PARMS are
    the template parameters.  */
 
 void
@@ -2074,7 +2073,7 @@ enter_scope_of (sr)
 /* Finish processing a BASE_CLASS with the indicated ACCESS_SPECIFIER.
    Return a TREE_LIST containing the ACCESS_SPECIFIER and the
    BASE_CLASS, or NULL_TREE if an error occurred.  The
-   ACCESSS_SPECIFIER is one of
+   ACCESS_SPECIFIER is one of
    access_{default,public,protected_private}[_virtual]_node.*/
 
 tree 
@@ -2084,13 +2083,18 @@ finish_base_specifier (access_specifier, base_class)
 {
   tree result;
 
-  if (! is_aggr_type (base_class, 1))
+  if (base_class == error_mark_node)
+    {
+      error ("invalid base-class specification");
+      result = NULL_TREE;
+    }
+  else if (! is_aggr_type (base_class, 1))
     result = NULL_TREE;
   else
     {
-      if (CP_TYPE_QUALS (base_class) != 0)
+      if (cp_type_quals (base_class) != 0)
         {
-          cp_error ("base class `%T' has cv qualifiers", base_class);
+          error ("base class `%T' has cv qualifiers", base_class);
           base_class = TYPE_MAIN_VARIANT (base_class);
         }
       result = build_tree_list (access_specifier, base_class);
@@ -2112,20 +2116,21 @@ check_multiple_declarators ()
      contain at most one declarator.  
 
      We don't just use PROCESSING_TEMPLATE_DECL for the first
-     condition since that would disallow the perfectly legal code, 
+     condition since that would disallow the perfectly valid code, 
      like `template <class T> struct S { int i, j; };'.  */
-  tree scope = current_scope ();
-
-  if (scope && TREE_CODE (scope) == FUNCTION_DECL)
+  if (at_function_scope_p ())
     /* It's OK to write `template <class T> void f() { int i, j;}'.  */
     return;
      
   if (PROCESSING_REAL_TEMPLATE_DECL_P () 
       || processing_explicit_instantiation
       || processing_specialization)
-    cp_error ("multiple declarators in template declaration");
+    error ("multiple declarators in template declaration");
 }
 
+/* Implement the __typeof keyword: Return the type of EXPR, suitable for
+   use as a type-specifier.  */
+
 tree
 finish_typeof (expr)
      tree expr;
@@ -2146,6 +2151,31 @@ finish_typeof (expr)
   return TREE_TYPE (expr);
 }
 
+/* Compute the value of the `sizeof' operator.  */
+
+tree
+finish_sizeof (t)
+     tree t;
+{
+  if (processing_template_decl)
+    return build_min_nt (SIZEOF_EXPR, t);
+
+  return TYPE_P (t) ? cxx_sizeof (t) : expr_sizeof (t);
+}
+
+/* Implement the __alignof keyword: Return the minimum required
+   alignment of T, measured in bytes.  */
+
+tree
+finish_alignof (t)
+     tree t;
+{
+  if (processing_template_decl)
+    return build_min_nt (ALIGNOF_EXPR, t);
+
+  return TYPE_P (t) ? cxx_alignof (t) : c_alignof_expr (t);
+}
+
 /* Generate RTL for the statement T, and its substatements, and any
    other statements at its nesting level.  */
 
@@ -2155,16 +2185,6 @@ cp_expand_stmt (t)
 {
   switch (TREE_CODE (t))
     {
-    case CLEANUP_STMT:
-      /* Don't destroy the chosen named return value.  */
-      if (CLEANUP_DECL (t) != current_function_return_value)
-       genrtl_decl_cleanup (CLEANUP_DECL (t), CLEANUP_EXPR (t));
-      break;
-
-    case CTOR_STMT:
-      genrtl_ctor_stmt (t);
-      break;
-
     case TRY_BLOCK:
       genrtl_try_block (t);
       break;
@@ -2177,10 +2197,6 @@ cp_expand_stmt (t)
       genrtl_handler (t);
       break;
 
-    case SUBOBJECT:
-      genrtl_subobject (SUBOBJECT_CLEANUP (t));
-      break;
-
     case RETURN_INIT:
       genrtl_named_return_value ();
       break;
@@ -2189,7 +2205,7 @@ cp_expand_stmt (t)
       break;
     
     default:
-      my_friendly_abort (19990810);
+      abort ();
       break;
     }
 }
@@ -2235,7 +2251,7 @@ simplify_aggr_init_exprs_r (tp, walk_subtrees, data)
     {
       /* Replace the first argument with the address of the third
         argument to the AGGR_INIT_EXPR.  */
-      mark_addressable (slot);
+      cxx_mark_addressable (slot);
       args = tree_cons (NULL_TREE, 
                        build1 (ADDR_EXPR, 
                                build_pointer_type (TREE_TYPE (slot)),
@@ -2257,7 +2273,8 @@ simplify_aggr_init_exprs_r (tp, walk_subtrees, data)
       int old_ac = flag_access_control;
 
       flag_access_control = 0;
-      call_expr = build_aggr_init (slot, call_expr, LOOKUP_ONLYCONVERTING);
+      call_expr = build_aggr_init (slot, call_expr,
+                                  DIRECT_BIND | LOOKUP_ONLYCONVERTING);
       flag_access_control = old_ac;
       copy_from_buffer_p = 1;
     }
@@ -2292,7 +2309,7 @@ emit_associated_thunks (fn)
      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))
+  if (DECL_VIRTUAL_P (fn))
     {
       tree binfo;
       tree v;
@@ -2334,6 +2351,7 @@ expand_body (fn)
 {
   int saved_lineno;
   const char *saved_input_filename;
+  tree saved_function;
 
   /* 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
@@ -2358,8 +2376,8 @@ expand_body (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 this is a constructor or destructor body, we have to clone
+     it.  */
   if (maybe_clone_body (fn))
     {
       /* We don't want to process FN again, so pretend we've written
@@ -2378,12 +2396,10 @@ expand_body (fn)
      to decide whether to write it out or not.  */
   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.  */
+      /* Or if we have to emit code for inline functions anyhow.  */
       && !flag_keep_inline_functions
       /* Or if we actually have a reference to the function.  */
-      && !DECL_NEEDED_P (fn)
-      /* Or if this is a nested function.  */
-      && !decl_function_context (fn))
+      && !DECL_NEEDED_P (fn))
     {
       /* Set DECL_EXTERNAL so that assemble_external will be called as
         necessary.  We'll clear it again in finish_file.  */
@@ -2395,8 +2411,8 @@ expand_body (fn)
       /* Remember this function.  In finish_file we'll decide if
         we actually need to write this function out.  */
       defer_fn (fn);
-      /* Let the back-end know that this funtion exists.  */
-      note_deferral_of_defined_inline_function (fn);
+      /* Let the back-end know that this function exists.  */
+      (*debug_hooks->deferred_inline_function) (fn);
       return;
     }
 
@@ -2405,24 +2421,31 @@ expand_body (fn)
   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);
-
-  timevar_pop (TV_INTEGRATION);
-  timevar_push (TV_EXPAND);
+  /* If FN is external, then there's no point in generating RTL for
+     it.  This situation can arise with an inline function under
+     `-fexternal-templates'; we instantiate the function, even though
+     we're not planning on emitting it, in case we get a chance to
+     inline it.  */
+  if (DECL_EXTERNAL (fn))
+    return;
 
   /* 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.  */
   saved_lineno = lineno;
   saved_input_filename = input_filename;
+  saved_function = current_function_decl;
   lineno = DECL_SOURCE_LINE (fn);
   input_filename = DECL_SOURCE_FILE (fn);
+  current_function_decl = 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);
 
   genrtl_start_function (fn);
   current_function_is_thunk = DECL_THUNK_P (fn);
@@ -2455,27 +2478,38 @@ expand_body (fn)
     DECL_SAVED_TREE (fn) = NULL_TREE;
 
   /* And restore the current source position.  */
+  current_function_decl = saved_function;
   lineno = saved_lineno;
   input_filename = saved_input_filename;
   extract_interface_info ();
 
   timevar_pop (TV_EXPAND);
+
+  /* Emit any thunks that should be emitted at the same time as FN.  */
+  emit_associated_thunks (fn);
 }
 
-/* Helper function for walk_tree, used by genrtl_start_function to override
-   all the RETURN_STMTs for the named return value optimization.  */
+/* Helper function for walk_tree, used by finish_function to override all
+   the RETURN_STMTs and pertinent CLEANUP_STMTs for the named return
+   value optimization.  */
 
-static tree
+tree
 nullify_returns_r (tp, walk_subtrees, data)
      tree *tp;
      int *walk_subtrees;
-     void *data ATTRIBUTE_UNUSED;
+     void *data;
 {
-  /* No need to walk into types.  */
+  tree nrv = (tree) data;
+
+  /* No need to walk into types.  There wouldn't be any need to walk into
+     non-statements, except that we have to consider STMT_EXPRs.  */
   if (TYPE_P (*tp))
     *walk_subtrees = 0;
   else if (TREE_CODE (*tp) == RETURN_STMT)
-    RETURN_NULLIFIED_P (*tp) = 1;
+    RETURN_STMT_EXPR (*tp) = NULL_TREE;
+  else if (TREE_CODE (*tp) == CLEANUP_STMT
+          && CLEANUP_DECL (*tp) == nrv)
+    CLEANUP_EH_ONLY (*tp) = 1;
 
   /* Keep iterating.  */
   return NULL_TREE;
@@ -2487,8 +2521,6 @@ 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.  */
@@ -2524,56 +2556,25 @@ genrtl_start_function (fn)
       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;
+      /* We don't need the saved data anymore.  Unless this is an inline
+         function; we need the named return value info for
+         cp_copy_res_decl_for_inlining.  */
+      if (! DECL_INLINE (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);
+  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);
 
-  /* Set up the named return value optimization, if we can.  */
-  if (current_function_return_value
-      && current_function_return_value != error_mark_node)
-    {
-      tree r = current_function_return_value;
-      /* This is only worth doing for fns that return in memory--and
-        simpler, since we don't have to worry about promoted modes.  */
-      if (aggregate_value_p (TREE_TYPE (TREE_TYPE (fn))))
-       {
-         COPY_DECL_RTL (DECL_RESULT (fn), r);
-         DECL_ALIGN (r) = DECL_ALIGN (DECL_RESULT (fn));
-         walk_tree_without_duplicates (&DECL_SAVED_TREE (fn),
-                                       nullify_returns_r, NULL_TREE);
-       }
-    }
+  /* Give our named return value the same RTL as our RESULT_DECL.  */
+  if (current_function_return_value)
+    COPY_DECL_RTL (DECL_RESULT (fn), current_function_return_value);
 }
 
 /* Finish generating the RTL for FN.  */
@@ -2582,7 +2583,7 @@ static void
 genrtl_finish_function (fn)
      tree fn;
 {
-  tree no_return_label = NULL_TREE;
+  tree t;
 
 #if 0
   if (write_symbols != NO_DEBUG)
@@ -2610,59 +2611,10 @@ genrtl_finish_function (fn)
   /* 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
-      && ! 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)
+  /* If we have a named return value, we need to force a return so that
+     the return register is USEd.  */
+  if (DECL_NAME (DECL_RESULT (fn)))
     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
@@ -2671,7 +2623,7 @@ genrtl_finish_function (fn)
   immediate_size_expand = 1;
 
   /* Generate rtl for function exit.  */
-  expand_function_end (input_filename, lineno, 1);
+  expand_function_end (input_filename, lineno, 0);
 
   /* If this is a nested function (like a template instantiation that
      we're compiling in the midst of compiling something else), push a
@@ -2693,16 +2645,6 @@ genrtl_finish_function (fn)
   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) */
@@ -2725,32 +2667,30 @@ genrtl_finish_function (fn)
 
   --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);
+  /* In C++, we should never be saving RTL for the function.  */
+  my_friendly_assert (!DECL_SAVED_INSNS (fn), 20010903);
 
-      /* 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;
-       }
+  /* Since 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.  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);
 
-      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;
+  /* 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