c-common.h (flag_dump_translation_unit): Remove.
[gcc.git] / gcc / cp / semantics.c
index 5c5756775e8f4da1eb95946a1810aaa48b3c4e55..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"
 
@@ -51,14 +52,15 @@ static tree simplify_aggr_init_exprs_r PARAMS ((tree *, int *, void *));
 static void deferred_type_access_control PARAMS ((void));
 static void emit_associated_thunks PARAMS ((tree));
 static void genrtl_try_block PARAMS ((tree));
+static void genrtl_eh_spec_block PARAMS ((tree));
 static void genrtl_handler PARAMS ((tree));
-static void genrtl_catch_block PARAMS ((tree));
 static void genrtl_ctor_stmt PARAMS ((tree));
 static void genrtl_subobject PARAMS ((tree));
 static void genrtl_named_return_value PARAMS ((void));
 static void cp_expand_stmt PARAMS ((tree));
 static void genrtl_start_function PARAMS ((tree));
 static void genrtl_finish_function PARAMS ((tree));
+static tree clear_decl_rtl PARAMS ((tree *, int *, void *));
 
 /* Finish processing the COND, the SUBSTMT condition for STMT.  */
 
@@ -150,7 +152,7 @@ do_pushlevel ()
 
 /* Finish a goto-statement.  */
 
-void
+tree
 finish_goto_stmt (destination)
      tree destination;
 {
@@ -171,7 +173,7 @@ finish_goto_stmt (destination)
   
   check_goto (destination);
 
-  add_stmt (build_stmt (GOTO_STMT, destination));
+  return add_stmt (build_stmt (GOTO_STMT, destination));
 }
 
 /* COND is the condition-expression for an if, while, etc.,
@@ -196,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
@@ -212,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_stmt (build_stmt (EXPR_STMT, expr));
+      r = add_stmt (build_stmt (EXPR_STMT, expr));
     }
 
   finish_stmt ();
@@ -223,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;
 }
 
 
@@ -280,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 ()
@@ -375,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)
@@ -391,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_stmt (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.  */
@@ -482,18 +487,18 @@ finish_for_stmt (for_stmt)
 
 /* Finish a break-statement.  */
 
-void
+tree
 finish_break_stmt ()
 {
-  add_stmt (build_break_stmt ());
+  return add_stmt (build_break_stmt ());
 }
 
 /* Finish a continue-statement.  */
 
-void
+tree
 finish_continue_stmt ()
 {
-  add_stmt (build_continue_stmt ());
+  return add_stmt (build_continue_stmt ());
 }
 
 /* Begin a switch-statement.  Returns a new SWITCH_STMT if
@@ -571,14 +576,14 @@ genrtl_try_block (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)) 
        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))
@@ -599,6 +604,21 @@ 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.  */
 
@@ -700,15 +720,11 @@ 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.  */
@@ -719,7 +735,10 @@ begin_handler ()
   tree r;
   r = build_stmt (HANDLER, NULL_TREE, NULL_TREE);
   add_stmt (r);
+  /* Create a binding level for the eh_info and the exception object
+     cleanup.  */
   do_pushlevel ();
+  note_level_for_catch ();
   return r;
 }
 
@@ -727,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)
@@ -742,47 +760,24 @@ 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. */
-
-static void
-genrtl_catch_block (type)
-     tree type;
-{
-  start_catch_handler (type);
-}
-
-/* Note the beginning of a handler for TYPE.  This function is called
-   at the point to which control should be transferred when an
-   appropriately-typed exception is thrown.  */
-
-void
-begin_catch_block (type)
-     tree type;
-{
-  add_stmt (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));
 }
@@ -828,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
@@ -837,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
-      && !function_name_declared_p
-      && !has_no_scope)
-    {
-      function_name_declared_p = 1;
-      declare_function_name ();
-    }
-
   return r;
 }
 
@@ -884,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;
@@ -909,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_stmt (r);
+  return add_stmt (r);
 }
 
 /* Finish a label with the indicated NAME.  */
@@ -975,17 +975,12 @@ finish_decl_cleanup (decl, cleanup)
 static void
 genrtl_named_return_value ()
 {
-  tree decl;
-
-  decl = DECL_RESULT (current_function_decl);
-
-  emit_local_var (decl);
+  tree decl = DECL_RESULT (current_function_decl);
 
   /* If this named return value comes in a register, put it in a
      pseudo-register.  */
   if (DECL_REGISTER (decl))
     {
-      original_result_rtx = DECL_RTL (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
@@ -993,10 +988,12 @@ genrtl_named_return_value ()
         SImode but the DECL_RTL for the DECL_RESULT has DImode.  So,
         here, we use the mode the back-end has already assigned for
         the return value.  */
-      DECL_RTL (decl) = gen_reg_rtx (GET_MODE (original_result_rtx));
+      SET_DECL_RTL (decl, gen_reg_rtx (GET_MODE (DECL_RTL (decl))));
       if (TREE_ADDRESSABLE (decl))
        put_var_into_stack (decl);
     }
+
+  emit_local_var (decl);
 }
 
 /* Bind a name and initialization to the return value of
@@ -1018,10 +1015,7 @@ finish_named_return_value (return_id, init)
   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);
@@ -1156,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
@@ -1177,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 = function_name_declared_p;
-      function_name_declared_p = 1;
       compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
-      function_name_declared_p = saved_cfnd;
 
       /* Make all virtual function table pointers in non-virtual base
         classes point to CURRENT_CLASS_TYPE's virtual function
@@ -1483,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
@@ -1537,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;
 }
 
@@ -1579,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
@@ -1622,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;
 }
@@ -1652,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 ();
 }
 
@@ -1687,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);
 }
 
@@ -1698,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;
 }
 
@@ -1714,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))
     {
@@ -1793,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.  */
@@ -1853,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.
@@ -1936,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 ();
 
@@ -2021,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);
 
@@ -2067,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;
 }
@@ -2127,6 +2128,9 @@ finish_typeof (expr)
       return t;
     }
 
+  if (TREE_CODE (expr) == OFFSET_REF)
+    expr = resolve_offset_ref (expr);
+
   return TREE_TYPE (expr);
 }
 
@@ -2143,10 +2147,6 @@ cp_expand_stmt (t)
       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;
@@ -2155,6 +2155,10 @@ cp_expand_stmt (t)
       genrtl_try_block (t);
       break;
 
+    case EH_SPEC_BLOCK:
+      genrtl_eh_spec_block (t);
+      break;
+
     case HANDLER:
       genrtl_handler (t);
       break;
@@ -2167,6 +2171,9 @@ cp_expand_stmt (t)
       genrtl_named_return_value ();
       break;
 
+    case USING_STMT:
+      break;
+    
     default:
       my_friendly_abort (19990810);
       break;
@@ -2188,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;
@@ -2211,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
@@ -2231,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);
@@ -2363,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))
@@ -2381,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);
@@ -2403,11 +2419,6 @@ expand_body (fn)
   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.  */
-  function_name_declared_p = 1;
-
   /* Expand the body.  */
   expand_stmt (DECL_SAVED_TREE (fn));
 
@@ -2424,7 +2435,7 @@ expand_body (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)
@@ -2528,8 +2539,6 @@ static void
 genrtl_finish_function (fn)
      tree fn;
 {
-  int returns_null;
-  int returns_value;
   tree no_return_label = NULL_TREE;
 
 #if 0
@@ -2564,9 +2573,6 @@ genrtl_finish_function (fn)
       && ! DECL_NAME (DECL_RESULT (current_function_decl)))
     no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
 
-  if (flag_exceptions)
-    expand_exception_blocks ();
-
   /* If this function is supposed to return a value, ensure that
      we do not fall into the cleanups by mistake.  The end of our
      function will look like this:
@@ -2604,14 +2610,9 @@ genrtl_finish_function (fn)
       emit_label (cleanup_label);
     }
 
-  /* Get return value into register if that's where it's supposed to
-     be.  */
-  if (original_result_rtx)
-    fixup_result_decl (DECL_RESULT (fn), original_result_rtx);
-
   /* Finish building code that will trigger warnings if users forget
      to make their functions return values.  */
-  if (no_return_label || cleanup_label)
+  if (return_label)
     emit_jump (return_label);
   if (no_return_label)
     {
@@ -2630,14 +2631,6 @@ genrtl_finish_function (fn)
   /* Generate rtl for function exit.  */
   expand_function_end (input_filename, lineno, 1);
 
-  /* So we can tell if jump_optimize sets it to 1.  */
-  can_reach_end = 0;
-
-  /* Before we call rest_of_compilation (which will pop the
-     CURRENT_FUNCTION), we must save these values.  */
-  returns_null = current_function_returns_null;
-  returns_value = current_function_returns_value;
-
   /* If this is a nested function (like a template instantiation that
      we're compiling in the midst of compiling something else), push a
      new GC context.  That will keep local variables on the stack from
@@ -2646,6 +2639,10 @@ genrtl_finish_function (fn)
   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);
@@ -2684,46 +2681,56 @@ genrtl_finish_function (fn)
   if (DECL_STATIC_DESTRUCTOR (fn))
     static_dtors = tree_cons (NULL_TREE, fn, static_dtors);
 
-  if (DECL_NAME (DECL_RESULT (fn)))
-    returns_value |= can_reach_end;
-  else
-    returns_null |= can_reach_end;
-
-  if (TREE_THIS_VOLATILE (fn) && returns_null)
-    warning ("`noreturn' function does return");
-  else if (returns_null
-          && TREE_CODE (TREE_TYPE (TREE_TYPE (fn))) != VOID_TYPE)
-    {
-      /* Always complain if there's just no return statement.  */
-      if (!returns_value)
-       warning ("no return statement in function returning non-void");
-      else if (warn_return_type || pedantic)
-       /* If this function returns non-void and control can drop through,
-              complain.  */
-       warning ("control reaches end of non-void function");
-    }
-
   --function_depth;
 
-  if (!DECL_SAVED_INSNS (fn)
-      && !(flag_inline_trees && DECL_INLINE (fn)))
+  /* 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;
 
-      /* Stop pointing to the local nodes about to be freed.  */
-      /* But DECL_INITIAL must remain nonzero so we know this
-        was an actual function definition.  */
-      DECL_INITIAL (fn) = error_mark_node;
+      /* 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))
-       DECL_RTL (t) = DECL_INCOMING_RTL (t) = NULL_RTX;
-    }
+       {
+         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