325c369115
* c-common.c (lang_gimplify_stmt): Remove next_p argument. (if_elt, if_stack, if_stack_space, c_expand_start_cond, c_finish_then, c_expand_end_cond, c_expand_start_else, c_finish_else, c_begin_if_stmt, c_begin_while_stmt, c_finish_while_stmt_cond): Move to c-typeck.c. (finish_fname_decls, fname_decl): Use statement_lists. (c_expand_expr_stmt): Don't set last_expr_type. (c_type_hash): Fix indentation. (c_safe_from_p): Don't follow TREE_CHAIN. (c_tree_chain_matters_p): Remove. * c-common.def (SCOPE_STMT): Remove. (CLEANUP_STMT): Redefine to contain its own body. * c-common.h (struct stmt_tree_s): Remove x_last_stmt, x_last_expr_type, x_last_expr_filename, x_scope_stmt_stack. Add x_cur_stmt_list. (last_tree, last_expr_type, last_expr_filename, RECHAIN_STMTS): Remove. (cur_stmt_list): New. (STATEMENT_LIST_STMT_EXPR): New. (SCOPE_BEGIN_P, SCOPE_END_P, SCOPE_STMT_BLOCK, SCOPE_NULLIFIED_P, SCOPE_NO_CLEANUPS_P, SCOPE_PARTIAL_P, NEW_FOR_SCOPE_P): Remove. (CLEANUP_BODY): New. (CLEANUP_DECL): Move to operand 2. (c_common_stmt_codes): Remove SCOPE_STMT. (COMPOUND_STMT_NO_SCOPE, COMPOUND_STMT_BODY_BLOCK): Remove. * c-decl.c (c_scope_stmt_stack, current_scope_stmt_stack): Remove. (c_push_function_context, c_pop_function_context): Don't save it. (finish_decl): Set TREE_USED on the decl for a cleanup. Use push_cleanup. (store_parm_decls): Use statement lists. (finish_function): Remove compstmt rule workaround. Use statement lists. Call finish_fname_decls after finalizing the body. (c_begin_compound_stmt): Move to c-typeck.c. * c-dump.c (c_dump_tree): Remove SCOPE_STMT. * c-gimplify.c (gimplify_cleanup_stmt, gimplify_cleanup_stmts): New. (c_genericize): Invoke them. (c_gimplify_stmt): Don't look through TREE_CHAIN. Kill SCOPE_STMT. (c_build_bind_expr): Export. (gimplify_block, gimplify_cleanup): Remove. (gimplify_condition): Use gimplify_stmt. (gimplify_for_stmt): Remove FOR_INIT_STMT chaining hack. (gimplify_if_stmt): Remove recursion hack. (c_gimplify_expr): Remove STMT_EXPR handling. (stmt_expr_last_stmt, gimplify_stmt_expr): Remove. (is_last_stmt_of_scope): Remove. * c-lang.c (LANG_HOOKS_TREE_INLINING_TREE_CHAIN_MATTERS_P): Remove. * c-mudflap.c (mflang_flush_calls): Use c_begin_compound_stmt, c_end_compound_stmt. * c-objc-common.c (build_cdtor): Likewise. * c-parse.in (primary): Use c_finish_stmt_expr. (push_scope, pop_scope): Remove. (c99_block_start, compstmt_start): Use c_begin_compound_stmt. (c99_block_end, compstmt): Use c_end_compound_stmt. (c99_block_lineno_labeled_stmt): Likewise. (compstmt_primary_start): Use c_begin_stmt_expr. (simple_if, select_or_iter_stmt): Update calls to stmt builders. (do_stmt_start): Fill in body directly. (lineno_stmt): Avoid setting lineno on constants. * c-pretty-print.c (pp_c_statement): Handle STATEMENT_LIST. Remove SCOPE_STMT. * c-semantics.c (begin_stmt_tree): Remove. (push_stmt_list, re_push_stmt_list, pop_stmt_list): New. (add_stmt): Use statement lists. (add_scope_stmt, finish_stmt_tree): Remove. (push_cleanup): New. * c-tree.h: Move some decls from c-common.h. * c-typeck.c (c_tree_expr_nonnegative_p): Simplify for statement lists. (do_case, c_finish_case): Likewise. (c_finish_then): Take body for then as argument. (c_finish_else): Similarly. (c_begin_for_stmt, c_finish_for_stmt_init, c_finish_for_stmt_cond, c_finish_for_stmt_incr, c_finish_for_stmt): New. (c_begin_stmt_expr, c_finish_stmt_expr): New. (c_begin_compound_stmt): Do scope management. (c_end_compound_stmt): New. * fold-const.c (tree_expr_nonnegative_p): Fix BIND_EXPR. * gimplify.c (voidify_wrapper_expr): Accept temporary argument. Look through exception handling constructs. (gimplify_bind_expr): Accept temporary argument. (gimplify_target_expr): Special case BIND_EXPR bodies. (gimplify_expr): Handle fallback == fb_none like a statement. * langhooks-def.h (LANG_HOOKS_TREE_INLINING_TREE_CHAIN_MATTERS_P): Kill. * langhooks.c (lhd_tree_inlining_tree_chain_matters_p): Remove. * langhooks.h (tree_chain_matters_p): Remove. * stub-objc.c (objc_clear_super_receiver): New. * tree-gimple.h (voidify_wrapper_expr): Update decl. (append_to_statement_list, append_to_statement_list_force): Move to tree-iterator.h. * tree-inline.c (expand_call_inline): Update call. (clone_body): Use statement lists. (walk_tree): Don't check tree_chain_matters_p. (copy_tree_r): Likewise. * tree-iterator.c (alloc_stmt_list): Clear lang bits. (tsi_link_before, tsi_link_after): Set TREE_SIDE_EFFECTS properly. * tree-iterator.h (append_to_statement_list, append_to_statement_list_force): Moved from tree-gimple.h. * tree-pretty-print.c (dump_generic_node): Clean up TARGET_EXPR dump. * objc/objc-act.c (build_module_descriptor): Use c_begin_compound_stmt. (objc_enter_block): Likewise. (objc_exit_block): Use c_end_compound_stmt. (objc_build_try_enter_fragment): Add #error and comment for rewriting for OBJCPLUS. (objc_build_extract_fragment, objc_build_try_epilogue, objc_build_catch_stmt, objc_build_finally_prologue, objc_build_finally_epilogue): Update for C statement builders. * objc/objc-lang.c (LANG_HOOKS_TREE_INLINING_TREE_CHAIN_MATTERS_P): Remove. cp/ * call.c (initialize_reference): Don't build CLEANUP_STMT here. * cp-gimplify.c (cp_gimplify_stmt): Remove next_p argument. (genericize_try_block): Use gimplify_stmt. (genericize_catch_block, genericize_eh_spec_block): Likewise. (cp_gimplify_init_expr): Remove STMT_EXPR special case. (gimplify_must_not_throw_expr): Update voidify_wrapper_expr call. * cp-lang.c (LANG_HOOKS_TREE_INLINING_TREE_CHAIN_MATTERS_P): Remove. (cp_tree_chain_matters_p): Remove. * cp-tree.h (COMPOUND_STMT_TRY_BLOCK): New. (COMPOUND_STMT_BODY_BLOCK): New. (STATEMENT_LIST_NO_SCOPE, STATEMENT_LIST_TRY_BLOCK): New. (EXPR_STMT_STMT_EXPR_RESULT): New. (building_stmt_tree): Check cur_stmt_list. (tf_stmt_expr_cmpd, tf_stmt_expr_body): Remove. (BCS_NO_SCOPE, BCS_TRY_BLOCK, BCS_FN_BODY): New. * decl.c (poplevel): Use pop_stmt_list for minding cleanups. (cp_finish_decl): Use push_cleanup. (start_function, finish_function): Use statement lists. (finish_stmt): Do nothing. * except.c (begin_eh_spec_block): Use statement lists. (check_handlers_1, check_handlers): Likewise. * init.c (construct_virtual_base): Don't add extra compound stmts. (build_vec_init): Likewise. * name-lookup.c (maybe_push_cleanup_level): Use statement lists. * name-lookup.h (struct cp_binding_level): Add statement_list. * parser.c (cp_parser_statement): Take the STMT_EXPR node, not a bool. (cp_parser_labeled_statement, cp_parser_expression_statement, cp_parser_statement_seq_opt): Likewise. (cp_parser_compound_statement): Likewise. Take bool for try block. (cp_parser_selection_statement): Tidy if processing. (cp_parser_already_scoped_statement): Rewrite to do what it says. * pt.c (tsubst_copy): Move STMT_EXPR to tsubst_expr. (tsubst_expr): Rewrite STMT_EXPR processing. Handle STATEMENT_LIST. Mind COMPOUND_STMT_TRY_BLOCK, EXPR_STMT_STMT_EXPR_RESULT. * semantics.c (do_poplevel, do_pushlevel): Use statement lists. (finish_cond): New, rewritten from FINISH_COND. (simplify_loop_decl_cond): New. (finish_expr_stmt): Avoid nested EXPR_STMTs. (begin_if_stmt, finish_if_stmt_cond, finish_then_clause, begin_else_clause, finish_else_clause, finish_if_stmt, begin_while_stmt, finish_while_stmt_cond, finish_while_stmt, begin_do_stmt, finish_do_body, begin_for_stmt, finish_for_init_stmt, finish_for_cond, finish_for_stmt, begin_switch_stmt, finish_switch_cond, finish_switch_stmt, begin_try_block, finish_try_block, finish_cleanup_try_block, finish_function_try_block, finish_handler_sequence, finish_function_handler_sequence, begin_handler, finish_handler_parms, finish_handler, begin_stmt_expr, finish_stmt_expr_expr, finish_stmt_expr): Rewrite using statement lists. (begin_compound_stmt): Replace has_no_scope argument with flags. Update all callers. Use statement lists. (finish_compound_stmt): Likewise. (finish_decl_cleanup, finish_eh_cleanup): Use push_cleanup. (current_scope_stmt_stack): Remove. (simplify_aggr_init_expr): Don't muck with TREE_CHAIN. * typeck2.c (split_nonconstant_init_1, split_nonconstant_init): Rewrite with statement lists. testsuite/ * g++.dg/ext/stmtexpr1.C: XFAIL. * gcc.dg/20030612-1.c: XFAIL. From-SVN: r83221
368 lines
8.0 KiB
C
368 lines
8.0 KiB
C
/* Iterator routines for manipulating GENERIC and GIMPLE tree statements.
|
|
Copyright (C) 2003, 2004 Free Software Foundation, Inc.
|
|
Contributed by Andrew MacLeod <amacleod@redhat.com>
|
|
|
|
This file is part of GCC.
|
|
|
|
GCC is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2, or (at your option)
|
|
any later version.
|
|
|
|
GCC is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GCC; see the file COPYING. If not, write to
|
|
the Free Software Foundation, 59 Temple Place - Suite 330,
|
|
Boston, MA 02111-1307, USA. */
|
|
|
|
#include "config.h"
|
|
#include "system.h"
|
|
#include "coretypes.h"
|
|
#include "tree.h"
|
|
#include "tree-gimple.h"
|
|
#include "tree-iterator.h"
|
|
#include "ggc.h"
|
|
|
|
|
|
/* This is a cache of STATEMENT_LIST nodes. We create and destroy them
|
|
fairly often during gimplification. */
|
|
|
|
static GTY ((deletable (""))) tree stmt_list_cache;
|
|
|
|
tree
|
|
alloc_stmt_list (void)
|
|
{
|
|
tree list = stmt_list_cache;
|
|
if (list)
|
|
{
|
|
stmt_list_cache = TREE_CHAIN (list);
|
|
memset (list, 0, sizeof(struct tree_common));
|
|
TREE_SET_CODE (list, STATEMENT_LIST);
|
|
}
|
|
else
|
|
list = make_node (STATEMENT_LIST);
|
|
TREE_TYPE (list) = void_type_node;
|
|
return list;
|
|
}
|
|
|
|
void
|
|
free_stmt_list (tree t)
|
|
{
|
|
#ifdef ENABLE_CHECKING
|
|
if (STATEMENT_LIST_HEAD (t) || STATEMENT_LIST_TAIL (t))
|
|
abort ();
|
|
#endif
|
|
TREE_CHAIN (t) = stmt_list_cache;
|
|
stmt_list_cache = t;
|
|
}
|
|
|
|
/* Links a statement, or a chain of statements, before the current stmt. */
|
|
|
|
void
|
|
tsi_link_before (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
|
|
{
|
|
struct tree_statement_list_node *head, *tail, *cur;
|
|
|
|
/* Die on looping. */
|
|
if (t == i->container)
|
|
abort ();
|
|
|
|
if (TREE_CODE (t) == STATEMENT_LIST)
|
|
{
|
|
head = STATEMENT_LIST_HEAD (t);
|
|
tail = STATEMENT_LIST_TAIL (t);
|
|
STATEMENT_LIST_HEAD (t) = NULL;
|
|
STATEMENT_LIST_TAIL (t) = NULL;
|
|
|
|
free_stmt_list (t);
|
|
|
|
/* Empty statement lists need no work. */
|
|
if (!head || !tail)
|
|
{
|
|
if (head != tail)
|
|
abort ();
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
head = ggc_alloc (sizeof (*head));
|
|
head->prev = NULL;
|
|
head->next = NULL;
|
|
head->stmt = t;
|
|
tail = head;
|
|
}
|
|
|
|
TREE_SIDE_EFFECTS (i->container) = 1;
|
|
|
|
cur = i->ptr;
|
|
|
|
/* Link it into the list. */
|
|
if (cur)
|
|
{
|
|
head->prev = cur->prev;
|
|
if (head->prev)
|
|
head->prev->next = head;
|
|
else
|
|
STATEMENT_LIST_HEAD (i->container) = head;
|
|
tail->next = cur;
|
|
cur->prev = tail;
|
|
}
|
|
else
|
|
{
|
|
if (STATEMENT_LIST_TAIL (i->container))
|
|
abort ();
|
|
STATEMENT_LIST_HEAD (i->container) = head;
|
|
STATEMENT_LIST_TAIL (i->container) = tail;
|
|
}
|
|
|
|
/* Update the iterator, if requested. */
|
|
switch (mode)
|
|
{
|
|
case TSI_NEW_STMT:
|
|
case TSI_CONTINUE_LINKING:
|
|
case TSI_CHAIN_START:
|
|
i->ptr = head;
|
|
break;
|
|
case TSI_CHAIN_END:
|
|
i->ptr = tail;
|
|
break;
|
|
case TSI_SAME_STMT:
|
|
if (!cur)
|
|
abort ();
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Links a statement, or a chain of statements, after the current stmt. */
|
|
|
|
void
|
|
tsi_link_after (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
|
|
{
|
|
struct tree_statement_list_node *head, *tail, *cur;
|
|
|
|
/* Die on looping. */
|
|
if (t == i->container)
|
|
abort ();
|
|
|
|
if (TREE_CODE (t) == STATEMENT_LIST)
|
|
{
|
|
head = STATEMENT_LIST_HEAD (t);
|
|
tail = STATEMENT_LIST_TAIL (t);
|
|
STATEMENT_LIST_HEAD (t) = NULL;
|
|
STATEMENT_LIST_TAIL (t) = NULL;
|
|
|
|
free_stmt_list (t);
|
|
|
|
/* Empty statement lists need no work. */
|
|
if (!head || !tail)
|
|
{
|
|
if (head != tail)
|
|
abort ();
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
head = ggc_alloc (sizeof (*head));
|
|
head->prev = NULL;
|
|
head->next = NULL;
|
|
head->stmt = t;
|
|
tail = head;
|
|
}
|
|
|
|
TREE_SIDE_EFFECTS (i->container) = 1;
|
|
|
|
cur = i->ptr;
|
|
|
|
/* Link it into the list. */
|
|
if (cur)
|
|
{
|
|
tail->next = cur->next;
|
|
if (tail->next)
|
|
tail->next->prev = tail;
|
|
else
|
|
STATEMENT_LIST_TAIL (i->container) = tail;
|
|
head->prev = cur;
|
|
cur->next = head;
|
|
}
|
|
else
|
|
{
|
|
if (STATEMENT_LIST_TAIL (i->container))
|
|
abort ();
|
|
STATEMENT_LIST_HEAD (i->container) = head;
|
|
STATEMENT_LIST_TAIL (i->container) = tail;
|
|
}
|
|
|
|
/* Update the iterator, if requested. */
|
|
switch (mode)
|
|
{
|
|
case TSI_NEW_STMT:
|
|
case TSI_CHAIN_START:
|
|
i->ptr = head;
|
|
break;
|
|
case TSI_CONTINUE_LINKING:
|
|
case TSI_CHAIN_END:
|
|
i->ptr = tail;
|
|
break;
|
|
case TSI_SAME_STMT:
|
|
if (!cur)
|
|
abort ();
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Remove a stmt from the tree list. The iterator is updated to point to
|
|
the next stmt. */
|
|
|
|
void
|
|
tsi_delink (tree_stmt_iterator *i)
|
|
{
|
|
struct tree_statement_list_node *cur, *next, *prev;
|
|
|
|
cur = i->ptr;
|
|
next = cur->next;
|
|
prev = cur->prev;
|
|
|
|
if (prev)
|
|
prev->next = next;
|
|
else
|
|
STATEMENT_LIST_HEAD (i->container) = next;
|
|
if (next)
|
|
next->prev = prev;
|
|
else
|
|
STATEMENT_LIST_TAIL (i->container) = prev;
|
|
|
|
if (!next && !prev)
|
|
TREE_SIDE_EFFECTS (i->container) = 0;
|
|
|
|
i->ptr = next;
|
|
}
|
|
|
|
/* Move all statements in the statement list after I to a new
|
|
statement list. I itself is unchanged. */
|
|
|
|
tree
|
|
tsi_split_statement_list_after (const tree_stmt_iterator *i)
|
|
{
|
|
struct tree_statement_list_node *cur, *next;
|
|
tree old_sl, new_sl;
|
|
|
|
cur = i->ptr;
|
|
/* How can we possibly split after the end, or before the beginning? */
|
|
if (cur == NULL)
|
|
abort ();
|
|
next = cur->next;
|
|
|
|
old_sl = i->container;
|
|
new_sl = alloc_stmt_list ();
|
|
TREE_SIDE_EFFECTS (new_sl) = 1;
|
|
|
|
STATEMENT_LIST_HEAD (new_sl) = next;
|
|
STATEMENT_LIST_TAIL (new_sl) = STATEMENT_LIST_TAIL (old_sl);
|
|
STATEMENT_LIST_TAIL (old_sl) = cur;
|
|
cur->next = NULL;
|
|
next->prev = NULL;
|
|
|
|
return new_sl;
|
|
}
|
|
|
|
/* Move all statements in the statement list before I to a new
|
|
statement list. I is set to the head of the new list. */
|
|
|
|
tree
|
|
tsi_split_statement_list_before (tree_stmt_iterator *i)
|
|
{
|
|
struct tree_statement_list_node *cur, *prev;
|
|
tree old_sl, new_sl;
|
|
|
|
cur = i->ptr;
|
|
/* How can we possibly split after the end, or before the beginning? */
|
|
if (cur == NULL)
|
|
abort ();
|
|
prev = cur->prev;
|
|
|
|
old_sl = i->container;
|
|
new_sl = alloc_stmt_list ();
|
|
TREE_SIDE_EFFECTS (new_sl) = 1;
|
|
i->container = new_sl;
|
|
|
|
STATEMENT_LIST_HEAD (new_sl) = cur;
|
|
STATEMENT_LIST_TAIL (new_sl) = STATEMENT_LIST_TAIL (old_sl);
|
|
STATEMENT_LIST_TAIL (old_sl) = prev;
|
|
cur->prev = NULL;
|
|
prev->next = NULL;
|
|
|
|
return new_sl;
|
|
}
|
|
|
|
/* Return the first expression in a sequence of COMPOUND_EXPRs,
|
|
or in a STATEMENT_LIST. */
|
|
|
|
tree
|
|
expr_first (tree expr)
|
|
{
|
|
if (expr == NULL_TREE)
|
|
return expr;
|
|
|
|
if (TREE_CODE (expr) == STATEMENT_LIST)
|
|
{
|
|
struct tree_statement_list_node *n = STATEMENT_LIST_HEAD (expr);
|
|
return n ? n->stmt : NULL_TREE;
|
|
}
|
|
|
|
while (TREE_CODE (expr) == COMPOUND_EXPR)
|
|
expr = TREE_OPERAND (expr, 0);
|
|
return expr;
|
|
}
|
|
|
|
/* Return the last expression in a sequence of COMPOUND_EXPRs,
|
|
or in a STATEMENT_LIST. */
|
|
|
|
tree
|
|
expr_last (tree expr)
|
|
{
|
|
if (expr == NULL_TREE)
|
|
return expr;
|
|
|
|
if (TREE_CODE (expr) == STATEMENT_LIST)
|
|
{
|
|
struct tree_statement_list_node *n = STATEMENT_LIST_TAIL (expr);
|
|
return n ? n->stmt : NULL_TREE;
|
|
}
|
|
|
|
while (TREE_CODE (expr) == COMPOUND_EXPR)
|
|
expr = TREE_OPERAND (expr, 1);
|
|
return expr;
|
|
}
|
|
|
|
/* If EXPR is a single statement, naked or in a STATEMENT_LIST, then
|
|
return it. Otherwise return NULL. */
|
|
|
|
tree
|
|
expr_only (tree expr)
|
|
{
|
|
if (expr == NULL_TREE)
|
|
return NULL_TREE;
|
|
|
|
if (TREE_CODE (expr) == STATEMENT_LIST)
|
|
{
|
|
struct tree_statement_list_node *n = STATEMENT_LIST_TAIL (expr);
|
|
if (n && STATEMENT_LIST_HEAD (expr) == n)
|
|
return n->stmt;
|
|
else
|
|
return NULL_TREE;
|
|
}
|
|
|
|
if (TREE_CODE (expr) == COMPOUND_EXPR)
|
|
return NULL_TREE;
|
|
|
|
return expr;
|
|
}
|
|
|
|
#include "gt-tree-iterator.h"
|