summaryrefslogtreecommitdiff
path: root/gcc/c-family
diff options
context:
space:
mode:
authorvries <vries@138bc75d-0d04-0410-961f-82ee72b054a4>2015-05-18 08:19:29 +0000
committervries <vries@138bc75d-0d04-0410-961f-82ee72b054a4>2015-05-18 08:19:29 +0000
commit2e4748207954207fa388f73eb0ef49a204cf52fb (patch)
tree6fc922cafa797c756299ad1c165a14cb319e70a5 /gcc/c-family
parent67a8fb5ddf882041e408f3a3a06a507c1371be85 (diff)
downloadgcc-2e4748207954207fa388f73eb0ef49a204cf52fb.tar.gz
Move array-type va_list handling to build_va_arg
2015-05-18 Tom de Vries <tom@codesourcery.com> * gimplify.c (gimplify_modify_expr): Remove do_deref handling. (gimplify_va_arg_expr): Remove do_deref handling. Remove adding of address operator to va_list operand. * tree-stdarg.c (expand_ifn_va_arg_1): Do deref of va_list operand unconditionally. * config/i386/i386.c (ix86_gimplify_va_arg): Remove deref on va_list operand. * config/rs6000/rs6000.c (rs6000_gimplify_va_arg): Same. * config/s390/s390.c (s390_gimplify_va_arg): Same. * config/spu/spu.c (spu_gimplify_va_arg_expr): Same. * c-common.c (build_va_arg_1): New function. (build_va_arg): Add address operator to va_list operand if necessary. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@223286 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/c-family')
-rw-r--r--gcc/c-family/ChangeLog5
-rw-r--r--gcc/c-family/c-common.c127
2 files changed, 117 insertions, 15 deletions
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 199ba43de4f..a6abd601b08 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,8 @@
+2015-05-18 Tom de Vries <tom@codesourcery.com>
+
+ * c-common.c (build_va_arg_1): New function.
+ (build_va_arg): Add address operator to va_list operand if necessary.
+
2015-05-15 Mikhail Maltsev <maltsevm@gmail.com>
PR c/48956
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 8c7fdd23991..6d8504905d1 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -6084,6 +6084,20 @@ set_compound_literal_name (tree decl)
DECL_NAME (decl) = get_identifier (name);
}
+/* build_va_arg helper function. Return a VA_ARG_EXPR with location LOC, type
+ TYPE and operand OP. */
+
+static tree
+build_va_arg_1 (location_t loc, tree type, tree op)
+{
+ tree expr = build1 (VA_ARG_EXPR, type, op);
+ SET_EXPR_LOCATION (expr, loc);
+ return expr;
+}
+
+/* Return a VA_ARG_EXPR corresponding to a source-level expression
+ va_arg (EXPR, TYPE) at source location LOC. */
+
tree
build_va_arg (location_t loc, tree expr, tree type)
{
@@ -6092,24 +6106,107 @@ build_va_arg (location_t loc, tree expr, tree type)
? NULL_TREE
: targetm.canonical_va_list_type (va_type));
- if (canon_va_type != NULL)
+ if (va_type == error_mark_node
+ || canon_va_type == NULL_TREE)
{
- /* When the va_arg ap argument is a parm decl with declared type va_list,
- and the va_list type is an array, then grokdeclarator changes the type
- of the parm decl to the corresponding pointer type. We know that that
- pointer is constant, so there's no need to modify it, so there's no
- need to pass it around using an address operator, so there's no need to
- mark it addressable. */
- if (!(TREE_CODE (canon_va_type) == ARRAY_TYPE
- && TREE_CODE (va_type) != ARRAY_TYPE))
- /* In gimplify_va_arg_expr we take the address of the ap argument, mark
- it addressable now. */
- mark_addressable (expr);
+ /* Let's handle things neutrallly, if expr:
+ - has undeclared type, or
+ - is not an va_list type. */
+ return build_va_arg_1 (loc, type, expr);
}
- expr = build1 (VA_ARG_EXPR, type, expr);
- SET_EXPR_LOCATION (expr, loc);
- return expr;
+ if (TREE_CODE (canon_va_type) != ARRAY_TYPE)
+ {
+ /* Case 1: Not an array type. */
+
+ /* Take the address, to get '&ap'. */
+ mark_addressable (expr);
+ expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (expr)), expr);
+
+ /* Verify that &ap is still recognized as having va_list type. */
+ tree canon_expr_type
+ = targetm.canonical_va_list_type (TREE_TYPE (expr));
+ gcc_assert (canon_expr_type != NULL_TREE);
+
+ return build_va_arg_1 (loc, type, expr);
+ }
+
+ /* Case 2: Array type.
+
+ Background:
+
+ For contrast, let's start with the simple case (case 1). If
+ canon_va_type is not an array type, but say a char *, then when
+ passing-by-value a va_list, the type of the va_list param decl is
+ the same as for another va_list decl (all ap's are char *):
+
+ f2_1 (char * ap)
+ D.1815 = VA_ARG (&ap, 0B, 1);
+ return D.1815;
+
+ f2 (int i)
+ char * ap.0;
+ char * ap;
+ __builtin_va_start (&ap, 0);
+ ap.0 = ap;
+ res = f2_1 (ap.0);
+ __builtin_va_end (&ap);
+ D.1812 = res;
+ return D.1812;
+
+ However, if canon_va_type is ARRAY_TYPE, then when passing-by-value a
+ va_list the type of the va_list param decl (case 2b, struct * ap) is not
+ the same as for another va_list decl (case 2a, struct ap[1]).
+
+ f2_1 (struct * ap)
+ D.1844 = VA_ARG (ap, 0B, 0);
+ return D.1844;
+
+ f2 (int i)
+ struct ap[1];
+ __builtin_va_start (&ap, 0);
+ res = f2_1 (&ap);
+ __builtin_va_end (&ap);
+ D.1841 = res;
+ return D.1841;
+
+ Case 2b is different because:
+ - on the callee side, the parm decl has declared type va_list, but
+ grokdeclarator changes the type of the parm decl to a pointer to the
+ array elem type.
+ - on the caller side, the pass-by-value uses &ap.
+
+ We unify these two cases (case 2a: va_list is array type,
+ case 2b: va_list is pointer to array elem type), by adding '&' for the
+ array type case, such that we have a pointer to array elem in both
+ cases. */
+
+ if (TREE_CODE (va_type) == ARRAY_TYPE)
+ {
+ /* Case 2a: va_list is array type. */
+
+ /* Take the address, to get '&ap'. Make sure it's a pointer to array
+ elem type. */
+ mark_addressable (expr);
+ expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (canon_va_type)),
+ expr);
+
+ /* Verify that &ap is still recognized as having va_list type. */
+ tree canon_expr_type
+ = targetm.canonical_va_list_type (TREE_TYPE (expr));
+ gcc_assert (canon_expr_type != NULL_TREE);
+ }
+ else
+ {
+ /* Case 2b: va_list is pointer to array elem type. */
+ gcc_assert (POINTER_TYPE_P (va_type));
+ gcc_assert (TREE_TYPE (va_type) == TREE_TYPE (canon_va_type));
+
+ /* Don't take the address. We've already got '&ap'. */
+ ;
+ }
+
+ return build_va_arg_1 (loc, type, expr);
}