+2011-04-12 Richard Guenther <rguenther@suse.de>
+
+ PR tree-optimization/46076
+ * gimple.h (struct gimple_statement_call): Add fntype field.
+ (gimple_call_fntype): Adjust.
+ (gimple_call_set_fntype): New function.
+ * gimple.c (gimple_build_call_1): Set the call function type.
+ * gimplify.c (gimplify_call_expr): Preserve the function
+ type the frontend used for the call.
+ (gimplify_modify_expr): Likewise.
+ * lto-streamer-in.c (input_gimple_stmt): Input the call stmts
+ function type.
+ * lto-streamer-out.c (output_gimple_stmt): Output the call stmts
+ function type.
+ * tree-ssa.c (useless_type_conversion_p): Function pointer
+ conversions are useless.
+
2011-04-12 Martin Jambor <mjambor@suse.cz>
* cgraph.h (cgraph_node): Remove function declaration.
if (TREE_CODE (fn) == FUNCTION_DECL)
fn = build_fold_addr_expr (fn);
gimple_set_op (s, 1, fn);
+ gimple_call_set_fntype (s, TREE_TYPE (TREE_TYPE (fn)));
gimple_call_reset_alias_info (s);
return s;
}
struct pt_solution call_used;
struct pt_solution call_clobbered;
- /* [ WORD 13 ]
+ /* [ WORD 13 ] */
+ tree fntype;
+
+ /* [ WORD 14 ]
Operand vector. NOTE! This must always be the last field
of this structure. In particular, this means that this
structure cannot be embedded inside another one. */
}
-/* Return the tree node representing the function called by call
- statement GS. */
+/* Return the function type of the function called by GS. */
static inline tree
-gimple_call_fn (const_gimple gs)
+gimple_call_fntype (const_gimple gs)
{
GIMPLE_CHECK (gs, GIMPLE_CALL);
- return gimple_op (gs, 1);
+ return gs->gimple_call.fntype;
}
-/* Return the function type of the function called by GS. */
+/* Set the type of the function called by GS to FNTYPE. */
+
+static inline void
+gimple_call_set_fntype (gimple gs, tree fntype)
+{
+ GIMPLE_CHECK (gs, GIMPLE_CALL);
+ gs->gimple_call.fntype = fntype;
+}
+
+
+/* Return the tree node representing the function called by call
+ statement GS. */
static inline tree
-gimple_call_fntype (const_gimple gs)
+gimple_call_fn (const_gimple gs)
{
- return TREE_TYPE (TREE_TYPE (gimple_call_fn (gs)));
+ GIMPLE_CHECK (gs, GIMPLE_CALL);
+ return gimple_op (gs, 1);
}
/* Return a pointer to the tree node representing the function called by call
static enum gimplify_status
gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value)
{
- tree fndecl, parms, p;
+ tree fndecl, parms, p, fnptrtype;
enum gimplify_status ret;
int i, nargs;
gimple call;
}
}
+ /* Remember the original function pointer type. */
+ fnptrtype = TREE_TYPE (CALL_EXPR_FN (*expr_p));
+
/* There is a sequence point before the call, so any side effects in
the calling expression must occur before the actual call. Force
gimplify_expr to use an internal post queue. */
/* Verify the function result. */
if (want_value && fndecl
- && VOID_TYPE_P (TREE_TYPE (TREE_TYPE (fndecl))))
+ && VOID_TYPE_P (TREE_TYPE (TREE_TYPE (fnptrtype))))
{
error_at (loc, "using result of function returning %<void%>");
ret = GS_ERROR;
have to do is replicate it as a GIMPLE_CALL tuple. */
gimple_stmt_iterator gsi;
call = gimple_build_call_from_tree (*expr_p);
+ gimple_call_set_fntype (call, TREE_TYPE (fnptrtype));
gimplify_seq_add_stmt (pre_p, call);
gsi = gsi_last (*pre_p);
fold_stmt (&gsi);
*expr_p = NULL_TREE;
}
+ else
+ /* Remember the original function type. */
+ CALL_EXPR_FN (*expr_p) = build1 (NOP_EXPR, fnptrtype,
+ CALL_EXPR_FN (*expr_p));
return ret;
}
{
/* Since the RHS is a CALL_EXPR, we need to create a GIMPLE_CALL
instead of a GIMPLE_ASSIGN. */
+ tree fnptrtype = TREE_TYPE (CALL_EXPR_FN (*from_p));
+ CALL_EXPR_FN (*from_p) = TREE_OPERAND (CALL_EXPR_FN (*from_p), 0);
+ STRIP_USELESS_TYPE_CONVERSION (CALL_EXPR_FN (*from_p));
assign = gimple_build_call_from_tree (*from_p);
+ gimple_call_set_fntype (assign, TREE_TYPE (fnptrtype));
if (!gimple_call_noreturn_p (assign))
gimple_call_set_lhs (assign, *to_p);
}
op = TREE_OPERAND (op, 0);
}
}
+ if (is_gimple_call (stmt))
+ gimple_call_set_fntype (stmt, lto_input_tree (ib, data_in));
break;
case GIMPLE_NOP:
}
lto_output_tree_ref (ob, op);
}
+ if (is_gimple_call (stmt))
+ lto_output_tree_ref (ob, gimple_call_fntype (stmt));
break;
case GIMPLE_NOP:
+2011-04-12 Richard Guenther <rguenther@suse.de>
+
+ PR tree-optimization/46076
+ * gcc.dg/tree-ssa/pr46076.c: Un-XFAIL.
+
2011-04-12 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
PR testsuite/21164
/* { dg-do link } */
/* { dg-options "-O2" } */
-extern void link_error (void) { /* XFAIL */ }
+extern void link_error (void);
typedef unsigned char(*Calculable)(void);
&& TYPE_RESTRICT (outer_type))
return false;
- /* If the outer type is (void *) or a pointer to an incomplete
- record type or a pointer to an unprototyped function,
- then the conversion is not necessary. */
- if (VOID_TYPE_P (TREE_TYPE (outer_type))
- || ((TREE_CODE (TREE_TYPE (outer_type)) == FUNCTION_TYPE
- || TREE_CODE (TREE_TYPE (outer_type)) == METHOD_TYPE)
- && (TREE_CODE (TREE_TYPE (outer_type))
- == TREE_CODE (TREE_TYPE (inner_type)))
- && !prototype_p (TREE_TYPE (outer_type))
- && useless_type_conversion_p (TREE_TYPE (TREE_TYPE (outer_type)),
- TREE_TYPE (TREE_TYPE (inner_type)))))
+ /* If the outer type is (void *), the conversion is not necessary. */
+ if (VOID_TYPE_P (TREE_TYPE (outer_type)))
return true;
}
/* Do not lose casts to function pointer types. */
if ((TREE_CODE (TREE_TYPE (outer_type)) == FUNCTION_TYPE
|| TREE_CODE (TREE_TYPE (outer_type)) == METHOD_TYPE)
- && !useless_type_conversion_p (TREE_TYPE (outer_type),
- TREE_TYPE (inner_type)))
+ && !(TREE_CODE (TREE_TYPE (inner_type)) == FUNCTION_TYPE
+ || TREE_CODE (TREE_TYPE (inner_type)) == METHOD_TYPE))
return false;
/* We do not care for const qualification of the pointed-to types