summaryrefslogtreecommitdiff
path: root/gcc/cp/tree.c
diff options
context:
space:
mode:
authoraoliva <aoliva@138bc75d-0d04-0410-961f-82ee72b054a4>2001-10-05 02:48:47 +0000
committeraoliva <aoliva@138bc75d-0d04-0410-961f-82ee72b054a4>2001-10-05 02:48:47 +0000
commit1e3b023ca8a1e3c71fbc30d4bb9b84cd1623903d (patch)
tree8512628500ca03ba513e5684fba6a6a044156017 /gcc/cp/tree.c
parentb632977bd166019a4589082e383c5519b5f31558 (diff)
downloadgcc-1e3b023ca8a1e3c71fbc30d4bb9b84cd1623903d.tar.gz
* Make-lang.in (cp/decl.o, cp/tree.o): Depend on tree-inline.h.
(cp/pt.o, cp/semantics.o, cp/optimize.o): Likewise. * cp-tree.h (lang_decl): Moved inlined_fns to tree_decl. (TREE_READONLY_DECL_P, DECL_INLINED_FNS): Moved to ../tree.h. (flag_inline_trees): Moved declaration to ../tree-inline.h. (walk_tree): Moved declaration to ../tree-inline.h. (walk_tree_without_duplicates, copy_tree_r): Likewise. (remap_save_expr): Likewise. * decl.c: Include tree-inline.h. (lang_mark_tree): Don't mark inlined_fns. * decl2.c (flag_inline_trees): Moved defn to ../tree-inline.c. * optimize.c: Include tree-inline.h. (optimize_inline_calls): Move declaration to ../tree.h, as non-static. (remap_decl): Use language-independent constructs and hooks. (remap_block, copy_body_r, declare_return_variable): Likewise. (inlinable_function_p): Likewise. Don't test for DECL_LANG_SPECIFIC before DECL_INLINED_FNS as inlined_fns is no longer language-specific. (optimize_inline_calls): Likewise. Make it non-static. Moved call of dump_function to... (optimize_function): Here... (clone_body): New function, extracted from... (maybe_clone_body): ... here. Build decl_map locally and pass it on to clone_body. * pt.c, semantics.c: Include tree-inline.h. * tree.c: Likewise. (cp_walk_subtrees): New language-specific hook for tree inlining. (cp_cannot_inline_tree_fn, cp_add_pending_fn_decls, cp_is_overload_p, cp_auto_var_in_fn_p, cp_copy_res_decl_for_inlining): Likewise. (walk_tree): Move language-specific constructs into... (cp_walk_subtrees): this new function. (copy_tree_r): Use language-independent constructs and hooks. (init_tree): Initialize tree inlining hooks. (remap_save_expr): Adjust prototype so that the declaration does not require the definition of splay_tree. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@46020 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/cp/tree.c')
-rw-r--r--gcc/cp/tree.c271
1 files changed, 239 insertions, 32 deletions
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 32783adc728..ec51eaa7e41 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -31,6 +31,7 @@ Boston, MA 02111-1307, USA. */
#include "ggc.h"
#include "insn-config.h"
#include "integrate.h"
+#include "tree-inline.h"
static tree bot_manip PARAMS ((tree *, int *, void *));
static tree bot_replace PARAMS ((tree *, int *, void *));
@@ -49,6 +50,12 @@ static tree count_trees_r PARAMS ((tree *, int *, void *));
static tree verify_stmt_tree_r PARAMS ((tree *, int *, void *));
static tree find_tree_r PARAMS ((tree *, int *, void *));
extern int cp_statement_code_p PARAMS ((enum tree_code));
+static treeopt_walk_subtrees_type cp_walk_subtrees;
+static treeopt_cannot_inline_tree_fn_type cp_cannot_inline_tree_fn;
+static treeopt_add_pending_fn_decls_type cp_add_pending_fn_decls;
+static treeopt_tree_chain_matters_p_type cp_is_overload_p;
+static treeopt_auto_var_in_fn_p_type cp_auto_var_in_fn_p;
+static treeopt_copy_res_decl_for_inlining_type cp_copy_res_decl_for_inlining;
static tree handle_java_interface_attribute PARAMS ((tree *, tree, tree, int, bool *));
static tree handle_com_interface_attribute PARAMS ((tree *, tree, tree, int, bool *));
@@ -1154,12 +1161,13 @@ bind_template_template_parm (t, newargs)
once. */
tree
-walk_tree (tp, func, data, htab)
+walk_tree (tp, func, data, htab_)
tree *tp;
walk_tree_fn func;
void *data;
- htab_t htab;
+ void *htab_;
{
+ htab_t htab = (htab_t) htab_;
enum tree_code code;
int walk_subtrees;
tree result;
@@ -1204,7 +1212,8 @@ walk_tree (tp, func, data, htab)
interesting below this point in the tree. */
if (!walk_subtrees)
{
- if (statement_code_p (code) || code == TREE_LIST || code == OVERLOAD)
+ if (statement_code_p (code) || code == TREE_LIST
+ || LANG_TREE_CHAIN_MATTERS_P (*tp))
/* But we still need to check our siblings. */
return walk_tree (&TREE_CHAIN (*tp), func, data, htab);
else
@@ -1268,6 +1277,10 @@ walk_tree (tp, func, data, htab)
return NULL_TREE;
}
+ result = LANG_WALK_SUBTREES (tp, &walk_subtrees, func, data, htab);
+ if (result || ! walk_subtrees)
+ return result;
+
/* Not one of the easy cases. We must explicitly go through the
children. */
switch (code)
@@ -1277,47 +1290,29 @@ walk_tree (tp, func, data, htab)
case INTEGER_CST:
case REAL_CST:
case STRING_CST:
- case DEFAULT_ARG:
- case TEMPLATE_TEMPLATE_PARM:
- case BOUND_TEMPLATE_TEMPLATE_PARM:
- case TEMPLATE_PARM_INDEX:
- case TEMPLATE_TYPE_PARM:
case REAL_TYPE:
case COMPLEX_TYPE:
case VECTOR_TYPE:
case VOID_TYPE:
case BOOLEAN_TYPE:
- case TYPENAME_TYPE:
case UNION_TYPE:
case ENUMERAL_TYPE:
- case TYPEOF_TYPE:
case BLOCK:
+ case RECORD_TYPE:
/* None of thse have subtrees other than those already walked
above. */
break;
- case PTRMEM_CST:
- WALK_SUBTREE (TREE_TYPE (*tp));
- break;
-
case POINTER_TYPE:
case REFERENCE_TYPE:
WALK_SUBTREE (TREE_TYPE (*tp));
break;
case TREE_LIST:
- /* A BASELINK_P's TREE_PURPOSE is a BINFO, and hence circular. */
- if (!BASELINK_P (*tp))
- WALK_SUBTREE (TREE_PURPOSE (*tp));
WALK_SUBTREE (TREE_VALUE (*tp));
WALK_SUBTREE (TREE_CHAIN (*tp));
break;
- case OVERLOAD:
- WALK_SUBTREE (OVL_FUNCTION (*tp));
- WALK_SUBTREE (OVL_CHAIN (*tp));
- break;
-
case TREE_VEC:
{
int len = TREE_VEC_LENGTH (*tp);
@@ -1365,13 +1360,8 @@ walk_tree (tp, func, data, htab)
WALK_SUBTREE (TYPE_OFFSET_BASETYPE (*tp));
break;
- case RECORD_TYPE:
- if (TYPE_PTRMEMFUNC_P (*tp))
- WALK_SUBTREE (TYPE_PTRMEMFUNC_FN_TYPE (*tp));
- break;
-
default:
- my_friendly_abort (19990803);
+ abort ();
}
/* We didn't find what we were looking for. */
@@ -1539,7 +1529,7 @@ copy_tree_r (tp, walk_subtrees, data)
|| TREE_CODE_CLASS (code) == 's'
|| code == TREE_LIST
|| code == TREE_VEC
- || code == OVERLOAD)
+ || LANG_TREE_CHAIN_MATTERS_P (*tp))
{
/* Because the chain gets clobbered when we make a copy, we save it
here. */
@@ -1550,7 +1540,8 @@ copy_tree_r (tp, walk_subtrees, data)
/* Now, restore the chain, if appropriate. That will cause
walk_tree to walk into the chain as well. */
- if (code == PARM_DECL || code == TREE_LIST || code == OVERLOAD
+ if (code == PARM_DECL || code == TREE_LIST
+ || LANG_TREE_CHAIN_MATTERS_P (*tp)
|| statement_code_p (code))
TREE_CHAIN (*tp) = chain;
@@ -2344,12 +2335,227 @@ make_ptrmem_cst (type, member)
return ptrmem_cst;
}
+/* Apply FUNC to all language-specific sub-trees of TP in a pre-order
+ traversal. Called from walk_tree(). */
+
+static tree
+cp_walk_subtrees (tp, walk_subtrees_p, func, data, htab)
+ tree *tp;
+ int *walk_subtrees_p;
+ walk_tree_fn func;
+ void *data;
+ void *htab;
+{
+ enum tree_code code = TREE_CODE (*tp);
+ tree result;
+
+#define WALK_SUBTREE(NODE) \
+ do \
+ { \
+ result = walk_tree (&(NODE), func, data, htab); \
+ if (result) \
+ return result; \
+ } \
+ while (0)
+
+ /* Not one of the easy cases. We must explicitly go through the
+ children. */
+ switch (code)
+ {
+ case DEFAULT_ARG:
+ case TEMPLATE_TEMPLATE_PARM:
+ case BOUND_TEMPLATE_TEMPLATE_PARM:
+ case TEMPLATE_PARM_INDEX:
+ case TEMPLATE_TYPE_PARM:
+ case TYPENAME_TYPE:
+ case TYPEOF_TYPE:
+ /* None of thse have subtrees other than those already walked
+ above. */
+ *walk_subtrees_p = 0;
+ break;
+
+ case PTRMEM_CST:
+ WALK_SUBTREE (TREE_TYPE (*tp));
+ *walk_subtrees_p = 0;
+ break;
+
+ case TREE_LIST:
+ /* A BASELINK_P's TREE_PURPOSE is a BINFO, and hence circular. */
+ if (!BASELINK_P (*tp))
+ WALK_SUBTREE (TREE_PURPOSE (*tp));
+ break;
+
+ case OVERLOAD:
+ WALK_SUBTREE (OVL_FUNCTION (*tp));
+ WALK_SUBTREE (OVL_CHAIN (*tp));
+ *walk_subtrees_p = 0;
+ break;
+
+ case RECORD_TYPE:
+ if (TYPE_PTRMEMFUNC_P (*tp))
+ WALK_SUBTREE (TYPE_PTRMEMFUNC_FN_TYPE (*tp));
+ break;
+
+ default:
+ break;
+ }
+
+ /* We didn't find what we were looking for. */
+ return NULL_TREE;
+
+#undef WALK_SUBTREE
+}
+
+/* Decide whether there are language-specific reasons to not inline a
+ function as a tree. */
+
+static int
+cp_cannot_inline_tree_fn (fnp)
+ tree *fnp;
+{
+ tree fn = *fnp;
+
+ /* We can inline a template instantiation only if it's fully
+ instantiated. */
+ if (DECL_TEMPLATE_INFO (fn)
+ && TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (fn)))
+ {
+ fn = *fnp = instantiate_decl (fn, /*defer_ok=*/0);
+ return TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (fn));
+ }
+
+ if (varargs_function_p (fn))
+ {
+ DECL_UNINLINABLE (fn) = 1;
+ return 1;
+ }
+
+ if (! function_attribute_inlinable_p (fn))
+ {
+ DECL_UNINLINABLE (fn) = 1;
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Add any pending functions other than the current function (already
+ handled by the caller), that thus cannot be inlined, to FNS_P, then
+ return the latest function added to the array, PREV_FN. */
+
+static tree
+cp_add_pending_fn_decls (fns_p, prev_fn)
+ void *fns_p;
+ tree prev_fn;
+{
+ varray_type *fnsp = (varray_type *)fns_p;
+ struct saved_scope *s;
+
+ for (s = scope_chain; s; s = s->prev)
+ if (s->function_decl && s->function_decl != prev_fn)
+ {
+ VARRAY_PUSH_TREE (*fnsp, s->function_decl);
+ prev_fn = s->function_decl;
+ }
+
+ return prev_fn;
+}
+
+/* Determine whether a tree node is an OVERLOAD node. Used to decide
+ whether to copy a node or to preserve its chain when inlining a
+ function. */
+
+static int
+cp_is_overload_p (t)
+ tree t;
+{
+ return TREE_CODE (t) == OVERLOAD;
+}
+
+/* Determine whether VAR is a declaration of an automatic variable in
+ function FN. */
+
+static int
+cp_auto_var_in_fn_p (var, fn)
+ tree var, fn;
+{
+ return (DECL_P (var) && DECL_CONTEXT (var) == fn
+ && nonstatic_local_decl_p (var));
+}
+
+/* Tell whether a declaration is needed for the RESULT of a function
+ FN being inlined into CALLER or if the top node of target_exprs is
+ to be used. */
+
+static tree
+cp_copy_res_decl_for_inlining (result, fn, caller, decl_map_,
+ need_decl, target_exprs)
+ tree result, fn, caller;
+ void *decl_map_;
+ int *need_decl;
+ void *target_exprs;
+{
+ splay_tree decl_map = (splay_tree)decl_map_;
+ varray_type *texps = (varray_type *)target_exprs;
+ tree var;
+ int aggregate_return_p;
+
+ /* Figure out whether or not FN returns an aggregate. */
+ aggregate_return_p = IS_AGGR_TYPE (TREE_TYPE (result));
+ *need_decl = ! aggregate_return_p;
+
+ /* If FN returns an aggregate then the caller will always create the
+ temporary (using a TARGET_EXPR) and the call will be the
+ initializing expression for the TARGET_EXPR. If we were just to
+ create a new VAR_DECL here, then the result of this function
+ would be copied (bitwise) into the variable initialized by the
+ TARGET_EXPR. That's incorrect, so we must transform any
+ references to the RESULT into references to the target. */
+ if (aggregate_return_p)
+ {
+ if (VARRAY_ACTIVE_SIZE (*texps) == 0)
+ abort ();
+ var = TREE_OPERAND (VARRAY_TOP_TREE (*texps), 0);
+ if (! same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (var),
+ TREE_TYPE (result)))
+ abort ();
+ }
+ /* Otherwise, make an appropriate copy. */
+ else
+ var = copy_decl_for_inlining (result, fn, caller);
+
+ if (DECL_SAVED_FUNCTION_DATA (fn))
+ {
+ tree nrv = DECL_SAVED_FUNCTION_DATA (fn)->x_return_value;
+ if (nrv)
+ {
+ /* We have a named return value; copy the name and source
+ position so we can get reasonable debugging information, and
+ register the return variable as its equivalent. */
+ DECL_NAME (var) = DECL_NAME (nrv);
+ DECL_SOURCE_FILE (var) = DECL_SOURCE_FILE (nrv);
+ DECL_SOURCE_LINE (var) = DECL_SOURCE_LINE (nrv);
+ splay_tree_insert (decl_map,
+ (splay_tree_key) nrv,
+ (splay_tree_value) var);
+ }
+ }
+
+ return var;
+}
+
/* Initialize tree.c. */
void
init_tree ()
{
make_lang_type_fn = cp_make_lang_type;
+ lang_walk_subtrees = cp_walk_subtrees;
+ lang_cannot_inline_tree_fn = cp_cannot_inline_tree_fn;
+ lang_add_pending_fn_decls = cp_add_pending_fn_decls;
+ lang_tree_chain_matters_p = cp_is_overload_p;
+ lang_auto_var_in_fn_p = cp_auto_var_in_fn_p;
+ lang_copy_res_decl_for_inlining = cp_copy_res_decl_for_inlining;
lang_unsave = cp_unsave;
lang_statement_code_p = cp_statement_code_p;
lang_set_decl_assembler_name = mangle_decl;
@@ -2365,12 +2571,13 @@ init_tree ()
ST. FN is the function into which the copy will be placed. */
void
-remap_save_expr (tp, st, fn, walk_subtrees)
+remap_save_expr (tp, st_, fn, walk_subtrees)
tree *tp;
- splay_tree st;
+ void *st_;
tree fn;
int *walk_subtrees;
{
+ splay_tree st = (splay_tree) st_;
splay_tree_node n;
/* See if we already encountered this SAVE_EXPR. */