public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* PATCH: avoid constructing temporary arglists in C and C++ front ends
@ 2007-02-17  6:06 Sandra Loosemore
  2007-02-26 22:37 ` Joseph S. Myers
  2007-02-27 15:53 ` Nathan Sidwell
  0 siblings, 2 replies; 4+ messages in thread
From: Sandra Loosemore @ 2007-02-17  6:06 UTC (permalink / raw)
  To: GCC Patches

[-- Attachment #1: Type: text/plain, Size: 1648 bytes --]

This is the second of the two remaining CALL-EXPR related patches I'm bringing 
over from the LTO branch.  The previous version from last August is at
http://gcc.gnu.org/ml/gcc-patches/2006-08/msg00443.html .

The problem this patch addresses is that, as things stand now, both the C and 
C++ front ends take the list of argument expressions built by the parser and 
copy its list structure during the process of type conversion on the argument 
values.  This second list used to be stored in the CALL_EXPR object, but now 
it's simply discarded.  So, for more efficient memory use, we'd like the 
argument conversion to use some stack-allocated scratch memory instead.

This patch consists of three main chunks of changes.  The first chunk changes 
some of the high-level constructor functions in fold-const.c and builtins.c 
(groan!) to work off an argument array instead of a list.  The second chunk 
changes build_function_call in c-typeck.c to alloca an array which eventually 
gets passed to those constructors, and propagates the change in representation 
around to the various other helper functions it invokes.  The third chunk makes 
similar changes to the C++ front end, which has a somewhat larger set of related 
call-processing-and-construction functions.

I expect folks will probably have comments and suggestions on how to improve 
this patch.  Unlike most of the changes in the CALL_EXPR megapatch, which were 
mostly localized and/or mechanical, this one involves more actual code 
restructuring.

As far as testing goes, I've done an incremental build and test on x86_64 so far 
and have a full bootstrap in progress.

-Sandra


[-- Attachment #2: frontends.log --]
[-- Type: text/x-log, Size: 2292 bytes --]

2007-02-16  Sandra Loosemore  <sandra@codesourcery.com>

	* gcc/builtins.c (fold_builtin_call_list, fold_builtin_call_valist):
	Delete, and replace with...
	(fold_builtin_call_array): This.  Update callers to use it.
	* gcc/fold-const.c (fold_build_call_list): Delete, and replace with...
	(fold_build_call_array): This.
	(fold_build_call_list_initializer): Delete, and replace with...
	(fold_build_call_array_initializer): This.
	* gcc/tree.h: Update declarations to reflect above changes.

	* gcc/c-typeck.c (build_function_call): Store converted arguments
	in a stack-allocated array instead of building a list.
	(convert_arguments): Store arguments in the array passed in as an
	argument, and return the actual number of arguments.
	* gcc/c-format.c: (check_function_format): Pass arguments in an
	array instead of a list.
	* gcc/c-common.c (check_function_nonnull): Likewise.
	(check_function_sentinel): Likewise.
	(check_function_arguments): Likewise.
	* gcc/c-common.h: Update declarations to reflect above changes.

	* gcc/cp/typeck.c (build_function_call): Store converted arguments
	in a stack-allocated array instead of building a list.
	(convert_arguments): Store arguments in the array passed in as an
	argument, and return the actual number of arguments.
	* gcc/cp/call.c (build_call): Delete, and replace with...
	(build_call_n, build_call_a): New.
	(build_op_delete_call): Rewrite to avoid constructing argument lists.
	(build_over_call): Store converted arguments in a stack-allocated
	array instead of building a list.
	(build_cxx_call): Pass arguments in an array instead of as a list.
	(build_java_interface_fn_ref): Rewrite to avoid constructing
	argument lists.
	* gcc/cp/tree.h: Update declarations to reflect above changes.
	* gcc/cp/method.c (use_thunk): Use a stack-allocated array to hold
	the arguments instead of a list.
	* gcc/cp/rtti.c (throw_bad_cast): Update call to cxx_call.
	(throw_bad_typeid): Likewise.
	(build_dynamic_cast_1): Likewise.
	* gcc/cp/init.c (build_builtin_delete_call): Use build_call_n.
	* gcc/cp/decl.c (expand_static_init): Likewise.
	* gcc/cp/except.c (cp_protect_cleanup_actions): Likewise.
	* gcc/cp/cp-gimplify.c (genericize_eh_spec_block): Likewise.
	(gimplify_must_not_throw_expr): Likewise.
	(cxx_omp_apply_fn): Use build_call_a.

[-- Attachment #3: frontends.patch --]
[-- Type: text/x-patch, Size: 74902 bytes --]

Index: gcc/builtins.c
===================================================================
*** gcc/builtins.c	(revision 122018)
--- gcc/builtins.c	(working copy)
*************** build_function_call_expr (tree fndecl, t
*** 9835,9890 ****
  {
    tree fntype = TREE_TYPE (fndecl);
    tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
!   return fold_builtin_call_list (TREE_TYPE (fntype), fn, arglist);
! }
! 
! /* Construct a CALL_EXPR with type TYPE with FN as the function expression.
!    ARGLIST is a TREE_LIST of arguments.  */
! 
! tree
! fold_builtin_call_list (tree type, tree fn, tree arglist)
! {
!   tree ret = NULL_TREE;
!   if (TREE_CODE (fn) == ADDR_EXPR)
!     {
!       tree fndecl = TREE_OPERAND (fn, 0);
!       if (TREE_CODE (fndecl) == FUNCTION_DECL
! 	  && DECL_BUILT_IN (fndecl))
! 	{
! 	  /* FIXME: Don't use a list in this interface.  */
! 	  if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
! 	    {
! 	      ret = targetm.fold_builtin (fndecl, arglist, false);
! 	      if (ret)
! 		return ret;
! 	    }
! 	  else
! 	    {
! 	      tree tail = arglist;
! 	      tree args[MAX_ARGS_TO_FOLD_BUILTIN];
! 	      int nargs;
! 	      tree exp;
! 
! 	      for (nargs = 0; nargs < MAX_ARGS_TO_FOLD_BUILTIN; nargs++)
! 		{
! 		  if (!tail)
! 		    break;
! 		  args[nargs] = TREE_VALUE (tail);
! 		  tail = TREE_CHAIN (tail);
! 		}
! 	      if (nargs <= MAX_ARGS_TO_FOLD_BUILTIN)
! 		{
! 		  ret = fold_builtin_n (fndecl, args, nargs, false);
! 		  if (ret)
! 		    return ret;
! 		}
! 	      exp = build_call_list (type, fn, arglist);
! 	      ret = fold_builtin_varargs (fndecl, exp, false);
! 	      return ret ? ret : exp;
! 	    }
! 	}
!     }
!   return build_call_list (type, fn, arglist);
  }
  
  /* Conveniently construct a function call expression.  FNDECL names the
--- 9835,9847 ----
  {
    tree fntype = TREE_TYPE (fndecl);
    tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
!   int n = list_length (arglist);
!   tree *argarray = (tree *) alloca (n * sizeof (tree));
!   int i;
!   
!   for (i = 0; i < n; i++, arglist = TREE_CHAIN (arglist))
!     argarray[i] = TREE_VALUE (arglist);
!   return fold_builtin_call_array (TREE_TYPE (fntype), fn, n, argarray);
  }
  
  /* Conveniently construct a function call expression.  FNDECL names the
*************** tree
*** 9895,9918 ****
  build_call_expr (tree fndecl, int n, ...)
  {
    va_list ap;
-   tree ret;
    tree fntype = TREE_TYPE (fndecl);
    tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
  
    va_start (ap, n);
!   ret = fold_builtin_call_valist (TREE_TYPE (fntype), fn, n, ap);
    va_end (ap);
!   return ret;
  }
  
  /* Construct a CALL_EXPR with type TYPE with FN as the function expression.
!    N arguments are passed in the va_list AP.  */
  
  tree
! fold_builtin_call_valist (tree type,
! 			  tree fn,
! 			  int n,
! 			  va_list ap)
  {
    tree ret = NULL_TREE;
    int i;
--- 9852,9877 ----
  build_call_expr (tree fndecl, int n, ...)
  {
    va_list ap;
    tree fntype = TREE_TYPE (fndecl);
    tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
+   tree *argarray = (tree *) alloca (n * sizeof (tree));
+   int i;
  
    va_start (ap, n);
!   for (i = 0; i < n; i++)
!     argarray[i] = va_arg (ap, tree);
    va_end (ap);
!   return fold_builtin_call_array (TREE_TYPE (fntype), fn, n, argarray);
  }
  
  /* Construct a CALL_EXPR with type TYPE with FN as the function expression.
!    N arguments are passed in the array ARGARRAY.  */
  
  tree
! fold_builtin_call_array (tree type,
! 			 tree fn,
! 			 int n,
! 			 tree *argarray)
  {
    tree ret = NULL_TREE;
    int i;
*************** fold_builtin_call_valist (tree type,
*** 9927,9941 ****
          if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
            {
              tree arglist = NULL_TREE;
!             va_list ap0;
!             va_copy (ap0, ap);
!             for (i = 0; i < n; i++)
!               {
!                 tree arg = va_arg (ap0, tree);
!                 arglist = tree_cons (NULL_TREE, arg, arglist);
! 	       }
!             va_end (ap0);
!             arglist = nreverse (arglist);
              ret = targetm.fold_builtin (fndecl, arglist, false);
              if (ret)
                return ret;
--- 9886,9893 ----
          if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
            {
              tree arglist = NULL_TREE;
! 	    for (i = n - 1; i >= 0; i--)
! 	      arglist = tree_cons (NULL_TREE, argarray[i], arglist);
              ret = targetm.fold_builtin (fndecl, arglist, false);
              if (ret)
                return ret;
*************** fold_builtin_call_valist (tree type,
*** 9944,9968 ****
            {
              /* First try the transformations that don't require consing up
                 an exp.  */
!             tree args[MAX_ARGS_TO_FOLD_BUILTIN];
!             va_list ap0;
!             va_copy (ap0, ap);
!             for (i = 0; i < n; i++)
!               args[i] = va_arg (ap0, tree);
!             va_end (ap0);
!             ret = fold_builtin_n (fndecl, args, n, false);
              if (ret)
                return ret;
            }
  
          /* If we got this far, we need to build an exp.  */
!         exp = build_call_valist (type, fn, n, ap);
          ret = fold_builtin_varargs (fndecl, exp, false);
          return ret ? ret : exp;
        }
    }
  
!   return build_call_valist (type, fn, n, ap);
  }
  
  /* Construct a new CALL_EXPR using the tail of the argument list of EXP
--- 9896,9914 ----
            {
              /* First try the transformations that don't require consing up
                 an exp.  */
!             ret = fold_builtin_n (fndecl, argarray, n, false);
              if (ret)
                return ret;
            }
  
          /* If we got this far, we need to build an exp.  */
!         exp = build_call_array (type, fn, n, argarray);
          ret = fold_builtin_varargs (fndecl, exp, false);
          return ret ? ret : exp;
        }
    }
  
!   return build_call_array (type, fn, n, argarray);
  }
  
  /* Construct a new CALL_EXPR using the tail of the argument list of EXP
Index: gcc/fold-const.c
===================================================================
*** gcc/fold-const.c	(revision 122018)
--- gcc/fold-const.c	(working copy)
*************** fold_build3_stat (enum tree_code code, t
*** 12827,12839 ****
    return tem;
  }
  
! /* Fold a CALL_EXPR expression of type TYPE with operands FN and ARGLIST
!    and a null static chain.
     Return a folded expression if successful.  Otherwise, return a CALL_EXPR
!    of type TYPE from the given operands as constructed by build_call_list.  */
  
  tree
! fold_build_call_list (tree type, tree fn, tree arglist)
  {
    tree tem;
  #ifdef ENABLE_FOLD_CHECKING
--- 12827,12839 ----
    return tem;
  }
  
! /* Fold a CALL_EXPR expression of type TYPE with operands FN and NARGS
!    arguments in ARGARRAY, and a null static chain.
     Return a folded expression if successful.  Otherwise, return a CALL_EXPR
!    of type TYPE from the given operands as constructed by build_call_array.  */
  
  tree
! fold_build_call_array (tree type, tree fn, int nargs, tree *argarray)
  {
    tree tem;
  #ifdef ENABLE_FOLD_CHECKING
*************** fold_build_call_list (tree type, tree fn
*** 12843,12848 ****
--- 12843,12849 ----
  		checksum_after_arglist[16];
    struct md5_ctx ctx;
    htab_t ht;
+   int i;
  
    ht = htab_create (32, htab_hash_pointer, htab_eq_pointer, NULL);
    md5_init_ctx (&ctx);
*************** fold_build_call_list (tree type, tree fn
*** 12851,12862 ****
    htab_empty (ht);
  
    md5_init_ctx (&ctx);
!   fold_checksum_tree (arglist, &ctx, ht);
    md5_finish_ctx (&ctx, checksum_before_arglist);
    htab_empty (ht);
  #endif
  
!   tem = fold_builtin_call_list (type, fn, arglist);
        
  #ifdef ENABLE_FOLD_CHECKING
    md5_init_ctx (&ctx);
--- 12852,12864 ----
    htab_empty (ht);
  
    md5_init_ctx (&ctx);
!   for (i = 0; i < nargs; i++)
!     fold_checksum_tree (argarray[i], &ctx, ht);
    md5_finish_ctx (&ctx, checksum_before_arglist);
    htab_empty (ht);
  #endif
  
!   tem = fold_builtin_call_array (type, fn, nargs, argarray);
        
  #ifdef ENABLE_FOLD_CHECKING
    md5_init_ctx (&ctx);
*************** fold_build_call_list (tree type, tree fn
*** 12868,12879 ****
      fold_check_failed (fn, tem);
    
    md5_init_ctx (&ctx);
!   fold_checksum_tree (arglist, &ctx, ht);
    md5_finish_ctx (&ctx, checksum_after_arglist);
    htab_delete (ht);
  
    if (memcmp (checksum_before_arglist, checksum_after_arglist, 16))
!     fold_check_failed (arglist, tem);
  #endif
    return tem;
  }
--- 12870,12882 ----
      fold_check_failed (fn, tem);
    
    md5_init_ctx (&ctx);
!   for (i = 0; i < nargs; i++)
!     fold_checksum_tree (argarray[i], &ctx, ht);
    md5_finish_ctx (&ctx, checksum_after_arglist);
    htab_delete (ht);
  
    if (memcmp (checksum_before_arglist, checksum_after_arglist, 16))
!     fold_check_failed (NULL_TREE, tem);
  #endif
    return tem;
  }
*************** fold_build3_initializer (enum tree_code 
*** 12939,12950 ****
  }
  
  tree
! fold_build_call_list_initializer (tree type, tree fn, tree arglist)
  {
    tree result;
    START_FOLD_INIT;
  
!   result = fold_build_call_list (type, fn, arglist);
  
    END_FOLD_INIT;
    return result;
--- 12942,12954 ----
  }
  
  tree
! fold_build_call_array_initializer (tree type, tree fn,
! 				   int nargs, tree *argarray)
  {
    tree result;
    START_FOLD_INIT;
  
!   result = fold_build_call_array (type, fn, nargs, argarray);
  
    END_FOLD_INIT;
    return result;
Index: gcc/tree.h
===================================================================
*** gcc/tree.h	(revision 122018)
--- gcc/tree.h	(working copy)
*************** extern tree fold_build3_stat (enum tree_
*** 4376,4383 ****
  extern tree fold_build1_initializer (enum tree_code, tree, tree);
  extern tree fold_build2_initializer (enum tree_code, tree, tree, tree);
  extern tree fold_build3_initializer (enum tree_code, tree, tree, tree, tree);
! extern tree fold_build_call_list (tree, tree, tree);
! extern tree fold_build_call_list_initializer (tree, tree, tree);
  extern tree fold_convert (tree, tree);
  extern tree fold_single_bit_test (enum tree_code, tree, tree, tree);
  extern tree fold_ignored_result (tree);
--- 4376,4383 ----
  extern tree fold_build1_initializer (enum tree_code, tree, tree);
  extern tree fold_build2_initializer (enum tree_code, tree, tree, tree);
  extern tree fold_build3_initializer (enum tree_code, tree, tree, tree, tree);
! extern tree fold_build_call_array (tree, tree, int, tree *);
! extern tree fold_build_call_array_initializer (tree, tree, int, tree *);
  extern tree fold_convert (tree, tree);
  extern tree fold_single_bit_test (enum tree_code, tree, tree, tree);
  extern tree fold_ignored_result (tree);
*************** extern bool fold_builtin_next_arg (tree,
*** 4476,4483 ****
  extern enum built_in_function builtin_mathfn_code (tree);
  extern tree build_function_call_expr (tree, tree);
  extern tree fold_build_call_expr (tree, tree, tree, tree);
! extern tree fold_builtin_call_list (tree, tree, tree);
! extern tree fold_builtin_call_valist (tree, tree, int, va_list);
  extern tree build_call_expr (tree, int, ...);
  extern tree mathfn_built_in (tree, enum built_in_function fn);
  extern tree strip_float_extensions (tree);
--- 4476,4482 ----
  extern enum built_in_function builtin_mathfn_code (tree);
  extern tree build_function_call_expr (tree, tree);
  extern tree fold_build_call_expr (tree, tree, tree, tree);
! extern tree fold_builtin_call_array (tree, tree, int, tree *);
  extern tree build_call_expr (tree, int, ...);
  extern tree mathfn_built_in (tree, enum built_in_function fn);
  extern tree strip_float_extensions (tree);
Index: gcc/c-typeck.c
===================================================================
*** gcc/c-typeck.c	(revision 122018)
--- gcc/c-typeck.c	(working copy)
*************** static int function_types_compatible_p (
*** 83,89 ****
  static int type_lists_compatible_p (tree, tree);
  static tree decl_constant_value_for_broken_optimization (tree);
  static tree lookup_field (tree, tree);
! static tree convert_arguments (tree, tree, tree, tree);
  static tree pointer_diff (tree, tree);
  static tree convert_for_assignment (tree, tree, enum impl_conv, tree, tree,
  				    int);
--- 83,89 ----
  static int type_lists_compatible_p (tree, tree);
  static tree decl_constant_value_for_broken_optimization (tree);
  static tree lookup_field (tree, tree);
! static int convert_arguments (int, tree *, tree, tree, tree, tree);
  static tree pointer_diff (tree, tree);
  static tree convert_for_assignment (tree, tree, enum impl_conv, tree, tree,
  				    int);
*************** tree
*** 2228,2236 ****
  build_function_call (tree function, tree params)
  {
    tree fntype, fundecl = 0;
-   tree coerced_params;
    tree name = NULL_TREE, result;
    tree tem;
  
    /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue.  */
    STRIP_TYPE_NOPS (function);
--- 2228,2238 ----
  build_function_call (tree function, tree params)
  {
    tree fntype, fundecl = 0;
    tree name = NULL_TREE, result;
    tree tem;
+   int nargs;
+   tree *argarray;
+   
  
    /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue.  */
    STRIP_TYPE_NOPS (function);
*************** build_function_call (tree function, tree
*** 2317,2346 ****
    /* Convert the parameters to the types declared in the
       function prototype, or apply default promotions.  */
  
!   coerced_params
!     = convert_arguments (TYPE_ARG_TYPES (fntype), params, function, fundecl);
! 
!   if (coerced_params == error_mark_node)
      return error_mark_node;
  
    /* Check that the arguments to the function are valid.  */
  
!   check_function_arguments (TYPE_ATTRIBUTES (fntype), coerced_params,
  			    TYPE_ARG_TYPES (fntype));
  
    if (require_constant_value)
      {
!       result = fold_build_call_list_initializer (TREE_TYPE (fntype),
! 						 function,
! 						 coerced_params);
        if (TREE_CONSTANT (result)
  	  && (name == NULL_TREE
  	      || strncmp (IDENTIFIER_POINTER (name), "__builtin_", 10) != 0))
  	pedwarn_init ("initializer element is not constant");
      }
    else
!     result = fold_build_call_list (TREE_TYPE (fntype),
! 				   function, coerced_params);
  
    if (VOID_TYPE_P (TREE_TYPE (result)))
      return result;
--- 2319,2348 ----
    /* Convert the parameters to the types declared in the
       function prototype, or apply default promotions.  */
  
!   nargs = list_length (params);
!   argarray = (tree *) alloca (nargs * sizeof (tree));
!   nargs = convert_arguments (nargs, argarray, TYPE_ARG_TYPES (fntype), 
! 			     params, function, fundecl);
!   if (nargs < 0)
      return error_mark_node;
  
    /* Check that the arguments to the function are valid.  */
  
!   check_function_arguments (TYPE_ATTRIBUTES (fntype), nargs, argarray,
  			    TYPE_ARG_TYPES (fntype));
  
    if (require_constant_value)
      {
!       result = fold_build_call_array_initializer (TREE_TYPE (fntype),
! 						  function, nargs, argarray);
        if (TREE_CONSTANT (result)
  	  && (name == NULL_TREE
  	      || strncmp (IDENTIFIER_POINTER (name), "__builtin_", 10) != 0))
  	pedwarn_init ("initializer element is not constant");
      }
    else
!     result = fold_build_call_array (TREE_TYPE (fntype),
! 				    function, nargs, argarray);
  
    if (VOID_TYPE_P (TREE_TYPE (result)))
      return result;
*************** build_function_call (tree function, tree
*** 2348,2356 ****
  }
  \f
  /* Convert the argument expressions in the list VALUES
!    to the types in the list TYPELIST.  The result is a list of converted
!    argument expressions, unless there are too few arguments in which
!    case it is error_mark_node.
  
     If TYPELIST is exhausted, or when an element has NULL as its type,
     perform the default conversions.
--- 2350,2357 ----
  }
  \f
  /* Convert the argument expressions in the list VALUES
!    to the types in the list TYPELIST.  The resulting arguments are
!    stored in the array ARGARRAY which has size NARGS.
  
     If TYPELIST is exhausted, or when an element has NULL as its type,
     perform the default conversions.
*************** build_function_call (tree function, tree
*** 2364,2377 ****
  
     This is also where warnings about wrong number of args are generated.
  
!    Both VALUES and the returned value are chains of TREE_LIST nodes
!    with the elements of the list in the TREE_VALUE slots of those nodes.  */
  
! static tree
! convert_arguments (tree typelist, tree values, tree function, tree fundecl)
  {
    tree typetail, valtail;
-   tree result = NULL;
    int parmnum;
    tree selector;
  
--- 2365,2381 ----
  
     This is also where warnings about wrong number of args are generated.
  
!    VALUES is a chain of TREE_LIST nodes with the elements of the list
!    in the TREE_VALUE slots of those nodes.
  
!    Returns the actual number of arguments processed (which may be less
!    than NARGS in some error situations), or -1 on failure.  */
! 
! static int
! convert_arguments (int nargs, tree *argarray,
! 		   tree typelist, tree values, tree function, tree fundecl)
  {
    tree typetail, valtail;
    int parmnum;
    tree selector;
  
*************** convert_arguments (tree typelist, tree v
*** 2385,2391 ****
    selector = objc_message_selector ();
  
    /* Scan the given expressions and types, producing individual
!      converted arguments and pushing them on RESULT in reverse order.  */
  
    for (valtail = values, typetail = typelist, parmnum = 0;
         valtail;
--- 2389,2395 ----
    selector = objc_message_selector ();
  
    /* Scan the given expressions and types, producing individual
!      converted arguments and storing them in ARGARRAY.  */
  
    for (valtail = values, typetail = typelist, parmnum = 0;
         valtail;
*************** convert_arguments (tree typelist, tree v
*** 2400,2406 ****
        if (type == void_type_node)
  	{
  	  error ("too many arguments to function %qE", function);
! 	  break;
  	}
  
        if (selector && argnum > 2)
--- 2404,2410 ----
        if (type == void_type_node)
  	{
  	  error ("too many arguments to function %qE", function);
! 	  return parmnum;
  	}
  
        if (selector && argnum > 2)
*************** convert_arguments (tree typelist, tree v
*** 2558,2592 ****
  		  && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
  		parmval = default_conversion (parmval);
  	    }
! 	  result = tree_cons (NULL_TREE, parmval, result);
  	}
        else if (TREE_CODE (TREE_TYPE (val)) == REAL_TYPE
  	       && (TYPE_PRECISION (TREE_TYPE (val))
  		   < TYPE_PRECISION (double_type_node))
  	       && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (val))))
  	/* Convert `float' to `double'.  */
! 	result = tree_cons (NULL_TREE, convert (double_type_node, val), result);
        else if ((invalid_func_diag =
  		targetm.calls.invalid_arg_for_unprototyped_fn (typelist, fundecl, val)))
  	{
  	  error (invalid_func_diag);
! 	  return error_mark_node;
  	}
        else
  	/* Convert `short' and `char' to full-size `int'.  */
! 	result = tree_cons (NULL_TREE, default_conversion (val), result);
  
        if (typetail)
  	typetail = TREE_CHAIN (typetail);
      }
  
    if (typetail != 0 && TREE_VALUE (typetail) != void_type_node)
      {
        error ("too few arguments to function %qE", function);
!       return error_mark_node;
      }
  
!   return nreverse (result);
  }
  \f
  /* This is the entry point used by the parser to build unary operators
--- 2562,2598 ----
  		  && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
  		parmval = default_conversion (parmval);
  	    }
! 	  argarray[parmnum] = parmval;
  	}
        else if (TREE_CODE (TREE_TYPE (val)) == REAL_TYPE
  	       && (TYPE_PRECISION (TREE_TYPE (val))
  		   < TYPE_PRECISION (double_type_node))
  	       && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (val))))
  	/* Convert `float' to `double'.  */
! 	argarray[parmnum] = convert (double_type_node, val);
        else if ((invalid_func_diag =
  		targetm.calls.invalid_arg_for_unprototyped_fn (typelist, fundecl, val)))
  	{
  	  error (invalid_func_diag);
! 	  return -1;
  	}
        else
  	/* Convert `short' and `char' to full-size `int'.  */
! 	argarray[parmnum] = default_conversion (val);
  
        if (typetail)
  	typetail = TREE_CHAIN (typetail);
      }
  
+   gcc_assert (parmnum == nargs);
+ 
    if (typetail != 0 && TREE_VALUE (typetail) != void_type_node)
      {
        error ("too few arguments to function %qE", function);
!       return -1;
      }
  
!   return parmnum;
  }
  \f
  /* This is the entry point used by the parser to build unary operators
Index: gcc/c-format.c
===================================================================
*** gcc/c-format.c	(revision 122017)
--- gcc/c-format.c	(working copy)
*************** decode_format_type (const char *s)
*** 851,863 ****
  
  \f
  /* Check the argument list of a call to printf, scanf, etc.
!    ATTRS are the attributes on the function type.
!    PARAMS is the list of argument values.  Also, if -Wmissing-format-attribute,
     warn for calls to vprintf or vscanf in functions with no such format
     attribute themselves.  */
  
  void
! check_function_format (tree attrs, tree params)
  {
    tree a;
  
--- 851,864 ----
  
  \f
  /* Check the argument list of a call to printf, scanf, etc.
!    ATTRS are the attributes on the function type.  There are NARGS argument
!    values in the array ARGARRAY.
!    Also, if -Wmissing-format-attribute,
     warn for calls to vprintf or vscanf in functions with no such format
     attribute themselves.  */
  
  void
! check_function_format (tree attrs, int nargs, tree *argarray)
  {
    tree a;
  
*************** check_function_format (tree attrs, tree 
*** 870,876 ****
  	  function_format_info info;
  	  decode_format_attr (TREE_VALUE (a), &info, 1);
  	  if (warn_format)
! 	    check_format_info (&info, params);
  	  if (warn_missing_format_attribute && info.first_arg_num == 0
  	      && (format_types[info.format_type].flags
  		  & (int) FMT_FLAG_ARG_CONVERT))
--- 871,886 ----
  	  function_format_info info;
  	  decode_format_attr (TREE_VALUE (a), &info, 1);
  	  if (warn_format)
! 	    {
! 	      /* FIXME: Rewrite all the internal functions in this file
! 		 to use the ARGARRAY directly instead of constructing this
! 		 temporary list.  */
! 	      tree params = NULL_TREE;
! 	      int i;
! 	      for (i = nargs - 1; i >= 0; i--)
! 		params = tree_cons (NULL_TREE, argarray[i], params);
! 	      check_format_info (&info, params);
! 	    }
  	  if (warn_missing_format_attribute && info.first_arg_num == 0
  	      && (format_types[info.format_type].flags
  		  & (int) FMT_FLAG_ARG_CONVERT))
Index: gcc/c-common.c
===================================================================
*** gcc/c-common.c	(revision 122018)
--- gcc/c-common.c	(working copy)
*************** static tree handle_warn_unused_result_at
*** 554,560 ****
  						 bool *);
  static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *);
  
! static void check_function_nonnull (tree, tree);
  static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT);
  static bool nonnull_check_p (tree, unsigned HOST_WIDE_INT);
  static bool get_nonnull_operand (tree, unsigned HOST_WIDE_INT *);
--- 554,560 ----
  						 bool *);
  static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *);
  
! static void check_function_nonnull (tree, int, tree *);
  static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT);
  static bool nonnull_check_p (tree, unsigned HOST_WIDE_INT);
  static bool get_nonnull_operand (tree, unsigned HOST_WIDE_INT *);
*************** handle_nonnull_attribute (tree *node, tr
*** 5621,5633 ****
  }
  
  /* Check the argument list of a function call for null in argument slots
!    that are marked as requiring a non-null pointer argument.  */
  
  static void
! check_function_nonnull (tree attrs, tree params)
  {
!   tree a, args, param;
!   int param_num;
  
    for (a = attrs; a; a = TREE_CHAIN (a))
      {
--- 5621,5635 ----
  }
  
  /* Check the argument list of a function call for null in argument slots
!    that are marked as requiring a non-null pointer argument.  The NARGS
!    arguments are passed in the array ARGARRAY.
! */
  
  static void
! check_function_nonnull (tree attrs, int nargs, tree *argarray)
  {
!   tree a, args;
!   int i;
  
    for (a = attrs; a; a = TREE_CHAIN (a))
      {
*************** check_function_nonnull (tree attrs, tree
*** 5639,5723 ****
  	     should check for non-null, do it.  If the attribute has no args,
  	     then every pointer argument is checked (in which case the check
  	     for pointer type is done in check_nonnull_arg).  */
! 	  for (param = params, param_num = 1; ;
! 	       param_num++, param = TREE_CHAIN (param))
  	    {
! 	      if (!param)
! 		break;
! 	      if (!args || nonnull_check_p (args, param_num))
  		check_function_arguments_recurse (check_nonnull_arg, NULL,
! 						  TREE_VALUE (param),
! 						  param_num);
  	    }
  	}
      }
  }
  
  /* Check that the Nth argument of a function call (counting backwards
!    from the end) is a (pointer)0.  */
  
  static void
! check_function_sentinel (tree attrs, tree params, tree typelist)
  {
    tree attr = lookup_attribute ("sentinel", attrs);
  
    if (attr)
      {
!       /* Skip over the named arguments.  */
!       while (typelist && params)
!       {
! 	typelist = TREE_CHAIN (typelist);
! 	params = TREE_CHAIN (params);
!       }
  
!       if (typelist || !params)
! 	warning (OPT_Wformat,
! 		 "not enough variable arguments to fit a sentinel");
!       else
  	{
! 	  tree sentinel, end;
! 	  unsigned pos = 0;
! 
! 	  if (TREE_VALUE (attr))
! 	    {
! 	      tree p = TREE_VALUE (TREE_VALUE (attr));
! 	      pos = TREE_INT_CST_LOW (p);
! 	    }
! 
! 	  sentinel = end = params;
! 
! 	  /* Advance `end' ahead of `sentinel' by `pos' positions.  */
! 	  while (pos > 0 && TREE_CHAIN (end))
! 	    {
! 	      pos--;
! 	      end = TREE_CHAIN (end);
! 	    }
! 	  if (pos > 0)
! 	    {
! 	      warning (OPT_Wformat,
! 		       "not enough variable arguments to fit a sentinel");
! 	      return;
! 	    }
  
! 	  /* Now advance both until we find the last parameter.  */
! 	  while (TREE_CHAIN (end))
! 	    {
! 	      end = TREE_CHAIN (end);
! 	      sentinel = TREE_CHAIN (sentinel);
! 	    }
  
! 	  /* Validate the sentinel.  */
! 	  if ((!POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (sentinel)))
! 	       || !integer_zerop (TREE_VALUE (sentinel)))
! 	      /* Although __null (in C++) is only an integer we allow it
! 		 nevertheless, as we are guaranteed that it's exactly
! 		 as wide as a pointer, and we don't want to force
! 		 users to cast the NULL they have written there.
! 		 We warn with -Wstrict-null-sentinel, though.  */
! 	      && (warn_strict_null_sentinel
! 		  || null_node != TREE_VALUE (sentinel)))
! 	    warning (OPT_Wformat, "missing sentinel in function call");
  	}
      }
  }
  
--- 5641,5705 ----
  	     should check for non-null, do it.  If the attribute has no args,
  	     then every pointer argument is checked (in which case the check
  	     for pointer type is done in check_nonnull_arg).  */
! 	  for (i = 0; i < nargs; i++)
  	    {
! 	      if (!args || nonnull_check_p (args, i + 1))
  		check_function_arguments_recurse (check_nonnull_arg, NULL,
! 						  argarray[i],
! 						  i + 1);
  	    }
  	}
      }
  }
  
  /* Check that the Nth argument of a function call (counting backwards
!    from the end) is a (pointer)0.  The NARGS arguments are passed in the
!    array ARGARRAY.  */
  
  static void
! check_function_sentinel (tree attrs, int nargs, tree *argarray, tree typelist)
  {
    tree attr = lookup_attribute ("sentinel", attrs);
  
    if (attr)
      {
!       int len = 0;
!       int pos = 0;
!       tree sentinel;
  
!       /* Skip over the named arguments.  */
!       while (typelist && len < nargs)
  	{
! 	  typelist = TREE_CHAIN (typelist);
! 	  len++;
! 	}
  
!       if (TREE_VALUE (attr))
! 	{
! 	  tree p = TREE_VALUE (TREE_VALUE (attr));
! 	  pos = TREE_INT_CST_LOW (p);
! 	}
  
!       /* The sentinel must be one of the varargs, i.e.
! 	 in position >= the number of fixed arguments.  */
!       if ((nargs - 1 - pos) < len)
! 	{
! 	  warning (OPT_Wformat,
! 		   "not enough variable arguments to fit a sentinel");
! 	  return;
  	}
+ 
+       /* Validate the sentinel.  */
+       sentinel = argarray[nargs - 1 - pos];
+       if ((!POINTER_TYPE_P (TREE_TYPE (sentinel))
+ 	   || !integer_zerop (sentinel))
+ 	  /* Although __null (in C++) is only an integer we allow it
+ 	     nevertheless, as we are guaranteed that it's exactly
+ 	     as wide as a pointer, and we don't want to force
+ 	     users to cast the NULL they have written there.
+ 	     We warn with -Wstrict-null-sentinel, though.  */
+ 	  && (warn_strict_null_sentinel || null_node != sentinel))
+ 	warning (OPT_Wformat, "missing sentinel in function call");
      }
  }
  
*************** handle_sentinel_attribute (tree *node, t
*** 5907,5929 ****
    return NULL_TREE;
  }
  \f
! /* Check for valid arguments being passed to a function.  */
  void
! check_function_arguments (tree attrs, tree params, tree typelist)
  {
    /* Check for null being passed in a pointer argument that must be
       non-null.  We also need to do this if format checking is enabled.  */
  
    if (warn_nonnull)
!     check_function_nonnull (attrs, params);
  
    /* Check for errors in format strings.  */
  
    if (warn_format || warn_missing_format_attribute)
!       check_function_format (attrs, params);
  
    if (warn_format)
!     check_function_sentinel (attrs, params, typelist);
  }
  
  /* Generic argument checking recursion routine.  PARAM is the argument to
--- 5889,5914 ----
    return NULL_TREE;
  }
  \f
! /* Check for valid arguments being passed to a function.
!    ATTRS is a list of attributes.  There are NARGS arguments in the array
!    ARGARRAY.  TYPELIST is the list of argument types for the function.
!  */
  void
! check_function_arguments (tree attrs, int nargs, tree *argarray, tree typelist)
  {
    /* Check for null being passed in a pointer argument that must be
       non-null.  We also need to do this if format checking is enabled.  */
  
    if (warn_nonnull)
!     check_function_nonnull (attrs, nargs, argarray);
  
    /* Check for errors in format strings.  */
  
    if (warn_format || warn_missing_format_attribute)
!     check_function_format (attrs, nargs, argarray);
  
    if (warn_format)
!     check_function_sentinel (attrs, nargs, argarray, typelist);
  }
  
  /* Generic argument checking recursion routine.  PARAM is the argument to
Index: gcc/c-common.h
===================================================================
*** gcc/c-common.h	(revision 122017)
--- gcc/c-common.h	(working copy)
*************** extern void finish_fname_decls (void);
*** 640,652 ****
  extern const char *fname_as_string (int);
  extern tree fname_decl (unsigned, tree);
  
! extern void check_function_arguments (tree, tree, tree);
  extern void check_function_arguments_recurse (void (*)
  					      (void *, tree,
  					       unsigned HOST_WIDE_INT),
  					      void *, tree,
  					      unsigned HOST_WIDE_INT);
! extern void check_function_format (tree, tree);
  extern void set_Wformat (int);
  extern tree handle_format_attribute (tree *, tree, tree, int, bool *);
  extern tree handle_format_arg_attribute (tree *, tree, tree, int, bool *);
--- 640,652 ----
  extern const char *fname_as_string (int);
  extern tree fname_decl (unsigned, tree);
  
! extern void check_function_arguments (tree, int, tree *, tree);
  extern void check_function_arguments_recurse (void (*)
  					      (void *, tree,
  					       unsigned HOST_WIDE_INT),
  					      void *, tree,
  					      unsigned HOST_WIDE_INT);
! extern void check_function_format (tree, int, tree *);
  extern void set_Wformat (int);
  extern tree handle_format_attribute (tree *, tree, tree, int, bool *);
  extern tree handle_format_arg_attribute (tree *, tree, tree, int, bool *);
Index: gcc/cp/typeck.c
===================================================================
*** gcc/cp/typeck.c	(revision 122017)
--- gcc/cp/typeck.c	(working copy)
*************** static void casts_away_constness_r (tree
*** 60,66 ****
  static bool casts_away_constness (tree, tree);
  static void maybe_warn_about_returning_address_of_local (tree);
  static tree lookup_destructor (tree, tree, tree);
! static tree convert_arguments (tree, tree, tree, int);
  
  /* Do `exp = require_complete_type (exp);' to make sure exp
     does not have an incomplete type.  (That includes void types.)
--- 60,66 ----
  static bool casts_away_constness (tree, tree);
  static void maybe_warn_about_returning_address_of_local (tree);
  static tree lookup_destructor (tree, tree, tree);
! static int convert_arguments (int, tree *, tree, tree, tree, int);
  
  /* Do `exp = require_complete_type (exp);' to make sure exp
     does not have an incomplete type.  (That includes void types.)
*************** tree
*** 2670,2679 ****
  build_function_call (tree function, tree params)
  {
    tree fntype, fndecl;
-   tree coerced_params;
    tree name = NULL_TREE;
    int is_method;
    tree original = function;
  
    /* For Objective-C, convert any calls via a cast to OBJC_TYPE_REF
       expressions, like those used for ObjC messenger dispatches.  */
--- 2670,2681 ----
  build_function_call (tree function, tree params)
  {
    tree fntype, fndecl;
    tree name = NULL_TREE;
    int is_method;
    tree original = function;
+   int nargs, parm_types_len;
+   tree *argarray;
+   tree parm_types;
  
    /* For Objective-C, convert any calls via a cast to OBJC_TYPE_REF
       expressions, like those used for ObjC messenger dispatches.  */
*************** build_function_call (tree function, tree
*** 2739,2760 ****
  
    /* fntype now gets the type of function pointed to.  */
    fntype = TREE_TYPE (fntype);
  
    /* Convert the parameters to the types declared in the
       function prototype, or apply default promotions.  */
! 
!   coerced_params = convert_arguments (TYPE_ARG_TYPES (fntype),
! 				      params, fndecl, LOOKUP_NORMAL);
!   if (coerced_params == error_mark_node)
      return error_mark_node;
  
    /* Check for errors in format strings and inappropriately
       null parameters.  */
  
!   check_function_arguments (TYPE_ATTRIBUTES (fntype), coerced_params,
! 			    TYPE_ARG_TYPES (fntype));
  
!   return build_cxx_call (function, coerced_params);
  }
  \f
  /* Convert the actual parameter expressions in the list VALUES
--- 2741,2769 ----
  
    /* fntype now gets the type of function pointed to.  */
    fntype = TREE_TYPE (fntype);
+   parm_types = TYPE_ARG_TYPES (fntype);
+ 
+   /* Allocate storage for converted arguments.  */
+   parm_types_len = list_length (parm_types);
+   nargs = list_length (params);
+   if (parm_types_len > nargs)
+     nargs = parm_types_len;
+   argarray = (tree *) alloca (nargs * sizeof (tree));
  
    /* Convert the parameters to the types declared in the
       function prototype, or apply default promotions.  */
!   nargs = convert_arguments (nargs, argarray, parm_types,
! 			     params, fndecl, LOOKUP_NORMAL);
!   if (nargs < 0)
      return error_mark_node;
  
    /* Check for errors in format strings and inappropriately
       null parameters.  */
  
!   check_function_arguments (TYPE_ATTRIBUTES (fntype), nargs, argarray,
! 			    parm_types);
  
!   return build_cxx_call (function, nargs, argarray);
  }
  \f
  /* Convert the actual parameter expressions in the list VALUES
*************** build_function_call (tree function, tree
*** 2762,2784 ****
     If parmdecls is exhausted, or when an element has NULL as its type,
     perform the default conversions.
  
     NAME is an IDENTIFIER_NODE or 0.  It is used only for error messages.
  
     This is also where warnings about wrong number of args are generated.
  
!    Return a list of expressions for the parameters as converted.
  
!    Both VALUES and the returned value are chains of TREE_LIST nodes
!    with the elements of the list in the TREE_VALUE slots of those nodes.
  
     In C++, unspecified trailing parameters can be filled in with their
     default arguments, if such were specified.  Do so here.  */
  
! static tree
! convert_arguments (tree typelist, tree values, tree fndecl, int flags)
  {
    tree typetail, valtail;
-   tree result = NULL_TREE;
    const char *called_thing = 0;
    int i = 0;
  
--- 2771,2796 ----
     If parmdecls is exhausted, or when an element has NULL as its type,
     perform the default conversions.
  
+    Store the converted arguments in ARGARRAY.  NARGS is the size of this array.
+ 
     NAME is an IDENTIFIER_NODE or 0.  It is used only for error messages.
  
     This is also where warnings about wrong number of args are generated.
  
!    Returns the actual number of arguments processed (which might be less
!    than NARGS), or -1 on error.
  
!    VALUES is a chain of TREE_LIST nodes with the elements of the list
!    in the TREE_VALUE slots of those nodes.
  
     In C++, unspecified trailing parameters can be filled in with their
     default arguments, if such were specified.  Do so here.  */
  
! static int
! convert_arguments (int nargs, tree *argarray,
! 		   tree typelist, tree values, tree fndecl, int flags)
  {
    tree typetail, valtail;
    const char *called_thing = 0;
    int i = 0;
  
*************** convert_arguments (tree typelist, tree v
*** 2807,2813 ****
        tree val = TREE_VALUE (valtail);
  
        if (val == error_mark_node || type == error_mark_node)
! 	return error_mark_node;
  
        if (type == void_type_node)
  	{
--- 2819,2825 ----
        tree val = TREE_VALUE (valtail);
  
        if (val == error_mark_node || type == error_mark_node)
! 	return -1;
  
        if (type == void_type_node)
  	{
*************** convert_arguments (tree typelist, tree v
*** 2818,2828 ****
  	    }
  	  else
  	    error ("too many arguments to function");
! 	  /* In case anybody wants to know if this argument
! 	     list is valid.  */
! 	  if (result)
! 	    TREE_TYPE (tree_last (result)) = error_mark_node;
! 	  break;
  	}
  
        /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
--- 2830,2836 ----
  	    }
  	  else
  	    error ("too many arguments to function");
! 	  return i;
  	}
  
        /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
*************** convert_arguments (tree typelist, tree v
*** 2841,2847 ****
  	}
  
        if (val == error_mark_node)
! 	return error_mark_node;
  
        if (type != 0)
  	{
--- 2849,2855 ----
  	}
  
        if (val == error_mark_node)
! 	return -1;
  
        if (type != 0)
  	{
*************** convert_arguments (tree typelist, tree v
*** 2866,2874 ****
  	    }
  
  	  if (parmval == error_mark_node)
! 	    return error_mark_node;
  
! 	  result = tree_cons (NULL_TREE, parmval, result);
  	}
        else
  	{
--- 2874,2882 ----
  	    }
  
  	  if (parmval == error_mark_node)
! 	    return -1;
  
! 	  argarray[i] = parmval;
  	}
        else
  	{
*************** convert_arguments (tree typelist, tree v
*** 2881,2887 ****
  	  else
  	    val = convert_arg_to_ellipsis (val);
  
! 	  result = tree_cons (NULL_TREE, val, result);
  	}
  
        if (typetail)
--- 2889,2895 ----
  	  else
  	    val = convert_arg_to_ellipsis (val);
  
! 	  argarray[i] = val;
  	}
  
        if (typetail)
*************** convert_arguments (tree typelist, tree v
*** 2902,2910 ****
  				       fndecl, i);
  
  	      if (parmval == error_mark_node)
! 		return error_mark_node;
  
! 	      result = tree_cons (0, parmval, result);
  	      typetail = TREE_CHAIN (typetail);
  	      /* ends with `...'.  */
  	      if (typetail == NULL_TREE)
--- 2910,2918 ----
  				       fndecl, i);
  
  	      if (parmval == error_mark_node)
! 		return -1;
  
! 	      argarray[i] = parmval;
  	      typetail = TREE_CHAIN (typetail);
  	      /* ends with `...'.  */
  	      if (typetail == NULL_TREE)
*************** convert_arguments (tree typelist, tree v
*** 2920,2930 ****
  	    }
  	  else
  	    error ("too few arguments to function");
! 	  return error_mark_node;
  	}
      }
  
!   return nreverse (result);
  }
  \f
  /* Build a binary-operation expression, after performing default
--- 2928,2939 ----
  	    }
  	  else
  	    error ("too few arguments to function");
! 	  return -1;
  	}
      }
  
!   gcc_assert (i <= nargs);
!   return i;
  }
  \f
  /* Build a binary-operation expression, after performing default
Index: gcc/cp/call.c
===================================================================
*** gcc/cp/call.c	(revision 122018)
--- gcc/cp/call.c	(working copy)
*************** build_addr_func (tree function)
*** 269,285 ****
  
  /* Build a CALL_EXPR, we can handle FUNCTION_TYPEs, METHOD_TYPEs, or
     POINTER_TYPE to those.  Note, pointer to member function types
!    (TYPE_PTRMEMFUNC_P) must be handled by our callers.  */
  
  tree
! build_call (tree function, tree parms)
  {
    int is_constructor = 0;
    int nothrow;
-   tree tmp;
    tree decl;
    tree result_type;
    tree fntype;
  
    function = build_addr_func (function);
  
--- 269,306 ----
  
  /* Build a CALL_EXPR, we can handle FUNCTION_TYPEs, METHOD_TYPEs, or
     POINTER_TYPE to those.  Note, pointer to member function types
!    (TYPE_PTRMEMFUNC_P) must be handled by our callers.  There are
!    two variants.  build_call_a is the primitive taking an array of
!    arguments, while build_call_n is a wrapper that handles varargs.  */
  
  tree
! build_call_n (tree function, int n, ...)
! {
!   if (n == 0)
!     return build_call_a (function, 0, NULL);
!   else
!     {
!       tree *argarray = (tree *) alloca (n * sizeof (tree));
!       va_list ap;
!       int i;
! 
!       va_start (ap, n);
!       for (i = 0; i < n; i++)
! 	argarray[i] = va_arg (ap, tree);
!       va_end (ap);
!       return build_call_a (function, n, argarray);
!     }
! }
! 
! tree
! build_call_a (tree function, int n, tree *argarray)
  {
    int is_constructor = 0;
    int nothrow;
    tree decl;
    tree result_type;
    tree fntype;
+   int i;
  
    function = build_addr_func (function);
  
*************** build_call (tree function, tree parms)
*** 327,342 ****
       for tags in STL, which are used to control overload resolution.
       We don't need to handle other cases of copying empty classes.  */
    if (! decl || ! DECL_BUILT_IN (decl))
!     for (tmp = parms; tmp; tmp = TREE_CHAIN (tmp))
!       if (is_empty_class (TREE_TYPE (TREE_VALUE (tmp)))
! 	  && ! TREE_ADDRESSABLE (TREE_TYPE (TREE_VALUE (tmp))))
  	{
! 	  tree t = build0 (EMPTY_CLASS_EXPR, TREE_TYPE (TREE_VALUE (tmp)));
! 	  TREE_VALUE (tmp) = build2 (COMPOUND_EXPR, TREE_TYPE (t),
! 				     TREE_VALUE (tmp), t);
  	}
  
!   function = build_call_list (result_type, function, parms);
    TREE_HAS_CONSTRUCTOR (function) = is_constructor;
    TREE_NOTHROW (function) = nothrow;
  
--- 348,363 ----
       for tags in STL, which are used to control overload resolution.
       We don't need to handle other cases of copying empty classes.  */
    if (! decl || ! DECL_BUILT_IN (decl))
!     for (i = 0; i < n; i++)
!       if (is_empty_class (TREE_TYPE (argarray[i]))
! 	  && ! TREE_ADDRESSABLE (TREE_TYPE (argarray[i])))
  	{
! 	  tree t = build0 (EMPTY_CLASS_EXPR, TREE_TYPE (argarray[i]));
! 	  argarray[i] = build2 (COMPOUND_EXPR, TREE_TYPE (t),
! 				argarray[i], t);
  	}
  
!   function = build_call_array (result_type, function, n, argarray);
    TREE_HAS_CONSTRUCTOR (function) = is_constructor;
    TREE_NOTHROW (function) = nothrow;
  
*************** build_op_delete_call (enum tree_code cod
*** 4005,4011 ****
  		      tree alloc_fn)
  {
    tree fn = NULL_TREE;
!   tree fns, fnname, argtypes, args, type;
    int pass;
  
    if (addr == error_mark_node)
--- 4026,4032 ----
  		      tree alloc_fn)
  {
    tree fn = NULL_TREE;
!   tree fns, fnname, argtypes, type;
    int pass;
  
    if (addr == error_mark_node)
*************** build_op_delete_call (enum tree_code cod
*** 4036,4060 ****
    if (fns == NULL_TREE)
      fns = lookup_name_nonclass (fnname);
  
    if (placement)
      {
        /* Get the parameter types for the allocation function that is
  	 being called.  */
        gcc_assert (alloc_fn != NULL_TREE);
        argtypes = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (alloc_fn)));
-       /* Also the second argument.  */
-       args = TREE_CHAIN (TREE_OPERAND (placement, 1));
      }
    else
      {
        /* First try it without the size argument.  */
        argtypes = void_list_node;
-       args = NULL_TREE;
      }
  
-   /* Strip const and volatile from addr.  */
-   addr = cp_convert (ptr_type_node, addr);
- 
    /* We make two tries at finding a matching `operator delete'.  On
       the first pass, we look for a one-operator (or placement)
       operator delete.  If we're not doing placement delete, then on
--- 4057,4078 ----
    if (fns == NULL_TREE)
      fns = lookup_name_nonclass (fnname);
  
+   /* Strip const and volatile from addr.  */
+   addr = cp_convert (ptr_type_node, addr);
+ 
    if (placement)
      {
        /* Get the parameter types for the allocation function that is
  	 being called.  */
        gcc_assert (alloc_fn != NULL_TREE);
        argtypes = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (alloc_fn)));
      }
    else
      {
        /* First try it without the size argument.  */
        argtypes = void_list_node;
      }
  
    /* We make two tries at finding a matching `operator delete'.  On
       the first pass, we look for a one-operator (or placement)
       operator delete.  If we're not doing placement delete, then on
*************** build_op_delete_call (enum tree_code cod
*** 4113,4133 ****
        if (DECL_CLASS_SCOPE_P (fn))
  	perform_or_defer_access_check (TYPE_BINFO (type), fn, fn);
  
-       if (pass == 0)
- 	args = tree_cons (NULL_TREE, addr, args);
-       else
- 	args = tree_cons (NULL_TREE, addr,
- 			  build_tree_list (NULL_TREE, size));
- 
        if (placement)
  	{
  	  /* The placement args might not be suitable for overload
  	     resolution at this point, so build the call directly.  */
  	  mark_used (fn);
! 	  return build_cxx_call (fn, args);
  	}
        else
! 	return build_function_call (fn, args);
      }
  
    /* If we are doing placement delete we do nothing if we don't find a
--- 4131,4159 ----
        if (DECL_CLASS_SCOPE_P (fn))
  	perform_or_defer_access_check (TYPE_BINFO (type), fn, fn);
  
        if (placement)
  	{
  	  /* The placement args might not be suitable for overload
  	     resolution at this point, so build the call directly.  */
+ 	  int nargs = call_expr_nargs (placement);
+ 	  tree *argarray = (tree *) alloca (nargs * sizeof (tree));
+ 	  int i;
+ 	  argarray[0] = addr;
+ 	  for (i = 1; i < nargs; i++)
+ 	    argarray[i] = CALL_EXPR_ARG (placement, i);
  	  mark_used (fn);
! 	  return build_cxx_call (fn, nargs, argarray);
  	}
        else
! 	{
! 	  tree args;
! 	  if (pass == 0)
! 	    args = tree_cons (NULL_TREE, addr, NULL_TREE);
! 	  else
! 	    args = tree_cons (NULL_TREE, addr,
! 			      build_tree_list (NULL_TREE, size));
! 	  return build_function_call (fn, args);
! 	}
      }
  
    /* If we are doing placement delete we do nothing if we don't find a
*************** call_builtin_trap (void)
*** 4494,4500 ****
    tree fn = implicit_built_in_decls[BUILT_IN_TRAP];
  
    gcc_assert (fn != NULL);
!   fn = build_call (fn, NULL_TREE);
    return fn;
  }
  
--- 4520,4526 ----
    tree fn = implicit_built_in_decls[BUILT_IN_TRAP];
  
    gcc_assert (fn != NULL);
!   fn = build_call_n (fn, 0);
    return fn;
  }
  
*************** build_over_call (struct z_candidate *can
*** 4725,4735 ****
    tree args = cand->args;
    conversion **convs = cand->convs;
    conversion *conv;
-   tree converted_args = NULL_TREE;
    tree parm = TYPE_ARG_TYPES (TREE_TYPE (fn));
    tree arg, val;
    int i = 0;
    int is_method = 0;
  
    /* In a template, there is no need to perform all of the work that
       is normally done.  We are only interested in the type of the call
--- 4751,4764 ----
    tree args = cand->args;
    conversion **convs = cand->convs;
    conversion *conv;
    tree parm = TYPE_ARG_TYPES (TREE_TYPE (fn));
+   int parmlen;
    tree arg, val;
    int i = 0;
+   int j = 0;
    int is_method = 0;
+   int nargs;
+   tree *argarray;
  
    /* In a template, there is no need to perform all of the work that
       is normally done.  We are only interested in the type of the call
*************** build_over_call (struct z_candidate *can
*** 4795,4805 ****
      args = build_tree_list (NULL_TREE, args);
    arg = args;
  
    /* The implicit parameters to a constructor are not considered by overload
       resolution, and must be of the proper type.  */
    if (DECL_CONSTRUCTOR_P (fn))
      {
!       converted_args = tree_cons (NULL_TREE, TREE_VALUE (arg), converted_args);
        arg = TREE_CHAIN (arg);
        parm = TREE_CHAIN (parm);
        /* We should never try to call the abstract constructor.  */
--- 4824,4841 ----
      args = build_tree_list (NULL_TREE, args);
    arg = args;
  
+   /* Find maximum size of vector to hold converted arguments.  */
+   parmlen = list_length (parm);
+   nargs = list_length (args);
+   if (parmlen > nargs)
+     nargs = parmlen;
+   argarray = (tree *) alloca (nargs * sizeof (tree));
+ 
    /* The implicit parameters to a constructor are not considered by overload
       resolution, and must be of the proper type.  */
    if (DECL_CONSTRUCTOR_P (fn))
      {
!       argarray[j++] = TREE_VALUE (arg);
        arg = TREE_CHAIN (arg);
        parm = TREE_CHAIN (parm);
        /* We should never try to call the abstract constructor.  */
*************** build_over_call (struct z_candidate *can
*** 4807,4814 ****
  
        if (DECL_HAS_VTT_PARM_P (fn))
  	{
! 	  converted_args = tree_cons
! 	    (NULL_TREE, TREE_VALUE (arg), converted_args);
  	  arg = TREE_CHAIN (arg);
  	  parm = TREE_CHAIN (parm);
  	}
--- 4843,4849 ----
  
        if (DECL_HAS_VTT_PARM_P (fn))
  	{
! 	  argarray[j++] = TREE_VALUE (arg);
  	  arg = TREE_CHAIN (arg);
  	  parm = TREE_CHAIN (parm);
  	}
*************** build_over_call (struct z_candidate *can
*** 4852,4858 ****
        converted_arg = build_base_path (PLUS_EXPR, converted_arg,
  				       base_binfo, 1);
  
!       converted_args = tree_cons (NULL_TREE, converted_arg, converted_args);
        parm = TREE_CHAIN (parm);
        arg = TREE_CHAIN (arg);
        ++i;
--- 4887,4893 ----
        converted_arg = build_base_path (PLUS_EXPR, converted_arg,
  				       base_binfo, 1);
  
!       argarray[j++] = converted_arg;
        parm = TREE_CHAIN (parm);
        arg = TREE_CHAIN (arg);
        ++i;
*************** build_over_call (struct z_candidate *can
*** 4875,4892 ****
  	(conv, TREE_VALUE (arg), fn, i - is_method);
  
        val = convert_for_arg_passing (type, val);
!       converted_args = tree_cons (NULL_TREE, val, converted_args);
      }
  
    /* Default arguments */
    for (; parm && parm != void_list_node; parm = TREE_CHAIN (parm), i++)
!     converted_args
!       = tree_cons (NULL_TREE,
! 		   convert_default_arg (TREE_VALUE (parm),
! 					TREE_PURPOSE (parm),
! 					fn, i - is_method),
! 		   converted_args);
! 
    /* Ellipsis */
    for (; arg; arg = TREE_CHAIN (arg))
      {
--- 4910,4923 ----
  	(conv, TREE_VALUE (arg), fn, i - is_method);
  
        val = convert_for_arg_passing (type, val);
!       argarray[j++] = val;
      }
  
    /* Default arguments */
    for (; parm && parm != void_list_node; parm = TREE_CHAIN (parm), i++)
!     argarray[j++] = convert_default_arg (TREE_VALUE (parm),
! 					 TREE_PURPOSE (parm),
! 					 fn, i - is_method);
    /* Ellipsis */
    for (; arg; arg = TREE_CHAIN (arg))
      {
*************** build_over_call (struct z_candidate *can
*** 4895,4907 ****
  	/* Do no conversions for magic varargs.  */;
        else
  	a = convert_arg_to_ellipsis (a);
!       converted_args = tree_cons (NULL_TREE, a, converted_args);
      }
  
!   converted_args = nreverse (converted_args);
  
    check_function_arguments (TYPE_ATTRIBUTES (TREE_TYPE (fn)),
! 			    converted_args, TYPE_ARG_TYPES (TREE_TYPE (fn)));
  
    /* Avoid actually calling copy constructors and copy assignment operators,
       if possible.  */
--- 4926,4939 ----
  	/* Do no conversions for magic varargs.  */;
        else
  	a = convert_arg_to_ellipsis (a);
!       argarray[j++] = a;
      }
  
!   gcc_assert (j <= nargs);
!   nargs = j;
  
    check_function_arguments (TYPE_ATTRIBUTES (TREE_TYPE (fn)),
! 			    nargs, argarray, TYPE_ARG_TYPES (TREE_TYPE (fn)));
  
    /* Avoid actually calling copy constructors and copy assignment operators,
       if possible.  */
*************** build_over_call (struct z_candidate *can
*** 4911,4918 ****
    else if (cand->num_convs == 1 && DECL_COPY_CONSTRUCTOR_P (fn))
      {
        tree targ;
!       arg = skip_artificial_parms_for (fn, converted_args);
!       arg = TREE_VALUE (arg);
  
        /* Pull out the real argument, disregarding const-correctness.  */
        targ = arg;
--- 4943,4949 ----
    else if (cand->num_convs == 1 && DECL_COPY_CONSTRUCTOR_P (fn))
      {
        tree targ;
!       arg = argarray[num_artificial_parms_for (fn)];
  
        /* Pull out the real argument, disregarding const-correctness.  */
        targ = arg;
*************** build_over_call (struct z_candidate *can
*** 4967,4977 ****
  	   && TYPE_HAS_TRIVIAL_ASSIGN_REF (DECL_CONTEXT (fn)))
      {
        tree to = stabilize_reference
! 	(build_indirect_ref (TREE_VALUE (converted_args), 0));
        tree type = TREE_TYPE (to);
        tree as_base = CLASSTYPE_AS_BASE (type);
  
!       arg = TREE_VALUE (TREE_CHAIN (converted_args));
        if (tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (as_base)))
  	{
  	  arg = build_indirect_ref (arg, 0);
--- 4998,5008 ----
  	   && TYPE_HAS_TRIVIAL_ASSIGN_REF (DECL_CONTEXT (fn)))
      {
        tree to = stabilize_reference
! 	(build_indirect_ref (argarray[0], 0));
        tree type = TREE_TYPE (to);
        tree as_base = CLASSTYPE_AS_BASE (type);
  
!       arg = argarray[1];
        if (tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (as_base)))
  	{
  	  arg = build_indirect_ref (arg, 0);
*************** build_over_call (struct z_candidate *can
*** 4981,4997 ****
  	{
  	  /* We must only copy the non-tail padding parts.
  	     Use __builtin_memcpy for the bitwise copy.  */
  
! 	  tree args, t;
! 
! 	  args = tree_cons (NULL, TYPE_SIZE_UNIT (as_base), NULL);
! 	  args = tree_cons (NULL, arg, args);
! 	  t = build_unary_op (ADDR_EXPR, to, 0);
! 	  args = tree_cons (NULL, t, args);
  	  t = implicit_built_in_decls[BUILT_IN_MEMCPY];
! 	  t = build_call (t, args);
  
! 	  t = convert (TREE_TYPE (TREE_VALUE (args)), t);
  	  val = build_indirect_ref (t, 0);
  	}
  
--- 5012,5027 ----
  	{
  	  /* We must only copy the non-tail padding parts.
  	     Use __builtin_memcpy for the bitwise copy.  */
+ 	
+ 	  tree arg0, arg1, arg2, t;
  
! 	  arg2 = TYPE_SIZE_UNIT (as_base);
! 	  arg1 = arg;
! 	  arg0 = build_unary_op (ADDR_EXPR, to, 0);
  	  t = implicit_built_in_decls[BUILT_IN_MEMCPY];
! 	  t = build_call_n (t, 3, arg0, arg1, arg2);
  
! 	  t = convert (TREE_TYPE (arg0), t);
  	  val = build_indirect_ref (t, 0);
  	}
  
*************** build_over_call (struct z_candidate *can
*** 5002,5021 ****
  
    if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0)
      {
!       tree t, *p = &TREE_VALUE (converted_args);
!       tree binfo = lookup_base (TREE_TYPE (TREE_TYPE (*p)),
  				DECL_CONTEXT (fn),
  				ba_any, NULL);
        gcc_assert (binfo && binfo != error_mark_node);
  
!       *p = build_base_path (PLUS_EXPR, *p, binfo, 1);
!       if (TREE_SIDE_EFFECTS (*p))
! 	*p = save_expr (*p);
        t = build_pointer_type (TREE_TYPE (fn));
        if (DECL_CONTEXT (fn) && TYPE_JAVA_INTERFACE (DECL_CONTEXT (fn)))
! 	fn = build_java_interface_fn_ref (fn, *p);
        else
! 	fn = build_vfn_ref (*p, DECL_VINDEX (fn));
        TREE_TYPE (fn) = t;
      }
    else if (DECL_INLINE (fn))
--- 5032,5051 ----
  
    if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0)
      {
!       tree t;
!       tree binfo = lookup_base (TREE_TYPE (TREE_TYPE (argarray[0])),
  				DECL_CONTEXT (fn),
  				ba_any, NULL);
        gcc_assert (binfo && binfo != error_mark_node);
  
!       argarray[0] = build_base_path (PLUS_EXPR, argarray[0], binfo, 1);
!       if (TREE_SIDE_EFFECTS (argarray[0]))
! 	argarray[0] = save_expr (argarray[0]);
        t = build_pointer_type (TREE_TYPE (fn));
        if (DECL_CONTEXT (fn) && TYPE_JAVA_INTERFACE (DECL_CONTEXT (fn)))
! 	fn = build_java_interface_fn_ref (fn, argarray[0]);
        else
! 	fn = build_vfn_ref (argarray[0], DECL_VINDEX (fn));
        TREE_TYPE (fn) = t;
      }
    else if (DECL_INLINE (fn))
*************** build_over_call (struct z_candidate *can
*** 5023,5041 ****
    else
      fn = build_addr_func (fn);
  
!   return build_cxx_call (fn, converted_args);
  }
  
! /* Build and return a call to FN, using ARGS.  This function performs
!    no overload resolution, conversion, or other high-level
!    operations.  */
  
  tree
! build_cxx_call (tree fn, tree args)
  {
    tree fndecl;
  
!   fn = build_call (fn, args);
  
    /* If this call might throw an exception, note that fact.  */
    fndecl = get_callee_fndecl (fn);
--- 5053,5071 ----
    else
      fn = build_addr_func (fn);
  
!   return build_cxx_call (fn, nargs, argarray);
  }
  
! /* Build and return a call to FN, using NARGS arguments in ARGARRAY.
!    This function performs no overload resolution, conversion, or other
!    high-level operations.  */
  
  tree
! build_cxx_call (tree fn, int nargs, tree *argarray)
  {
    tree fndecl;
  
!   fn = build_call_a (fn, nargs, argarray);
  
    /* If this call might throw an exception, note that fact.  */
    fndecl = get_callee_fndecl (fn);
*************** static GTY(()) tree java_iface_lookup_fn
*** 5069,5075 ****
  static tree
  build_java_interface_fn_ref (tree fn, tree instance)
  {
!   tree lookup_args, lookup_fn, method, idx;
    tree klass_ref, iface, iface_ref;
    int i;
  
--- 5099,5105 ----
  static tree
  build_java_interface_fn_ref (tree fn, tree instance)
  {
!   tree lookup_fn, method, idx;
    tree klass_ref, iface, iface_ref;
    int i;
  
*************** build_java_interface_fn_ref (tree fn, tr
*** 5116,5128 ****
      }
    idx = build_int_cst (NULL_TREE, i);
  
-   lookup_args = tree_cons (NULL_TREE, klass_ref,
- 			   tree_cons (NULL_TREE, iface_ref,
- 				      build_tree_list (NULL_TREE, idx)));
    lookup_fn = build1 (ADDR_EXPR,
  		      build_pointer_type (TREE_TYPE (java_iface_lookup_fn)),
  		      java_iface_lookup_fn);
!   return build_call_list (ptr_type_node, lookup_fn, lookup_args);
  }
  
  /* Returns the value to use for the in-charge parameter when making a
--- 5146,5156 ----
      }
    idx = build_int_cst (NULL_TREE, i);
  
    lookup_fn = build1 (ADDR_EXPR,
  		      build_pointer_type (TREE_TYPE (java_iface_lookup_fn)),
  		      java_iface_lookup_fn);
!   return build_call_nary (ptr_type_node, lookup_fn,
! 			  3, klass_ref, iface_ref, idx);
  }
  
  /* Returns the value to use for the in-charge parameter when making a
Index: gcc/cp/cp-tree.h
===================================================================
*** gcc/cp/cp-tree.h	(revision 122018)
--- gcc/cp/cp-tree.h	(working copy)
*************** extern bool check_dtor_name			(tree, tre
*** 3861,3867 ****
  extern tree build_vfield_ref			(tree, tree);
  extern tree build_conditional_expr		(tree, tree, tree);
  extern tree build_addr_func			(tree);
! extern tree build_call				(tree, tree);
  extern bool null_ptr_cst_p			(tree);
  extern bool sufficient_parms_p			(tree);
  extern tree type_decays_to			(tree);
--- 3861,3868 ----
  extern tree build_vfield_ref			(tree, tree);
  extern tree build_conditional_expr		(tree, tree, tree);
  extern tree build_addr_func			(tree);
! extern tree build_call_a			(tree, int, tree*);
! extern tree build_call_n			(tree, int, ...);
  extern bool null_ptr_cst_p			(tree);
  extern bool sufficient_parms_p			(tree);
  extern tree type_decays_to			(tree);
*************** extern tree strip_top_quals			(tree);
*** 3891,3897 ****
  extern tree perform_implicit_conversion		(tree, tree);
  extern tree perform_direct_initialization_if_possible (tree, tree, bool);
  extern tree in_charge_arg_for_name		(tree);
! extern tree build_cxx_call			(tree, tree);
  #ifdef ENABLE_CHECKING
  extern void validate_conversion_obstack		(void);
  #endif /* ENABLE_CHECKING */
--- 3892,3898 ----
  extern tree perform_implicit_conversion		(tree, tree);
  extern tree perform_direct_initialization_if_possible (tree, tree, bool);
  extern tree in_charge_arg_for_name		(tree);
! extern tree build_cxx_call			(tree, int, tree *);
  #ifdef ENABLE_CHECKING
  extern void validate_conversion_obstack		(void);
  #endif /* ENABLE_CHECKING */
*************** extern void synthesize_method			(tree);
*** 4176,4181 ****
--- 4177,4183 ----
  extern tree lazily_declare_fn			(special_function_kind,
  						 tree);
  extern tree skip_artificial_parms_for		(tree, tree);
+ extern int num_artificial_parms_for		(tree);
  extern tree make_alias_for			(tree, tree);
  
  /* In optimize.c */
Index: gcc/cp/method.c
===================================================================
*** gcc/cp/method.c	(revision 122017)
--- gcc/cp/method.c	(working copy)
*************** use_thunk (tree thunk_fndecl, bool emit_
*** 452,457 ****
--- 452,459 ----
      }
    else
      {
+       int i;
+       tree *argarray = (tree *) alloca (list_length (a) * sizeof (tree));
        /* If this is a covariant thunk, or we don't have the necessary
  	 code for efficient thunks, generate a thunk function that
  	 just makes a call to the real function.  Unfortunately, this
*************** use_thunk (tree thunk_fndecl, bool emit_
*** 475,485 ****
  			  fixed_offset, virtual_offset);
  
        /* Build up the call to the real function.  */
!       t = tree_cons (NULL_TREE, t, NULL_TREE);
!       for (a = TREE_CHAIN (a); a; a = TREE_CHAIN (a))
! 	t = tree_cons (NULL_TREE, a, t);
!       t = nreverse (t);
!       t = build_call (alias, t);
        CALL_FROM_THUNK_P (t) = 1;
  
        if (VOID_TYPE_P (TREE_TYPE (t)))
--- 477,486 ----
  			  fixed_offset, virtual_offset);
  
        /* Build up the call to the real function.  */
!       argarray[0] = t;
!       for (i = 1, a = TREE_CHAIN (a); a; a = TREE_CHAIN (a), i++)
! 	argarray[i] = a;
!       t = build_call_a (alias, i, argarray);
        CALL_FROM_THUNK_P (t) = 1;
  
        if (VOID_TYPE_P (TREE_TYPE (t)))
*************** skip_artificial_parms_for (tree fn, tree
*** 1191,1194 ****
--- 1192,1216 ----
    return list;
  }
  
+ /* Given a FUNCTION_DECL FN and a chain LIST, return the number of
+    artificial parms in FN.  */
+ 
+ int
+ num_artificial_parms_for (tree fn)
+ {
+   int count = 0;
+ 
+   if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
+     count++;
+   else
+     return 0;
+ 
+   if (DECL_HAS_IN_CHARGE_PARM_P (fn))
+     count++;
+   if (DECL_HAS_VTT_PARM_P (fn))
+     count++;
+   return count;
+ }
+ 
+ 
  #include "gt-cp-method.h"
Index: gcc/cp/rtti.c
===================================================================
*** gcc/cp/rtti.c	(revision 122017)
--- gcc/cp/rtti.c	(working copy)
*************** throw_bad_cast (void)
*** 196,202 ****
      fn = push_throw_library_fn (fn, build_function_type (ptr_type_node,
  							 void_list_node));
  
!   return build_cxx_call (fn, NULL_TREE);
  }
  
  /* Return an expression for "__cxa_bad_typeid()".  The expression
--- 196,202 ----
      fn = push_throw_library_fn (fn, build_function_type (ptr_type_node,
  							 void_list_node));
  
!   return build_cxx_call (fn, 0, NULL);
  }
  
  /* Return an expression for "__cxa_bad_typeid()".  The expression
*************** throw_bad_typeid (void)
*** 215,221 ****
        fn = push_throw_library_fn (fn, t);
      }
  
!   return build_cxx_call (fn, NULL_TREE);
  }
  \f
  /* Return an lvalue expression whose type is "const std::type_info"
--- 215,221 ----
        fn = push_throw_library_fn (fn, t);
      }
  
!   return build_cxx_call (fn, 0, NULL);
  }
  \f
  /* Return an lvalue expression whose type is "const std::type_info"
*************** build_dynamic_cast_1 (tree type, tree ex
*** 588,594 ****
        else
  	{
  	  tree retval;
! 	  tree result, td2, td3, elems;
  	  tree static_type, target_type, boff;
  
  	  /* If we got here, we can't convert statically.  Therefore,
--- 588,595 ----
        else
  	{
  	  tree retval;
! 	  tree result, td2, td3;
! 	  tree elems[4];
  	  tree static_type, target_type, boff;
  
  	  /* If we got here, we can't convert statically.  Therefore,
*************** build_dynamic_cast_1 (tree type, tree ex
*** 646,656 ****
  	  if (tc == REFERENCE_TYPE)
  	    expr1 = build_unary_op (ADDR_EXPR, expr1, 0);
  
! 	  elems = tree_cons
! 	    (NULL_TREE, expr1, tree_cons
! 	     (NULL_TREE, td3, tree_cons
! 	      (NULL_TREE, td2, tree_cons
! 	       (NULL_TREE, boff, NULL_TREE))));
  
  	  dcast_fn = dynamic_cast_node;
  	  if (!dcast_fn)
--- 647,656 ----
  	  if (tc == REFERENCE_TYPE)
  	    expr1 = build_unary_op (ADDR_EXPR, expr1, 0);
  
! 	  elems[0] = expr1;
! 	  elems[1] = td3;
! 	  elems[2] = td2;
! 	  elems[3] = boff;
  
  	  dcast_fn = dynamic_cast_node;
  	  if (!dcast_fn)
*************** build_dynamic_cast_1 (tree type, tree ex
*** 680,686 ****
  	      pop_nested_namespace (ns);
  	      dynamic_cast_node = dcast_fn;
  	    }
! 	  result = build_cxx_call (dcast_fn, elems);
  
  	  if (tc == REFERENCE_TYPE)
  	    {
--- 680,686 ----
  	      pop_nested_namespace (ns);
  	      dynamic_cast_node = dcast_fn;
  	    }
! 	  result = build_cxx_call (dcast_fn, 4, elems);
  
  	  if (tc == REFERENCE_TYPE)
  	    {
Index: gcc/cp/init.c
===================================================================
*** gcc/cp/init.c	(revision 122017)
--- gcc/cp/init.c	(working copy)
*************** static tree
*** 1540,1546 ****
  build_builtin_delete_call (tree addr)
  {
    mark_used (global_delete_fndecl);
!   return build_call (global_delete_fndecl, build_tree_list (NULL_TREE, addr));
  }
  \f
  /* Build and return a NEW_EXPR.  If NELTS is non-NULL, TYPE[NELTS] is
--- 1540,1546 ----
  build_builtin_delete_call (tree addr)
  {
    mark_used (global_delete_fndecl);
!   return build_call_n (global_delete_fndecl, 1, addr);
  }
  \f
  /* Build and return a NEW_EXPR.  If NELTS is non-NULL, TYPE[NELTS] is
Index: gcc/cp/decl.c
===================================================================
*** gcc/cp/decl.c	(revision 122017)
--- gcc/cp/decl.c	(working copy)
*************** expand_static_init (tree decl, tree init
*** 5641,5647 ****
        /* Emit code to perform this initialization but once.  */
        tree if_stmt = NULL_TREE, inner_if_stmt = NULL_TREE;
        tree then_clause = NULL_TREE, inner_then_clause = NULL_TREE;
!       tree guard, guard_addr, guard_addr_list;
        tree acquire_fn, release_fn, abort_fn;
        tree flag, begin;
  
--- 5641,5647 ----
        /* Emit code to perform this initialization but once.  */
        tree if_stmt = NULL_TREE, inner_if_stmt = NULL_TREE;
        tree then_clause = NULL_TREE, inner_then_clause = NULL_TREE;
!       tree guard, guard_addr;
        tree acquire_fn, release_fn, abort_fn;
        tree flag, begin;
  
*************** expand_static_init (tree decl, tree init
*** 5693,5699 ****
        if (flag_threadsafe_statics)
  	{
  	  guard_addr = build_address (guard);
- 	  guard_addr_list = build_tree_list (NULL_TREE, guard_addr);
  
  	  acquire_fn = get_identifier ("__cxa_guard_acquire");
  	  release_fn = get_identifier ("__cxa_guard_release");
--- 5693,5698 ----
*************** expand_static_init (tree decl, tree init
*** 5715,5721 ****
  	    }
  
  	  inner_if_stmt = begin_if_stmt ();
! 	  finish_if_stmt_cond (build_call (acquire_fn, guard_addr_list),
  			       inner_if_stmt);
  
  	  inner_then_clause = begin_compound_stmt (BCS_NO_SCOPE);
--- 5714,5720 ----
  	    }
  
  	  inner_if_stmt = begin_if_stmt ();
! 	  finish_if_stmt_cond (build_call_n (acquire_fn, 1, guard_addr),
  			       inner_if_stmt);
  
  	  inner_then_clause = begin_compound_stmt (BCS_NO_SCOPE);
*************** expand_static_init (tree decl, tree init
*** 5725,5731 ****
  	  TARGET_EXPR_CLEANUP (begin)
  	    = build3 (COND_EXPR, void_type_node, flag,
  		      void_zero_node,
! 		      build_call (abort_fn, guard_addr_list));
  	  CLEANUP_EH_ONLY (begin) = 1;
  
  	  /* Do the initialization itself.  */
--- 5724,5730 ----
  	  TARGET_EXPR_CLEANUP (begin)
  	    = build3 (COND_EXPR, void_type_node, flag,
  		      void_zero_node,
! 		      build_call_n (abort_fn, 1, guard_addr));
  	  CLEANUP_EH_ONLY (begin) = 1;
  
  	  /* Do the initialization itself.  */
*************** expand_static_init (tree decl, tree init
*** 5733,5739 ****
  	  init = add_stmt_to_compound
  	    (init, build2 (MODIFY_EXPR, void_type_node, flag, boolean_true_node));
  	  init = add_stmt_to_compound
! 	    (init, build_call (release_fn, guard_addr_list));
  	}
        else
  	init = add_stmt_to_compound (init, set_guard (guard));
--- 5732,5738 ----
  	  init = add_stmt_to_compound
  	    (init, build2 (MODIFY_EXPR, void_type_node, flag, boolean_true_node));
  	  init = add_stmt_to_compound
! 	    (init, build_call_n (release_fn, 1, guard_addr));
  	}
        else
  	init = add_stmt_to_compound (init, set_guard (guard));
Index: gcc/cp/except.c
===================================================================
*** gcc/cp/except.c	(revision 122017)
--- gcc/cp/except.c	(working copy)
*************** cp_protect_cleanup_actions (void)
*** 99,105 ****
  
       When the destruction of an object during stack unwinding exits
       using an exception ... void terminate(); is called.  */
!   return build_call (terminate_node, NULL_TREE);
  }
  
  static tree
--- 99,105 ----
  
       When the destruction of an object during stack unwinding exits
       using an exception ... void terminate(); is called.  */
!   return build_call_n (terminate_node, 0);
  }
  
  static tree
Index: gcc/cp/cp-gimplify.c
===================================================================
*** gcc/cp/cp-gimplify.c	(revision 122018)
--- gcc/cp/cp-gimplify.c	(working copy)
*************** genericize_eh_spec_block (tree *stmt_p)
*** 146,154 ****
  {
    tree body = EH_SPEC_STMTS (*stmt_p);
    tree allowed = EH_SPEC_RAISES (*stmt_p);
!   tree failure = build_call (call_unexpected_node,
! 			     tree_cons (NULL_TREE, build_exc_ptr (),
! 					NULL_TREE));
    gimplify_stmt (&body);
  
    *stmt_p = gimple_build_eh_filter (body, allowed, failure);
--- 146,152 ----
  {
    tree body = EH_SPEC_STMTS (*stmt_p);
    tree allowed = EH_SPEC_RAISES (*stmt_p);
!   tree failure = build_call_n (call_unexpected_node, 1, build_exc_ptr ());
    gimplify_stmt (&body);
  
    *stmt_p = gimple_build_eh_filter (body, allowed, failure);
*************** gimplify_must_not_throw_expr (tree *expr
*** 432,438 ****
    gimplify_stmt (&body);
  
    stmt = gimple_build_eh_filter (body, NULL_TREE,
! 				 build_call (terminate_node, NULL_TREE));
  
    if (temp)
      {
--- 430,436 ----
    gimplify_stmt (&body);
  
    stmt = gimple_build_eh_filter (body, NULL_TREE,
! 				 build_call_n (terminate_node, 0));
  
    if (temp)
      {
*************** static tree
*** 766,776 ****
  cxx_omp_clause_apply_fn (tree fn, tree arg1, tree arg2)
  {
    tree defparm, parm;
!   int i;
  
    if (fn == NULL)
      return NULL;
  
    defparm = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (fn)));
    if (arg2)
      defparm = TREE_CHAIN (defparm);
--- 764,779 ----
  cxx_omp_clause_apply_fn (tree fn, tree arg1, tree arg2)
  {
    tree defparm, parm;
!   int i = 0;
!   int nargs;
!   tree *argarray;
  
    if (fn == NULL)
      return NULL;
  
+   nargs = list_length (DECL_ARGUMENTS (fn));
+   argarray = (tree *) alloca (nargs * sizeof (tree));
+ 
    defparm = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (fn)));
    if (arg2)
      defparm = TREE_CHAIN (defparm);
*************** cxx_omp_clause_apply_fn (tree fn, tree a
*** 817,832 ****
        t = build1 (LABEL_EXPR, void_type_node, lab);
        append_to_statement_list (t, &ret);
  
!       t = tree_cons (NULL, p1, NULL);
        if (arg2)
! 	t = tree_cons (NULL, p2, t);
        /* Handle default arguments.  */
!       i = 1 + (arg2 != NULL);
!       for (parm = defparm; parm != void_list_node; parm = TREE_CHAIN (parm))
! 	t = tree_cons (NULL, convert_default_arg (TREE_VALUE (parm),
! 						  TREE_PURPOSE (parm),
! 						  fn, i++), t);
!       t = build_call (fn, nreverse (t));
        append_to_statement_list (t, &ret);
  
        t = fold_convert (TREE_TYPE (p1), TYPE_SIZE_UNIT (inner_type));
--- 820,833 ----
        t = build1 (LABEL_EXPR, void_type_node, lab);
        append_to_statement_list (t, &ret);
  
!       argarray[i++] = p1;
        if (arg2)
! 	argarray[i++] = p2;
        /* Handle default arguments.  */
!       for (parm = defparm; parm != void_list_node; parm = TREE_CHAIN (parm), i++)
! 	argarray[i] = convert_default_arg (TREE_VALUE (parm),
! 					   TREE_PURPOSE (parm), fn, i);
!       t = build_call_a (fn, i, argarray);
        append_to_statement_list (t, &ret);
  
        t = fold_convert (TREE_TYPE (p1), TYPE_SIZE_UNIT (inner_type));
*************** cxx_omp_clause_apply_fn (tree fn, tree a
*** 850,865 ****
      }
    else
      {
!       tree t = tree_cons (NULL, build_fold_addr_expr (arg1), NULL);
        if (arg2)
! 	t = tree_cons (NULL, build_fold_addr_expr (arg2), t);
        /* Handle default arguments.  */
!       i = 1 + (arg2 != NULL);
!       for (parm = defparm; parm != void_list_node; parm = TREE_CHAIN (parm))
! 	t = tree_cons (NULL, convert_default_arg (TREE_VALUE (parm),
! 						  TREE_PURPOSE (parm),
! 						  fn, i++), t);
!       return build_call (fn, nreverse (t));
      }
  }
  
--- 851,866 ----
      }
    else
      {
!       argarray[i++] = build_fold_addr_expr (arg1);
        if (arg2)
! 	argarray[i++] = build_fold_addr_expr (arg2);
        /* Handle default arguments.  */
!       for (parm = defparm; parm != void_list_node;
! 	   parm = TREE_CHAIN (parm), i++)
! 	argarray[i] = convert_default_arg (TREE_VALUE (parm),
! 					   TREE_PURPOSE (parm),
! 					   fn, i);
!       return build_call_a (fn, i, argarray);
      }
  }
  

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: PATCH: avoid constructing temporary arglists in C and C++ front  ends
  2007-02-17  6:06 PATCH: avoid constructing temporary arglists in C and C++ front ends Sandra Loosemore
@ 2007-02-26 22:37 ` Joseph S. Myers
  2007-02-28 23:56   ` [committed] " Sandra Loosemore
  2007-02-27 15:53 ` Nathan Sidwell
  1 sibling, 1 reply; 4+ messages in thread
From: Joseph S. Myers @ 2007-02-26 22:37 UTC (permalink / raw)
  To: Sandra Loosemore; +Cc: GCC Patches

The C front end parts of this patch are OK.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: PATCH: avoid constructing temporary arglists in C and C++ front  ends
  2007-02-17  6:06 PATCH: avoid constructing temporary arglists in C and C++ front ends Sandra Loosemore
  2007-02-26 22:37 ` Joseph S. Myers
@ 2007-02-27 15:53 ` Nathan Sidwell
  1 sibling, 0 replies; 4+ messages in thread
From: Nathan Sidwell @ 2007-02-27 15:53 UTC (permalink / raw)
  To: Sandra Loosemore; +Cc: GCC Patches

Sandra Loosemore wrote:

> This patch consists of three main chunks of changes.  The first chunk 
> changes some of the high-level constructor functions in fold-const.c and 
> builtins.c (groan!) to work off an argument array instead of a list.  
> The second chunk changes build_function_call in c-typeck.c to alloca an 
> array which eventually gets passed to those constructors, and propagates 
> the change in representation around to the various other helper 
> functions it invokes.  The third chunk makes similar changes to the C++ 
> front end, which has a somewhat larger set of related 
> call-processing-and-construction functions.
> 

the C++ bits are ok.

nathan

-- 
Nathan Sidwell    ::   http://www.codesourcery.com   ::         CodeSourcery
nathan@codesourcery.com    ::     http://www.planetfall.pwp.blueyonder.co.uk

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [committed] Re: PATCH: avoid constructing temporary arglists in C  and C++ front ends
  2007-02-26 22:37 ` Joseph S. Myers
@ 2007-02-28 23:56   ` Sandra Loosemore
  0 siblings, 0 replies; 4+ messages in thread
From: Sandra Loosemore @ 2007-02-28 23:56 UTC (permalink / raw)
  To: GCC Patches

Joseph S. Myers wrote:
> The C front end parts of this patch are OK.

Nathan Sidwell wrote:
> the C++ bits are ok.

OK, patch has been re-tested and committed.

-Sandra



^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2007-02-28 19:24 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-02-17  6:06 PATCH: avoid constructing temporary arglists in C and C++ front ends Sandra Loosemore
2007-02-26 22:37 ` Joseph S. Myers
2007-02-28 23:56   ` [committed] " Sandra Loosemore
2007-02-27 15:53 ` Nathan Sidwell

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).