cp-tree.h (struct lang_decl_inlined_fns): New.
[gcc.git] / gcc / cp / optimize.c
index 9863d4abfe1f683bed64832ea701ed635f416a85..9850c6ff9718f16636c9aec39c18c4fbc4e26ba9 100644 (file)
@@ -1,5 +1,5 @@
 /* Perform optimizations on tree structure.
-   Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
    Written by Mark Michell (mark@codesourcery.com).
 
 This file is part of GNU CC.
@@ -28,6 +28,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "input.h"
 #include "integrate.h"
 #include "varray.h"
+#include "ggc.h"
 
 /* To Do:
 
@@ -60,6 +61,10 @@ typedef struct inline_data
   /* Nonzero if we are currently within the cleanup for a
      TARGET_EXPR.  */
   int in_target_cleanup_p;
+  /* A stack of the TARGET_EXPRs that we are currently processing.  */
+  varray_type target_exprs;
+  /* A list of the functions current function has inlined.  */
+  varray_type inlined_fns;
 } inline_data;
 
 /* Prototypes.  */
@@ -107,8 +112,8 @@ remap_decl (decl, id)
       /* The decl T could be a dynamic array or other variable size type,
         in which case some fields need to be remapped because they may
         contain SAVE_EXPRs.  */
-      walk_tree (&DECL_SIZE (t), copy_body_r, id);
-      walk_tree (&DECL_SIZE_UNIT (t), copy_body_r, id);
+      walk_tree (&DECL_SIZE (t), copy_body_r, id, NULL);
+      walk_tree (&DECL_SIZE_UNIT (t), copy_body_r, id, NULL);
       if (TREE_TYPE (t) && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE
          && TYPE_DOMAIN (TREE_TYPE (t)))
        {
@@ -116,7 +121,7 @@ remap_decl (decl, id)
          TYPE_DOMAIN (TREE_TYPE (t)) 
            = copy_node (TYPE_DOMAIN (TREE_TYPE (t)));
          walk_tree (&TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (t))),
-                    copy_body_r, id);
+                    copy_body_r, id, NULL);
        }
 
       /* Remember it, so that if we encounter this local entity
@@ -159,7 +164,6 @@ remap_block (scope_stmt, decls, id)
       tree old_block;
       tree new_block;
       tree old_var;
-      tree *first_block;
       tree fn;
 
       /* Make the new block.  */
@@ -193,16 +197,24 @@ remap_block (scope_stmt, decls, id)
        }
       /* We put the BLOCK_VARS in reverse order; fix that now.  */
       BLOCK_VARS (new_block) = nreverse (BLOCK_VARS (new_block));
-      /* Attach this new block after the DECL_INITIAL block for the
-        function into which this block is being inlined.  In
-        rest_of_compilation we will straighten out the BLOCK tree.  */
       fn = VARRAY_TREE (id->fns, 0);
-      if (DECL_INITIAL (fn))
-       first_block = &BLOCK_CHAIN (DECL_INITIAL (fn));
+      if (fn == current_function_decl)
+       /* We're building a clone; DECL_INITIAL is still error_mark_node, and
+          current_binding_level is the parm binding level.  */
+       insert_block (new_block);
       else
-       first_block = &DECL_INITIAL (fn);
-      BLOCK_CHAIN (new_block) = *first_block;
-      *first_block = new_block;
+       {
+         /* Attach this new block after the DECL_INITIAL block for the
+            function into which this block is being inlined.  In
+            rest_of_compilation we will straighten out the BLOCK tree.  */
+         tree *first_block;
+         if (DECL_INITIAL (fn))
+           first_block = &BLOCK_CHAIN (DECL_INITIAL (fn));
+         else
+           first_block = &DECL_INITIAL (fn);
+         BLOCK_CHAIN (new_block) = *first_block;
+         *first_block = new_block;
+       }
       /* Remember the remapped block.  */
       splay_tree_insert (id->decl_map,
                         (splay_tree_key) old_block,
@@ -277,7 +289,7 @@ copy_body_r (tp, walk_subtrees, data)
       tree goto_stmt;
 
       /* Build the GOTO_STMT.  */
-      goto_stmt = build_min_nt (GOTO_STMT, id->ret_label);
+      goto_stmt = build_stmt (GOTO_STMT, id->ret_label);
       TREE_CHAIN (goto_stmt) = TREE_CHAIN (return_stmt);
 
       /* If we're returning something, just turn that into an
@@ -285,8 +297,9 @@ copy_body_r (tp, walk_subtrees, data)
         RESULT_DECL.  */
       if (RETURN_EXPR (return_stmt))
        {
-         *tp = build_min_nt (EXPR_STMT, 
-                             RETURN_EXPR (return_stmt));
+         *tp = build_stmt (EXPR_STMT, 
+                           RETURN_EXPR (return_stmt));
+         STMT_IS_FULL_EXPR_P (*tp) = 1;
          /* And then jump to the end of the function.  */
          TREE_CHAIN (*tp) = goto_stmt;
        }
@@ -316,6 +329,7 @@ copy_body_r (tp, walk_subtrees, data)
     remap_save_expr (tp, id->decl_map, VARRAY_TREE (id->fns, 0), 
                     walk_subtrees);
   else if (TREE_CODE (*tp) == UNSAVE_EXPR)
+    /* UNSAVE_EXPRs should not be generated until expansion time.  */
     my_friendly_abort (19991113);
   /* For a SCOPE_STMT, we must copy the associated block so that we
      can write out debugging information for the inlined variables.  */
@@ -334,10 +348,26 @@ copy_body_r (tp, walk_subtrees, data)
          TREE_OPERAND (*tp, 1) = TREE_OPERAND (*tp, 3);
          TREE_OPERAND (*tp, 3) = NULL_TREE;
        }
-      /* Similarly, if we're copying a CALL_EXPR, the RTL for the
-        result is no longer valid.  */
-      else if (TREE_CODE (*tp) == CALL_EXPR)
-       CALL_EXPR_RTL (*tp) = NULL_RTX;
+      else if (TREE_CODE (*tp) == MODIFY_EXPR
+              && TREE_OPERAND (*tp, 0) == TREE_OPERAND (*tp, 1)
+              && nonstatic_local_decl_p (TREE_OPERAND (*tp, 0))
+              && DECL_CONTEXT (TREE_OPERAND (*tp, 0)) == fn)
+       {
+         /* Some assignments VAR = VAR; don't generate any rtl code
+            and thus don't count as variable modification.  Avoid
+            keeping bogosities like 0 = 0.  */
+         tree decl = TREE_OPERAND (*tp, 0), value;
+         splay_tree_node n;
+
+         n = splay_tree_lookup (id->decl_map, (splay_tree_key) decl);
+         if (n)
+           {
+             value = (tree) n->value;
+             STRIP_TYPE_NOPS (value);
+             if (TREE_CONSTANT (value) || TREE_READONLY_DECL_P (value))
+               *tp = value;
+           }
+       }
     }
 
   /* Keep iterating.  */
@@ -354,7 +384,7 @@ copy_body (id)
   tree body;
 
   body = DECL_SAVED_TREE (VARRAY_TOP_TREE (id->fns));
-  walk_tree (&body, copy_body_r, id);
+  walk_tree (&body, copy_body_r, id, NULL);
 
   return body;
 }
@@ -392,7 +422,9 @@ initialize_inlined_parameters (id, args, fn)
       /* If the parameter is never assigned to, we may not need to
         create a new variable here at all.  Instead, we may be able
         to just use the argument value.  */
-      if (TREE_READONLY (p) && !TREE_SIDE_EFFECTS (value))
+      if (TREE_READONLY (p) 
+         && !TREE_ADDRESSABLE (p)
+         && !TREE_SIDE_EFFECTS (value))
        {
          /* Simplify the value, if possible.  */
          value = fold (decl_constant_value (value));
@@ -425,21 +457,30 @@ initialize_inlined_parameters (id, args, fn)
       splay_tree_insert (id->decl_map, 
                         (splay_tree_key) p,
                         (splay_tree_value) var);
+
+      /* Declare this new variable.  */
+      init_stmt = build_stmt (DECL_STMT, var);
+      TREE_CHAIN (init_stmt) = init_stmts;
+      init_stmts = init_stmt;
+
       /* Initialize this VAR_DECL from the equivalent argument.  If
         the argument is an object, created via a constructor or copy,
         this will not result in an extra copy: the TARGET_EXPR
         representing the argument will be bound to VAR, and the
         object will be constructed in VAR.  */
-      init_stmt = build_min_nt (EXPR_STMT,
-                               build (INIT_EXPR, TREE_TYPE (p),
-                                      var, value));
-      /* Declare this new variable.  Note that we do this *after* the
-        initialization because we are going to reverse all the
-        initialization statements below.  */
-      TREE_CHAIN (init_stmt) = build_min_nt (DECL_STMT, var);
-      /* Add this initialization to the list.  */
-      TREE_CHAIN (TREE_CHAIN (init_stmt)) = init_stmts;
-      init_stmts = init_stmt;
+      if (! TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (p)))
+       DECL_INITIAL (var) = value;
+      else
+       {
+         init_stmt = build_stmt (EXPR_STMT,
+                                 build (INIT_EXPR, TREE_TYPE (p),
+                                        var, value));
+         /* Add this initialization to the list.  Note that we want the
+            declaration *after* the initialization because we are going
+            to reverse all the initialization statements below.  */
+         TREE_CHAIN (init_stmt) = init_stmts;
+         init_stmts = init_stmt;
+       }
     }
 
   /* The initialization statements have been built up in reverse
@@ -460,18 +501,40 @@ declare_return_variable (id, use_stmt)
   tree fn = VARRAY_TOP_TREE (id->fns);
   tree result = DECL_RESULT (fn);
   tree var;
+  int aggregate_return_p;
 
   /* We don't need to do anything for functions that don't return
      anything.  */
-  if (!result || same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (result)), 
-                             void_type_node))
+  if (!result || VOID_TYPE_P (TREE_TYPE (result)))
     {
       *use_stmt = NULL_TREE;
       return NULL_TREE;
     }
 
-  /* Make an appropriate copy.  */
-  var = copy_decl_for_inlining (result, fn, VARRAY_TREE (id->fns, 0));
+  /* Figure out whether or not FN returns an aggregate.  */
+  aggregate_return_p = IS_AGGR_TYPE (TREE_TYPE (result));
+
+  /* If FN returns an aggregate then the caller will always create the
+     temporary (using a TARGET_EXPR) and the call will be the
+     initializing expression for the TARGET_EXPR.  If we were just to
+     create a new VAR_DECL here, then the result of this function
+     would be copied (bitwise) into the variable initialized by the
+     TARGET_EXPR.  That's incorrect, so we must transform any
+     references to the RESULT into references to the target.  */
+  if (aggregate_return_p)
+    {
+      my_friendly_assert (VARRAY_ACTIVE_SIZE (id->target_exprs) != 0,
+                         20000430);
+      var = TREE_OPERAND (VARRAY_TOP_TREE (id->target_exprs), 0);
+      my_friendly_assert 
+       (same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (var), 
+                                                   TREE_TYPE (result)),
+        20000430);
+    }
+  /* Otherwise, make an appropriate copy.  */
+  else
+    var = copy_decl_for_inlining (result, fn, VARRAY_TREE (id->fns, 0));
+
   /* Register the VAR_DECL as the equivalent for the RESULT_DECL; that
      way, when the RESULT_DECL is encountered, it will be
      automatically replaced by the VAR_DECL.  */
@@ -480,10 +543,16 @@ declare_return_variable (id, use_stmt)
                     (splay_tree_value) var);
 
   /* Build the USE_STMT.  */
-  *use_stmt = build_min_nt (EXPR_STMT, var);
-
-  /* Build the declaration statement.  */
-  return build_min_nt (DECL_STMT, var);
+  *use_stmt = build_stmt (EXPR_STMT, var);
+
+  /* Build the declaration statement if FN does not return an
+     aggregate.  */
+  if (!aggregate_return_p)
+    return build_stmt (DECL_STMT, var);
+  /* If FN does return an aggregate, there's no need to declare the
+     return variable; we're using a variable in our caller's frame.  */
+  else
+    return NULL_TREE;
 }
 
 /* Returns non-zero if FN is a function that can be inlined.  */
@@ -539,14 +608,23 @@ inlinable_function_p (fn, id)
     inlinable = 0;
 
   /* Don't do recursive inlining, either.  We don't record this in
-     DECL_UNLINABLE; we may be able to inline this function later.  */
+     DECL_UNINLINABLE; we may be able to inline this function later.  */
   if (inlinable)
     {
       size_t i;
 
-      for (i = 0; i < id->fns->elements_used; ++i)
+      for (i = 0; i < VARRAY_ACTIVE_SIZE (id->fns); ++i)
        if (VARRAY_TREE (id->fns, i) == fn)
-         inlinable = 0;
+         return 0;
+
+      if (inlinable && DECL_LANG_SPECIFIC (fn) && DECL_INLINED_FNS (fn))
+       {
+         struct lang_decl_inlined_fns *ifn = DECL_INLINED_FNS (fn);
+
+         for (i = 0; i < ifn->num_fns; ++i)
+           if (ifn->fns [i] == VARRAY_TREE (id->fns, 0))
+             return 0;
+       }
     }
 
   /* Return the result.  */
@@ -569,6 +647,7 @@ expand_call_inline (tp, walk_subtrees, data)
   tree scope_stmt;
   tree use_stmt;
   tree arg_inits;
+  tree *inlined_body;
   splay_tree st;
 
   /* See what we've got.  */
@@ -584,6 +663,9 @@ expand_call_inline (tp, walk_subtrees, data)
       /* We're walking our own subtrees.  */
       *walk_subtrees = 0;
 
+      /* Push *TP on the stack of pending TARGET_EXPRs.  */
+      VARRAY_PUSH_TREE (id->target_exprs, *tp);
+
       /* Actually walk over them.  This loop is the body of
         walk_trees, omitting the case where the TARGET_EXPR
         itself is handled.  */
@@ -591,14 +673,24 @@ expand_call_inline (tp, walk_subtrees, data)
        {
          if (i == 2)
            ++id->in_target_cleanup_p;
-         walk_tree (&TREE_OPERAND (*tp, i), expand_call_inline, data);
+         walk_tree (&TREE_OPERAND (*tp, i), expand_call_inline, data,
+                    NULL);
          if (i == 2)
            --id->in_target_cleanup_p;
        }
 
+      /* We're done with this TARGET_EXPR now.  */
+      VARRAY_POP (id->target_exprs);
+
       return NULL_TREE;
     }
 
+  if (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
+    /* Because types were not copied in copy_body, CALL_EXPRs beneath
+       them should not be expanded.  This can happen if the type is a
+       dynamic array type, for example.  */
+    *walk_subtrees = 0;
+
   /* From here on, we're only interested in CALL_EXPRs.  */
   if (TREE_CODE (t) != CALL_EXPR)
     return NULL_TREE;
@@ -648,6 +740,19 @@ expand_call_inline (tp, walk_subtrees, data)
      recursing into it.  */
   VARRAY_PUSH_TREE (id->fns, fn);
 
+  /* Record the function we are about to inline if optimize_function
+     has not been called on it yet and we don't have it in the list.  */
+  if (DECL_LANG_SPECIFIC (fn) && !DECL_INLINED_FNS (fn))
+    {
+      int i;
+
+      for (i = VARRAY_ACTIVE_SIZE (id->inlined_fns) - 1; i >= 0; i--)
+       if (VARRAY_TREE (id->inlined_fns, i) == fn)
+         break;
+      if (i < 0)
+       VARRAY_PUSH_TREE (id->inlined_fns, fn);
+    }
+
   /* Return statements in the function body will be replaced by jumps
      to the RET_LABEL.  */
   id->ret_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
@@ -656,7 +761,7 @@ expand_call_inline (tp, walk_subtrees, data)
   /* Create a block to put the parameters in.  We have to do this
      after the parameters have been remapped because remapping
      parameters is different from remapping ordinary variables.  */
-  scope_stmt = build_min_nt (SCOPE_STMT, DECL_INITIAL (fn));
+  scope_stmt = build_stmt (SCOPE_STMT, DECL_INITIAL (fn));
   SCOPE_BEGIN_P (scope_stmt) = 1;
   SCOPE_NO_CLEANUPS_P (scope_stmt) = 1;
   remap_block (scope_stmt, DECL_ARGUMENTS (fn), id);
@@ -675,11 +780,13 @@ expand_call_inline (tp, walk_subtrees, data)
   
   /* After we've initialized the parameters, we insert the body of the
      function itself.  */
-  STMT_EXPR_STMT (expr)
-    = chainon (STMT_EXPR_STMT (expr), copy_body (id));
+  inlined_body = &STMT_EXPR_STMT (expr);
+  while (*inlined_body)
+    inlined_body = &TREE_CHAIN (*inlined_body);
+  *inlined_body = copy_body (id);
 
   /* Close the block for the parameters.  */
-  scope_stmt = build_min_nt (SCOPE_STMT, DECL_INITIAL (fn));
+  scope_stmt = build_stmt (SCOPE_STMT, DECL_INITIAL (fn));
   SCOPE_NO_CLEANUPS_P (scope_stmt) = 1;
   my_friendly_assert (DECL_INITIAL (fn) 
                      && TREE_CODE (DECL_INITIAL (fn)) == BLOCK,
@@ -693,7 +800,7 @@ expand_call_inline (tp, walk_subtrees, data)
      may cause RTL to be generated.  */
   STMT_EXPR_STMT (expr)
     = chainon (STMT_EXPR_STMT (expr), 
-              build_min_nt (LABEL_STMT, id->ret_label));
+              build_stmt (LABEL_STMT, id->ret_label));
 
   /* Finally, mention the returned value so that the value of the
      statement-expression is the returned value of the function.  */
@@ -722,7 +829,7 @@ expand_call_inline (tp, walk_subtrees, data)
   TREE_USED (*tp) = 1;
 
   /* Recurse into the body of the just inlined function.  */
-  expand_calls_inline (tp, id);
+  expand_calls_inline (inlined_body, id);
   VARRAY_POP (id->fns);
 
   /* Don't walk into subtrees.  We've already handled them above.  */
@@ -742,7 +849,7 @@ expand_calls_inline (tp, id)
 {
   /* Search through *TP, replacing all calls to inline functions by
      appropriate equivalents.  */
-  walk_tree (tp, expand_call_inline, id);
+  walk_tree (tp, expand_call_inline, id, NULL);
 }
 
 /* Optimize the body of FN.  */
@@ -751,6 +858,17 @@ void
 optimize_function (fn)
      tree fn;
 {
+  /* While in this function, we may choose to go off and compile
+     another function.  For example, we might instantiate a function
+     in the hopes of inlining it.  Normally, that wouldn't trigger any
+     actual RTL code-generation -- but it will if the template is
+     actually needed.  (For example, if it's address is taken, or if
+     some other function already refers to the template.)  If
+     code-generation occurs, then garbage collection will occur, so we
+     must protect ourselves, just as we do while building up the body
+     of the function.  */
+  ++function_depth;
+
   /* Expand calls to inline functions.  */
   if (flag_inline_trees)
     {
@@ -778,13 +896,36 @@ optimize_function (fn)
            prev_fn = s->function_decl;
          }
 
+      /* Create the stack of TARGET_EXPRs.  */
+      VARRAY_TREE_INIT (id.target_exprs, 32, "target_exprs");
+
+      /* Create the list of functions this call will inline.  */
+      VARRAY_TREE_INIT (id.inlined_fns, 32, "inlined_fns");
+
       /* Replace all calls to inline functions with the bodies of those
         functions.  */
       expand_calls_inline (&DECL_SAVED_TREE (fn), &id);
 
       /* Clean up.  */
       VARRAY_FREE (id.fns);
+      VARRAY_FREE (id.target_exprs);
+      if (DECL_LANG_SPECIFIC (fn))
+       {
+         struct lang_decl_inlined_fns *ifn;
+
+         ifn = ggc_alloc (sizeof (struct lang_decl_inlined_fns)
+                          + (VARRAY_ACTIVE_SIZE (id.inlined_fns) - 1)
+                            * sizeof (tree));
+         ifn->num_fns = VARRAY_ACTIVE_SIZE (id.inlined_fns);
+         memcpy (&ifn->fns[0], &VARRAY_TREE (id.inlined_fns, 0),
+                 ifn->num_fns * sizeof (tree));
+         DECL_INLINED_FNS (fn) = ifn;
+       }
+      VARRAY_FREE (id.inlined_fns);
     }
+
+  /* Undo the call to ggc_push_context above.  */
+  --function_depth;
 }
 
 /* Called from calls_setjmp_p via walk_tree.  */
@@ -811,8 +952,9 @@ int
 calls_setjmp_p (fn)
      tree fn;
 {
-  return (walk_tree (&DECL_SAVED_TREE (fn), calls_setjmp_r, NULL) 
-         != NULL_TREE);
+  return walk_tree_without_duplicates (&DECL_SAVED_TREE (fn), 
+                                      calls_setjmp_r, 
+                                      NULL) != NULL_TREE;
 }
 
 /* FN is a function that has a complete body.  Clone the body as
@@ -826,15 +968,14 @@ maybe_clone_body (fn)
   inline_data id;
   tree clone;
 
-  /* We don't clone constructors and destructors under the old ABI.  */
-  if (!flag_new_abi)
-    return 0;
-
   /* We only clone constructors and destructors.  */
   if (!DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn)
       && !DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn))
     return 0;
 
+  /* Emit the DWARF1 abstract instance.  */
+  note_deferral_of_defined_inline_function (fn);
+
   /* We know that any clones immediately follow FN in the TYPE_METHODS
      list.  */
   for (clone = TREE_CHAIN (fn);
@@ -848,11 +989,20 @@ maybe_clone_body (fn)
       /* Update CLONE's source position information to match FN's.  */
       DECL_SOURCE_FILE (clone) = DECL_SOURCE_FILE (fn);
       DECL_SOURCE_LINE (clone) = DECL_SOURCE_LINE (fn);
+      DECL_INLINE (clone) = DECL_INLINE (fn);
+      DECL_THIS_INLINE (clone) = DECL_THIS_INLINE (fn);
+      DECL_COMDAT (clone) = DECL_COMDAT (fn);
+      DECL_WEAK (clone) = DECL_WEAK (fn);
+      DECL_ONE_ONLY (clone) = DECL_ONE_ONLY (fn);
+      DECL_SECTION_NAME (clone) = DECL_SECTION_NAME (fn);
+      DECL_USE_TEMPLATE (clone) = DECL_USE_TEMPLATE (fn);
+      DECL_EXTERNAL (clone) = DECL_EXTERNAL (fn);
+      DECL_INTERFACE_KNOWN (clone) = DECL_INTERFACE_KNOWN (fn);
+      DECL_NOT_REALLY_EXTERN (clone) = DECL_NOT_REALLY_EXTERN (fn);
 
       /* Start processing the function.  */
       push_to_top_level ();
       start_function (NULL_TREE, clone, NULL_TREE, SF_PRE_PARSED);
-      store_parm_decls ();
 
       /* Just clone the body, as if we were making an inline call.
         But, remap the parameters in the callee to the parameters of
@@ -880,12 +1030,35 @@ maybe_clone_body (fn)
              in_charge = in_charge_arg_for_name (DECL_NAME (clone));
              splay_tree_insert (id.decl_map,
                                 (splay_tree_key) parm,
-                                (splay_tree_key) in_charge);
+                                (splay_tree_value) in_charge);
+           }
+         else if (DECL_ARTIFICIAL (parm)
+                  && DECL_NAME (parm) == vtt_parm_identifier)
+           {
+             /* For a subobject constructor or destructor, the next
+                argument is the VTT parameter.  Remap the VTT_PARM
+                from the CLONE to this parameter.  */
+             if (DECL_HAS_VTT_PARM_P (clone))
+               {
+                 DECL_ABSTRACT_ORIGIN (clone_parm) = parm;
+                 splay_tree_insert (id.decl_map,
+                                    (splay_tree_key) parm,
+                                    (splay_tree_value) clone_parm);
+                 clone_parm = TREE_CHAIN (clone_parm);
+               }
+             /* Otherwise, map the VTT parameter to `NULL'.  */
+             else
+               {
+                 splay_tree_insert (id.decl_map,
+                                    (splay_tree_key) parm,
+                                    (splay_tree_value) null_pointer_node);
+               }
            }
          /* Map other parameters to their equivalents in the cloned
             function.  */
          else
            {
+             DECL_ABSTRACT_ORIGIN (clone_parm) = parm;
              splay_tree_insert (id.decl_map,
                                 (splay_tree_key) parm,
                                 (splay_tree_value) clone_parm);
@@ -901,8 +1074,10 @@ maybe_clone_body (fn)
       VARRAY_FREE (id.fns);
 
       /* Now, expand this function into RTL, if appropriate.  */
-      current_function_name_declared = 1;
-      expand_body (finish_function (0));
+      function_name_declared_p = 1;
+      finish_function (0);
+      BLOCK_ABSTRACT_ORIGIN (DECL_INITIAL (clone)) = DECL_INITIAL (fn);
+      expand_body (clone);
       pop_from_top_level ();
     }