#include "cgraph.h"
static bool c_tree_printer (pretty_printer *, text_info *);
-static tree inline_forbidden_p (tree *, int *, void *);
static tree start_cdtor (int);
static void finish_cdtor (tree);
return DECL_DECLARED_INLINE_P (fn) && DECL_EXTERNAL (fn);
}
-static tree
-inline_forbidden_p (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED,
- void *fn)
-{
- tree node = *nodep;
- tree t;
-
- switch (TREE_CODE (node))
- {
- case CALL_EXPR:
- t = get_callee_fndecl (node);
-
- if (! t)
- break;
-
- /* We cannot inline functions that call setjmp. */
- if (setjmp_call_p (t))
- return node;
-
- switch (DECL_FUNCTION_CODE (t))
- {
- /* We cannot inline functions that take a variable number of
- arguments. */
- case BUILT_IN_VA_START:
- case BUILT_IN_STDARG_START:
-#if 0
- /* Functions that need information about the address of the
- caller can't (shouldn't?) be inlined. */
- case BUILT_IN_RETURN_ADDRESS:
-#endif
- return node;
-
- default:
- break;
- }
-
- break;
-
- case DECL_STMT:
- /* We cannot inline functions that contain other functions. */
- if (TREE_CODE (TREE_OPERAND (node, 0)) == FUNCTION_DECL
- && DECL_INITIAL (TREE_OPERAND (node, 0)))
- return node;
- break;
-
- case GOTO_STMT:
- case GOTO_EXPR:
- t = TREE_OPERAND (node, 0);
-
- /* We will not inline a function which uses computed goto. The
- addresses of its local labels, which may be tucked into
- global storage, are of course not constant across
- instantiations, which causes unexpected behavior. */
- if (TREE_CODE (t) != LABEL_DECL)
- return node;
-
- /* We cannot inline a nested function that jumps to a nonlocal
- label. */
- if (TREE_CODE (t) == LABEL_DECL
- && !DECL_FILE_SCOPE_P (t) && DECL_CONTEXT (t) != fn)
- return node;
-
- break;
-
- case RECORD_TYPE:
- case UNION_TYPE:
- /* We cannot inline a function of the form
-
- void F (int i) { struct S { int ar[i]; } s; }
-
- Attempting to do so produces a catch-22 in tree-inline.c.
- If walk_tree examines the TYPE_FIELDS chain of RECORD_TYPE/
- UNION_TYPE nodes, then it goes into infinite recursion on a
- structure containing a pointer to its own type. If it doesn't,
- then the type node for S doesn't get adjusted properly when
- F is inlined, and we abort in find_function_data. */
- for (t = TYPE_FIELDS (node); t; t = TREE_CHAIN (t))
- if (variably_modified_type_p (TREE_TYPE (t)))
- return node;
-
- default:
- break;
- }
-
- return NULL_TREE;
-}
-
int
c_cannot_inline_tree_fn (tree *fnp)
{
tree fn = *fnp;
tree t;
+ bool do_warning = (warn_inline
+ && DECL_INLINE (fn)
+ && DECL_DECLARED_INLINE_P (fn)
+ && !DECL_IN_SYSTEM_HEADER (fn));
if (flag_really_no_inline
&& lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn)) == NULL)
- return 1;
+ {
+ if (do_warning)
+ warning ("%Hfunction '%F' can never be inlined because it "
+ "is supressed using -fno-inline",
+ &DECL_SOURCE_LOCATION (fn), fn);
+ goto cannot_inline;
+ }
/* Don't auto-inline anything that might not be bound within
this unit of translation. */
if (!DECL_DECLARED_INLINE_P (fn) && !(*targetm.binds_local_p) (fn))
- goto cannot_inline;
+ {
+ if (do_warning)
+ warning ("%Hfunction '%F' can never be inlined because it might not "
+ "be bound within this unit of translation",
+ &DECL_SOURCE_LOCATION (fn), fn);
+ goto cannot_inline;
+ }
if (! function_attribute_inlinable_p (fn))
- goto cannot_inline;
+ {
+ if (do_warning)
+ warning ("%Hfunction '%F' can never be inlined because it uses "
+ "attributes conflicting with inlining",
+ &DECL_SOURCE_LOCATION (fn), fn);
+ goto cannot_inline;
+ }
/* If a function has pending sizes, we must not defer its
compilation, and we can't inline it as a tree. */
put_pending_sizes (t);
if (t)
- goto cannot_inline;
+ {
+ if (do_warning)
+ warning ("%Hfunction '%F' can never be inlined because it has "
+ "pending sizes",
+ &DECL_SOURCE_LOCATION (fn), fn);
+ goto cannot_inline;
+ }
}
if (! DECL_FILE_SCOPE_P (fn))
/* If a nested function has pending sizes, we may have already
saved them. */
if (DECL_LANG_SPECIFIC (fn)->pending_sizes)
- goto cannot_inline;
- }
- else
- {
- /* We rely on the fact that this function is called upfront,
- just before we start expanding a function. If FN is active
- (i.e., it's the current_function_decl or a parent thereof),
- we have to walk FN's saved tree. Otherwise, we can safely
- assume we have done it before and, if we didn't mark it as
- uninlinable (in which case we wouldn't have been called), it
- is inlinable. Unfortunately, this strategy doesn't work for
- nested functions, because they're only expanded as part of
- their enclosing functions, so the inlinability test comes in
- late. */
- t = current_function_decl;
-
- while (t && t != fn)
- t = DECL_CONTEXT (t);
- if (! t)
- return 0;
+ {
+ if (do_warning)
+ warning ("%Hnested function '%F' can never be inlined because it "
+ "has possibly saved pending sizes",
+ &DECL_SOURCE_LOCATION (fn), fn);
+ goto cannot_inline;
+ }
}
- if (walk_tree (&DECL_SAVED_TREE (fn), inline_forbidden_p, fn, NULL))
- goto cannot_inline;
-
return 0;
cannot_inline:
static void remap_block (tree *, tree, inline_data *);
static tree add_stmt_to_compound (tree, tree, tree);
#endif /* INLINER_FOR_JAVA */
-static tree find_alloca_call_1 (tree *, int *, void *);
-static tree find_alloca_call (tree);
-static tree find_builtin_longjmp_call_1 (tree *, int *, void *);
-static tree find_builtin_longjmp_call (tree);
/* Remap DECL during the copying of the BLOCK tree for the function. */
return inlinable_function_p (fn);
}
-/* If *TP is possibly call to alloca, return nonzero. */
-static tree
-find_alloca_call_1 (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
- void *data ATTRIBUTE_UNUSED)
-{
- if (alloca_call_p (*tp))
- return *tp;
- return NULL;
-}
+static const char *inline_forbidden_reason;
-/* Return subexpression representing possible alloca call, if any. */
static tree
-find_alloca_call (tree exp)
+inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED,
+ void *fn)
{
- location_t saved_loc = input_location;
- tree ret = walk_tree_without_duplicates
- (&exp, find_alloca_call_1, NULL);
- input_location = saved_loc;
- return ret;
-}
+ tree node = *nodep;
+ tree t;
-static tree
-find_builtin_longjmp_call_1 (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
- void *data ATTRIBUTE_UNUSED)
-{
- tree exp = *tp, decl;
+ switch (TREE_CODE (node))
+ {
+ case CALL_EXPR:
+ /* Refuse to inline alloca call unless user explicitly forced so as this
+ may change program's memory overhead drastically when the function
+ using alloca is called in loop. In GCC present in SPEC2000 inlining
+ into schedule_block cause it to require 2GB of ram instead of 256MB. */
+ if (alloca_call_p (node)
+ && !lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn)))
+ {
+ inline_forbidden_reason = "%Hfunction '%F' can never be inlined "
+ "because it uses alloca (override using "
+ "the always_inline attribute)";
+ return node;
+ }
+ t = get_callee_fndecl (node);
+ if (! t)
+ break;
+
+
+ /* We cannot inline functions that call setjmp. */
+ if (setjmp_call_p (t))
+ {
+ inline_forbidden_reason = "%Hfunction '%F' can never be inlined"
+ " because it uses setjmp";
+ return node;
+ }
- if (TREE_CODE (exp) == CALL_EXPR
- && TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
- && (decl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
- TREE_CODE (decl) == FUNCTION_DECL)
- && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
- && DECL_FUNCTION_CODE (decl) == BUILT_IN_LONGJMP)
- return decl;
+ switch (DECL_FUNCTION_CODE (t))
+ {
+ /* We cannot inline functions that take a variable number of
+ arguments. */
+ case BUILT_IN_VA_START:
+ case BUILT_IN_STDARG_START:
+ {
+ inline_forbidden_reason = "%Hfunction '%F' can never be inlined "
+ "because it uses variable argument lists";
+ return node;
+ }
+ case BUILT_IN_LONGJMP:
+ {
+ /* We can't inline functions that call __builtin_longjmp at all.
+ The non-local goto machinery really requires the destination
+ be in a different function. If we allow the function calling
+ __builtin_longjmp to be inlined into the function calling
+ __builtin_setjmp, Things will Go Awry. */
+ /* ??? Need front end help to identify "regular" non-local goto. */
+ if (DECL_BUILT_IN_CLASS (t) == BUILT_IN_NORMAL)
+ {
+ inline_forbidden_reason = "%Hfunction '%F' can never be inlined "
+ "because it uses setjmp-longjmp "
+ "exception handling";
+ return node;
+ }
+ }
+
+ default:
+ break;
+ }
+ break;
- return NULL;
+#ifndef INLINER_FOR_JAVA
+ case DECL_STMT:
+ /* We cannot inline functions that contain other functions. */
+ if (TREE_CODE (TREE_OPERAND (node, 0)) == FUNCTION_DECL
+ && DECL_INITIAL (TREE_OPERAND (node, 0)))
+ {
+ inline_forbidden_reason = "%Hfunction '%F' can never be inlined "
+ "because it contains a nested function";
+ return node;
+ }
+ break;
+
+ case GOTO_STMT:
+ case GOTO_EXPR:
+ t = TREE_OPERAND (node, 0);
+
+ /* We will not inline a function which uses computed goto. The
+ addresses of its local labels, which may be tucked into
+ global storage, are of course not constant across
+ instantiations, which causes unexpected behavior. */
+ if (TREE_CODE (t) != LABEL_DECL)
+ {
+ inline_forbidden_reason = "%Hfunction '%F' can never be inlined "
+ "because it contains a nonlocal label";
+ return node;
+ }
+
+ /* We cannot inline a nested function that jumps to a nonlocal
+ label. */
+ if (TREE_CODE (t) == LABEL_DECL && DECL_CONTEXT (t) != fn)
+ {
+ inline_forbidden_reason = "%Hfunction '%F' can never be inlined "
+ "because it contains a nonlocal goto";
+ return node;
+ }
+
+ break;
+
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ /* We cannot inline a function of the form
+
+ void F (int i) { struct S { int ar[i]; } s; }
+
+ Attempting to do so produces a catch-22.
+ If walk_tree examines the TYPE_FIELDS chain of RECORD_TYPE/
+ UNION_TYPE nodes, then it goes into infinite recursion on a
+ structure containing a pointer to its own type. If it doesn't,
+ then the type node for S doesn't get adjusted properly when
+ F is inlined, and we abort in find_function_data. */
+ for (t = TYPE_FIELDS (node); t; t = TREE_CHAIN (t))
+ if (variably_modified_type_p (TREE_TYPE (t)))
+ {
+ inline_forbidden_reason = "%Hfunction '%F' can never be inlined "
+ "because it uses variable sized variables";
+ return node;
+ }
+#endif
+ default:
+ break;
+ }
+
+ return NULL_TREE;
}
+/* Return subexpression representing possible alloca call, if any. */
static tree
-find_builtin_longjmp_call (tree exp)
+inline_forbidden_p (tree fndecl)
{
location_t saved_loc = input_location;
tree ret = walk_tree_without_duplicates
- (&exp, find_builtin_longjmp_call_1, NULL);
+ (&DECL_SAVED_TREE (fndecl), inline_forbidden_p_1, fndecl);
input_location = saved_loc;
return ret;
}
inlinable_function_p (tree fn)
{
bool inlinable = true;
- bool calls_builtin_longjmp = false;
- bool calls_alloca = false;
/* If we've already decided this function shouldn't be inlined,
there's no need to check again. */
inlinable = false;
#endif /* INLINER_FOR_JAVA */
- /* We can't inline functions that call __builtin_longjmp at all.
- The non-local goto machinery really requires the destination
- be in a different function. If we allow the function calling
- __builtin_longjmp to be inlined into the function calling
- __builtin_setjmp, Things will Go Awry. */
- /* ??? Need front end help to identify "regular" non-local goto. */
- else if (find_builtin_longjmp_call (DECL_SAVED_TREE (fn)))
- calls_builtin_longjmp = true;
-
- /* Refuse to inline alloca call unless user explicitly forced so as this
- may change program's memory overhead drastically when the function
- using alloca is called in loop. In GCC present in SPEC2000 inlining
- into schedule_block cause it to require 2GB of ram instead of 256MB. */
- else if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn)) == NULL
- && find_alloca_call (DECL_SAVED_TREE (fn)))
- calls_alloca = true;
-
- if (calls_builtin_longjmp || calls_alloca)
+ else if (inline_forbidden_p (fn))
{
/* See if we should warn about uninlinable functions. Previously,
some of these warnings would be issued while trying to expand
&& DECL_DECLARED_INLINE_P (fn)
&& !DECL_IN_SYSTEM_HEADER (fn));
- if (do_warning && calls_builtin_longjmp)
- warning ("%Hfunction '%F' can never be inlined because it uses "
- "setjmp-longjmp exception handling",
- &DECL_SOURCE_LOCATION (fn), fn);
- if (do_warning && calls_alloca)
- warning ("%Hfunction '%F' can never be inlined because it uses "
- "setjmp-longjmp exception handling",
+ if (do_warning)
+ warning (inline_forbidden_reason,
&DECL_SOURCE_LOCATION (fn), fn);
inlinable = false;