diff options
Diffstat (limited to 'gcc/c-semantics.c')
-rw-r--r-- | gcc/c-semantics.c | 159 |
1 files changed, 92 insertions, 67 deletions
diff --git a/gcc/c-semantics.c b/gcc/c-semantics.c index ce36fb5..4a48191 100644 --- a/gcc/c-semantics.c +++ b/gcc/c-semantics.c @@ -43,20 +43,84 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "timevar.h" #include "predict.h" #include "tree-inline.h" +#include "tree-gimple.h" #include "langhooks.h" /* Create an empty statement tree rooted at T. */ -void -begin_stmt_tree (tree *t) +tree +push_stmt_list (void) { - /* We create a trivial EXPR_STMT so that last_tree is never NULL in - what follows. We remove the extraneous statement in - finish_stmt_tree. */ - *t = build_nt (EXPR_STMT, void_zero_node); - last_tree = *t; - last_expr_type = NULL_TREE; - last_expr_filename = input_filename; + tree t; + t = alloc_stmt_list (); + TREE_CHAIN (t) = cur_stmt_list; + cur_stmt_list = t; + return t; +} + +/* Similarly, except that T may have already been pushed/popped, and + thus may already contain statement(s). Arrage for new statements + to be appended. */ + +tree +re_push_stmt_list (tree t) +{ + if (t) + { + if (TREE_CODE (t) != STATEMENT_LIST) + { + tree u = alloc_stmt_list (); + append_to_statement_list_force (t, &u); + t = u; + } + } + else + t = alloc_stmt_list (); + TREE_CHAIN (t) = cur_stmt_list; + cur_stmt_list = t; + return t; +} + +/* Finish the statement tree rooted at T. */ + +tree +pop_stmt_list (tree t) +{ + tree u = cur_stmt_list, chain; + + /* Pop statement lists until we reach the target level. The extra + nestings will be due to outstanding cleanups. */ + while (1) + { + chain = TREE_CHAIN (u); + TREE_CHAIN (u) = NULL_TREE; + if (t == u) + break; + u = chain; + } + cur_stmt_list = chain; + + /* If the statement list is completely empty, just return it. This is + just as good small as build_empty_stmt, with the advantage that + statement lists are merged when they appended to one another. So + using the STATEMENT_LIST avoids pathological buildup of EMPTY_STMT_P + statements. */ + if (TREE_SIDE_EFFECTS (t)) + { + tree_stmt_iterator i = tsi_start (t); + + /* If the statement list contained exactly one statement, then + extract it immediately. */ + if (tsi_one_before_end_p (i)) + { + u = tsi_stmt (i); + tsi_delink (&i); + free_stmt_list (t); + t = u; + } + } + + return t; } /* T is a statement. Add it to the statement-tree. */ @@ -64,16 +128,19 @@ begin_stmt_tree (tree *t) tree add_stmt (tree t) { - if (!EXPR_LOCUS (t)) - annotate_with_locus (t, input_location); + if (EXPR_P (t) || STATEMENT_CODE_P (TREE_CODE (t))) + { + if (!EXPR_LOCUS (t)) + annotate_with_locus (t, input_location); - /* Add T to the statement-tree. */ - TREE_CHAIN (last_tree) = t; - last_tree = t; + /* When we expand a statement-tree, we must know whether or not the + statements are full-expressions. We record that fact here. */ + STMT_IS_FULL_EXPR_P (t) = stmts_are_full_exprs_p (); + } - /* When we expand a statement-tree, we must know whether or not the - statements are full-expressions. We record that fact here. */ - STMT_IS_FULL_EXPR_P (last_tree) = stmts_are_full_exprs_p (); + /* Add T to the statement-tree. Non-side-effect statements need to be + recorded during statement expressions. */ + append_to_statement_list_force (t, &cur_stmt_list); return t; } @@ -91,59 +158,17 @@ add_decl_stmt (tree decl) add_stmt (decl_stmt); } -/* Add a scope-statement to the statement-tree. BEGIN_P indicates - whether this statements opens or closes a scope. PARTIAL_P is true - for a partial scope, i.e, the scope that begins after a label when - an object that needs a cleanup is created. If BEGIN_P is nonzero, - returns a new TREE_LIST representing the top of the SCOPE_STMT - stack. The TREE_PURPOSE is the new SCOPE_STMT. If BEGIN_P is - zero, returns a TREE_LIST whose TREE_VALUE is the new SCOPE_STMT, - and whose TREE_PURPOSE is the matching SCOPE_STMT with - SCOPE_BEGIN_P set. */ - -tree -add_scope_stmt (int begin_p, int partial_p) -{ - tree *stack_ptr = current_scope_stmt_stack (); - tree ss; - tree top = *stack_ptr; - - /* Build the statement. */ - ss = build_stmt (SCOPE_STMT, NULL_TREE); - SCOPE_BEGIN_P (ss) = begin_p; - SCOPE_PARTIAL_P (ss) = partial_p; - - /* Keep the scope stack up to date. */ - if (begin_p) - { - top = tree_cons (ss, NULL_TREE, top); - *stack_ptr = top; - } - else - { - if (partial_p != SCOPE_PARTIAL_P (TREE_PURPOSE (top))) - abort (); - TREE_VALUE (top) = ss; - *stack_ptr = TREE_CHAIN (top); - } - - /* Add the new statement to the statement-tree. */ - add_stmt (ss); - - return top; -} - -/* Finish the statement tree rooted at T. */ +/* Queue a cleanup. CLEANUP is an expression/statement to be executed + when the current scope is exited. EH_ONLY is true when this is not + meant to apply to normal control flow transfer. */ void -finish_stmt_tree (tree *t) +push_cleanup (tree decl, tree cleanup, bool eh_only) { - tree stmt; - - /* Remove the fake extra statement added in begin_stmt_tree. */ - stmt = TREE_CHAIN (*t); - *t = stmt; - last_tree = NULL_TREE; + tree stmt = build_stmt (CLEANUP_STMT, NULL, cleanup, decl); + CLEANUP_EH_ONLY (stmt) = eh_only; + add_stmt (stmt); + CLEANUP_BODY (stmt) = push_stmt_list (); } /* Build a generic statement based on the given type of node and |