re PR c++/36631 (attribute always_inline -> sorry, unimplemented: recursive inlining)

PR c++/36631
	* gimplify.c (gimplify_call_expr): Defer most of the cannot inline
	checking until GIMPLE lowering.
	* gimple-low.c (check_call_args): New function.
	(lower_stmt) <case GIMPLE_CALL>: Call it.

	* g++.dg/template/call5.C: New test.

From-SVN: r142033
This commit is contained in:
Jakub Jelinek 2008-11-20 02:47:10 +01:00 committed by Jakub Jelinek
parent 104320132f
commit f9487002a4
5 changed files with 111 additions and 43 deletions

View File

@ -1,3 +1,11 @@
2008-11-20 Jakub Jelinek <jakub@redhat.com>
PR c++/36631
* gimplify.c (gimplify_call_expr): Defer most of the cannot inline
checking until GIMPLE lowering.
* gimple-low.c (check_call_args): New function.
(lower_stmt) <case GIMPLE_CALL>: Call it.
2008-11-19 Adam Nemet <anemet@caviumnetworks.com>
* config/mips/mips.c (mips_gimplify_va_arg_expr): Use -rsize

View File

@ -1,6 +1,7 @@
/* GIMPLE lowering pass. Converts High GIMPLE into Low GIMPLE.
Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
This file is part of GCC.
@ -218,6 +219,80 @@ struct gimple_opt_pass pass_lower_cf =
};
/* Verify if the type of the argument matches that of the function
declaration. If we cannot verify this or there is a mismatch,
mark the call expression so it doesn't get inlined later. */
static void
check_call_args (gimple stmt)
{
tree fndecl, parms, p;
unsigned int i, nargs;
if (gimple_call_cannot_inline_p (stmt))
return;
nargs = gimple_call_num_args (stmt);
/* Get argument types for verification. */
fndecl = gimple_call_fndecl (stmt);
parms = NULL_TREE;
if (fndecl)
parms = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
else if (POINTER_TYPE_P (TREE_TYPE (gimple_call_fn (stmt))))
parms = TYPE_ARG_TYPES (TREE_TYPE (TREE_TYPE (gimple_call_fn (stmt))));
/* Verify if the type of the argument matches that of the function
declaration. If we cannot verify this or there is a mismatch,
mark the call expression so it doesn't get inlined later. */
if (fndecl && DECL_ARGUMENTS (fndecl))
{
for (i = 0, p = DECL_ARGUMENTS (fndecl);
i < nargs;
i++, p = TREE_CHAIN (p))
{
/* We cannot distinguish a varargs function from the case
of excess parameters, still deferring the inlining decision
to the callee is possible. */
if (!p)
break;
if (p == error_mark_node
|| gimple_call_arg (stmt, i) == error_mark_node
|| !fold_convertible_p (DECL_ARG_TYPE (p),
gimple_call_arg (stmt, i)))
{
gimple_call_set_cannot_inline (stmt, true);
break;
}
}
}
else if (parms)
{
for (i = 0, p = parms; i < nargs; i++, p = TREE_CHAIN (p))
{
/* If this is a varargs function defer inlining decision
to callee. */
if (!p)
break;
if (TREE_VALUE (p) == error_mark_node
|| gimple_call_arg (stmt, i) == error_mark_node
|| TREE_CODE (TREE_VALUE (p)) == VOID_TYPE
|| !fold_convertible_p (TREE_VALUE (p),
gimple_call_arg (stmt, i)))
{
gimple_call_set_cannot_inline (stmt, true);
break;
}
}
}
else
{
if (nargs != 0)
gimple_call_set_cannot_inline (stmt, true);
}
}
/* Lower sequence SEQ. Unlike gimplification the statements are not relowered
when they are changed -- if this has to be done, the lowering routine must
do it explicitly. DATA is passed through the recursion. */
@ -320,6 +395,7 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
lower_builtin_setjmp (gsi);
return;
}
check_call_args (stmt);
}
break;

View File

@ -2352,56 +2352,18 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value)
else if (POINTER_TYPE_P (TREE_TYPE (CALL_EXPR_FN (*expr_p))))
parms = TYPE_ARG_TYPES (TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (*expr_p))));
/* Verify if the type of the argument matches that of the function
declaration. If we cannot verify this or there is a mismatch,
mark the call expression so it doesn't get inlined later. */
if (fndecl && DECL_ARGUMENTS (fndecl))
{
for (i = 0, p = DECL_ARGUMENTS (fndecl);
i < nargs;
i++, p = TREE_CHAIN (p))
{
/* We cannot distinguish a varargs function from the case
of excess parameters, still deferring the inlining decision
to the callee is possible. */
if (!p)
break;
if (p == error_mark_node
|| CALL_EXPR_ARG (*expr_p, i) == error_mark_node
|| !fold_convertible_p (DECL_ARG_TYPE (p),
CALL_EXPR_ARG (*expr_p, i)))
{
CALL_CANNOT_INLINE_P (*expr_p) = 1;
break;
}
}
}
p = DECL_ARGUMENTS (fndecl);
else if (parms)
{
for (i = 0, p = parms; i < nargs; i++, p = TREE_CHAIN (p))
{
/* If this is a varargs function defer inlining decision
to callee. */
if (!p)
break;
if (TREE_VALUE (p) == error_mark_node
|| CALL_EXPR_ARG (*expr_p, i) == error_mark_node
|| TREE_CODE (TREE_VALUE (p)) == VOID_TYPE
|| !fold_convertible_p (TREE_VALUE (p),
CALL_EXPR_ARG (*expr_p, i)))
{
CALL_CANNOT_INLINE_P (*expr_p) = 1;
break;
}
}
}
p = parms;
else
{
if (nargs != 0)
CALL_CANNOT_INLINE_P (*expr_p) = 1;
i = 0;
p = NULL_TREE;
}
for (i = 0; i < nargs && p; i++, p = TREE_CHAIN (p))
;
/* If the last argument is __builtin_va_arg_pack () and it is not
passed as a named argument, decrease the number of CALL_EXPR

View File

@ -1,3 +1,8 @@
2008-11-20 Jakub Jelinek <jakub@redhat.com>
PR c++/36631
* g++.dg/template/call5.C: New test.
2008-11-19 Adam Nemet <anemet@caviumnetworks.com>
* gcc.c-torture/compile/20081119-1.c: New test.

View File

@ -0,0 +1,17 @@
// PR c++/36631
// { dg-options "-O0" }
template <typename T> struct B
{
struct C
{
__attribute__ ((always_inline)) C (C const &c) {}
};
void __attribute__ ((always_inline)) g (C c) {}
};
void
trigger (B <int> b, B <int>::C c)
{
b.g (c);
}