make function_args_iterator a proper iterator

Message ID fd983596-f26b-547f-cdf9-15f6bf741f6a@gmail.com
State New
Headers show
Series
  • make function_args_iterator a proper iterator
Related show

Commit Message

Martin Sebor Nov. 16, 2018, 11:05 p.m.
To encourage and simplify the adoption of iterator classes in
GCC the attached patch turns the function_args_iterator struct
into an (almost) proper C++ iterator class that can be used
the same way as traditional forward iterators.

The patch also replaces all of the 26 uses of the legacy
FOREACH_FUNCTION_ARGS macro with ordinary for loops that use
function_args_iterator directly, and also poisons both
FOREACH_FUNCTION_ARGS and the unused FOREACH_FUNCTION_ARGS_PTR
macros.

The few dozen (hundred?) existing uses of for loops that iterate
over function parameter types using the TREE_CHAIN() macro can
be relatively easily modified to adopt the iterator approach over
time.  (The patch stops of short of making this change.)

Eventually, when GCC moves to more a recent C++ revision, it will
become possible to simplify the for loops to make use of the range
based for loop syntax along the lines of:

   for (auto argtype: function_args (functype))
     {
       ...
     }

Tested on x86_64-linux, and (lightly) on powerpc64le-linux using
a cross-compiler.  I'll test the changes to the other back ends
before committing.

Martin

PS For some additional background on this change see:
   https://gcc.gnu.org/ml/gcc-patches/2018-11/msg00493.html

Comments

Richard Biener Nov. 19, 2018, 10:32 a.m. | #1
On Sat, Nov 17, 2018 at 12:05 AM Martin Sebor <msebor@gmail.com> wrote:
>

> To encourage and simplify the adoption of iterator classes in

> GCC the attached patch turns the function_args_iterator struct

> into an (almost) proper C++ iterator class that can be used

> the same way as traditional forward iterators.

>

> The patch also replaces all of the 26 uses of the legacy

> FOREACH_FUNCTION_ARGS macro with ordinary for loops that use

> function_args_iterator directly, and also poisons both

> FOREACH_FUNCTION_ARGS and the unused FOREACH_FUNCTION_ARGS_PTR

> macros.

>

> The few dozen (hundred?) existing uses of for loops that iterate

> over function parameter types using the TREE_CHAIN() macro can

> be relatively easily modified to adopt the iterator approach over

> time.  (The patch stops of short of making this change.)

>

> Eventually, when GCC moves to more a recent C++ revision, it will

> become possible to simplify the for loops to make use of the range

> based for loop syntax along the lines of:

>

>    for (auto argtype: function_args (functype))

>      {

>        ...

>      }

>

> Tested on x86_64-linux, and (lightly) on powerpc64le-linux using

> a cross-compiler.  I'll test the changes to the other back ends

> before committing.


This isn't stage3 material.

Richard.

>

> Martin

>

> PS For some additional background on this change see:

>    https://gcc.gnu.org/ml/gcc-patches/2018-11/msg00493.html
Eric Botcazou Nov. 19, 2018, 10:48 a.m. | #2
> Eventually, when GCC moves to more a recent C++ revision, it will

> become possible to simplify the for loops to make use of the range

> based for loop syntax along the lines of:

> 

>    for (auto argtype: function_args (functype))

>      {

>        ...

>      }

> 

> Tested on x86_64-linux, and (lightly) on powerpc64le-linux using

> a cross-compiler.  I'll test the changes to the other back ends

> before committing.


How does this interact with debugging?  Because, in my experience, the more 
you convert things to modernish C++, the less you can easily debug them...

-- 
Eric Botcazou
Martin Sebor Nov. 19, 2018, 3:36 p.m. | #3
On 11/19/2018 03:32 AM, Richard Biener wrote:
> On Sat, Nov 17, 2018 at 12:05 AM Martin Sebor <msebor@gmail.com> wrote:

>>

>> To encourage and simplify the adoption of iterator classes in

>> GCC the attached patch turns the function_args_iterator struct

>> into an (almost) proper C++ iterator class that can be used

>> the same way as traditional forward iterators.

>>

>> The patch also replaces all of the 26 uses of the legacy

>> FOREACH_FUNCTION_ARGS macro with ordinary for loops that use

>> function_args_iterator directly, and also poisons both

>> FOREACH_FUNCTION_ARGS and the unused FOREACH_FUNCTION_ARGS_PTR

>> macros.

>>

>> The few dozen (hundred?) existing uses of for loops that iterate

>> over function parameter types using the TREE_CHAIN() macro can

>> be relatively easily modified to adopt the iterator approach over

>> time.  (The patch stops of short of making this change.)

>>

>> Eventually, when GCC moves to more a recent C++ revision, it will

>> become possible to simplify the for loops to make use of the range

>> based for loop syntax along the lines of:

>>

>>    for (auto argtype: function_args (functype))

>>      {

>>        ...

>>      }

>>

>> Tested on x86_64-linux, and (lightly) on powerpc64le-linux using

>> a cross-compiler.  I'll test the changes to the other back ends

>> before committing.

>

> This isn't stage3 material.


In the response referenced below Jeff requested I make use of
iterators in my patch.  This simply does what he asked for,
except throughout all of GCC.

Martin

>

> Richard.

>

>>

>> Martin

>>

>> PS For some additional background on this change see:

>>    https://gcc.gnu.org/ml/gcc-patches/2018-11/msg00493.html
Martin Sebor Nov. 19, 2018, 3:57 p.m. | #4
On 11/19/2018 03:48 AM, Eric Botcazou wrote:
>> Eventually, when GCC moves to more a recent C++ revision, it will

>> become possible to simplify the for loops to make use of the range

>> based for loop syntax along the lines of:

>>

>>    for (auto argtype: function_args (functype))

>>      {

>>        ...

>>      }

>>

>> Tested on x86_64-linux, and (lightly) on powerpc64le-linux using

>> a cross-compiler.  I'll test the changes to the other back ends

>> before committing.

>

> How does this interact with debugging?  Because, in my experience, the more

> you convert things to modernish C++, the less you can easily debug them...


There are no unexpected interactions that I'm aware of.  The C++
11 range for loop is just convenient syntax that the front end
"expands" to a conventional loop using ordinary iterators.  Calls
to the iterator members that implicitly take place can be stepped
into using the debugger just like any other functions.  In terms
of the user experience, I'd say the range for loop is pretty close
to a macro that expands to the use iterators.

Martin
Richard Biener Nov. 20, 2018, 9:21 a.m. | #5
On Mon, Nov 19, 2018 at 4:36 PM Martin Sebor <msebor@gmail.com> wrote:
>

> On 11/19/2018 03:32 AM, Richard Biener wrote:

> > On Sat, Nov 17, 2018 at 12:05 AM Martin Sebor <msebor@gmail.com> wrote:

> >>

> >> To encourage and simplify the adoption of iterator classes in

> >> GCC the attached patch turns the function_args_iterator struct

> >> into an (almost) proper C++ iterator class that can be used

> >> the same way as traditional forward iterators.

> >>

> >> The patch also replaces all of the 26 uses of the legacy

> >> FOREACH_FUNCTION_ARGS macro with ordinary for loops that use

> >> function_args_iterator directly, and also poisons both

> >> FOREACH_FUNCTION_ARGS and the unused FOREACH_FUNCTION_ARGS_PTR

> >> macros.

> >>

> >> The few dozen (hundred?) existing uses of for loops that iterate

> >> over function parameter types using the TREE_CHAIN() macro can

> >> be relatively easily modified to adopt the iterator approach over

> >> time.  (The patch stops of short of making this change.)

> >>

> >> Eventually, when GCC moves to more a recent C++ revision, it will

> >> become possible to simplify the for loops to make use of the range

> >> based for loop syntax along the lines of:

> >>

> >>    for (auto argtype: function_args (functype))

> >>      {

> >>        ...

> >>      }

> >>

> >> Tested on x86_64-linux, and (lightly) on powerpc64le-linux using

> >> a cross-compiler.  I'll test the changes to the other back ends

> >> before committing.

> >

> > This isn't stage3 material.

>

> In the response referenced below Jeff requested I make use of

> iterators in my patch.  This simply does what he asked for,

> except throughout all of GCC.


I don't think he said you should invent new iterators - we have
existing ones.

Richard.

>

> Martin

>

> >

> > Richard.

> >

> >>

> >> Martin

> >>

> >> PS For some additional background on this change see:

> >>    https://gcc.gnu.org/ml/gcc-patches/2018-11/msg00493.html

>
Martin Sebor Nov. 20, 2018, 3:28 p.m. | #6
On 11/20/2018 02:21 AM, Richard Biener wrote:
> On Mon, Nov 19, 2018 at 4:36 PM Martin Sebor <msebor@gmail.com> wrote:

>>

>> On 11/19/2018 03:32 AM, Richard Biener wrote:

>>> On Sat, Nov 17, 2018 at 12:05 AM Martin Sebor <msebor@gmail.com> wrote:

>>>>

>>>> To encourage and simplify the adoption of iterator classes in

>>>> GCC the attached patch turns the function_args_iterator struct

>>>> into an (almost) proper C++ iterator class that can be used

>>>> the same way as traditional forward iterators.

>>>>

>>>> The patch also replaces all of the 26 uses of the legacy

>>>> FOREACH_FUNCTION_ARGS macro with ordinary for loops that use

>>>> function_args_iterator directly, and also poisons both

>>>> FOREACH_FUNCTION_ARGS and the unused FOREACH_FUNCTION_ARGS_PTR

>>>> macros.

>>>>

>>>> The few dozen (hundred?) existing uses of for loops that iterate

>>>> over function parameter types using the TREE_CHAIN() macro can

>>>> be relatively easily modified to adopt the iterator approach over

>>>> time.  (The patch stops of short of making this change.)

>>>>

>>>> Eventually, when GCC moves to more a recent C++ revision, it will

>>>> become possible to simplify the for loops to make use of the range

>>>> based for loop syntax along the lines of:

>>>>

>>>>    for (auto argtype: function_args (functype))

>>>>      {

>>>>        ...

>>>>      }

>>>>

>>>> Tested on x86_64-linux, and (lightly) on powerpc64le-linux using

>>>> a cross-compiler.  I'll test the changes to the other back ends

>>>> before committing.

>>>

>>> This isn't stage3 material.

>>

>> In the response referenced below Jeff requested I make use of

>> iterators in my patch.  This simply does what he asked for,

>> except throughout all of GCC.

>

> I don't think he said you should invent new iterators - we have

> existing ones.


The patch doesn't add a new iterator: it makes the existing
function_args_iterator a proper iterator class with the expected
iterator members like increment and equality operator, to make
it usable in contexts where other iterators (and pointers) are
expected.

Martin

>

> Richard.

>

>>

>> Martin

>>

>>>

>>> Richard.

>>>

>>>>

>>>> Martin

>>>>

>>>> PS For some additional background on this change see:

>>>>    https://gcc.gnu.org/ml/gcc-patches/2018-11/msg00493.html

>>
Jeff Law Nov. 29, 2018, 4:40 a.m. | #7
On 11/20/18 8:28 AM, Martin Sebor wrote:
> On 11/20/2018 02:21 AM, Richard Biener wrote:

>> On Mon, Nov 19, 2018 at 4:36 PM Martin Sebor <msebor@gmail.com> wrote:

>>>

>>> On 11/19/2018 03:32 AM, Richard Biener wrote:

>>>> On Sat, Nov 17, 2018 at 12:05 AM Martin Sebor <msebor@gmail.com> wrote:

>>>>>

>>>>> To encourage and simplify the adoption of iterator classes in

>>>>> GCC the attached patch turns the function_args_iterator struct

>>>>> into an (almost) proper C++ iterator class that can be used

>>>>> the same way as traditional forward iterators.

>>>>>

>>>>> The patch also replaces all of the 26 uses of the legacy

>>>>> FOREACH_FUNCTION_ARGS macro with ordinary for loops that use

>>>>> function_args_iterator directly, and also poisons both

>>>>> FOREACH_FUNCTION_ARGS and the unused FOREACH_FUNCTION_ARGS_PTR

>>>>> macros.

>>>>>

>>>>> The few dozen (hundred?) existing uses of for loops that iterate

>>>>> over function parameter types using the TREE_CHAIN() macro can

>>>>> be relatively easily modified to adopt the iterator approach over

>>>>> time.  (The patch stops of short of making this change.)

>>>>>

>>>>> Eventually, when GCC moves to more a recent C++ revision, it will

>>>>> become possible to simplify the for loops to make use of the range

>>>>> based for loop syntax along the lines of:

>>>>>

>>>>>    for (auto argtype: function_args (functype))

>>>>>      {

>>>>>        ...

>>>>>      }

>>>>>

>>>>> Tested on x86_64-linux, and (lightly) on powerpc64le-linux using

>>>>> a cross-compiler.  I'll test the changes to the other back ends

>>>>> before committing.

>>>>

>>>> This isn't stage3 material.

>>>

>>> In the response referenced below Jeff requested I make use of

>>> iterators in my patch.  This simply does what he asked for,

>>> except throughout all of GCC.

>>

>> I don't think he said you should invent new iterators - we have

>> existing ones.

> 

> The patch doesn't add a new iterator: it makes the existing

> function_args_iterator a proper iterator class with the expected

> iterator members like increment and equality operator, to make

> it usable in contexts where other iterators (and pointers) are

> expected.

The way to go would have been to just use the existing iterator in your
patch and queue a gcc-10 change to a proper iterator.

Patch

gcc/c/ChangeLog:

	* c-parser.c (check_tgmath_function): Replace FOREACH_FUNCTION_ARGS
	with direct function_args_iterator operations.
	(c_parser_postfix_expression): Same.

gcc/c-family/ChangeLog:

	* c-ada-spec.c (dump_forward_type): Same.
	* c-common.c (check_function_sentinel): Same.
	* c-format.c (handle_format_attribute): Same.
	* c-warn.c (sizeof_pointer_memaccess_warning): Same.

gcc/ChangeLog:

	* config/arm/arm.c (arm_handle_notshared_attribute): Same.
	(cmse_nonsecure_call_clear_caller_saved): Same.
	* config/i386/i386.c (init_cumulative_args): Same.
	* config/i386/winnt.c (gen_stdcall_or_fastcall_suffix): Same.
	* config/powerpcspe/powerpcspe.c (rs6000_function_parms_need_stack):
	Same.
	(rs6000_function_ok_for_sibcall): Same.
	* config/rs6000/rs6000.c (rs6000_function_parms_need_stack): Same.
	(rs6000_function_ok_for_sibcall): Same.
	(rs6000_mangle_decl_assembler_name): Same.
	* godump.c (go_format_type): Same.
	* tree.c (type_argument_type): Same.
	(get_name): Same.
	* tree-core.h (function_args_iterator): Move from here...
	* tree.h (function_args_iterator): to here.  Define member and
	non-member functions.
	(FOREACH_FUNCTION_ARGS): Poison macro.
	(FOREACH_FUNCTION_ARGS_PTR): Poison unused macro.

Index: gcc/c/c-parser.c
===================================================================
--- gcc/c/c-parser.c	(revision 266219)
+++ gcc/c/c-parser.c	(working copy)
@@ -7762,14 +7762,10 @@  check_tgmath_function (c_expr *expr, unsigned int
       return 0;
     }
   unsigned int nargs = 0;
-  function_args_iterator iter;
-  tree t;
-  FOREACH_FUNCTION_ARGS (type, t, iter)
-    {
-      if (t == void_type_node)
-	break;
-      nargs++;
-    }
+  for (function_args_iterator iter (type); iter; ++iter, ++nargs)
+    if (*iter == void_type_node)
+      break;
+
   if (nargs == 0)
     {
       error_at (expr->get_location (),
@@ -8340,11 +8336,11 @@  c_parser_postfix_expression (c_parser *parser)
 	    parm_first.quick_push (first_ret);
 	    parm_complex.quick_push (TREE_CODE (first_ret) == COMPLEX_TYPE);
 	    parm_varies.quick_push (false);
-	    function_args_iterator iter;
-	    tree t;
+
 	    unsigned int argpos;
-	    FOREACH_FUNCTION_ARGS (first_type, t, iter)
+	    for (function_args_iterator iter (first_type); iter; ++iter)
 	      {
+		tree t = *iter;
 		if (t == void_type_node)
 		  break;
 		parm_first.quick_push (TYPE_MAIN_VARIANT (t));
@@ -8382,8 +8378,9 @@  c_parser_postfix_expression (c_parser *parser)
 		if (TREE_CODE (ret) == COMPLEX_TYPE)
 		  parm_complex[0] = true;
 		argpos = 1;
-		FOREACH_FUNCTION_ARGS (type, t, iter)
+		for (function_args_iterator iter (type); iter; ++iter)
 		  {
+		    tree t = *iter;
 		    if (t == void_type_node)
 		      break;
 		    t = TYPE_MAIN_VARIANT (t);
@@ -8469,8 +8466,9 @@  c_parser_postfix_expression (c_parser *parser)
 	      {
 		tree type = TREE_TYPE (TREE_TYPE ((*cexpr_list)[j].value));
 		argpos = 1;
-		FOREACH_FUNCTION_ARGS (type, t, iter)
+		for (function_args_iterator iter (type); iter; ++iter)
 		  {
+		    tree t = *iter;
 		    if (argpos == tgarg)
 		      {
 			tg_type.quick_push (TYPE_MAIN_VARIANT (t));
@@ -8489,6 +8487,7 @@  c_parser_postfix_expression (c_parser *parser)
 	    bool all_binary = true;
 	    bool all_decimal = true;
 	    hash_set<tree> tg_types;
+	    tree t;
 	    FOR_EACH_VEC_ELT (tg_type, i, t)
 	      {
 		if (TREE_CODE (t) == COMPLEX_TYPE)
@@ -8533,8 +8532,9 @@  c_parser_postfix_expression (c_parser *parser)
 		    goto out;
 		  }
 		argpos = 1;
-		FOREACH_FUNCTION_ARGS (type, t, iter)
+		for (function_args_iterator iter (type); iter; ++iter)
 		  {
+		    tree t = *iter;
 		    if (t == void_type_node)
 		      break;
 		    t = TYPE_MAIN_VARIANT (t);
Index: gcc/c-family/c-ada-spec.c
===================================================================
--- gcc/c-family/c-ada-spec.c	(revision 266219)
+++ gcc/c-family/c-ada-spec.c	(working copy)
@@ -2411,11 +2411,9 @@  dump_forward_type (pretty_printer *buffer, tree ty
 	dump_forward_type (buffer, TREE_TYPE (type), t, spc);
       else if (TREE_CODE (type) == FUNCTION_TYPE)
 	{
-	  function_args_iterator args_iter;
-	  tree arg;
 	  dump_forward_type (buffer, TREE_TYPE (type), t, spc);
-	  FOREACH_FUNCTION_ARGS (type, arg, args_iter)
-	    dump_forward_type (buffer, arg, t, spc);
+	  for (function_args_iterator iter (type); iter; ++iter)
+	    dump_forward_type (buffer, *iter, t, spc);
 	}
       return;
     }
Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(revision 266219)
+++ gcc/c-family/c-common.c	(working copy)
@@ -5309,11 +5309,9 @@  check_function_sentinel (const_tree fntype, int na
       int len = 0;
       int pos = 0;
       tree sentinel;
-      function_args_iterator iter;
-      tree t;
 
       /* Skip over the named arguments.  */
-      FOREACH_FUNCTION_ARGS (fntype, t, iter)
+      for (function_args_iterator iter (fntype); iter; ++iter)
 	{
 	  if (len == nargs)
 	    break;
Index: gcc/c-family/c-format.c
===================================================================
--- gcc/c-family/c-format.c	(revision 266219)
+++ gcc/c-family/c-format.c	(working copy)
@@ -179,18 +179,17 @@  static bool
 check_format_string (const_tree fntype, unsigned HOST_WIDE_INT format_num,
 		     int flags, bool *no_add_attrs, int expected_format_type)
 {
-  unsigned HOST_WIDE_INT i;
   bool is_objc_sref, is_target_sref, is_char_ref;
-  tree ref;
   int fmt_flags;
-  function_args_iterator iter;
 
-  i = 1;
-  FOREACH_FUNCTION_ARGS (fntype, ref, iter)
+  tree ref = NULL_TREE;
+  unsigned HOST_WIDE_INT i = 1;
+  for (function_args_iterator iter (fntype); iter; ++iter, ++i)
     {
+      ref = *iter;
+
       if (i == format_num)
 	break;
-      i++;
     }
 
   if (!ref
@@ -4180,12 +4179,10 @@  handle_format_attribute (tree *node, tree atname,
       if (info.first_arg_num != 0)
 	{
 	  unsigned HOST_WIDE_INT arg_num = 1;
-	  function_args_iterator iter;
-	  tree arg_type;
 
 	  /* Verify that first_arg_num points to the last arg,
 	     the ...  */
-	  FOREACH_FUNCTION_ARGS (type, arg_type, iter)
+	  for (function_args_iterator iter (type); iter; ++iter)
 	    arg_num++;
 
 	  if (arg_num != info.first_arg_num)
Index: gcc/c-family/c-warn.c
===================================================================
--- gcc/c-family/c-warn.c	(revision 266219)
+++ gcc/c-family/c-warn.c	(working copy)
@@ -1012,12 +1012,11 @@  sizeof_pointer_memaccess_warning (location_t *size
 void
 check_main_parameter_types (tree decl)
 {
-  function_args_iterator iter;
-  tree type;
   int argct = 0;
 
-  FOREACH_FUNCTION_ARGS (TREE_TYPE (decl), type, iter)
+  for (function_args_iterator iter (TREE_TYPE (decl)); iter; ++iter)
     {
+      tree type = *iter;
       /* XXX void_type_node belies the abstraction.  */
       if (type == void_type_node || type == error_mark_node)
 	break;
Index: gcc/config/arm/arm.c
===================================================================
--- gcc/config/arm/arm.c	(revision 266219)
+++ gcc/config/arm/arm.c	(working copy)
@@ -6945,17 +6945,17 @@  arm_handle_notshared_attribute (tree *node,
 static bool
 cmse_func_args_or_return_in_stack (tree fndecl, tree name, tree fntype)
 {
-  function_args_iterator args_iter;
   CUMULATIVE_ARGS args_so_far_v;
   cumulative_args_t args_so_far;
   bool first_param = true;
-  tree arg_type, prev_arg_type = NULL_TREE, ret_type;
+  tree prev_arg_type = NULL_TREE, ret_type;
 
   /* Error out if any argument is passed on the stack.  */
   arm_init_cumulative_args (&args_so_far_v, fntype, NULL_RTX, fndecl);
   args_so_far = pack_cumulative_args (&args_so_far_v);
-  FOREACH_FUNCTION_ARGS (fntype, arg_type, args_iter)
+  for (function_args_iterator iter (fntype); iter; ++iter)
     {
+      tree arg_type = *iter;
       rtx arg_rtx;
       machine_mode arg_mode = TYPE_MODE (arg_type);
 
@@ -17233,7 +17233,6 @@  cmse_nonsecure_call_clear_caller_saved (void)
 	  cumulative_args_t args_so_far;
 	  tree arg_type, fntype;
 	  bool first_param = true;
-	  function_args_iterator args_iter;
 	  uint32_t padding_bits_to_clear[4] = {0U, 0U, 0U, 0U};
 
 	  if (!NONDEBUG_INSN_P (insn))
@@ -17299,8 +17298,9 @@  cmse_nonsecure_call_clear_caller_saved (void)
 	  arm_init_cumulative_args (&args_so_far_v, fntype, NULL_RTX,
 				    NULL_TREE);
 	  args_so_far = pack_cumulative_args (&args_so_far_v);
-	  FOREACH_FUNCTION_ARGS (fntype, arg_type, args_iter)
+	  for (function_args_iterator iter (fntype); iter; ++iter)
 	    {
+	      tree arg_type = *iter;
 	      rtx arg_rtx;
 	      uint64_t to_clear_args_mask;
 	      machine_mode arg_mode = TYPE_MODE (arg_type);
Index: gcc/config/i386/i386.c
===================================================================
--- gcc/config/i386/i386.c	(revision 266219)
+++ gcc/config/i386/i386.c	(working copy)
@@ -7074,11 +7074,10 @@  init_cumulative_args (CUMULATIVE_ARGS *cum,  /* Ar
   cum->warn_empty = !warn_abi || cum->stdarg;
   if (!cum->warn_empty && fntype)
     {
-      function_args_iterator iter;
-      tree argtype;
       bool seen_empty_type = false;
-      FOREACH_FUNCTION_ARGS (fntype, argtype, iter)
+      for (function_args_iterator iter (fntype); iter; ++iter)
 	{
+	  tree argtype = *iter;
 	  if (argtype == error_mark_node || VOID_TYPE_P (argtype))
 	    break;
 	  if (TYPE_EMPTY_P (argtype))
Index: gcc/config/i386/winnt.c
===================================================================
--- gcc/config/i386/winnt.c	(revision 266219)
+++ gcc/config/i386/winnt.c	(working copy)
@@ -182,8 +182,6 @@  gen_stdcall_or_fastcall_suffix (tree decl, tree id
   const char *old_str = IDENTIFIER_POINTER (id != NULL_TREE ? id : DECL_NAME (decl));
   char *new_str, *p;
   tree type = TREE_TYPE (DECL_ORIGIN (decl));
-  tree arg;
-  function_args_iterator args_iter;
 
   gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);  
 
@@ -195,8 +193,9 @@  gen_stdcall_or_fastcall_suffix (tree decl, tree id
 
       /* Quit if we hit an incomplete type.  Error is reported
 	 by convert_arguments in c-typeck.c or cp/typeck.c.  */
-      FOREACH_FUNCTION_ARGS(type, arg, args_iter)
+      for (function_args_iterator iter (type); iter; ++iter)
 	{
+	  tree arg = *iter;
 	  HOST_WIDE_INT parm_size;
 	  HOST_WIDE_INT parm_boundary_bytes = PARM_BOUNDARY / BITS_PER_UNIT;
 
Index: gcc/config/powerpcspe/powerpcspe.c
===================================================================
--- gcc/config/powerpcspe/powerpcspe.c	(revision 266219)
+++ gcc/config/powerpcspe/powerpcspe.c	(working copy)
@@ -13541,11 +13541,8 @@  rs6000_function_parms_need_stack (tree fun, bool i
     }
   else
     {
-      function_args_iterator args_iter;
-      tree arg_type;
-
-      FOREACH_FUNCTION_ARGS (fntype, arg_type, args_iter)
-	if (rs6000_parm_needs_stack (args_so_far, arg_type))
+      for (function_args_iterator iter (fntype); iter; ++iter)
+	if (rs6000_parm_needs_stack (args_so_far, *iter))
 	  return true;
     }
 
@@ -28037,22 +28034,27 @@  rs6000_function_ok_for_sibcall (tree decl, tree ex
       && TARGET_ALTIVEC_VRSAVE
       && !(decl && decl == current_function_decl))
     {
-      function_args_iterator args_iter;
-      tree type;
       int nvreg = 0;
 
       /* Functions with vector parameters are required to have a
 	 prototype, so the argument type info must be available
 	 here.  */
-      FOREACH_FUNCTION_ARGS(fntype, type, args_iter)
-	if (TREE_CODE (type) == VECTOR_TYPE
-	    && ALTIVEC_OR_VSX_VECTOR_MODE (TYPE_MODE (type)))
-	  nvreg++;
+      for (function_args_iterator iter (fntype); iter; ++iter)
+	{
+	  tree type = *iter;
+	  if (TREE_CODE (type) == VECTOR_TYPE
+	      && ALTIVEC_OR_VSX_VECTOR_MODE (TYPE_MODE (type)))
+	    nvreg++;
+	}
 
-      FOREACH_FUNCTION_ARGS(TREE_TYPE (current_function_decl), type, args_iter)
-	if (TREE_CODE (type) == VECTOR_TYPE
-	    && ALTIVEC_OR_VSX_VECTOR_MODE (TYPE_MODE (type)))
-	  nvreg--;
+      for (function_args_iterator iter (TREE_TYPE (current_function_decl));
+	   iter; ++iter)
+	{
+	  tree type = *iter;
+	  if (TREE_CODE (type) == VECTOR_TYPE
+	      && ALTIVEC_OR_VSX_VECTOR_MODE (TYPE_MODE (type)))
+	    nvreg--;
+	}
 
       if (nvreg > 0)
 	return false;
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(revision 266219)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -12288,11 +12288,8 @@  rs6000_function_parms_need_stack (tree fun, bool i
     }
   else
     {
-      function_args_iterator args_iter;
-      tree arg_type;
-
-      FOREACH_FUNCTION_ARGS (fntype, arg_type, args_iter)
-	if (rs6000_parm_needs_stack (args_so_far, arg_type))
+      for (function_args_iterator iter (fntype); iter; ++iter)
+	if (rs6000_parm_needs_stack (args_so_far, *iter))
 	  return true;
     }
 
@@ -24569,15 +24566,22 @@  rs6000_function_ok_for_sibcall (tree decl, tree ex
       /* Functions with vector parameters are required to have a
 	 prototype, so the argument type info must be available
 	 here.  */
-      FOREACH_FUNCTION_ARGS(fntype, type, args_iter)
-	if (TREE_CODE (type) == VECTOR_TYPE
-	    && ALTIVEC_OR_VSX_VECTOR_MODE (TYPE_MODE (type)))
-	  nvreg++;
+      for (function_args_iterator iter (fntype); iter; ++iter)
+	{
+	  tree type = *iter;
+	  if (TREE_CODE (type) == VECTOR_TYPE
+	      && ALTIVEC_OR_VSX_VECTOR_MODE (TYPE_MODE (type)))
+	    nvreg++;
+	}
 
-      FOREACH_FUNCTION_ARGS(TREE_TYPE (current_function_decl), type, args_iter)
-	if (TREE_CODE (type) == VECTOR_TYPE
-	    && ALTIVEC_OR_VSX_VECTOR_MODE (TYPE_MODE (type)))
-	  nvreg--;
+      for (function_args_iterator iter (TREE_TYPE (current_function_decl));
+	   iter; ++iter)
+	{
+	  tree type = *iter;
+	  if (TREE_CODE (type) == VECTOR_TYPE
+	      && ALTIVEC_OR_VSX_VECTOR_MODE (TYPE_MODE (type)))
+	    nvreg--;
+	}
 
       if (nvreg > 0)
 	return false;
@@ -38996,13 +39000,11 @@  rs6000_mangle_decl_assembler_name (tree decl, tree
 	    uses_ieee128_p = true;
 	  else
 	    {
-	      function_args_iterator args_iter;
-	      tree arg;
-
 	      /* See if the function passes a IEEE 128-bit floating point type
 		 or complex type.  */
-	      FOREACH_FUNCTION_ARGS (type, arg, args_iter)
+	      for (function_args_iterator iter (type); iter; ++iter)
 		{
+		  tree arg = *iter;
 		  machine_mode arg_mode = TYPE_MODE (arg);
 		  if (arg_mode == TFmode || arg_mode == TCmode)
 		    {
Index: gcc/godump.c
===================================================================
--- gcc/godump.c	(revision 266219)
+++ gcc/godump.c	(working copy)
@@ -1032,10 +1032,8 @@  go_format_type (struct godump_container *container
 
     case FUNCTION_TYPE:
       {
-	tree arg_type;
 	bool is_varargs;
 	tree result;
-	function_args_iterator iter;
 	bool seen_arg;
 
 	/* Go has no way to write a type which is a function but not a
@@ -1049,8 +1047,9 @@  go_format_type (struct godump_container *container
 	obstack_1grow (ob, '(');
 	is_varargs = stdarg_p (type);
 	seen_arg = false;
-	FOREACH_FUNCTION_ARGS (type, arg_type, iter)
+	for (function_args_iterator iter (type); iter; ++iter)
 	  {
+	    tree arg_type = *iter;
 	    if (VOID_TYPE_P (arg_type))
 	      break;
 	    if (seen_arg)
Index: gcc/tree-core.h
===================================================================
--- gcc/tree-core.h	(revision 266219)
+++ gcc/tree-core.h	(working copy)
@@ -2042,11 +2042,6 @@  typedef struct record_layout_info_s {
   int packed_maybe_necessary;
 } *record_layout_info;
 
-/* Iterator for going through the function arguments.  */
-struct function_args_iterator {
-  tree next;			/* TREE_LIST pointing to the next argument */
-};
-
 /* Structures to map from a tree to another tree.  */
 struct GTY(()) tree_map_base {
   tree from;
Index: gcc/tree.c
===================================================================
--- gcc/tree.c	(revision 266219)
+++ gcc/tree.c	(working copy)
@@ -6972,12 +6972,11 @@  type_argument_type (const_tree fntype, unsigned ar
   if (!argno)
     return void_type_node;
 
-  function_args_iterator iter;
-
-  tree argtype;
   unsigned i = 1;
-  FOREACH_FUNCTION_ARGS (fntype, argtype, iter)
+  for (function_args_iterator iter (fntype); iter; ++iter, ++i)
     {
+      tree argtype = *iter;
+
       /* A vararg function's argument list ends in a null.  Otherwise,
 	 an ordinary function's argument list ends with void.  Return
 	 null if ARGNO refers to a vararg argument, void_type_node if
@@ -6987,8 +6986,6 @@  type_argument_type (const_tree fntype, unsigned ar
 
       if (i == argno || VOID_TYPE_P (argtype))
 	return argtype;
-
-      ++i;
     }
 
   return NULL_TREE;
@@ -12223,22 +12220,15 @@  get_name (tree t)
     }
 }
 
-/* Return true if TYPE has a variable argument list.  */
+/* Return true if FNTYPE has a variable argument list.  */
 
 bool
 stdarg_p (const_tree fntype)
 {
-  function_args_iterator args_iter;
-  tree n = NULL_TREE, t;
+  tree n = NULL_TREE;
+  for (function_args_iterator iter (fntype); iter; ++iter)
+    n = *iter;
 
-  if (!fntype)
-    return false;
-
-  FOREACH_FUNCTION_ARGS (fntype, t, args_iter)
-    {
-      n = t;
-    }
-
   return n != NULL_TREE && n != void_type_node;
 }
 
Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(revision 266219)
+++ gcc/tree.h	(working copy)
@@ -4758,6 +4758,73 @@  extern tree decl_type_context (const_tree);
 /* Return true if EXPR is the real constant zero.  */
 extern bool real_zerop (const_tree);
 
+
+/* Forward iterator for iterating over the types of a function's argument
+   list.  */
+
+struct function_args_iterator
+{
+  tree next;			/* TREE_LIST pointing to the next argument */
+
+  /* Create an end iterator.  */
+  function_args_iterator ()
+    : next (NULL_TREE)
+  { /* No-op.  */ }
+
+  /* Create an iterator from a function type, or the end iterator
+     if FNTYPE is null.  */
+  function_args_iterator (const_tree fntype)
+    : next (fntype ? TYPE_ARG_TYPES (fntype) : NULL_TREE)
+  { /* No-op.  */ }
+
+  /* Contextual conversion to bool.  */
+  /* explicit (in C++ 11) */ operator bool () const
+  {
+    return next != NULL_TREE;
+  }
+
+  /* Dereference the iterator and return a reference to the type.  */
+  tree& operator* ()
+  {
+    return TREE_VALUE (next);
+  }
+
+  /* Dereference the const iterator and return the type value.  */
+  tree operator* () const
+  {
+    return TREE_VALUE (next);
+  }
+
+  /* Preincrement.  */
+  function_args_iterator& operator++ ()
+  {
+    next = TREE_CHAIN (next);
+    return *this;
+  }
+
+  /* Postincrement.  */
+  function_args_iterator operator++ (int)
+  {
+    const function_args_iterator tmp (*this);
+    ++*this;
+    return tmp;
+  }
+};
+
+inline bool
+operator== (const function_args_iterator &lhs,
+	    const function_args_iterator &rhs)
+{
+  return lhs.next == rhs.next;
+}
+
+inline bool
+operator!= (const function_args_iterator &lhs,
+	    const function_args_iterator &rhs)
+{
+  return lhs.next != rhs.next;
+}
+
 /* Initialize the iterator I with arguments from function FNDECL  */
 
 static inline void
@@ -4800,22 +4867,11 @@  inlined_function_outer_scope_p (const_tree block)
  return LOCATION_LOCUS (BLOCK_SOURCE_LOCATION (block)) != UNKNOWN_LOCATION;
 }
 
-/* Loop over all function arguments of FNTYPE.  In each iteration, PTR is set
-   to point to the next tree element.  ITER is an instance of
-   function_args_iterator used to iterate the arguments.  */
-#define FOREACH_FUNCTION_ARGS_PTR(FNTYPE, PTR, ITER)			\
-  for (function_args_iter_init (&(ITER), (FNTYPE));			\
-       (PTR = function_args_iter_cond_ptr (&(ITER))) != NULL;		\
-       function_args_iter_next (&(ITER)))
+/* Use function_args_iterator directly to loop over the types of function
+   parameters.  */
+#pragma GCC poison FOREACH_FUNCTION_ARGS
+#pragma GCC poison FOREACH_FUNCTION_ARGS_PTR
 
-/* Loop over all function arguments of FNTYPE.  In each iteration, TREE is set
-   to the next tree element.  ITER is an instance of function_args_iterator
-   used to iterate the arguments.  */
-#define FOREACH_FUNCTION_ARGS(FNTYPE, TREE, ITER)			\
-  for (function_args_iter_init (&(ITER), (FNTYPE));			\
-       (TREE = function_args_iter_cond (&(ITER))) != NULL_TREE;		\
-       function_args_iter_next (&(ITER)))
-
 /* In tree.c */
 extern unsigned crc32_unsigned_n (unsigned, unsigned, unsigned);
 extern unsigned crc32_string (unsigned, const char *);