This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
varargs fix for array 'va_list'.
- To: gcc-patches at gcc dot gnu dot org
- Subject: varargs fix for array 'va_list'.
- From: Geoff Keating <geoffk at cygnus dot com>
- Date: Thu, 23 Mar 2000 16:10:33 -0800
This fixes va-arg-13 and va-arg-14 on ppc.
The problems are caused by trying to deal with, for example,
void foo (va_list foo, va_list bar)
{
va_list baz;
va_copy (foo, bar);
va_copy (baz, bar);
}
because '&foo' has type 'va_list *' but '&baz' has type 'va_list'.
So we can't use '&foo' in the definitions of va_copy or va_start; the
previous hack that tried to work around this failed under the right
circumstances.
The only disadvantage of this is that now on machines where va_list
is not an array type, the builtins for va_copy and va_start
magically change their first parameter. If it was necessary to avoid
this, you'd probably have to define some other builtin or some magic
token that sometimes did '&foo' and sometimes didn't, and that seemed
even more ugly.
Bootstrapped and tested on ppc, x86, and alpha linux.
OK to commit?
--
- Geoffrey Keating <geoffk@cygnus.com>
===File /home/geoffk/patches/cygnus/egcs-vastart-fix-2.patch===
2000-03-22 Geoff Keating <geoffk@cygnus.com>
* c-common.c (c_common_nodes_and_builtins): The first parameter
to __builtin_va_start and __builtin_va_copy is now just an 'va_list',
which is magically changed.
* builtins.c (stabilize_va_list): Simplify now we don't have to
work around C array address decay.
* ginclude/stdarg.h (va_start): Don't take address of first parameter.
(va_copy): Likewise.
(__va_copy): Likewise.
* ginclude/stdarg.h (va_start): Likewise.
(__va_copy): Likewise.
Index: builtins.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/builtins.c,v
retrieving revision 1.39
diff -p -u -c -p -r1.39 builtins.c
*** builtins.c 2000/03/23 21:32:10 1.39
--- builtins.c 2000/03/24 00:02:46
*************** expand_builtin_next_arg (arglist)
*** 1866,1931 ****
from multiple evaluations. */
static tree
! stabilize_va_list (valist, was_ptr)
tree valist;
! int was_ptr;
{
if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
{
! /* If stdarg.h took the address of an array-type valist that was passed
! as a parameter, we'll have taken the address of the parameter itself
! rather than the array as we'd intended. Undo this mistake. */
!
! if (was_ptr)
! {
! STRIP_NOPS (valist);
!
! /* Two cases: either &array, which decomposed to
! <ptr <array <record> valist>>
! or &ptr, which turned into
! <ptr <ptr <record>>>
! In the first case we'll need to put the ADDR_EXPR back
! after frobbing the types as if &array[0]. */
!
! if (TREE_CODE (valist) != ADDR_EXPR)
! abort ();
! valist = TREE_OPERAND (valist, 0);
! }
! if (TYPE_MAIN_VARIANT (TREE_TYPE (valist))
! == TYPE_MAIN_VARIANT (va_list_type_node))
! {
! tree pt = build_pointer_type (TREE_TYPE (va_list_type_node));
! valist = build1 (ADDR_EXPR, pt, valist);
! TREE_SIDE_EFFECTS (valist)
! = TREE_SIDE_EFFECTS (TREE_OPERAND (valist, 0));
! }
! else
{
! if (! POINTER_TYPE_P (TREE_TYPE (valist))
! || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (valist)))
! != TYPE_MAIN_VARIANT (TREE_TYPE (va_list_type_node))))
! abort ();
}
-
- if (TREE_SIDE_EFFECTS (valist))
- valist = save_expr (valist);
}
else
{
! if (! was_ptr)
! {
! tree pt;
!
! if (! TREE_SIDE_EFFECTS (valist))
! return valist;
! pt = build_pointer_type (va_list_type_node);
! valist = fold (build1 (ADDR_EXPR, pt, valist));
! TREE_SIDE_EFFECTS (valist) = 1;
! }
! if (TREE_SIDE_EFFECTS (valist))
! valist = save_expr (valist);
valist = fold (build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)),
valist));
}
--- 1866,1902 ----
from multiple evaluations. */
static tree
! stabilize_va_list (valist, needs_lvalue)
tree valist;
! int needs_lvalue ATTRIBUTE_UNUSED;
{
if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
{
! if (TREE_SIDE_EFFECTS (valist))
! valist = save_expr (valist);
! /* For this case, the backends will be expecting a pointer to
! TREE_TYPE (va_list_type_node), but it's possible we've
! actually been given an array (an actual va_list_type_node).
! So fix it. */
! if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
{
! tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node));
! tree p2 = build_pointer_type (va_list_type_node);
! valist = build1 (ADDR_EXPR, p2, valist);
! valist = fold (build1 (NOP_EXPR, p1, valist));
}
}
else
{
! tree pt;
! if (! TREE_SIDE_EFFECTS (valist))
! return valist;
!
! pt = build_pointer_type (va_list_type_node);
! valist = fold (build1 (ADDR_EXPR, pt, valist));
! valist = save_expr (valist);
valist = fold (build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)),
valist));
}
Index: c-common.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/c-common.c,v
retrieving revision 1.101
diff -p -u -c -p -r1.101 c-common.c
*** c-common.c 2000/03/23 21:32:10 1.101
--- c-common.c 2000/03/24 00:02:47
*************** c_common_nodes_and_builtins (cplus_mode,
*** 3478,3484 ****
tree traditional_cptr_type_node;
tree traditional_len_type_node;
tree traditional_len_endlink;
- tree va_list_ptr_type_node;
tree va_list_arg_type_node;
pushdecl (build_decl (TYPE_DECL, get_identifier ("__builtin_va_list"),
--- 3478,3483 ----
*************** c_common_nodes_and_builtins (cplus_mode,
*** 3490,3497 ****
pushdecl (build_decl (TYPE_DECL, get_identifier ("__builtin_size_t"),
sizetype));
- va_list_ptr_type_node = build_pointer_type (va_list_type_node);
-
if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
va_list_arg_type_node = build_pointer_type (TREE_TYPE (va_list_type_node));
else
--- 3489,3494 ----
*************** c_common_nodes_and_builtins (cplus_mode,
*** 3714,3727 ****
builtin_function ("__builtin_varargs_start",
build_function_type (void_type_node,
tree_cons (NULL_TREE,
! va_list_ptr_type_node,
endlink)),
BUILT_IN_VARARGS_START, BUILT_IN_NORMAL, NULL_PTR);
builtin_function ("__builtin_stdarg_start",
build_function_type (void_type_node,
tree_cons (NULL_TREE,
! va_list_ptr_type_node,
NULL_TREE)),
BUILT_IN_STDARG_START, BUILT_IN_NORMAL, NULL_PTR);
--- 3711,3724 ----
builtin_function ("__builtin_varargs_start",
build_function_type (void_type_node,
tree_cons (NULL_TREE,
! va_list_arg_type_node,
endlink)),
BUILT_IN_VARARGS_START, BUILT_IN_NORMAL, NULL_PTR);
builtin_function ("__builtin_stdarg_start",
build_function_type (void_type_node,
tree_cons (NULL_TREE,
! va_list_arg_type_node,
NULL_TREE)),
BUILT_IN_STDARG_START, BUILT_IN_NORMAL, NULL_PTR);
*************** c_common_nodes_and_builtins (cplus_mode,
*** 3735,3741 ****
builtin_function ("__builtin_va_copy",
build_function_type (void_type_node,
tree_cons (NULL_TREE,
! va_list_ptr_type_node,
tree_cons (NULL_TREE,
va_list_arg_type_node,
endlink))),
--- 3732,3738 ----
builtin_function ("__builtin_va_copy",
build_function_type (void_type_node,
tree_cons (NULL_TREE,
! va_list_arg_type_node,
tree_cons (NULL_TREE,
va_list_arg_type_node,
endlink))),
Index: ginclude/stdarg.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/ginclude/stdarg.h,v
retrieving revision 1.14
diff -p -u -c -p -r1.14 stdarg.h
*** stdarg.h 2000/01/13 00:37:06 1.14
--- stdarg.h 2000/03/24 00:02:47
***************
*** 1,4 ****
! /* Copyright (C) 1989, 1997, 1998, 1999 Free Software Foundation, Inc.
This file is part of GNU CC.
--- 1,4 ----
! /* Copyright (C) 1989, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
This file is part of GNU CC.
*************** typedef __builtin_va_list __gnuc_va_list
*** 51,63 ****
actual type **after default promotions**.
Thus, va_arg (..., short) is not valid. */
! #define va_start(v,l) __builtin_stdarg_start(&(v),l)
#define va_end __builtin_va_end
#define va_arg __builtin_va_arg
#if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L
! #define va_copy(d,s) __builtin_va_copy(&(d),(s))
#endif
! #define __va_copy(d,s) __builtin_va_copy(&(d),(s))
/* Define va_list, if desired, from __gnuc_va_list. */
--- 51,63 ----
actual type **after default promotions**.
Thus, va_arg (..., short) is not valid. */
! #define va_start(v,l) __builtin_stdarg_start((v),l)
#define va_end __builtin_va_end
#define va_arg __builtin_va_arg
#if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L
! #define va_copy(d,s) __builtin_va_copy((d),(s))
#endif
! #define __va_copy(d,s) __builtin_va_copy((d),(s))
/* Define va_list, if desired, from __gnuc_va_list. */
Index: ginclude/varargs.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/ginclude/varargs.h,v
retrieving revision 1.14
diff -p -u -c -p -r1.14 varargs.h
*** varargs.h 2000/01/13 00:37:06 1.14
--- varargs.h 2000/03/24 00:02:47
***************
*** 1,4 ****
! /* Copyright (C) 1989, 1997, 1998, 1999 Free Software Foundation, Inc.
This file is part of GNU CC.
--- 1,4 ----
! /* Copyright (C) 1989, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
This file is part of GNU CC.
*************** typedef int __builtin_va_alist_t __attri
*** 63,72 ****
typedef __builtin_va_list __gnuc_va_list;
#endif
! #define va_start(v) __builtin_varargs_start(&(v))
#define va_end __builtin_va_end
#define va_arg __builtin_va_arg
! #define __va_copy(d,s) __builtin_va_copy(&(d),(s))
/* Define va_list from __gnuc_va_list. */
--- 63,72 ----
typedef __builtin_va_list __gnuc_va_list;
#endif
! #define va_start(v) __builtin_varargs_start((v))
#define va_end __builtin_va_end
#define va_arg __builtin_va_arg
! #define __va_copy(d,s) __builtin_va_copy((d),(s))
/* Define va_list from __gnuc_va_list. */
============================================================