c-common.c (lang_gimplify_stmt): Remove next_p argument.
* 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
This commit is contained in:
parent
aaab7bb6d7
commit
325c369115
108
gcc/ChangeLog
108
gcc/ChangeLog
@ -1,3 +1,111 @@
|
||||
2004-06-15 Richard Henderson <rth@redhat.com>
|
||||
|
||||
* 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.
|
||||
|
||||
2004-06-15 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>
|
||||
|
||||
* df.c (df_reg_clobber_gen): Removed.
|
||||
|
276
gcc/c-common.c
276
gcc/c-common.c
@ -690,7 +690,7 @@ int (*lang_statement_code_p) (enum tree_code);
|
||||
/* If non-NULL, the address of a language-specific function that does any
|
||||
language-specific gimplification for _STMT nodes and returns 1 iff
|
||||
handled. */
|
||||
int (*lang_gimplify_stmt) (tree *, tree *);
|
||||
int (*lang_gimplify_stmt) (tree *);
|
||||
|
||||
/* If non-NULL, the address of a language-specific function that takes
|
||||
any action required right before expand_function_end is called. */
|
||||
@ -723,27 +723,6 @@ const struct fname_var_t fname_vars[] =
|
||||
|
||||
static int constant_fits_type_p (tree, tree);
|
||||
|
||||
/* Keep a stack of if statements. We record the number of compound
|
||||
statements seen up to the if keyword, as well as the line number
|
||||
and file of the if. If a potentially ambiguous else is seen, that
|
||||
fact is recorded; the warning is issued when we can be sure that
|
||||
the enclosing if statement does not have an else branch. */
|
||||
typedef struct
|
||||
{
|
||||
int compstmt_count;
|
||||
location_t locus;
|
||||
int needs_warning;
|
||||
tree if_stmt;
|
||||
} if_elt;
|
||||
|
||||
static if_elt *if_stack;
|
||||
|
||||
/* Amount of space in the if statement stack. */
|
||||
static int if_stack_space = 0;
|
||||
|
||||
/* Stack pointer. */
|
||||
static int if_stack_pointer = 0;
|
||||
|
||||
static tree handle_packed_attribute (tree *, tree, tree, int, bool *);
|
||||
static tree handle_nocommon_attribute (tree *, tree, tree, int, bool *);
|
||||
static tree handle_common_attribute (tree *, tree, tree, int, bool *);
|
||||
@ -876,131 +855,6 @@ const struct attribute_spec c_common_format_attribute_table[] =
|
||||
{ NULL, 0, 0, false, false, false, NULL }
|
||||
};
|
||||
|
||||
/* Record the start of an if-then, and record the start of it
|
||||
for ambiguous else detection.
|
||||
|
||||
COND is the condition for the if-then statement.
|
||||
|
||||
IF_STMT is the statement node that has already been created for
|
||||
this if-then statement. It is created before parsing the
|
||||
condition to keep line number information accurate. */
|
||||
|
||||
void
|
||||
c_expand_start_cond (tree cond, int compstmt_count, tree if_stmt)
|
||||
{
|
||||
/* Make sure there is enough space on the stack. */
|
||||
if (if_stack_space == 0)
|
||||
{
|
||||
if_stack_space = 10;
|
||||
if_stack = xmalloc (10 * sizeof (if_elt));
|
||||
}
|
||||
else if (if_stack_space == if_stack_pointer)
|
||||
{
|
||||
if_stack_space += 10;
|
||||
if_stack = xrealloc (if_stack, if_stack_space * sizeof (if_elt));
|
||||
}
|
||||
|
||||
IF_COND (if_stmt) = cond;
|
||||
add_stmt (if_stmt);
|
||||
|
||||
/* Record this if statement. */
|
||||
if_stack[if_stack_pointer].compstmt_count = compstmt_count;
|
||||
if_stack[if_stack_pointer].locus = input_location;
|
||||
if_stack[if_stack_pointer].needs_warning = 0;
|
||||
if_stack[if_stack_pointer].if_stmt = if_stmt;
|
||||
if_stack_pointer++;
|
||||
}
|
||||
|
||||
/* Called after the then-clause for an if-statement is processed. */
|
||||
|
||||
void
|
||||
c_finish_then (void)
|
||||
{
|
||||
tree if_stmt = if_stack[if_stack_pointer - 1].if_stmt;
|
||||
RECHAIN_STMTS (if_stmt, THEN_CLAUSE (if_stmt));
|
||||
}
|
||||
|
||||
/* Record the end of an if-then. Optionally warn if a nested
|
||||
if statement had an ambiguous else clause. */
|
||||
|
||||
void
|
||||
c_expand_end_cond (void)
|
||||
{
|
||||
if_stack_pointer--;
|
||||
if (if_stack[if_stack_pointer].needs_warning)
|
||||
warning ("%Hsuggest explicit braces to avoid ambiguous `else'",
|
||||
&if_stack[if_stack_pointer].locus);
|
||||
last_expr_type = NULL_TREE;
|
||||
}
|
||||
|
||||
/* Called between the then-clause and the else-clause
|
||||
of an if-then-else. */
|
||||
|
||||
void
|
||||
c_expand_start_else (void)
|
||||
{
|
||||
/* An ambiguous else warning must be generated for the enclosing if
|
||||
statement, unless we see an else branch for that one, too. */
|
||||
if (warn_parentheses
|
||||
&& if_stack_pointer > 1
|
||||
&& (if_stack[if_stack_pointer - 1].compstmt_count
|
||||
== if_stack[if_stack_pointer - 2].compstmt_count))
|
||||
if_stack[if_stack_pointer - 2].needs_warning = 1;
|
||||
|
||||
/* Even if a nested if statement had an else branch, it can't be
|
||||
ambiguous if this one also has an else. So don't warn in that
|
||||
case. Also don't warn for any if statements nested in this else. */
|
||||
if_stack[if_stack_pointer - 1].needs_warning = 0;
|
||||
if_stack[if_stack_pointer - 1].compstmt_count--;
|
||||
}
|
||||
|
||||
/* Called after the else-clause for an if-statement is processed. */
|
||||
|
||||
void
|
||||
c_finish_else (void)
|
||||
{
|
||||
tree if_stmt = if_stack[if_stack_pointer - 1].if_stmt;
|
||||
RECHAIN_STMTS (if_stmt, ELSE_CLAUSE (if_stmt));
|
||||
}
|
||||
|
||||
/* Begin an if-statement. Returns a newly created IF_STMT if
|
||||
appropriate.
|
||||
|
||||
Unlike the C++ front-end, we do not call add_stmt here; it is
|
||||
probably safe to do so, but I am not very familiar with this
|
||||
code so I am being extra careful not to change its behavior
|
||||
beyond what is strictly necessary for correctness. */
|
||||
|
||||
tree
|
||||
c_begin_if_stmt (void)
|
||||
{
|
||||
tree r;
|
||||
r = build_stmt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Begin a while statement. Returns a newly created WHILE_STMT if
|
||||
appropriate.
|
||||
|
||||
Unlike the C++ front-end, we do not call add_stmt here; it is
|
||||
probably safe to do so, but I am not very familiar with this
|
||||
code so I am being extra careful not to change its behavior
|
||||
beyond what is strictly necessary for correctness. */
|
||||
|
||||
tree
|
||||
c_begin_while_stmt (void)
|
||||
{
|
||||
tree r;
|
||||
r = build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE);
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
c_finish_while_stmt_cond (tree cond, tree while_stmt)
|
||||
{
|
||||
WHILE_COND (while_stmt) = cond;
|
||||
}
|
||||
|
||||
/* Push current bindings for the function name VAR_DECLS. */
|
||||
|
||||
void
|
||||
@ -1026,43 +880,32 @@ start_fname_decls (void)
|
||||
saved_function_name_decls);
|
||||
}
|
||||
|
||||
/* Finish up the current bindings, adding them into the
|
||||
current function's statement tree. This is done by wrapping the
|
||||
function's body in a COMPOUND_STMT containing these decls too. This
|
||||
must be done _before_ finish_stmt_tree is called. If there is no
|
||||
current function, we must be at file scope and no statements are
|
||||
involved. Pop the previous bindings. */
|
||||
/* Finish up the current bindings, adding them into the current function's
|
||||
statement tree. This must be done _before_ finish_stmt_tree is called.
|
||||
If there is no current function, we must be at file scope and no statements
|
||||
are involved. Pop the previous bindings. */
|
||||
|
||||
void
|
||||
finish_fname_decls (void)
|
||||
{
|
||||
unsigned ix;
|
||||
tree body = NULL_TREE;
|
||||
tree stmts = NULL_TREE;
|
||||
tree stack = saved_function_name_decls;
|
||||
|
||||
for (; stack && TREE_VALUE (stack); stack = TREE_CHAIN (stack))
|
||||
body = chainon (TREE_VALUE (stack), body);
|
||||
append_to_statement_list (TREE_VALUE (stack), &stmts);
|
||||
|
||||
if (body)
|
||||
if (stmts)
|
||||
{
|
||||
/* They were called into existence, so add to statement tree. Add
|
||||
the DECL_STMTs inside the outermost scope. */
|
||||
tree *p = &DECL_SAVED_TREE (current_function_decl);
|
||||
/* Skip the dummy EXPR_STMT and any EH_SPEC_BLOCK. */
|
||||
while (TREE_CODE (*p) != COMPOUND_STMT)
|
||||
{
|
||||
if (TREE_CODE (*p) == EXPR_STMT)
|
||||
p = &TREE_CHAIN (*p);
|
||||
else
|
||||
p = &TREE_OPERAND(*p, 0);
|
||||
}
|
||||
tree *bodyp = &DECL_SAVED_TREE (current_function_decl);
|
||||
|
||||
p = &COMPOUND_BODY (*p);
|
||||
if (TREE_CODE (*p) == SCOPE_STMT)
|
||||
p = &TREE_CHAIN (*p);
|
||||
if (TREE_CODE (*bodyp) == COMPOUND_STMT)
|
||||
bodyp = &COMPOUND_BODY (*bodyp);
|
||||
if (TREE_CODE (*bodyp) == BIND_EXPR)
|
||||
bodyp = &BIND_EXPR_BODY (*bodyp);
|
||||
|
||||
body = chainon (body, *p);
|
||||
*p = body;
|
||||
append_to_statement_list (*bodyp, &stmts);
|
||||
*bodyp = stmts;
|
||||
}
|
||||
|
||||
for (ix = 0; fname_vars[ix].decl; ix++)
|
||||
@ -1167,30 +1010,23 @@ fname_decl (unsigned int rid, tree id)
|
||||
decl = *fname_vars[ix].decl;
|
||||
if (!decl)
|
||||
{
|
||||
tree saved_last_tree = last_tree;
|
||||
/* If a tree is built here, it would normally have the lineno of
|
||||
the current statement. Later this tree will be moved to the
|
||||
beginning of the function and this line number will be wrong.
|
||||
To avoid this problem set the lineno to 0 here; that prevents
|
||||
it from appearing in the RTL. */
|
||||
int saved_lineno = input_line;
|
||||
tree stmts;
|
||||
location_t saved_locus = input_location;
|
||||
input_line = 0;
|
||||
|
||||
stmts = push_stmt_list ();
|
||||
decl = (*make_fname_decl) (id, fname_vars[ix].pretty);
|
||||
if (last_tree != saved_last_tree)
|
||||
{
|
||||
/* We created some statement tree for the decl. This belongs
|
||||
at the start of the function, so remove it now and reinsert
|
||||
it after the function is complete. */
|
||||
tree stmts = TREE_CHAIN (saved_last_tree);
|
||||
|
||||
TREE_CHAIN (saved_last_tree) = NULL_TREE;
|
||||
last_tree = saved_last_tree;
|
||||
saved_function_name_decls = tree_cons (decl, stmts,
|
||||
saved_function_name_decls);
|
||||
}
|
||||
stmts = pop_stmt_list (stmts);
|
||||
if (!IS_EMPTY_STMT (stmts))
|
||||
saved_function_name_decls
|
||||
= tree_cons (decl, stmts, saved_function_name_decls);
|
||||
*fname_vars[ix].decl = decl;
|
||||
input_line = saved_lineno;
|
||||
input_location = saved_locus;
|
||||
}
|
||||
if (!ix && !current_function_decl)
|
||||
pedwarn ("%J'%D' is not defined outside of function scope", decl, decl);
|
||||
@ -1790,7 +1626,11 @@ c_expand_expr_stmt (tree expr)
|
||||
&& TREE_CODE (TREE_TYPE (expr)) != ARRAY_TYPE)
|
||||
error ("expression statement has incomplete type");
|
||||
|
||||
last_expr_type = TREE_TYPE (expr);
|
||||
/* As tempting as it might be, we can't diagnose statement with no
|
||||
effect yet. We have to wait until after statement expressions
|
||||
have been parsed, and that process modifies the trees we are
|
||||
creating here. */
|
||||
|
||||
return add_stmt (build_stmt (EXPR_STMT, expr));
|
||||
}
|
||||
|
||||
@ -2855,28 +2695,28 @@ c_type_hash (const void *p)
|
||||
tree t2;
|
||||
switch (TREE_CODE (t))
|
||||
{
|
||||
/* For pointers, hash on pointee type plus some swizzling. */
|
||||
case POINTER_TYPE:
|
||||
return c_type_hash (TREE_TYPE (t)) ^ 0x3003003;
|
||||
/* Hash on number of elements and total size. */
|
||||
case ENUMERAL_TYPE:
|
||||
shift = 3;
|
||||
t2 = TYPE_VALUES (t);
|
||||
break;
|
||||
case RECORD_TYPE:
|
||||
shift = 0;
|
||||
t2 = TYPE_FIELDS (t);
|
||||
break;
|
||||
case QUAL_UNION_TYPE:
|
||||
shift = 1;
|
||||
t2 = TYPE_FIELDS (t);
|
||||
break;
|
||||
case UNION_TYPE:
|
||||
shift = 2;
|
||||
t2 = TYPE_FIELDS (t);
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
/* For pointers, hash on pointee type plus some swizzling. */
|
||||
case POINTER_TYPE:
|
||||
return c_type_hash (TREE_TYPE (t)) ^ 0x3003003;
|
||||
/* Hash on number of elements and total size. */
|
||||
case ENUMERAL_TYPE:
|
||||
shift = 3;
|
||||
t2 = TYPE_VALUES (t);
|
||||
break;
|
||||
case RECORD_TYPE:
|
||||
shift = 0;
|
||||
t2 = TYPE_FIELDS (t);
|
||||
break;
|
||||
case QUAL_UNION_TYPE:
|
||||
shift = 1;
|
||||
t2 = TYPE_FIELDS (t);
|
||||
break;
|
||||
case UNION_TYPE:
|
||||
shift = 2;
|
||||
t2 = TYPE_FIELDS (t);
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
for (; t2; t2 = TREE_CHAIN (t2))
|
||||
i++;
|
||||
@ -4287,10 +4127,6 @@ c_safe_from_p (rtx target, tree exp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* For any statement, we must follow the statement-chain. */
|
||||
if (STATEMENT_CODE_P (TREE_CODE (exp)) && TREE_CHAIN (exp))
|
||||
return safe_from_p (target, TREE_CHAIN (exp), /*top_p=*/0);
|
||||
|
||||
/* Assume everything else is safe. */
|
||||
return 1;
|
||||
}
|
||||
@ -5727,18 +5563,6 @@ c_walk_subtrees (tree *tp, int *walk_subtrees_p ATTRIBUTE_UNUSED,
|
||||
#undef WALK_SUBTREE
|
||||
}
|
||||
|
||||
/* C implementation of lang_hooks.tree_inlining.tree_chain_matters_p.
|
||||
Apart from TREE_LISTs, the only trees whose TREE_CHAIN we care about are
|
||||
_STMT nodes. */
|
||||
|
||||
int
|
||||
c_tree_chain_matters_p (tree t)
|
||||
{
|
||||
/* For statements, we also walk the chain so that we cover the
|
||||
entire statement tree. */
|
||||
return STATEMENT_CODE_P (TREE_CODE (t));
|
||||
}
|
||||
|
||||
/* Function to help qsort sort FIELD_DECLs by name order. */
|
||||
|
||||
int
|
||||
|
@ -81,14 +81,6 @@ DEFTREECODE (LABEL_STMT, "label_stmt", 'e', 1)
|
||||
/* Used to represent an inline assembly statement. */
|
||||
DEFTREECODE (ASM_STMT, "asm_stmt", 'e', 4)
|
||||
|
||||
/* A SCOPE_STMT marks the beginning or end of a scope. If
|
||||
SCOPE_BEGIN_P holds, then this is the start of a scope. If
|
||||
SCOPE_END_P holds, then this is the end of a scope. If
|
||||
SCOPE_NULLIFIED_P holds then there turned out to be no variables in
|
||||
this scope. The SCOPE_STMT_BLOCK is the BLOCK containing the
|
||||
variables declared in this scope. */
|
||||
DEFTREECODE (SCOPE_STMT, "scope_stmt", 'e', 1)
|
||||
|
||||
/* Used to represent a CASE_LABEL. The operands are CASE_LOW and
|
||||
CASE_HIGH, respectively. If CASE_LOW is NULL_TREE, the label is a
|
||||
'default' label. If CASE_HIGH is NULL_TREE, the label is a normal case
|
||||
@ -107,9 +99,9 @@ DEFTREECODE (STMT_EXPR, "stmt_expr", 'e', 1)
|
||||
DEFTREECODE (COMPOUND_LITERAL_EXPR, "compound_literal_expr", 'e', 1)
|
||||
|
||||
/* A CLEANUP_STMT marks the point at which a declaration is fully
|
||||
constructed. If, after this point, the CLEANUP_DECL goes out of
|
||||
scope, the CLEANUP_EXPR must be run. */
|
||||
DEFTREECODE (CLEANUP_STMT, "cleanup_stmt", 'e', 2)
|
||||
constructed. The CLEANUP_EXPR is run on behalf of CLEANUP_DECL
|
||||
when CLEANUP_BODY completes. */
|
||||
DEFTREECODE (CLEANUP_STMT, "cleanup_stmt", 'e', 3)
|
||||
|
||||
/*
|
||||
Local variables:
|
||||
|
130
gcc/c-common.h
130
gcc/c-common.h
@ -27,20 +27,17 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
#include "ggc.h"
|
||||
|
||||
/* Usage of TREE_LANG_FLAG_?:
|
||||
0: COMPOUND_STMT_NO_SCOPE (in COMPOUND_STMT).
|
||||
TREE_NEGATED_INT (in INTEGER_CST).
|
||||
0: TREE_NEGATED_INT (in INTEGER_CST).
|
||||
IDENTIFIER_MARKED (used by search routines).
|
||||
SCOPE_BEGIN_P (in SCOPE_STMT)
|
||||
DECL_PRETTY_FUNCTION_P (in VAR_DECL)
|
||||
NEW_FOR_SCOPE_P (in FOR_STMT)
|
||||
ASM_INPUT_P (in ASM_STMT)
|
||||
STMT_EXPR_NO_SCOPE (in STMT_EXPR)
|
||||
1: C_DECLARED_LABEL_FLAG (in LABEL_DECL)
|
||||
STMT_IS_FULL_EXPR_P (in _STMT)
|
||||
STATEMENT_LIST_STMT_EXPR (in STATEMENT_LIST)
|
||||
2: unused
|
||||
3: SCOPE_NO_CLEANUPS_P (in SCOPE_STMT)
|
||||
COMPOUND_STMT_BODY_BLOCK (in COMPOUND_STMT)
|
||||
4: SCOPE_PARTIAL_P (in SCOPE_STMT)
|
||||
3: unused
|
||||
4: unused
|
||||
*/
|
||||
|
||||
/* Reserved identifiers. This is the union of all the keywords for C,
|
||||
@ -245,13 +242,9 @@ extern c_language_kind c_language;
|
||||
/* Information about a statement tree. */
|
||||
|
||||
struct stmt_tree_s GTY(()) {
|
||||
/* The last statement added to the tree. */
|
||||
tree x_last_stmt;
|
||||
/* The type of the last expression statement. (This information is
|
||||
needed to implement the statement-expression extension.) */
|
||||
tree x_last_expr_type;
|
||||
/* The last filename we recorded. */
|
||||
const char *x_last_expr_filename;
|
||||
/* The current statment list being collected. */
|
||||
tree x_cur_stmt_list;
|
||||
|
||||
/* In C++, Nonzero if we should treat statements as full
|
||||
expressions. In particular, this variable is no-zero if at the
|
||||
end of a statement we should destroy any temporaries created
|
||||
@ -278,38 +271,17 @@ struct c_language_function GTY(()) {
|
||||
/* While we are parsing the function, this contains information
|
||||
about the statement-tree that we are building. */
|
||||
struct stmt_tree_s x_stmt_tree;
|
||||
/* The stack of SCOPE_STMTs for the current function. */
|
||||
tree x_scope_stmt_stack;
|
||||
};
|
||||
|
||||
/* When building a statement-tree, this is the last statement added to
|
||||
the tree. */
|
||||
/* When building a statement-tree, this is the current statment list
|
||||
being collected. It's TREE_CHAIN is a back-pointer to the previous
|
||||
statment list. */
|
||||
|
||||
#define last_tree (current_stmt_tree ()->x_last_stmt)
|
||||
|
||||
/* The type of the last expression-statement we have seen. */
|
||||
|
||||
#define last_expr_type (current_stmt_tree ()->x_last_expr_type)
|
||||
|
||||
/* The name of the last file we have seen. */
|
||||
|
||||
#define last_expr_filename (current_stmt_tree ()->x_last_expr_filename)
|
||||
|
||||
/* LAST_TREE contains the last statement parsed. These are chained
|
||||
together through the TREE_CHAIN field, but often need to be
|
||||
re-organized since the parse is performed bottom-up. This macro
|
||||
makes LAST_TREE the indicated SUBSTMT of STMT. */
|
||||
|
||||
#define RECHAIN_STMTS(stmt, substmt) \
|
||||
do { \
|
||||
substmt = TREE_CHAIN (stmt); \
|
||||
TREE_CHAIN (stmt) = NULL_TREE; \
|
||||
last_tree = stmt; \
|
||||
} while (0)
|
||||
#define cur_stmt_list (current_stmt_tree ()->x_cur_stmt_list)
|
||||
|
||||
/* Language-specific hooks. */
|
||||
|
||||
extern int (*lang_gimplify_stmt) (tree *, tree *);
|
||||
extern int (*lang_gimplify_stmt) (tree *);
|
||||
extern void (*lang_expand_function_end) (void);
|
||||
|
||||
/* Callback that determines if it's ok for a function to have no
|
||||
@ -320,12 +292,12 @@ extern void push_file_scope (void);
|
||||
extern void pop_file_scope (void);
|
||||
extern int yyparse (void);
|
||||
extern stmt_tree current_stmt_tree (void);
|
||||
extern tree *current_scope_stmt_stack (void);
|
||||
extern void begin_stmt_tree (tree *);
|
||||
extern tree push_stmt_list (void);
|
||||
extern tree re_push_stmt_list (tree);
|
||||
extern tree pop_stmt_list (tree);
|
||||
extern tree add_stmt (tree);
|
||||
extern void add_decl_stmt (tree);
|
||||
extern tree add_scope_stmt (int, int);
|
||||
extern void finish_stmt_tree (tree *);
|
||||
extern void push_cleanup (tree, tree, bool);
|
||||
|
||||
extern tree walk_stmt_tree (tree *, walk_tree_fn, void *);
|
||||
extern void prep_stmt (tree);
|
||||
@ -891,11 +863,6 @@ extern void binary_op_error (enum tree_code);
|
||||
(((EXP) == 0) ? (fancy_abort (__FILE__, __LINE__, __FUNCTION__), 0) : 0)
|
||||
|
||||
extern tree c_expand_expr_stmt (tree);
|
||||
extern void c_expand_start_cond (tree, int, tree);
|
||||
extern void c_finish_then (void);
|
||||
extern void c_expand_start_else (void);
|
||||
extern void c_finish_else (void);
|
||||
extern void c_expand_end_cond (void);
|
||||
/* Validate the expression after `case' and apply default promotions. */
|
||||
extern tree check_case_value (tree);
|
||||
extern tree fix_string_type (tree);
|
||||
@ -952,6 +919,11 @@ extern void finish_file (void);
|
||||
will always be false, since there are no destructors.) */
|
||||
#define STMT_IS_FULL_EXPR_P(NODE) TREE_LANG_FLAG_1 ((NODE))
|
||||
|
||||
/* Nonzero if a given STATEMENT_LIST represents the outermost binding
|
||||
if a statement expression. */
|
||||
#define STATEMENT_LIST_STMT_EXPR(NODE) \
|
||||
TREE_LANG_FLAG_1 (STATEMENT_LIST_CHECK (NODE))
|
||||
|
||||
/* IF_STMT accessors. These give access to the condition of the if
|
||||
statement, the then block of the if statement, and the else block
|
||||
of the if statement if it exists. */
|
||||
@ -1019,53 +991,15 @@ extern void finish_file (void);
|
||||
#define COMPOUND_LITERAL_EXPR_DECL(NODE) \
|
||||
DECL_STMT_DECL (COMPOUND_LITERAL_EXPR_DECL_STMT (NODE))
|
||||
|
||||
/* Nonzero if this SCOPE_STMT is for the beginning of a scope. */
|
||||
#define SCOPE_BEGIN_P(NODE) \
|
||||
(TREE_LANG_FLAG_0 (SCOPE_STMT_CHECK (NODE)))
|
||||
|
||||
/* Nonzero if this SCOPE_STMT is for the end of a scope. */
|
||||
#define SCOPE_END_P(NODE) \
|
||||
(!SCOPE_BEGIN_P (SCOPE_STMT_CHECK (NODE)))
|
||||
|
||||
/* The BLOCK containing the declarations contained in this scope. */
|
||||
#define SCOPE_STMT_BLOCK(NODE) \
|
||||
(TREE_OPERAND (SCOPE_STMT_CHECK (NODE), 0))
|
||||
|
||||
/* Nonzero for a SCOPE_STMT if there were no variables in this scope. */
|
||||
#define SCOPE_NULLIFIED_P(NODE) \
|
||||
(SCOPE_STMT_BLOCK ((NODE)) == NULL_TREE)
|
||||
|
||||
/* Nonzero for a SCOPE_STMT which represents a lexical scope, but
|
||||
which should be treated as non-existent from the point of view of
|
||||
running cleanup actions. */
|
||||
#define SCOPE_NO_CLEANUPS_P(NODE) \
|
||||
(TREE_LANG_FLAG_3 (SCOPE_STMT_CHECK (NODE)))
|
||||
|
||||
/* Nonzero for a SCOPE_STMT if this statement is for a partial scope.
|
||||
For example, in:
|
||||
|
||||
S s;
|
||||
l:
|
||||
S s2;
|
||||
goto l;
|
||||
|
||||
there is (implicitly) a new scope after `l', even though there are
|
||||
no curly braces. In particular, when we hit the goto, we must
|
||||
destroy s2 and then re-construct it. For the implicit scope,
|
||||
SCOPE_PARTIAL_P will be set. */
|
||||
#define SCOPE_PARTIAL_P(NODE) \
|
||||
(TREE_LANG_FLAG_4 (SCOPE_STMT_CHECK (NODE)))
|
||||
|
||||
/* The VAR_DECL to clean up in a CLEANUP_STMT. */
|
||||
#define CLEANUP_DECL(NODE) \
|
||||
/* The body of the CLEANUP_STMT. */
|
||||
#define CLEANUP_BODY(NODE) \
|
||||
TREE_OPERAND (CLEANUP_STMT_CHECK (NODE), 0)
|
||||
/* The cleanup to run in a CLEANUP_STMT. */
|
||||
#define CLEANUP_EXPR(NODE) \
|
||||
TREE_OPERAND (CLEANUP_STMT_CHECK (NODE), 1)
|
||||
|
||||
/* Nonzero if we want the new ISO rules for pushing a new scope for `for'
|
||||
initialization variables. */
|
||||
#define NEW_FOR_SCOPE_P(NODE) (TREE_LANG_FLAG_0 (NODE))
|
||||
/* The VAR_DECL to clean up in a CLEANUP_STMT. */
|
||||
#define CLEANUP_DECL(NODE) \
|
||||
TREE_OPERAND (CLEANUP_STMT_CHECK (NODE), 2)
|
||||
|
||||
#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) SYM,
|
||||
|
||||
@ -1081,7 +1015,7 @@ enum c_tree_code {
|
||||
CLEANUP_STMT, EXPR_STMT, COMPOUND_STMT, \
|
||||
DECL_STMT, IF_STMT, FOR_STMT, \
|
||||
WHILE_STMT, DO_STMT, RETURN_STMT, \
|
||||
BREAK_STMT, CONTINUE_STMT, SCOPE_STMT, \
|
||||
BREAK_STMT, CONTINUE_STMT, \
|
||||
SWITCH_STMT, GOTO_STMT, LABEL_STMT, \
|
||||
ASM_STMT, CASE_LABEL
|
||||
|
||||
@ -1124,12 +1058,6 @@ extern tree build_continue_stmt (void);
|
||||
extern tree build_break_stmt (void);
|
||||
extern tree build_return_stmt (tree);
|
||||
|
||||
#define COMPOUND_STMT_NO_SCOPE(NODE) TREE_LANG_FLAG_0 (NODE)
|
||||
|
||||
/* Used by the C++ frontend to mark the block around the member
|
||||
initializers and cleanups. */
|
||||
#define COMPOUND_STMT_BODY_BLOCK(NODE) TREE_LANG_FLAG_3 (NODE)
|
||||
|
||||
extern void c_expand_asm_operands (tree, tree, tree, tree, int, location_t);
|
||||
|
||||
/* These functions must be defined by each front-end which implements
|
||||
@ -1204,14 +1132,13 @@ extern bool c_dump_tree (void *, tree);
|
||||
|
||||
extern int c_gimplify_expr (tree *, tree *, tree *);
|
||||
extern tree c_walk_subtrees (tree*, int*, walk_tree_fn, void*, void*);
|
||||
extern int c_tree_chain_matters_p (tree);
|
||||
|
||||
extern void c_warn_unused_result (tree *);
|
||||
|
||||
/* In c-simplify.c */
|
||||
extern void c_genericize (tree);
|
||||
extern int c_gimplify_stmt (tree *);
|
||||
extern tree stmt_expr_last_stmt (tree);
|
||||
extern tree c_build_bind_expr (tree, tree);
|
||||
|
||||
extern void pch_init (void);
|
||||
extern int c_common_valid_pch (cpp_reader *pfile, const char *name, int fd);
|
||||
@ -1236,6 +1163,7 @@ extern tree objc_message_selector (void);
|
||||
extern tree lookup_objc_ivar (tree);
|
||||
extern void *get_current_scope (void);
|
||||
extern void objc_mark_locals_volatile (void *);
|
||||
extern void objc_clear_super_receiver (void);
|
||||
extern int objc_is_public (tree, tree);
|
||||
|
||||
/* In c-ppoutput.c */
|
||||
|
55
gcc/c-decl.c
55
gcc/c-decl.c
@ -105,10 +105,6 @@ static location_t current_function_prototype_locus;
|
||||
|
||||
static GTY(()) struct stmt_tree_s c_stmt_tree;
|
||||
|
||||
/* The current scope statement stack. */
|
||||
|
||||
static GTY(()) tree c_scope_stmt_stack;
|
||||
|
||||
/* State saving variables. */
|
||||
int c_in_iteration_stmt;
|
||||
int c_in_case_stmt;
|
||||
@ -2999,6 +2995,7 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
|
||||
|
||||
/* Don't warn about decl unused; the cleanup uses it. */
|
||||
TREE_USED (decl) = 1;
|
||||
TREE_USED (cleanup_decl) = 1;
|
||||
|
||||
/* Initialize EH, if we've been told to do so. */
|
||||
if (flag_exceptions && !eh_initialized_p)
|
||||
@ -3011,7 +3008,7 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
|
||||
using_eh_for_cleanups ();
|
||||
}
|
||||
|
||||
add_stmt (build_stmt (CLEANUP_STMT, decl, cleanup));
|
||||
push_cleanup (decl, cleanup, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6142,7 +6139,7 @@ store_parm_decls (void)
|
||||
allocate_struct_function (fndecl);
|
||||
|
||||
/* Begin the statement tree for this function. */
|
||||
begin_stmt_tree (&DECL_SAVED_TREE (fndecl));
|
||||
DECL_SAVED_TREE (fndecl) = push_stmt_list ();
|
||||
|
||||
/* If this is a nested function, save away the sizes of any
|
||||
variable-size types so that we can expand them when generating
|
||||
@ -6214,22 +6211,6 @@ finish_function (void)
|
||||
{
|
||||
tree fndecl = current_function_decl;
|
||||
|
||||
/* When a function declaration is totally empty, e.g.
|
||||
void foo(void) { }
|
||||
(the argument list is irrelevant) the compstmt rule will not
|
||||
bother calling push_scope/pop_scope, which means we get here with
|
||||
the scope stack out of sync. Detect this situation by noticing
|
||||
that current_scope is still as store_parm_decls left it, and do
|
||||
a dummy push/pop to get back to consistency.
|
||||
Note that the call to push_scope does not actually push another
|
||||
scope - see there for details. */
|
||||
|
||||
if (current_scope->parm_flag && next_is_function_body)
|
||||
{
|
||||
push_scope ();
|
||||
pop_scope ();
|
||||
}
|
||||
|
||||
if (TREE_CODE (fndecl) == FUNCTION_DECL
|
||||
&& targetm.calls.promote_prototypes (TREE_TYPE (fndecl)))
|
||||
{
|
||||
@ -6273,10 +6254,10 @@ finish_function (void)
|
||||
}
|
||||
}
|
||||
|
||||
finish_fname_decls ();
|
||||
|
||||
/* Tie off the statement tree for this function. */
|
||||
finish_stmt_tree (&DECL_SAVED_TREE (fndecl));
|
||||
DECL_SAVED_TREE (fndecl) = pop_stmt_list (DECL_SAVED_TREE (fndecl));
|
||||
|
||||
finish_fname_decls ();
|
||||
|
||||
/* Complain if there's just no return statement. */
|
||||
if (warn_return_type
|
||||
@ -6438,7 +6419,6 @@ c_push_function_context (struct function *f)
|
||||
f->language = p;
|
||||
|
||||
p->base.x_stmt_tree = c_stmt_tree;
|
||||
p->base.x_scope_stmt_stack = c_scope_stmt_stack;
|
||||
p->x_in_iteration_stmt = c_in_iteration_stmt;
|
||||
p->x_in_case_stmt = c_in_case_stmt;
|
||||
p->returns_value = current_function_returns_value;
|
||||
@ -6466,7 +6446,6 @@ c_pop_function_context (struct function *f)
|
||||
}
|
||||
|
||||
c_stmt_tree = p->base.x_stmt_tree;
|
||||
c_scope_stmt_stack = p->base.x_scope_stmt_stack;
|
||||
c_in_iteration_stmt = p->x_in_iteration_stmt;
|
||||
c_in_case_stmt = p->x_in_case_stmt;
|
||||
current_function_returns_value = p->returns_value;
|
||||
@ -6518,14 +6497,6 @@ current_stmt_tree (void)
|
||||
return &c_stmt_tree;
|
||||
}
|
||||
|
||||
/* Returns the stack of SCOPE_STMTs for the current function. */
|
||||
|
||||
tree *
|
||||
current_scope_stmt_stack (void)
|
||||
{
|
||||
return &c_scope_stmt_stack;
|
||||
}
|
||||
|
||||
/* Nonzero if TYPE is an anonymous union or struct type. Always 0 in
|
||||
C. */
|
||||
|
||||
@ -6542,20 +6513,6 @@ extract_interface_info (void)
|
||||
{
|
||||
}
|
||||
|
||||
/* Return a new COMPOUND_STMT, after adding it to the current
|
||||
statement tree. */
|
||||
|
||||
tree
|
||||
c_begin_compound_stmt (void)
|
||||
{
|
||||
tree stmt;
|
||||
|
||||
/* Create the COMPOUND_STMT. */
|
||||
stmt = add_stmt (build_stmt (COMPOUND_STMT, NULL_TREE));
|
||||
|
||||
return stmt;
|
||||
}
|
||||
|
||||
/* Return the global value of T as a symbol. */
|
||||
|
||||
tree
|
||||
|
13
gcc/c-dump.c
13
gcc/c-dump.c
@ -169,19 +169,6 @@ c_dump_tree (void *dump_info, tree t)
|
||||
dump_next_stmt (di, t);
|
||||
break;
|
||||
|
||||
case SCOPE_STMT:
|
||||
dump_stmt (di, t);
|
||||
if (SCOPE_BEGIN_P (t))
|
||||
dump_string (di, "begn");
|
||||
else
|
||||
dump_string (di, "end");
|
||||
if (SCOPE_NULLIFIED_P (t))
|
||||
dump_string (di, "null");
|
||||
if (!SCOPE_NO_CLEANUPS_P (t))
|
||||
dump_string (di, "clnp");
|
||||
dump_next_stmt (di, t);
|
||||
break;
|
||||
|
||||
case STMT_EXPR:
|
||||
dump_child ("stmt", STMT_EXPR_STMT (t));
|
||||
break;
|
||||
|
542
gcc/c-gimplify.c
542
gcc/c-gimplify.c
@ -80,17 +80,11 @@ static enum gimplify_status gimplify_do_stmt (tree *);
|
||||
static enum gimplify_status gimplify_if_stmt (tree *);
|
||||
static enum gimplify_status gimplify_switch_stmt (tree *);
|
||||
static enum gimplify_status gimplify_return_stmt (tree *);
|
||||
static enum gimplify_status gimplify_stmt_expr (tree *);
|
||||
static enum gimplify_status gimplify_compound_literal_expr (tree *);
|
||||
#if defined ENABLE_CHECKING
|
||||
static int is_last_stmt_of_scope (tree);
|
||||
#endif
|
||||
static enum gimplify_status gimplify_block (tree *, tree *);
|
||||
static enum gimplify_status gimplify_cleanup (tree *, tree *);
|
||||
static void gimplify_cleanup_stmts (tree);
|
||||
static tree gimplify_c_loop (tree, tree, tree, bool);
|
||||
static void push_context (void);
|
||||
static void pop_context (void);
|
||||
static tree c_build_bind_expr (tree, tree);
|
||||
static void add_block_to_enclosing (tree);
|
||||
static void gimplify_condition (tree *);
|
||||
|
||||
@ -160,6 +154,7 @@ c_genericize (tree fndecl)
|
||||
|
||||
/* Go ahead and gimplify for now. */
|
||||
push_context ();
|
||||
gimplify_cleanup_stmts (fndecl);
|
||||
gimplify_function_tree (fndecl);
|
||||
pop_context ();
|
||||
|
||||
@ -174,14 +169,41 @@ c_genericize (tree fndecl)
|
||||
c_genericize (cgn->decl);
|
||||
}
|
||||
|
||||
/* Genericize a CLEANUP_STMT. This just turns into a TRY_FINALLY or
|
||||
TRY_CATCH depending on whether it's EH-only. */
|
||||
|
||||
static tree
|
||||
gimplify_cleanup_stmt (tree *stmt_p, int *walk_subtrees,
|
||||
void *data ATTRIBUTE_UNUSED)
|
||||
{
|
||||
tree stmt = *stmt_p;
|
||||
|
||||
if (DECL_P (stmt) || TYPE_P (stmt))
|
||||
*walk_subtrees = 0;
|
||||
else if (TREE_CODE (stmt) == CLEANUP_STMT)
|
||||
*stmt_p = build (CLEANUP_EH_ONLY (stmt) ? TRY_CATCH_EXPR : TRY_FINALLY_EXPR,
|
||||
void_type_node, CLEANUP_BODY (stmt), CLEANUP_EXPR (stmt));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gimplify_cleanup_stmts (tree fndecl)
|
||||
{
|
||||
walk_tree (&DECL_SAVED_TREE (fndecl), gimplify_cleanup_stmt, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Entry point for the tree lowering pass. Recursively scan
|
||||
*STMT_P and convert it to a GIMPLE tree. */
|
||||
|
||||
int
|
||||
c_gimplify_stmt (tree *stmt_p)
|
||||
{
|
||||
tree stmt, next;
|
||||
tree outer_pre = NULL_TREE;
|
||||
tree stmt = *stmt_p;
|
||||
tree pre, post;
|
||||
int saved_stmts_are_full_exprs_p;
|
||||
location_t stmt_locus;
|
||||
enum gimplify_status ret;
|
||||
|
||||
/* PRE and POST are tree chains that contain the side-effects of the
|
||||
gimplified tree. For instance, given the expression tree:
|
||||
@ -195,152 +217,130 @@ c_gimplify_stmt (tree *stmt_p)
|
||||
c = t1 + b;
|
||||
b = b + 1; <-- POST */
|
||||
|
||||
for (stmt = *stmt_p; stmt && stmt != error_mark_node; stmt = next)
|
||||
/* Set up context appropriately for handling this statement. */
|
||||
saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p ();
|
||||
prep_stmt (stmt);
|
||||
stmt_locus = input_location;
|
||||
|
||||
pre = NULL_TREE;
|
||||
post = NULL_TREE;
|
||||
|
||||
switch (TREE_CODE (stmt))
|
||||
{
|
||||
tree pre, post;
|
||||
int saved_stmts_are_full_exprs_p;
|
||||
location_t stmt_locus;
|
||||
enum gimplify_status ret;
|
||||
case COMPOUND_STMT:
|
||||
stmt = COMPOUND_BODY (stmt);
|
||||
ret = GS_OK;
|
||||
break;
|
||||
|
||||
/* Set up context appropriately for handling this statement. */
|
||||
saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p ();
|
||||
prep_stmt (stmt);
|
||||
stmt_locus = input_location;
|
||||
case FOR_STMT:
|
||||
ret = gimplify_for_stmt (&stmt, &pre);
|
||||
break;
|
||||
|
||||
pre = NULL_TREE;
|
||||
post = NULL_TREE;
|
||||
case WHILE_STMT:
|
||||
ret = gimplify_while_stmt (&stmt);
|
||||
break;
|
||||
|
||||
next = TREE_CHAIN (stmt);
|
||||
case DO_STMT:
|
||||
ret = gimplify_do_stmt (&stmt);
|
||||
break;
|
||||
|
||||
switch (TREE_CODE (stmt))
|
||||
case IF_STMT:
|
||||
ret = gimplify_if_stmt (&stmt);
|
||||
break;
|
||||
|
||||
case SWITCH_STMT:
|
||||
ret = gimplify_switch_stmt (&stmt);
|
||||
break;
|
||||
|
||||
case EXPR_STMT:
|
||||
ret = gimplify_expr_stmt (&stmt);
|
||||
break;
|
||||
|
||||
case RETURN_STMT:
|
||||
ret = gimplify_return_stmt (&stmt);
|
||||
break;
|
||||
|
||||
case DECL_STMT:
|
||||
ret = gimplify_decl_stmt (&stmt);
|
||||
break;
|
||||
|
||||
case LABEL_STMT:
|
||||
stmt = build1 (LABEL_EXPR, void_type_node, LABEL_STMT_LABEL (stmt));
|
||||
ret = GS_OK;
|
||||
break;
|
||||
|
||||
case GOTO_STMT:
|
||||
stmt = build1 (GOTO_EXPR, void_type_node, GOTO_DESTINATION (stmt));
|
||||
ret = GS_OK;
|
||||
break;
|
||||
|
||||
case CASE_LABEL:
|
||||
{
|
||||
tree label = create_artificial_label ();
|
||||
stmt = build (CASE_LABEL_EXPR, void_type_node,
|
||||
CASE_LOW (stmt), CASE_HIGH (stmt), label);
|
||||
ret = GS_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case CONTINUE_STMT:
|
||||
stmt = build_bc_goto (bc_continue);
|
||||
ret = GS_OK;
|
||||
break;
|
||||
|
||||
case BREAK_STMT:
|
||||
stmt = build_bc_goto (bc_break);
|
||||
ret = GS_OK;
|
||||
break;
|
||||
|
||||
case ASM_STMT:
|
||||
{
|
||||
tree new_stmt = build (ASM_EXPR, void_type_node, ASM_STRING (stmt),
|
||||
ASM_OUTPUTS (stmt), ASM_INPUTS (stmt),
|
||||
ASM_CLOBBERS (stmt));
|
||||
ASM_INPUT_P (new_stmt) = ASM_INPUT_P (stmt);
|
||||
ASM_VOLATILE_P (new_stmt) = ASM_VOLATILE_P (stmt);
|
||||
stmt = new_stmt;
|
||||
ret = GS_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (lang_gimplify_stmt && (*lang_gimplify_stmt) (&stmt))
|
||||
{
|
||||
case COMPOUND_STMT:
|
||||
stmt = COMPOUND_BODY (stmt);
|
||||
ret = GS_OK;
|
||||
break;
|
||||
|
||||
case SCOPE_STMT:
|
||||
ret = gimplify_block (&stmt, &next);
|
||||
break;
|
||||
|
||||
case FOR_STMT:
|
||||
ret = gimplify_for_stmt (&stmt, &next);
|
||||
break;
|
||||
|
||||
case WHILE_STMT:
|
||||
ret = gimplify_while_stmt (&stmt);
|
||||
break;
|
||||
|
||||
case DO_STMT:
|
||||
ret = gimplify_do_stmt (&stmt);
|
||||
break;
|
||||
|
||||
case IF_STMT:
|
||||
ret = gimplify_if_stmt (&stmt);
|
||||
break;
|
||||
|
||||
case SWITCH_STMT:
|
||||
ret = gimplify_switch_stmt (&stmt);
|
||||
break;
|
||||
|
||||
case EXPR_STMT:
|
||||
ret = gimplify_expr_stmt (&stmt);
|
||||
break;
|
||||
|
||||
case RETURN_STMT:
|
||||
ret = gimplify_return_stmt (&stmt);
|
||||
break;
|
||||
|
||||
case DECL_STMT:
|
||||
ret = gimplify_decl_stmt (&stmt);
|
||||
break;
|
||||
|
||||
case LABEL_STMT:
|
||||
stmt = build1 (LABEL_EXPR, void_type_node, LABEL_STMT_LABEL (stmt));
|
||||
ret = GS_OK;
|
||||
break;
|
||||
|
||||
case GOTO_STMT:
|
||||
stmt = build1 (GOTO_EXPR, void_type_node, GOTO_DESTINATION (stmt));
|
||||
ret = GS_OK;
|
||||
break;
|
||||
|
||||
case CASE_LABEL:
|
||||
{
|
||||
tree label = create_artificial_label ();
|
||||
stmt = build (CASE_LABEL_EXPR, void_type_node,
|
||||
CASE_LOW (stmt), CASE_HIGH (stmt), label);
|
||||
ret = GS_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case CONTINUE_STMT:
|
||||
stmt = build_bc_goto (bc_continue);
|
||||
ret = GS_OK;
|
||||
break;
|
||||
|
||||
case BREAK_STMT:
|
||||
stmt = build_bc_goto (bc_break);
|
||||
ret = GS_OK;
|
||||
break;
|
||||
|
||||
case CLEANUP_STMT:
|
||||
ret = gimplify_cleanup (&stmt, &next);
|
||||
break;
|
||||
|
||||
case ASM_STMT:
|
||||
{
|
||||
tree new_stmt = build (ASM_EXPR, void_type_node, ASM_STRING (stmt),
|
||||
ASM_OUTPUTS (stmt), ASM_INPUTS (stmt),
|
||||
ASM_CLOBBERS (stmt));
|
||||
ASM_INPUT_P (new_stmt) = ASM_INPUT_P (stmt);
|
||||
ASM_VOLATILE_P (new_stmt) = ASM_VOLATILE_P (stmt);
|
||||
stmt = new_stmt;
|
||||
ret = GS_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (lang_gimplify_stmt && (*lang_gimplify_stmt) (&stmt, &next))
|
||||
{
|
||||
ret = GS_OK;
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf (stderr, "unhandled statement node in c_gimplify_stmt:\n");
|
||||
debug_tree (stmt);
|
||||
abort ();
|
||||
break;
|
||||
}
|
||||
|
||||
switch (ret)
|
||||
{
|
||||
case GS_ERROR:
|
||||
goto cont;
|
||||
case GS_OK:
|
||||
gimplify_stmt (&stmt);
|
||||
break;
|
||||
case GS_ALL_DONE:
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* PRE and POST now contain a list of statements for all the
|
||||
side-effects in STMT. */
|
||||
|
||||
append_to_statement_list (stmt, &pre);
|
||||
append_to_statement_list (post, &pre);
|
||||
annotate_all_with_locus (&pre, stmt_locus);
|
||||
|
||||
append_to_statement_list (pre, &outer_pre);
|
||||
cont:
|
||||
/* Restore saved state. */
|
||||
current_stmt_tree ()->stmts_are_full_exprs_p
|
||||
= saved_stmts_are_full_exprs_p;
|
||||
fprintf (stderr, "unhandled statement node in c_gimplify_stmt:\n");
|
||||
debug_tree (stmt);
|
||||
abort ();
|
||||
break;
|
||||
}
|
||||
append_to_statement_list (stmt, &outer_pre);
|
||||
*stmt_p = outer_pre;
|
||||
|
||||
switch (ret)
|
||||
{
|
||||
case GS_ERROR:
|
||||
goto cont;
|
||||
case GS_OK:
|
||||
gimplify_stmt (&stmt);
|
||||
break;
|
||||
case GS_ALL_DONE:
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* PRE and POST now contain a list of statements for all the
|
||||
side-effects in STMT. */
|
||||
|
||||
append_to_statement_list (stmt, &pre);
|
||||
append_to_statement_list (post, &pre);
|
||||
annotate_all_with_locus (&pre, stmt_locus);
|
||||
cont:
|
||||
/* Restore saved state. */
|
||||
current_stmt_tree ()->stmts_are_full_exprs_p = saved_stmts_are_full_exprs_p;
|
||||
*stmt_p = pre;
|
||||
|
||||
return GS_ALL_DONE;
|
||||
}
|
||||
@ -366,7 +366,7 @@ add_block_to_enclosing (tree block)
|
||||
BODY is a chain of C _STMT nodes for the contents of the scope, to be
|
||||
genericized. */
|
||||
|
||||
static tree
|
||||
tree
|
||||
c_build_bind_expr (tree block, tree body)
|
||||
{
|
||||
tree decls, bind;
|
||||
@ -390,99 +390,15 @@ c_build_bind_expr (tree block, tree body)
|
||||
|
||||
if (!body)
|
||||
body = build_empty_stmt ();
|
||||
|
||||
bind = build (BIND_EXPR, void_type_node, decls, body, block);
|
||||
TREE_SIDE_EFFECTS (bind) = 1;
|
||||
|
||||
return bind;
|
||||
}
|
||||
|
||||
/* Genericize a syntactic block by removing the bracketing SCOPE_STMTs and
|
||||
wrapping the intervening code in a BIND_EXPR. This function assumes
|
||||
that matching SCOPE_STMTs will always appear in the same statement
|
||||
sequence. */
|
||||
|
||||
static enum gimplify_status
|
||||
gimplify_block (tree *stmt_p, tree *next_p)
|
||||
{
|
||||
tree *p;
|
||||
tree block;
|
||||
tree bind;
|
||||
int depth;
|
||||
location_t stmt_locus;
|
||||
|
||||
if (!SCOPE_BEGIN_P (*stmt_p))
|
||||
if (decls || block)
|
||||
{
|
||||
/* Can wind up mismatched with syntax errors. */
|
||||
if (!errorcount && !sorrycount)
|
||||
abort ();
|
||||
*stmt_p = NULL;
|
||||
return GS_ERROR;
|
||||
}
|
||||
|
||||
block = SCOPE_STMT_BLOCK (*stmt_p);
|
||||
|
||||
/* Find the matching ending SCOPE_STMT. */
|
||||
depth = 1;
|
||||
for (p = &TREE_CHAIN (*stmt_p);; p = &TREE_CHAIN (*p))
|
||||
{
|
||||
if (*p == NULL)
|
||||
break;
|
||||
if (TREE_CODE (*p) == SCOPE_STMT)
|
||||
{
|
||||
if (SCOPE_BEGIN_P (*p))
|
||||
++depth;
|
||||
else if (--depth == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
stmt_locus = input_location;
|
||||
if (*p)
|
||||
{
|
||||
if (SCOPE_STMT_BLOCK (*p) != block)
|
||||
abort ();
|
||||
if (EXPR_LOCUS (*p))
|
||||
stmt_locus = *EXPR_LOCUS (*p);
|
||||
*next_p = TREE_CHAIN (*p);
|
||||
*p = NULL_TREE;
|
||||
bind = build (BIND_EXPR, void_type_node, decls, body, block);
|
||||
TREE_SIDE_EFFECTS (bind) = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Can wind up mismatched with syntax errors. */
|
||||
if (!errorcount && !sorrycount)
|
||||
abort ();
|
||||
}
|
||||
bind = body;
|
||||
|
||||
bind = c_build_bind_expr (block, TREE_CHAIN (*stmt_p));
|
||||
*stmt_p = bind;
|
||||
input_location = stmt_locus;
|
||||
|
||||
return GS_OK;
|
||||
}
|
||||
|
||||
/* Genericize a CLEANUP_STMT. Just wrap everything from here to the end of
|
||||
the block in a TRY_FINALLY_EXPR. Or a TRY_CATCH_EXPR, if it's an
|
||||
EH-only cleanup. */
|
||||
|
||||
static enum gimplify_status
|
||||
gimplify_cleanup (tree *stmt_p, tree *next_p)
|
||||
{
|
||||
tree stmt = *stmt_p;
|
||||
tree body = TREE_CHAIN (stmt);
|
||||
tree cleanup = CLEANUP_EXPR (stmt);
|
||||
enum tree_code code
|
||||
= (CLEANUP_EH_ONLY (stmt) ? TRY_CATCH_EXPR : TRY_FINALLY_EXPR);
|
||||
|
||||
if (!body)
|
||||
body = build_empty_stmt ();
|
||||
if (!cleanup)
|
||||
cleanup = build_empty_stmt ();
|
||||
|
||||
*stmt_p = build (code, void_type_node, body, cleanup);
|
||||
*next_p = NULL_TREE;
|
||||
|
||||
return GS_OK;
|
||||
return bind;
|
||||
}
|
||||
|
||||
/* Gimplify an EXPR_STMT node.
|
||||
@ -549,7 +465,7 @@ gimplify_condition (tree *cond_p)
|
||||
{
|
||||
tree decl = TREE_PURPOSE (cond);
|
||||
tree value = TREE_VALUE (cond);
|
||||
c_gimplify_stmt (&decl);
|
||||
gimplify_stmt (&decl);
|
||||
*cond_p = build (COMPOUND_EXPR, TREE_TYPE (value), decl, value);
|
||||
}
|
||||
}
|
||||
@ -713,26 +629,17 @@ gimplify_c_loop (tree cond, tree body, tree incr, bool cond_is_first)
|
||||
prequeue and hand off to gimplify_c_loop. */
|
||||
|
||||
static enum gimplify_status
|
||||
gimplify_for_stmt (tree *stmt_p, tree *next_p)
|
||||
gimplify_for_stmt (tree *stmt_p, tree *pre_p)
|
||||
{
|
||||
tree stmt = *stmt_p;
|
||||
tree init = FOR_INIT_STMT (stmt);
|
||||
|
||||
if (init)
|
||||
if (FOR_INIT_STMT (stmt))
|
||||
{
|
||||
/* Reorganize the statements so that we do the right thing with a
|
||||
CLEANUP_STMT. We want the FOR_STMT and nothing else to be in the
|
||||
scope of the cleanup, so play with pointers to accomplish that. */
|
||||
FOR_INIT_STMT (stmt) = NULL_TREE;
|
||||
chainon (init, stmt);
|
||||
*stmt_p = init;
|
||||
*next_p = TREE_CHAIN (stmt);
|
||||
TREE_CHAIN (stmt) = NULL_TREE;
|
||||
c_gimplify_stmt (stmt_p);
|
||||
gimplify_stmt (&FOR_INIT_STMT (stmt));
|
||||
append_to_statement_list (FOR_INIT_STMT (stmt), pre_p);
|
||||
}
|
||||
else
|
||||
*stmt_p = gimplify_c_loop (FOR_COND (stmt), FOR_BODY (stmt),
|
||||
FOR_EXPR (stmt), 1);
|
||||
*stmt_p = gimplify_c_loop (FOR_COND (stmt), FOR_BODY (stmt),
|
||||
FOR_EXPR (stmt), 1);
|
||||
|
||||
return GS_ALL_DONE;
|
||||
}
|
||||
@ -767,7 +674,6 @@ gimplify_if_stmt (tree *stmt_p)
|
||||
tree stmt, then_, else_;
|
||||
|
||||
stmt = *stmt_p;
|
||||
restart:
|
||||
then_ = THEN_CLAUSE (stmt);
|
||||
else_ = ELSE_CLAUSE (stmt);
|
||||
|
||||
@ -780,17 +686,6 @@ gimplify_if_stmt (tree *stmt_p)
|
||||
gimplify_condition (& TREE_OPERAND (stmt, 0));
|
||||
*stmt_p = stmt;
|
||||
|
||||
/* Handle properly nested if-else chains via iteration instead of
|
||||
mutual recursion between gimplify.c and c-simplify.c. */
|
||||
annotate_with_locus (stmt, input_location);
|
||||
if (TREE_CODE (else_) == IF_STMT && !TREE_CHAIN (else_))
|
||||
{
|
||||
stmt_p = &COND_EXPR_ELSE (stmt);
|
||||
stmt = else_;
|
||||
prep_stmt (stmt);
|
||||
goto restart;
|
||||
}
|
||||
|
||||
return GS_OK;
|
||||
}
|
||||
|
||||
@ -960,130 +855,7 @@ c_gimplify_expr (tree *expr_p, tree *pre_p ATTRIBUTE_UNUSED,
|
||||
case COMPOUND_LITERAL_EXPR:
|
||||
return gimplify_compound_literal_expr (expr_p);
|
||||
|
||||
case STMT_EXPR:
|
||||
return gimplify_stmt_expr (expr_p);
|
||||
|
||||
default:
|
||||
return GS_UNHANDLED;
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns the final EXPR_STMT which represents the return value of a
|
||||
STMT_EXPR, or NULL_TREE if none. */
|
||||
|
||||
tree
|
||||
stmt_expr_last_stmt (tree stmt_expr)
|
||||
{
|
||||
tree body = STMT_EXPR_STMT (stmt_expr);
|
||||
tree last_stmt, substmt;
|
||||
|
||||
/* Splice the last expression out of the STMT chain. */
|
||||
last_stmt = NULL_TREE;
|
||||
for (substmt = COMPOUND_BODY (body); substmt;
|
||||
substmt = TREE_CHAIN (substmt))
|
||||
if (TREE_CODE (substmt) != SCOPE_STMT)
|
||||
last_stmt = substmt;
|
||||
|
||||
if (last_stmt == NULL_TREE
|
||||
|| TREE_CODE (last_stmt) != EXPR_STMT
|
||||
|| (TREE_TYPE (last_stmt)
|
||||
&& VOID_TYPE_P (TREE_TYPE (last_stmt))))
|
||||
{
|
||||
location_t loc;
|
||||
if (last_stmt && EXPR_LOCUS (last_stmt))
|
||||
loc = *EXPR_LOCUS (last_stmt);
|
||||
else if (EXPR_LOCUS (stmt_expr))
|
||||
loc = *EXPR_LOCUS (stmt_expr);
|
||||
else
|
||||
loc = input_location;
|
||||
warning ("%Hstatement-expressions should end with a "
|
||||
"non-void expression", &loc);
|
||||
last_stmt = NULL_TREE;
|
||||
}
|
||||
|
||||
#if defined ENABLE_CHECKING
|
||||
if (last_stmt && !is_last_stmt_of_scope (last_stmt))
|
||||
abort ();
|
||||
#endif
|
||||
|
||||
return last_stmt;
|
||||
}
|
||||
|
||||
/* Gimplify a STMT_EXPR. EXPR_P points to the expression to gimplify.
|
||||
After gimplification, if the STMT_EXPR returns a value, EXPR_P will
|
||||
point to a new temporary that holds that value; otherwise it will be
|
||||
null.
|
||||
|
||||
PRE_P points to the list where side effects that must happen before
|
||||
*EXPR_P should be stored. */
|
||||
|
||||
static enum gimplify_status
|
||||
gimplify_stmt_expr (tree *expr_p)
|
||||
{
|
||||
tree body = STMT_EXPR_STMT (*expr_p);
|
||||
|
||||
if (VOID_TYPE_P (TREE_TYPE (*expr_p)))
|
||||
{
|
||||
*expr_p = body;
|
||||
return c_gimplify_stmt (expr_p);
|
||||
}
|
||||
else
|
||||
{
|
||||
tree last_stmt = stmt_expr_last_stmt (*expr_p);
|
||||
tree last_expr = NULL_TREE;
|
||||
|
||||
if (last_stmt)
|
||||
{
|
||||
last_expr = EXPR_STMT_EXPR (last_stmt);
|
||||
|
||||
if (stmts_are_full_exprs_p ())
|
||||
last_expr = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (last_expr),
|
||||
last_expr);
|
||||
EXPR_STMT_EXPR (last_stmt) = NULL_TREE;
|
||||
}
|
||||
|
||||
/* Genericize the block. */
|
||||
c_gimplify_stmt (&body);
|
||||
|
||||
/* Now retrofit that last expression into the BIND_EXPR. */
|
||||
if (last_expr)
|
||||
{
|
||||
tree *sub_p;
|
||||
|
||||
if (!STMT_EXPR_NO_SCOPE (*expr_p))
|
||||
{
|
||||
/* Our BIND_EXPR will always be hidden within
|
||||
a STATEMENT_LIST. Discard that. */
|
||||
body = expr_first (body);
|
||||
sub_p = &BIND_EXPR_BODY (body);
|
||||
|
||||
/* Append the last expression to the end of the BIND_EXPR.
|
||||
We'll now re-process this, and let voidify_wrapper_expr
|
||||
do its job. */
|
||||
append_to_statement_list_force (last_expr, sub_p);
|
||||
TREE_TYPE (body) = TREE_TYPE (last_expr);
|
||||
}
|
||||
else
|
||||
append_to_compound_expr (last_expr, &body);
|
||||
}
|
||||
|
||||
*expr_p = body;
|
||||
return GS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/* Code generation. */
|
||||
|
||||
/* Miscellaneous helpers. */
|
||||
|
||||
#if defined ENABLE_CHECKING
|
||||
/* Return nonzero if STMT is the last statement of its scope. */
|
||||
|
||||
static int
|
||||
is_last_stmt_of_scope (tree stmt)
|
||||
{
|
||||
return (TREE_CHAIN (stmt) == NULL_TREE
|
||||
|| (TREE_CODE (TREE_CHAIN (stmt)) == SCOPE_STMT
|
||||
&& SCOPE_END_P (TREE_CHAIN (stmt))));
|
||||
}
|
||||
#endif
|
||||
|
@ -112,9 +112,6 @@ enum c_language_kind c_language = clk_c;
|
||||
#undef LANG_HOOKS_TREE_INLINING_DISREGARD_INLINE_LIMITS
|
||||
#define LANG_HOOKS_TREE_INLINING_DISREGARD_INLINE_LIMITS \
|
||||
c_disregard_inline_limits
|
||||
#undef LANG_HOOKS_TREE_INLINING_TREE_CHAIN_MATTERS_P
|
||||
#define LANG_HOOKS_TREE_INLINING_TREE_CHAIN_MATTERS_P \
|
||||
c_tree_chain_matters_p
|
||||
#undef LANG_HOOKS_TREE_INLINING_ANON_AGGR_TYPE_P
|
||||
#define LANG_HOOKS_TREE_INLINING_ANON_AGGR_TYPE_P \
|
||||
anon_aggr_type_p
|
||||
|
@ -67,7 +67,7 @@ mflang_lookup_decl (const char* name)
|
||||
void
|
||||
mflang_flush_calls (tree enqueued_call_stmt_chain)
|
||||
{
|
||||
tree fnname, t1, t2, body, block, scope;
|
||||
tree fnname, t1, t2, cs;
|
||||
|
||||
/* Short-circuit! */
|
||||
if (enqueued_call_stmt_chain == NULL_TREE)
|
||||
@ -84,17 +84,9 @@ mflang_flush_calls (tree enqueued_call_stmt_chain)
|
||||
TREE_USED (current_function_decl) = 1;
|
||||
mf_mark (current_function_decl);
|
||||
|
||||
body = c_begin_compound_stmt ();
|
||||
push_scope ();
|
||||
clear_last_expr ();
|
||||
add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0);
|
||||
|
||||
cs = c_begin_compound_stmt (true);
|
||||
c_expand_expr_stmt (enqueued_call_stmt_chain);
|
||||
add_stmt (c_end_compound_stmt (cs, true));
|
||||
|
||||
scope = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0);
|
||||
block = pop_scope ();
|
||||
SCOPE_STMT_BLOCK (TREE_PURPOSE (scope)) = block;
|
||||
SCOPE_STMT_BLOCK (TREE_VALUE (scope)) = block;
|
||||
RECHAIN_STMTS (body, COMPOUND_BODY (body));
|
||||
finish_function ();
|
||||
}
|
||||
|
@ -188,9 +188,7 @@ static void
|
||||
build_cdtor (int method_type, tree cdtors)
|
||||
{
|
||||
tree fnname = get_file_function_name (method_type);
|
||||
tree body;
|
||||
tree scope;
|
||||
tree block;
|
||||
tree cs;
|
||||
|
||||
start_function (void_list_node,
|
||||
build_nt (CALL_EXPR, fnname,
|
||||
@ -199,20 +197,12 @@ build_cdtor (int method_type, tree cdtors)
|
||||
NULL_TREE);
|
||||
store_parm_decls ();
|
||||
|
||||
body = c_begin_compound_stmt ();
|
||||
add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0);
|
||||
cs = c_begin_compound_stmt (true);
|
||||
|
||||
for (; cdtors; cdtors = TREE_CHAIN (cdtors))
|
||||
add_stmt (build_stmt (EXPR_STMT,
|
||||
build_function_call (TREE_VALUE (cdtors), 0)));
|
||||
add_stmt (build_function_call (TREE_VALUE (cdtors), 0));
|
||||
|
||||
scope = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0);
|
||||
|
||||
block = make_node (BLOCK);
|
||||
SCOPE_STMT_BLOCK (TREE_PURPOSE (scope)) = block;
|
||||
SCOPE_STMT_BLOCK (TREE_VALUE (scope)) = block;
|
||||
|
||||
RECHAIN_STMTS (body, COMPOUND_BODY (body));
|
||||
add_stmt (c_end_compound_stmt (cs, true));
|
||||
|
||||
finish_function ();
|
||||
}
|
||||
|
177
gcc/c-parse.in
177
gcc/c-parse.in
@ -208,10 +208,10 @@ do { \
|
||||
%type <ttype> maybe_attribute attributes attribute attribute_list attrib
|
||||
%type <ttype> any_word
|
||||
|
||||
%type <ttype> compstmt compstmt_start compstmt_nostart compstmt_primary_start
|
||||
%type <ttype> do_stmt_start pop_scope stmt label
|
||||
%type <ttype> compstmt compstmt_start compstmt_primary_start
|
||||
%type <ttype> do_stmt_start stmt label
|
||||
|
||||
%type <ttype> c99_block_start c99_block_end
|
||||
%type <ttype> c99_block_start c99_block_lineno_labeled_stmt
|
||||
%type <ttype> declarator
|
||||
%type <ttype> notype_declarator after_type_declarator
|
||||
%type <ttype> parm_declarator
|
||||
@ -650,24 +650,12 @@ primary:
|
||||
| '(' error ')'
|
||||
{ $$ = error_mark_node; }
|
||||
| compstmt_primary_start compstmt_nostart ')'
|
||||
{ tree saved_last_tree;
|
||||
|
||||
if (pedantic)
|
||||
pedwarn ("ISO C forbids braced-groups within expressions");
|
||||
saved_last_tree = COMPOUND_BODY ($1);
|
||||
RECHAIN_STMTS ($1, COMPOUND_BODY ($1));
|
||||
last_tree = saved_last_tree;
|
||||
TREE_CHAIN (last_tree) = NULL_TREE;
|
||||
if (!last_expr_type)
|
||||
last_expr_type = void_type_node;
|
||||
$$ = build1 (STMT_EXPR, last_expr_type, $1);
|
||||
TREE_SIDE_EFFECTS ($$) = 1;
|
||||
annotate_with_locus ($$, input_location);
|
||||
{ if (pedantic)
|
||||
pedwarn ("ISO C forbids braced-groups within expressions");
|
||||
$$ = c_finish_stmt_expr ($1);
|
||||
}
|
||||
| compstmt_primary_start error ')'
|
||||
{
|
||||
last_tree = COMPOUND_BODY ($1);
|
||||
TREE_CHAIN (last_tree) = NULL_TREE;
|
||||
{ c_finish_stmt_expr ($1);
|
||||
$$ = error_mark_node;
|
||||
}
|
||||
| primary '(' exprlist ')' %prec '.'
|
||||
@ -2010,51 +1998,9 @@ lineno_stmt_decl_or_labels:
|
||||
errstmt: error ';'
|
||||
;
|
||||
|
||||
push_scope: /* empty */
|
||||
{ push_scope ();
|
||||
clear_last_expr ();
|
||||
add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0);
|
||||
}
|
||||
;
|
||||
|
||||
pop_scope: /* empty */
|
||||
{
|
||||
@@ifobjc
|
||||
if (c_dialect_objc ())
|
||||
objc_clear_super_receiver ();
|
||||
@@end_ifobjc
|
||||
$$ = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0);
|
||||
}
|
||||
;
|
||||
|
||||
/* Start and end blocks created for the new scopes of C99. */
|
||||
c99_block_start: /* empty */
|
||||
{ if (flag_isoc99)
|
||||
{
|
||||
$$ = c_begin_compound_stmt ();
|
||||
push_scope ();
|
||||
clear_last_expr ();
|
||||
add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0);
|
||||
}
|
||||
else
|
||||
$$ = NULL_TREE;
|
||||
}
|
||||
;
|
||||
|
||||
/* Productions using c99_block_start and c99_block_end will need to do what's
|
||||
in compstmt: RECHAIN_STMTS ($1, COMPOUND_BODY ($1)); $$ = $2; where
|
||||
$1 is the value of c99_block_start and $2 of c99_block_end. */
|
||||
c99_block_end: /* empty */
|
||||
{ if (flag_isoc99)
|
||||
{
|
||||
tree scope_stmt = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0);
|
||||
$$ = pop_scope ();
|
||||
SCOPE_STMT_BLOCK (TREE_PURPOSE (scope_stmt))
|
||||
= SCOPE_STMT_BLOCK (TREE_VALUE (scope_stmt))
|
||||
= $$;
|
||||
}
|
||||
else
|
||||
$$ = NULL_TREE; }
|
||||
{ $$ = c_begin_compound_stmt (flag_isoc99); }
|
||||
;
|
||||
|
||||
/* Read zero or more forward-declarations for labels
|
||||
@ -2092,16 +2038,11 @@ compstmt_or_error:
|
||||
;
|
||||
|
||||
compstmt_start: '{' { compstmt_count++;
|
||||
$$ = c_begin_compound_stmt (); }
|
||||
$$ = c_begin_compound_stmt (true); }
|
||||
;
|
||||
|
||||
compstmt_nostart: '}'
|
||||
{ $$ = convert (void_type_node, integer_zero_node); }
|
||||
| push_scope maybe_label_decls compstmt_contents_nonempty '}' pop_scope
|
||||
{ $$ = pop_scope ();
|
||||
SCOPE_STMT_BLOCK (TREE_PURPOSE ($5))
|
||||
= SCOPE_STMT_BLOCK (TREE_VALUE ($5))
|
||||
= $$; }
|
||||
| maybe_label_decls compstmt_contents_nonempty '}'
|
||||
;
|
||||
|
||||
compstmt_contents_nonempty:
|
||||
@ -2113,30 +2054,24 @@ compstmt_primary_start:
|
||||
'(' '{'
|
||||
{ if (current_function_decl == 0)
|
||||
{
|
||||
error ("braced-group within expression allowed only inside a function");
|
||||
error ("braced-group within expression allowed "
|
||||
"only inside a function");
|
||||
YYERROR;
|
||||
}
|
||||
/* We must force a BLOCK for this level
|
||||
so that, if it is not expanded later,
|
||||
there is a way to turn off the entire subtree of blocks
|
||||
that are contained in it. */
|
||||
keep_next_level ();
|
||||
compstmt_count++;
|
||||
$$ = add_stmt (build_stmt (COMPOUND_STMT, last_tree));
|
||||
last_expr_type = NULL_TREE;
|
||||
$$ = c_begin_stmt_expr ();
|
||||
}
|
||||
;
|
||||
|
||||
compstmt: compstmt_start compstmt_nostart
|
||||
{ RECHAIN_STMTS ($1, COMPOUND_BODY ($1));
|
||||
last_expr_type = NULL_TREE;
|
||||
$$ = $1; }
|
||||
{ add_stmt (c_end_compound_stmt ($1, true));
|
||||
$$ = NULL_TREE; }
|
||||
;
|
||||
|
||||
/* Value is number of statements counted as of the closeparen. */
|
||||
simple_if:
|
||||
if_prefix c99_block_lineno_labeled_stmt
|
||||
{ c_finish_then (); }
|
||||
{ c_finish_then ($2); }
|
||||
/* Make sure c_expand_end_cond is run once
|
||||
for each call to c_expand_start_cond.
|
||||
Otherwise a crash is likely. */
|
||||
@ -2179,7 +2114,7 @@ do_stmt_start:
|
||||
DO_COND ($<ttype>$) = error_mark_node; }
|
||||
c99_block_lineno_labeled_stmt WHILE
|
||||
{ $$ = $<ttype>2;
|
||||
RECHAIN_STMTS ($$, DO_BODY ($$));
|
||||
DO_BODY ($$) = $3;
|
||||
c_in_iteration_stmt--; }
|
||||
;
|
||||
|
||||
@ -2200,14 +2135,24 @@ lineno_labeled_stmt:
|
||||
|
||||
/* Like lineno_labeled_stmt, but a block in C99. */
|
||||
c99_block_lineno_labeled_stmt:
|
||||
c99_block_start lineno_labeled_stmt c99_block_end
|
||||
{ if (flag_isoc99)
|
||||
RECHAIN_STMTS ($1, COMPOUND_BODY ($1)); }
|
||||
c99_block_start lineno_labeled_stmt
|
||||
{ $$ = c_end_compound_stmt ($1, flag_isoc99); }
|
||||
;
|
||||
|
||||
lineno_stmt:
|
||||
save_location stmt
|
||||
{ if ($2)
|
||||
{
|
||||
/* Two cases cannot and do not have line numbers associated:
|
||||
If stmt is degenerate, such as "2;", then stmt is an
|
||||
INTEGER_CST, which cannot hold line numbers. But that's
|
||||
ok because the statement will either be changed to a
|
||||
MODIFY_EXPR during gimplification of the statement expr,
|
||||
or discarded. If stmt was compound, but without new
|
||||
variables, we will have skipped the creation of a BIND
|
||||
and will have a bare STATEMENT_LIST. But that's ok
|
||||
because (recursively) all of the component statments
|
||||
should already have line numbers assigned. */
|
||||
if ($2 && EXPR_P ($2))
|
||||
{
|
||||
SET_EXPR_LOCUS ($2, NULL);
|
||||
annotate_with_locus ($2, $1);
|
||||
@ -2230,7 +2175,7 @@ select_or_iter_stmt:
|
||||
{ c_expand_start_else ();
|
||||
$<itype>1 = stmt_count; }
|
||||
c99_block_lineno_labeled_stmt
|
||||
{ c_finish_else ();
|
||||
{ c_finish_else ($4);
|
||||
c_expand_end_cond ();
|
||||
if (extra_warnings && stmt_count == $<itype>1)
|
||||
warning ("empty body in an else-statement"); }
|
||||
@ -2261,41 +2206,34 @@ select_or_iter_stmt:
|
||||
$<ttype>$ = c_begin_while_stmt (); }
|
||||
'(' expr ')'
|
||||
{ c_in_iteration_stmt++;
|
||||
$4 = lang_hooks.truthvalue_conversion ($4);
|
||||
c_finish_while_stmt_cond
|
||||
(lang_hooks.truthvalue_conversion ($4), $<ttype>2);
|
||||
$<ttype>$ = add_stmt ($<ttype>2); }
|
||||
c_finish_while_stmt_cond ($4, $<ttype>2); }
|
||||
c99_block_lineno_labeled_stmt
|
||||
{ c_in_iteration_stmt--;
|
||||
RECHAIN_STMTS ($<ttype>6, WHILE_BODY ($<ttype>6)); }
|
||||
c_finish_while_stmt ($7, $<ttype>2); }
|
||||
| do_stmt_start
|
||||
'(' expr ')' ';'
|
||||
{ DO_COND ($1) = lang_hooks.truthvalue_conversion ($3); }
|
||||
| do_stmt_start error
|
||||
{ }
|
||||
| FOR
|
||||
{ $<ttype>$ = build_stmt (FOR_STMT, NULL_TREE, NULL_TREE,
|
||||
NULL_TREE, NULL_TREE);
|
||||
add_stmt ($<ttype>$); }
|
||||
{ $<ttype>$ = c_begin_for_stmt (); }
|
||||
'(' for_init_stmt
|
||||
{ stmt_count++;
|
||||
RECHAIN_STMTS ($<ttype>2, FOR_INIT_STMT ($<ttype>2)); }
|
||||
c_finish_for_stmt_init ($<ttype>2); }
|
||||
xexpr ';'
|
||||
{ if ($6)
|
||||
FOR_COND ($<ttype>2)
|
||||
= lang_hooks.truthvalue_conversion ($6); }
|
||||
{ c_finish_for_stmt_cond ($6, $<ttype>2); }
|
||||
xexpr ')'
|
||||
{ c_in_iteration_stmt++;
|
||||
FOR_EXPR ($<ttype>2) = $9; }
|
||||
c_finish_for_stmt_incr ($9, $<ttype>2); }
|
||||
c99_block_lineno_labeled_stmt
|
||||
{ RECHAIN_STMTS ($<ttype>2, FOR_BODY ($<ttype>2));
|
||||
c_in_iteration_stmt--;}
|
||||
{ c_finish_for_stmt ($12, $<ttype>2);
|
||||
c_in_iteration_stmt--; }
|
||||
| SWITCH '(' expr ')'
|
||||
{ stmt_count++;
|
||||
$<ttype>$ = c_start_case ($3);
|
||||
c_in_case_stmt++; }
|
||||
c99_block_lineno_labeled_stmt
|
||||
{ c_finish_case ();
|
||||
{ c_finish_case ($6);
|
||||
c_in_case_stmt--; }
|
||||
;
|
||||
|
||||
@ -2319,28 +2257,27 @@ stmt:
|
||||
| expr ';'
|
||||
{ stmt_count++;
|
||||
$$ = c_expand_expr_stmt ($1); }
|
||||
| c99_block_start select_or_iter_stmt c99_block_end
|
||||
{ if (flag_isoc99)
|
||||
RECHAIN_STMTS ($1, COMPOUND_BODY ($1));
|
||||
| c99_block_start select_or_iter_stmt
|
||||
{ add_stmt (c_end_compound_stmt ($1, flag_isoc99));
|
||||
$$ = NULL_TREE; }
|
||||
| BREAK ';'
|
||||
{ stmt_count++;
|
||||
if (!(c_in_iteration_stmt || c_in_case_stmt))
|
||||
{
|
||||
error ("break statement not within loop or switch");
|
||||
$$ = NULL_TREE;
|
||||
}
|
||||
else
|
||||
$$ = add_stmt (build_break_stmt ()); }
|
||||
if (!(c_in_iteration_stmt || c_in_case_stmt))
|
||||
{
|
||||
error ("break statement not within loop or switch");
|
||||
$$ = NULL_TREE;
|
||||
}
|
||||
else
|
||||
$$ = add_stmt (build_break_stmt ()); }
|
||||
| CONTINUE ';'
|
||||
{ stmt_count++;
|
||||
if (!c_in_iteration_stmt)
|
||||
{
|
||||
error ("continue statement not within a loop");
|
||||
$$ = NULL_TREE;
|
||||
}
|
||||
else
|
||||
$$ = add_stmt (build_continue_stmt ()); }
|
||||
if (!c_in_iteration_stmt)
|
||||
{
|
||||
error ("continue statement not within a loop");
|
||||
$$ = NULL_TREE;
|
||||
}
|
||||
else
|
||||
$$ = add_stmt (build_continue_stmt ()); }
|
||||
| RETURN ';'
|
||||
{ stmt_count++;
|
||||
$$ = c_expand_return (NULL_TREE); }
|
||||
|
@ -26,6 +26,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
#include "real.h"
|
||||
#include "c-pretty-print.h"
|
||||
#include "c-tree.h"
|
||||
#include "tree-iterator.h"
|
||||
#include "diagnostic.h"
|
||||
|
||||
/* The pretty-printer code is primarily designed to closely follow
|
||||
@ -1892,6 +1893,22 @@ pp_c_statement (c_pretty_printer *pp, tree stmt)
|
||||
code = TREE_CODE (stmt);
|
||||
switch (code)
|
||||
{
|
||||
case STATEMENT_LIST:
|
||||
{
|
||||
tree_stmt_iterator tsi;
|
||||
|
||||
if (pp_needs_newline (pp))
|
||||
pp_newline_and_indent (pp, 0);
|
||||
pp_c_left_brace (pp);
|
||||
pp_newline_and_indent (pp, 3);
|
||||
for (tsi = tsi_start (stmt); !tsi_end_p (tsi); tsi_next (&tsi))
|
||||
pp_statement (pp, tsi_stmt (tsi));
|
||||
pp_newline_and_indent (pp, -3);
|
||||
pp_c_right_brace (pp);
|
||||
pp_needs_newline (pp) = true;
|
||||
}
|
||||
break;
|
||||
|
||||
/* labeled-statement:
|
||||
identifier : statement
|
||||
case constant-expression : statement
|
||||
@ -1940,8 +1957,7 @@ pp_c_statement (c_pretty_printer *pp, tree stmt)
|
||||
pp_newline_and_indent (pp, 0);
|
||||
pp_c_left_brace (pp);
|
||||
pp_newline_and_indent (pp, 3);
|
||||
for (stmt = COMPOUND_BODY (stmt); stmt; stmt = TREE_CHAIN (stmt))
|
||||
pp_statement (pp, stmt);
|
||||
pp_statement (pp, COMPOUND_BODY (stmt));
|
||||
pp_newline_and_indent (pp, -3);
|
||||
pp_c_right_brace (pp);
|
||||
pp_needs_newline (pp) = true;
|
||||
@ -2103,27 +2119,6 @@ pp_c_statement (c_pretty_printer *pp, tree stmt)
|
||||
}
|
||||
break;
|
||||
|
||||
case SCOPE_STMT:
|
||||
if (!SCOPE_NULLIFIED_P (stmt) && SCOPE_NO_CLEANUPS_P (stmt))
|
||||
{
|
||||
int i = 0;
|
||||
if (pp_needs_newline (pp))
|
||||
pp_newline_and_indent (pp, 0);
|
||||
if (SCOPE_BEGIN_P (stmt))
|
||||
{
|
||||
pp_left_brace (pp);
|
||||
i = 3;
|
||||
}
|
||||
else if (SCOPE_END_P (stmt))
|
||||
{
|
||||
pp_right_brace (pp);
|
||||
i = -3;
|
||||
}
|
||||
pp_indentation (pp) += i;
|
||||
pp_needs_newline (pp) = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case DECL_STMT:
|
||||
if (pp_needs_newline (pp))
|
||||
pp_newline_and_indent (pp, 0);
|
||||
|
@ -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
|
||||
|
22
gcc/c-tree.h
22
gcc/c-tree.h
@ -191,7 +191,7 @@ extern tree start_decl (tree, tree, int, tree);
|
||||
extern tree start_struct (enum tree_code, tree);
|
||||
extern void store_parm_decls (void);
|
||||
extern tree xref_tag (enum tree_code, tree);
|
||||
extern tree c_begin_compound_stmt (void);
|
||||
extern int c_expand_decl (tree);
|
||||
extern void c_static_assembler_name (tree);
|
||||
extern tree make_pointer_declarator (tree, tree);
|
||||
|
||||
@ -249,11 +249,29 @@ extern tree build_compound_literal (tree, tree);
|
||||
extern void pedwarn_c90 (const char *, ...) ATTRIBUTE_PRINTF_1;
|
||||
extern void pedwarn_c99 (const char *, ...) ATTRIBUTE_PRINTF_1;
|
||||
extern tree c_start_case (tree);
|
||||
extern void c_finish_case (void);
|
||||
extern void c_finish_case (tree);
|
||||
extern tree build_asm_expr (tree, tree, tree, tree, bool);
|
||||
extern tree build_asm_stmt (tree, tree);
|
||||
extern tree c_convert_parm_for_inlining (tree, tree, tree, int);
|
||||
extern int c_types_compatible_p (tree, tree);
|
||||
extern tree c_begin_compound_stmt (bool);
|
||||
extern tree c_end_compound_stmt (tree, bool);
|
||||
extern void c_expand_start_cond (tree, int, tree);
|
||||
extern void c_finish_then (tree);
|
||||
extern void c_expand_start_else (void);
|
||||
extern void c_finish_else (tree);
|
||||
extern void c_expand_end_cond (void);
|
||||
extern tree c_begin_if_stmt (void);
|
||||
extern tree c_begin_while_stmt (void);
|
||||
extern void c_finish_while_stmt_cond (tree, tree);
|
||||
extern void c_finish_while_stmt (tree, tree);
|
||||
extern tree c_begin_for_stmt (void);
|
||||
extern void c_finish_for_stmt_init (tree);
|
||||
extern void c_finish_for_stmt_cond (tree, tree);
|
||||
extern void c_finish_for_stmt_incr (tree, tree);
|
||||
extern void c_finish_for_stmt (tree, tree);
|
||||
extern tree c_begin_stmt_expr (void);
|
||||
extern tree c_finish_stmt_expr (tree);
|
||||
extern tree build_offsetof (tree, tree);
|
||||
|
||||
/* Set to 0 at beginning of a function definition, set to 1 if
|
||||
|
332
gcc/c-typeck.c
332
gcc/c-typeck.c
@ -45,6 +45,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
#include "intl.h"
|
||||
#include "ggc.h"
|
||||
#include "target.h"
|
||||
#include "tree-iterator.h"
|
||||
|
||||
|
||||
/* Nonzero if we've already printed a "missing braces around initializer"
|
||||
message within this initializer. */
|
||||
@ -2206,16 +2208,7 @@ int
|
||||
c_tree_expr_nonnegative_p (tree t)
|
||||
{
|
||||
if (TREE_CODE (t) == STMT_EXPR)
|
||||
{
|
||||
t = COMPOUND_BODY (STMT_EXPR_STMT (t));
|
||||
|
||||
/* Find the last statement in the chain, ignoring the final
|
||||
* scope statement */
|
||||
while (TREE_CHAIN (t) != NULL_TREE
|
||||
&& TREE_CODE (TREE_CHAIN (t)) != SCOPE_STMT)
|
||||
t = TREE_CHAIN (t);
|
||||
return tree_expr_nonnegative_p (TREE_OPERAND (t, 0));
|
||||
}
|
||||
t = expr_last (COMPOUND_BODY (STMT_EXPR_STMT (t)));
|
||||
return tree_expr_nonnegative_p (t);
|
||||
}
|
||||
|
||||
@ -6435,19 +6428,11 @@ do_case (tree low_value, tree high_value)
|
||||
|
||||
if (switch_stack)
|
||||
{
|
||||
bool switch_was_empty_p = (SWITCH_BODY (switch_stack->switch_stmt) == NULL_TREE);
|
||||
|
||||
label = c_add_case_label (switch_stack->cases,
|
||||
SWITCH_COND (switch_stack->switch_stmt),
|
||||
low_value, high_value);
|
||||
if (label == error_mark_node)
|
||||
label = NULL_TREE;
|
||||
else if (switch_was_empty_p)
|
||||
{
|
||||
/* Attach the first case label to the SWITCH_BODY. */
|
||||
SWITCH_BODY (switch_stack->switch_stmt) = TREE_CHAIN (switch_stack->switch_stmt);
|
||||
TREE_CHAIN (switch_stack->switch_stmt) = NULL_TREE;
|
||||
}
|
||||
}
|
||||
else if (low_value)
|
||||
error ("case label not within a switch statement");
|
||||
@ -6460,22 +6445,325 @@ do_case (tree low_value, tree high_value)
|
||||
/* Finish the switch statement. */
|
||||
|
||||
void
|
||||
c_finish_case (void)
|
||||
c_finish_case (tree body)
|
||||
{
|
||||
struct c_switch *cs = switch_stack;
|
||||
|
||||
SWITCH_BODY (cs->switch_stmt) = body;
|
||||
|
||||
/* Emit warnings as needed. */
|
||||
c_do_switch_warnings (cs->cases, cs->switch_stmt);
|
||||
|
||||
/* Rechain the next statements to the SWITCH_STMT. */
|
||||
last_tree = cs->switch_stmt;
|
||||
|
||||
/* Pop the stack. */
|
||||
switch_stack = switch_stack->next;
|
||||
splay_tree_delete (cs->cases);
|
||||
free (cs);
|
||||
}
|
||||
|
||||
/* Keep a stack of if statements. We record the number of compound
|
||||
statements seen up to the if keyword, as well as the line number
|
||||
and file of the if. If a potentially ambiguous else is seen, that
|
||||
fact is recorded; the warning is issued when we can be sure that
|
||||
the enclosing if statement does not have an else branch. */
|
||||
typedef struct
|
||||
{
|
||||
int compstmt_count;
|
||||
location_t locus;
|
||||
int needs_warning;
|
||||
tree if_stmt;
|
||||
} if_elt;
|
||||
|
||||
static if_elt *if_stack;
|
||||
|
||||
/* Amount of space in the if statement stack. */
|
||||
static int if_stack_space = 0;
|
||||
|
||||
/* Stack pointer. */
|
||||
static int if_stack_pointer = 0;
|
||||
|
||||
/* Begin an if-statement. Returns a newly created IF_STMT if
|
||||
appropriate. */
|
||||
|
||||
tree
|
||||
c_begin_if_stmt (void)
|
||||
{
|
||||
tree r;
|
||||
r = add_stmt (build_stmt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE));
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Record the start of an if-then, and record the start of it
|
||||
for ambiguous else detection.
|
||||
|
||||
COND is the condition for the if-then statement.
|
||||
|
||||
IF_STMT is the statement node that has already been created for
|
||||
this if-then statement. It is created before parsing the
|
||||
condition to keep line number information accurate. */
|
||||
|
||||
void
|
||||
c_expand_start_cond (tree cond, int compstmt_count, tree if_stmt)
|
||||
{
|
||||
/* Make sure there is enough space on the stack. */
|
||||
if (if_stack_space == 0)
|
||||
{
|
||||
if_stack_space = 10;
|
||||
if_stack = xmalloc (10 * sizeof (if_elt));
|
||||
}
|
||||
else if (if_stack_space == if_stack_pointer)
|
||||
{
|
||||
if_stack_space += 10;
|
||||
if_stack = xrealloc (if_stack, if_stack_space * sizeof (if_elt));
|
||||
}
|
||||
|
||||
IF_COND (if_stmt) = cond;
|
||||
|
||||
/* Record this if statement. */
|
||||
if_stack[if_stack_pointer].compstmt_count = compstmt_count;
|
||||
if_stack[if_stack_pointer].locus = input_location;
|
||||
if_stack[if_stack_pointer].needs_warning = 0;
|
||||
if_stack[if_stack_pointer].if_stmt = if_stmt;
|
||||
if_stack_pointer++;
|
||||
}
|
||||
|
||||
/* Called after the then-clause for an if-statement is processed. */
|
||||
|
||||
void
|
||||
c_finish_then (tree then_stmt)
|
||||
{
|
||||
tree if_stmt = if_stack[if_stack_pointer - 1].if_stmt;
|
||||
THEN_CLAUSE (if_stmt) = then_stmt;
|
||||
}
|
||||
|
||||
/* Record the end of an if-then. Optionally warn if a nested
|
||||
if statement had an ambiguous else clause. */
|
||||
|
||||
void
|
||||
c_expand_end_cond (void)
|
||||
{
|
||||
if_stack_pointer--;
|
||||
if (if_stack[if_stack_pointer].needs_warning)
|
||||
warning ("%Hsuggest explicit braces to avoid ambiguous `else'",
|
||||
&if_stack[if_stack_pointer].locus);
|
||||
}
|
||||
|
||||
/* Called between the then-clause and the else-clause
|
||||
of an if-then-else. */
|
||||
|
||||
void
|
||||
c_expand_start_else (void)
|
||||
{
|
||||
/* An ambiguous else warning must be generated for the enclosing if
|
||||
statement, unless we see an else branch for that one, too. */
|
||||
if (warn_parentheses
|
||||
&& if_stack_pointer > 1
|
||||
&& (if_stack[if_stack_pointer - 1].compstmt_count
|
||||
== if_stack[if_stack_pointer - 2].compstmt_count))
|
||||
if_stack[if_stack_pointer - 2].needs_warning = 1;
|
||||
|
||||
/* Even if a nested if statement had an else branch, it can't be
|
||||
ambiguous if this one also has an else. So don't warn in that
|
||||
case. Also don't warn for any if statements nested in this else. */
|
||||
if_stack[if_stack_pointer - 1].needs_warning = 0;
|
||||
if_stack[if_stack_pointer - 1].compstmt_count--;
|
||||
}
|
||||
|
||||
/* Called after the else-clause for an if-statement is processed. */
|
||||
|
||||
void
|
||||
c_finish_else (tree else_stmt)
|
||||
{
|
||||
tree if_stmt = if_stack[if_stack_pointer - 1].if_stmt;
|
||||
ELSE_CLAUSE (if_stmt) = else_stmt;
|
||||
}
|
||||
|
||||
/* Begin a while statement. Returns a newly created WHILE_STMT if
|
||||
appropriate. */
|
||||
|
||||
tree
|
||||
c_begin_while_stmt (void)
|
||||
{
|
||||
tree r;
|
||||
r = add_stmt (build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE));
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
c_finish_while_stmt_cond (tree cond, tree while_stmt)
|
||||
{
|
||||
WHILE_COND (while_stmt) = (*lang_hooks.truthvalue_conversion) (cond);
|
||||
}
|
||||
|
||||
void
|
||||
c_finish_while_stmt (tree body, tree while_stmt)
|
||||
{
|
||||
WHILE_BODY (while_stmt) = body;
|
||||
}
|
||||
|
||||
/* Create a for statement. */
|
||||
|
||||
tree
|
||||
c_begin_for_stmt (void)
|
||||
{
|
||||
tree r;
|
||||
r = add_stmt (build_stmt (FOR_STMT, NULL_TREE, NULL_TREE,
|
||||
NULL_TREE, NULL_TREE));
|
||||
FOR_INIT_STMT (r) = push_stmt_list ();
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
c_finish_for_stmt_init (tree for_stmt)
|
||||
{
|
||||
FOR_INIT_STMT (for_stmt) = pop_stmt_list (FOR_INIT_STMT (for_stmt));
|
||||
}
|
||||
|
||||
void
|
||||
c_finish_for_stmt_cond (tree cond, tree for_stmt)
|
||||
{
|
||||
if (cond)
|
||||
FOR_COND (for_stmt) = lang_hooks.truthvalue_conversion (cond);
|
||||
}
|
||||
|
||||
void
|
||||
c_finish_for_stmt_incr (tree expr, tree for_stmt)
|
||||
{
|
||||
FOR_EXPR (for_stmt) = expr;
|
||||
}
|
||||
|
||||
void
|
||||
c_finish_for_stmt (tree body, tree for_stmt)
|
||||
{
|
||||
FOR_BODY (for_stmt) = body;
|
||||
}
|
||||
|
||||
/* Create a statement expression. */
|
||||
|
||||
tree
|
||||
c_begin_stmt_expr (void)
|
||||
{
|
||||
tree ret;
|
||||
|
||||
/* We must force a BLOCK for this level so that, if it is not expanded
|
||||
later, there is a way to turn off the entire subtree of blocks that
|
||||
are contained in it. */
|
||||
keep_next_level ();
|
||||
ret = c_begin_compound_stmt (true);
|
||||
|
||||
/* Mark the current statement list as belonging to a statement list. */
|
||||
STATEMENT_LIST_STMT_EXPR (ret) = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
tree
|
||||
c_finish_stmt_expr (tree body)
|
||||
{
|
||||
tree ret, last, type;
|
||||
tree *last_p;
|
||||
|
||||
body = c_end_compound_stmt (body, true);
|
||||
|
||||
/* Locate the last statement in BODY. */
|
||||
last = body, last_p = &body;
|
||||
if (TREE_CODE (last) == BIND_EXPR)
|
||||
{
|
||||
last_p = &BIND_EXPR_BODY (last);
|
||||
last = BIND_EXPR_BODY (last);
|
||||
}
|
||||
if (TREE_CODE (last) == STATEMENT_LIST)
|
||||
{
|
||||
tree_stmt_iterator i = tsi_last (last);
|
||||
if (tsi_end_p (i))
|
||||
{
|
||||
type = void_type_node;
|
||||
/* ??? Warn */
|
||||
goto no_expr;
|
||||
}
|
||||
else
|
||||
{
|
||||
last_p = tsi_stmt_ptr (i);
|
||||
last = *last_p;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the last statement is an EXPR_STMT, then unwrap it. Otherwise
|
||||
voidify_wrapper_expr will stuff it inside a MODIFY_EXPR and we'll
|
||||
fail gimplification. */
|
||||
/* ??? Should we go ahead and perform voidify_wrapper_expr here?
|
||||
We've got about all the information we need here. All we'd have
|
||||
to do even for proper type safety is to create, in effect,
|
||||
( ({ ...; tmp = last; }), tmp )
|
||||
I.e. a COMPOUND_EXPR with the rhs being the compiler temporary.
|
||||
Not going to try this now, since it's not clear what should
|
||||
happen (wrt bindings) with new temporaries at this stage. It's
|
||||
easier once we begin gimplification. */
|
||||
if (TREE_CODE (last) == EXPR_STMT)
|
||||
*last_p = last = EXPR_STMT_EXPR (last);
|
||||
|
||||
/* Extract the type of said expression. */
|
||||
type = TREE_TYPE (last);
|
||||
if (!type)
|
||||
type = void_type_node;
|
||||
|
||||
no_expr:
|
||||
/* If what's left is compound, make sure we've got a BIND_EXPR, and
|
||||
that it has the proper type. */
|
||||
ret = body;
|
||||
if (TREE_CODE (ret) == STATEMENT_LIST)
|
||||
ret = build (BIND_EXPR, type, NULL, ret, NULL);
|
||||
else if (TREE_CODE (ret) == BIND_EXPR)
|
||||
TREE_TYPE (ret) = type;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Begin and end compound statements. This is as simple as pushing
|
||||
and popping new statement lists from the tree. */
|
||||
|
||||
tree
|
||||
c_begin_compound_stmt (bool do_scope)
|
||||
{
|
||||
tree stmt = push_stmt_list ();
|
||||
if (do_scope)
|
||||
{
|
||||
push_scope ();
|
||||
clear_last_expr ();
|
||||
}
|
||||
return stmt;
|
||||
}
|
||||
|
||||
tree
|
||||
c_end_compound_stmt (tree stmt, bool do_scope)
|
||||
{
|
||||
tree block = NULL;
|
||||
|
||||
if (do_scope)
|
||||
{
|
||||
if (c_dialect_objc ())
|
||||
objc_clear_super_receiver ();
|
||||
block = pop_scope ();
|
||||
}
|
||||
|
||||
stmt = pop_stmt_list (stmt);
|
||||
stmt = c_build_bind_expr (block, stmt);
|
||||
|
||||
/* If this compound statement is nested immediately inside a statement
|
||||
expression, then force a BIND_EXPR to be created. Otherwise we'll
|
||||
do the wrong thing for ({ { 1; } }) or ({ 1; { } }). In particular,
|
||||
STATEMENT_LISTs merge, and thus we can lose track of what statement
|
||||
was really last. */
|
||||
if (cur_stmt_list
|
||||
&& STATEMENT_LIST_STMT_EXPR (cur_stmt_list)
|
||||
&& TREE_CODE (stmt) != BIND_EXPR)
|
||||
{
|
||||
stmt = build (BIND_EXPR, void_type_node, NULL, stmt, NULL);
|
||||
TREE_SIDE_EFFECTS (stmt) = 1;
|
||||
}
|
||||
|
||||
return stmt;
|
||||
}
|
||||
|
||||
/* Build a binary-operation expression without default conversions.
|
||||
CODE is the kind of expression to build.
|
||||
This function differs from `build' in several ways:
|
||||
|
@ -1,3 +1,63 @@
|
||||
2004-06-15 Richard Henderson <rth@redhat.com>
|
||||
|
||||
* 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.
|
||||
|
||||
2004-06-15 Alexandre Oliva <aoliva@redhat.com>
|
||||
|
||||
* parser.c: Change all assignments of c_lex_string_translate
|
||||
|
@ -6362,9 +6362,9 @@ make_temporary_var_for_ref_to_temp (tree decl, tree type)
|
||||
the VAR_DECL being initialized with the EXPR. (In that case, the
|
||||
type of DECL will be TYPE.) If DECL is non-NULL, then CLEANUP must
|
||||
also be non-NULL, and with *CLEANUP initialized to NULL. Upon
|
||||
return, if *CLEANUP is no longer NULL, it will be a CLEANUP_STMT
|
||||
that should be inserted after the returned expression is used to
|
||||
initialize DECL.
|
||||
return, if *CLEANUP is no longer NULL, it will be an expression
|
||||
that should be pushed as a cleanup after the returned expression
|
||||
is used to initialize DECL.
|
||||
|
||||
Return the converted expression. */
|
||||
|
||||
@ -6485,26 +6485,25 @@ initialize_reference (tree type, tree expr, tree decl, tree *cleanup)
|
||||
{
|
||||
add_decl_stmt (var);
|
||||
*cleanup = cxx_maybe_build_cleanup (var);
|
||||
if (*cleanup)
|
||||
/* We must be careful to destroy the temporary only
|
||||
after its initialization has taken place. If the
|
||||
initialization throws an exception, then the
|
||||
destructor should not be run. We cannot simply
|
||||
transform INIT into something like:
|
||||
|
||||
/* We must be careful to destroy the temporary only
|
||||
after its initialization has taken place. If the
|
||||
initialization throws an exception, then the
|
||||
destructor should not be run. We cannot simply
|
||||
transform INIT into something like:
|
||||
|
||||
(INIT, ({ CLEANUP_STMT; }))
|
||||
|
||||
because emit_local_var always treats the
|
||||
initializer as a full-expression. Thus, the
|
||||
destructor would run too early; it would run at the
|
||||
end of initializing the reference variable, rather
|
||||
than at the end of the block enclosing the
|
||||
reference variable.
|
||||
because emit_local_var always treats the
|
||||
initializer as a full-expression. Thus, the
|
||||
destructor would run too early; it would run at the
|
||||
end of initializing the reference variable, rather
|
||||
than at the end of the block enclosing the
|
||||
reference variable.
|
||||
|
||||
The solution is to pass back a CLEANUP_STMT which
|
||||
the caller is responsible for attaching to the
|
||||
statement tree. */
|
||||
*cleanup = build_stmt (CLEANUP_STMT, var, *cleanup);
|
||||
The solution is to pass back a cleanup expression
|
||||
which the caller is responsible for attaching to
|
||||
the statement tree. */
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -39,7 +39,7 @@ static void cp_gimplify_init_expr (tree *, tree *, tree *);
|
||||
/* Genericize a C++ _STMT. Called from c_gimplify_stmt. */
|
||||
|
||||
int
|
||||
cp_gimplify_stmt (tree *stmt_p, tree *next_p ATTRIBUTE_UNUSED)
|
||||
cp_gimplify_stmt (tree *stmt_p)
|
||||
{
|
||||
tree stmt = *stmt_p;
|
||||
switch (TREE_CODE (stmt))
|
||||
@ -76,12 +76,12 @@ genericize_try_block (tree *stmt_p)
|
||||
tree body = TRY_STMTS (*stmt_p);
|
||||
tree cleanup = TRY_HANDLERS (*stmt_p);
|
||||
|
||||
c_gimplify_stmt (&body);
|
||||
gimplify_stmt (&body);
|
||||
|
||||
if (CLEANUP_P (*stmt_p))
|
||||
/* A cleanup is an expression, so it doesn't need to be genericized. */;
|
||||
else
|
||||
c_gimplify_stmt (&cleanup);
|
||||
gimplify_stmt (&cleanup);
|
||||
|
||||
*stmt_p = build (TRY_CATCH_EXPR, void_type_node, body, cleanup);
|
||||
}
|
||||
@ -94,7 +94,7 @@ genericize_catch_block (tree *stmt_p)
|
||||
tree type = HANDLER_TYPE (*stmt_p);
|
||||
tree body = HANDLER_BODY (*stmt_p);
|
||||
|
||||
c_gimplify_stmt (&body);
|
||||
gimplify_stmt (&body);
|
||||
|
||||
/* FIXME should the caught type go in TREE_TYPE? */
|
||||
*stmt_p = build (CATCH_EXPR, void_type_node, type, body);
|
||||
@ -111,7 +111,7 @@ genericize_eh_spec_block (tree *stmt_p)
|
||||
tree failure = build_call (call_unexpected_node,
|
||||
tree_cons (NULL_TREE, build_exc_ptr (),
|
||||
NULL_TREE));
|
||||
c_gimplify_stmt (&body);
|
||||
gimplify_stmt (&body);
|
||||
|
||||
*stmt_p = gimple_build_eh_filter (body, allowed, failure);
|
||||
}
|
||||
@ -182,16 +182,8 @@ cp_gimplify_init_expr (tree *expr_p, tree *pre_p, tree *post_p)
|
||||
if (TREE_CODE (from) == TARGET_EXPR)
|
||||
from = TARGET_EXPR_INITIAL (from);
|
||||
|
||||
sub = from;
|
||||
|
||||
/* If we are initializing from a STMT_EXPR, extract the returned
|
||||
expression. */
|
||||
if (TREE_CODE (from) == STMT_EXPR)
|
||||
sub = EXPR_STMT_EXPR (stmt_expr_last_stmt (from));
|
||||
|
||||
/* Look through any COMPOUND_EXPRs. */
|
||||
while (TREE_CODE (sub) == COMPOUND_EXPR)
|
||||
sub = TREE_OPERAND (sub, 1);
|
||||
sub = expr_last (from);
|
||||
|
||||
/* If we are initializing from an AGGR_INIT_EXPR, drop the INIT_EXPR and
|
||||
replace the slot operand with our target.
|
||||
@ -205,8 +197,7 @@ cp_gimplify_init_expr (tree *expr_p, tree *pre_p, tree *post_p)
|
||||
*expr_p = from;
|
||||
|
||||
/* The initialization is now a side-effect, so the container can
|
||||
become void. This is important for a STMT_EXPR, so we don't try
|
||||
to voidify it later by creating a temporary. */
|
||||
become void. */
|
||||
if (from != sub)
|
||||
TREE_TYPE (from) = void_type_node;
|
||||
}
|
||||
@ -218,7 +209,7 @@ static void
|
||||
gimplify_must_not_throw_expr (tree *expr_p, tree *pre_p)
|
||||
{
|
||||
tree stmt = *expr_p;
|
||||
tree temp = voidify_wrapper_expr (stmt);
|
||||
tree temp = voidify_wrapper_expr (stmt, NULL);
|
||||
tree body = TREE_OPERAND (stmt, 0);
|
||||
|
||||
gimplify_stmt (&body);
|
||||
|
@ -138,9 +138,6 @@ static void cxx_initialize_diagnostics (diagnostic_context *);
|
||||
#undef LANG_HOOKS_TREE_INLINING_ADD_PENDING_FN_DECLS
|
||||
#define LANG_HOOKS_TREE_INLINING_ADD_PENDING_FN_DECLS \
|
||||
cp_add_pending_fn_decls
|
||||
#undef LANG_HOOKS_TREE_INLINING_TREE_CHAIN_MATTERS_P
|
||||
#define LANG_HOOKS_TREE_INLINING_TREE_CHAIN_MATTERS_P \
|
||||
cp_tree_chain_matters_p
|
||||
#undef LANG_HOOKS_TREE_INLINING_AUTO_VAR_IN_FN_P
|
||||
#define LANG_HOOKS_TREE_INLINING_AUTO_VAR_IN_FN_P \
|
||||
cp_auto_var_in_fn_p
|
||||
@ -292,12 +289,6 @@ cp_expr_size (tree exp)
|
||||
return lhd_expr_size (exp);
|
||||
}
|
||||
|
||||
int
|
||||
cp_tree_chain_matters_p (tree t)
|
||||
{
|
||||
return cp_is_overload_p (t) || c_tree_chain_matters_p (t);
|
||||
}
|
||||
|
||||
/* Langhook for tree_size: determine size of our 'x' and 'c' nodes. */
|
||||
static size_t
|
||||
cp_tree_size (enum tree_code code)
|
||||
|
@ -82,7 +82,7 @@ mflang_flush_calls (tree enqueued_call_stmt_chain)
|
||||
mf_mark (current_function_decl);
|
||||
|
||||
/* Generate the body, one statement at a time. */
|
||||
body = begin_compound_stmt (/*has_no_scope=*/false);
|
||||
body = begin_compound_stmt (BCS_FN_BODY);
|
||||
|
||||
while (enqueued_call_stmt_chain)
|
||||
{
|
||||
|
@ -48,6 +48,9 @@ struct diagnostic_context;
|
||||
PARMLIST_ELLIPSIS_P (in PARMLIST)
|
||||
DECL_PRETTY_FUNCTION_P (in VAR_DECL)
|
||||
KOENIG_LOOKUP_P (in CALL_EXPR)
|
||||
STATEMENT_LIST_NO_SCOPE (in STATEMENT_LIST).
|
||||
EXPR_STMT_STMT_EXPR_RESULT (in EXPR_STMT)
|
||||
COMPOUND_STMT_TRY_BLOCK (in COMPOUND_STMT)
|
||||
1: IDENTIFIER_VIRTUAL_P.
|
||||
TI_PENDING_TEMPLATE_FLAG.
|
||||
TEMPLATE_PARMS_FOR_INLINE.
|
||||
@ -63,6 +66,7 @@ struct diagnostic_context;
|
||||
BINFO_LOST_PRIMARY_P (in BINFO)
|
||||
TREE_PARMLIST (in TREE_LIST)
|
||||
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL)
|
||||
STATEMENT_LIST_TRY_BLOCK (in STATEMENT_LIST)
|
||||
3: TYPE_USES_VIRTUAL_BASECLASSES (in a class TYPE).
|
||||
BINFO_VTABLE_PATH_MARKED.
|
||||
BINFO_PUSHDECLS_MARKED.
|
||||
@ -70,6 +74,7 @@ struct diagnostic_context;
|
||||
ICS_BAD_FLAG (in _CONV)
|
||||
FN_TRY_BLOCK_P (in TRY_BLOCK)
|
||||
IDENTIFIER_CTOR_OR_DTOR_P (in IDENTIFIER_NODE)
|
||||
COMPOUND_STMT_BODY_BLOCK (in COMPOUND_STMT)
|
||||
4: BINFO_NEW_VTABLE_MARKED.
|
||||
TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
|
||||
or FIELD_DECL).
|
||||
@ -266,6 +271,22 @@ typedef struct ptrmem_cst * ptrmem_cst_t;
|
||||
|
||||
#define CLEANUP_P(NODE) TREE_LANG_FLAG_0 (TRY_BLOCK_CHECK (NODE))
|
||||
|
||||
#define COMPOUND_STMT_TRY_BLOCK(NODE) \
|
||||
TREE_LANG_FLAG_0 (COMPOUND_STMT_CHECK (NODE))
|
||||
|
||||
/* Used to mark the block around the member initializers and cleanups. */
|
||||
#define COMPOUND_STMT_BODY_BLOCK(NODE) \
|
||||
TREE_LANG_FLAG_3 (COMPOUND_STMT_CHECK (NODE))
|
||||
|
||||
#define STATEMENT_LIST_NO_SCOPE(NODE) \
|
||||
TREE_LANG_FLAG_0 (STATEMENT_LIST_CHECK (NODE))
|
||||
#define STATEMENT_LIST_TRY_BLOCK(NODE) \
|
||||
TREE_LANG_FLAG_2 (STATEMENT_LIST_CHECK (NODE))
|
||||
|
||||
/* Marks the result of a statement expression. */
|
||||
#define EXPR_STMT_STMT_EXPR_RESULT(NODE) \
|
||||
TREE_LANG_FLAG_0 (EXPR_STMT_CHECK (NODE))
|
||||
|
||||
/* Returns nonzero iff TYPE1 and TYPE2 are the same type, in the usual
|
||||
sense of `same'. */
|
||||
#define same_type_p(TYPE1, TYPE2) \
|
||||
@ -278,7 +299,7 @@ typedef struct ptrmem_cst * ptrmem_cst_t;
|
||||
|
||||
/* Nonzero if we are presently building a statement tree, rather
|
||||
than expanding each statement as we encounter it. */
|
||||
#define building_stmt_tree() (last_tree != NULL_TREE)
|
||||
#define building_stmt_tree() (cur_stmt_list != NULL_TREE)
|
||||
|
||||
/* Returns nonzero iff NODE is a declaration for the global function
|
||||
`main'. */
|
||||
@ -3031,12 +3052,7 @@ typedef enum tsubst_flags_t {
|
||||
instantiate_type use) */
|
||||
tf_user = 1 << 5, /* found template must be a user template
|
||||
(lookup_template_class use) */
|
||||
tf_stmt_expr_cmpd = 1 << 6, /* tsubsting the compound statement of
|
||||
a statement expr. */
|
||||
tf_stmt_expr_body = 1 << 7, /* tsubsting the statements in the
|
||||
body of the compound statement of a
|
||||
statement expr. */
|
||||
tf_conv = 1 << 8 /* We are determining what kind of
|
||||
tf_conv = 1 << 6 /* We are determining what kind of
|
||||
conversion might be permissible,
|
||||
not actually performing the
|
||||
conversion. */
|
||||
@ -4004,9 +4020,9 @@ extern tree finish_expr_stmt (tree);
|
||||
extern tree begin_if_stmt (void);
|
||||
extern void finish_if_stmt_cond (tree, tree);
|
||||
extern tree finish_then_clause (tree);
|
||||
extern void begin_else_clause (void);
|
||||
extern void begin_else_clause (tree);
|
||||
extern void finish_else_clause (tree);
|
||||
extern void finish_if_stmt (void);
|
||||
extern void finish_if_stmt (tree);
|
||||
extern tree begin_while_stmt (void);
|
||||
extern void finish_while_stmt_cond (tree, tree);
|
||||
extern void finish_while_stmt (tree);
|
||||
@ -4040,8 +4056,15 @@ extern void finish_handler_parms (tree, tree);
|
||||
extern void begin_catch_block (tree);
|
||||
extern void finish_handler (tree);
|
||||
extern void finish_cleanup (tree, tree);
|
||||
extern tree begin_compound_stmt (bool);
|
||||
extern tree finish_compound_stmt (tree);
|
||||
|
||||
enum {
|
||||
BCS_NO_SCOPE = 1,
|
||||
BCS_TRY_BLOCK = 2,
|
||||
BCS_FN_BODY = 4
|
||||
};
|
||||
extern tree begin_compound_stmt (unsigned int);
|
||||
|
||||
extern void finish_compound_stmt (tree);
|
||||
extern tree finish_asm_stmt (int, tree, tree, tree, tree);
|
||||
extern tree finish_label_stmt (tree);
|
||||
extern void finish_label_decl (tree);
|
||||
@ -4049,7 +4072,7 @@ extern void finish_subobject (tree);
|
||||
extern tree finish_parenthesized_expr (tree);
|
||||
extern tree finish_non_static_data_member (tree, tree, tree);
|
||||
extern tree begin_stmt_expr (void);
|
||||
extern tree finish_stmt_expr_expr (tree);
|
||||
extern tree finish_stmt_expr_expr (tree, tree);
|
||||
extern tree finish_stmt_expr (tree, bool);
|
||||
extern tree perform_koenig_lookup (tree, tree);
|
||||
extern tree finish_call_expr (tree, tree, bool, bool);
|
||||
@ -4082,8 +4105,6 @@ extern void finish_decl_cleanup (tree, tree);
|
||||
extern void finish_eh_cleanup (tree);
|
||||
extern void expand_body (tree);
|
||||
extern void cxx_expand_function_start (void);
|
||||
extern void do_pushlevel (scope_kind);
|
||||
extern tree do_poplevel (void);
|
||||
extern void finish_mem_initializers (tree);
|
||||
extern void setup_vtbl_ptr (tree, tree);
|
||||
extern void clear_out_block (void);
|
||||
@ -4164,7 +4185,6 @@ extern tree find_tree (tree, tree);
|
||||
extern linkage_kind decl_linkage (tree);
|
||||
extern tree cp_walk_subtrees (tree*, int*, walk_tree_fn,
|
||||
void*, void*);
|
||||
extern int cp_tree_chain_matters_p (tree);
|
||||
extern int cp_cannot_inline_tree_fn (tree*);
|
||||
extern tree cp_add_pending_fn_decls (void*,tree);
|
||||
extern int cp_is_overload_p (tree);
|
||||
@ -4286,7 +4306,7 @@ extern bool cp_dump_tree (void *, tree);
|
||||
|
||||
/* in cp-simplify.c */
|
||||
extern int cp_gimplify_expr (tree *, tree *, tree *);
|
||||
extern int cp_gimplify_stmt (tree *, tree *);
|
||||
extern int cp_gimplify_stmt (tree *);
|
||||
|
||||
/* -- end of C++ */
|
||||
|
||||
|
@ -429,12 +429,15 @@ poplevel (int keep, int reverse, int functionbody)
|
||||
int tmp = functionbody;
|
||||
int real_functionbody;
|
||||
tree subblocks;
|
||||
tree block = NULL_TREE;
|
||||
tree block;
|
||||
tree decl;
|
||||
int leaving_for_scope;
|
||||
scope_kind kind;
|
||||
|
||||
timevar_push (TV_NAME_LOOKUP);
|
||||
restart:
|
||||
|
||||
block = NULL_TREE;
|
||||
|
||||
my_friendly_assert (current_binding_level->kind != sk_class, 19990916);
|
||||
|
||||
@ -657,6 +660,17 @@ poplevel (int keep, int reverse, int functionbody)
|
||||
}
|
||||
|
||||
kind = current_binding_level->kind;
|
||||
if (kind == sk_cleanup)
|
||||
{
|
||||
tree stmt;
|
||||
|
||||
/* If this is a temporary binding created for a cleanup, then we'll
|
||||
have pushed a statement list level. Pop that, create a new
|
||||
BIND_EXPR for the block, and insert it into the stream. */
|
||||
stmt = pop_stmt_list (current_binding_level->statement_list);
|
||||
stmt = c_build_bind_expr (block, stmt);
|
||||
add_stmt (stmt);
|
||||
}
|
||||
|
||||
leave_scope ();
|
||||
if (functionbody)
|
||||
@ -680,21 +694,9 @@ poplevel (int keep, int reverse, int functionbody)
|
||||
if (block)
|
||||
TREE_USED (block) = 1;
|
||||
|
||||
/* Take care of compiler's internal binding structures. */
|
||||
/* All temporary bindings created for cleanups are popped silently. */
|
||||
if (kind == sk_cleanup)
|
||||
{
|
||||
tree scope_stmts;
|
||||
|
||||
scope_stmts
|
||||
= add_scope_stmt (/*begin_p=*/0, /*partial_p=*/1);
|
||||
if (block)
|
||||
{
|
||||
SCOPE_STMT_BLOCK (TREE_PURPOSE (scope_stmts)) = block;
|
||||
SCOPE_STMT_BLOCK (TREE_VALUE (scope_stmts)) = block;
|
||||
}
|
||||
|
||||
block = poplevel (keep, reverse, functionbody);
|
||||
}
|
||||
goto restart;
|
||||
|
||||
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, block);
|
||||
}
|
||||
@ -4938,7 +4940,7 @@ cp_finish_decl (tree decl, tree init, tree asmspec_tree, int flags)
|
||||
/* If a CLEANUP_STMT was created to destroy a temporary bound to a
|
||||
reference, insert it in the statement-tree now. */
|
||||
if (cleanup)
|
||||
add_stmt (cleanup);
|
||||
push_cleanup (decl, cleanup, false);
|
||||
|
||||
finish_end:
|
||||
|
||||
@ -5174,7 +5176,7 @@ register_dtor_fn (tree decl)
|
||||
pop_deferring_access_checks ();
|
||||
|
||||
/* Create the body of the anonymous function. */
|
||||
compound_stmt = begin_compound_stmt (/*has_no_scope=*/false);
|
||||
compound_stmt = begin_compound_stmt (BCS_FN_BODY);
|
||||
finish_expr_stmt (fcall);
|
||||
finish_compound_stmt (compound_stmt);
|
||||
end_cleanup_fn ();
|
||||
@ -5252,7 +5254,7 @@ expand_static_init (tree decl, tree init)
|
||||
/* Begin the conditional initialization. */
|
||||
if_stmt = begin_if_stmt ();
|
||||
finish_if_stmt_cond (get_guard_cond (guard), if_stmt);
|
||||
then_clause = begin_compound_stmt (/*has_no_scope=*/false);
|
||||
then_clause = begin_compound_stmt (0);
|
||||
|
||||
/* Do the initialization itself. */
|
||||
assignment = init ? init : NULL_TREE;
|
||||
@ -5278,7 +5280,7 @@ expand_static_init (tree decl, tree init)
|
||||
|
||||
finish_compound_stmt (then_clause);
|
||||
finish_then_clause (if_stmt);
|
||||
finish_if_stmt ();
|
||||
finish_if_stmt (if_stmt);
|
||||
}
|
||||
else
|
||||
static_aggregates = tree_cons (init, decl, static_aggregates);
|
||||
@ -10225,7 +10227,7 @@ start_function (tree declspecs, tree declarator, tree attrs, int flags)
|
||||
cfun->x_dont_save_pending_sizes_p = 1;
|
||||
|
||||
/* Start the statement-tree, start the tree now. */
|
||||
begin_stmt_tree (&DECL_SAVED_TREE (decl1));
|
||||
DECL_SAVED_TREE (decl1) = push_stmt_list ();
|
||||
|
||||
/* Let the user know we're compiling this function. */
|
||||
announce_function (decl1);
|
||||
@ -10486,8 +10488,7 @@ save_function_data (tree decl)
|
||||
DECL_SAVED_FUNCTION_DATA (decl) = f;
|
||||
|
||||
/* Clear out the bits we don't need. */
|
||||
f->base.x_stmt_tree.x_last_stmt = NULL_TREE;
|
||||
f->base.x_stmt_tree.x_last_expr_type = NULL_TREE;
|
||||
f->base.x_stmt_tree.x_cur_stmt_list = NULL_TREE;
|
||||
f->x_named_label_uses = NULL;
|
||||
f->bindings = NULL;
|
||||
f->x_local_names = NULL;
|
||||
@ -10542,7 +10543,7 @@ begin_destructor_body (void)
|
||||
initialize the vtables.) */
|
||||
finish_if_stmt_cond (boolean_true_node, if_stmt);
|
||||
|
||||
compound_stmt = begin_compound_stmt (/*has_no_scope=*/false);
|
||||
compound_stmt = begin_compound_stmt (0);
|
||||
|
||||
/* Make all virtual function table pointers in non-virtual base
|
||||
classes point to CURRENT_CLASS_TYPE's virtual function
|
||||
@ -10551,7 +10552,7 @@ begin_destructor_body (void)
|
||||
|
||||
finish_compound_stmt (compound_stmt);
|
||||
finish_then_clause (if_stmt);
|
||||
finish_if_stmt ();
|
||||
finish_if_stmt (if_stmt);
|
||||
|
||||
/* And insert cleanups for our bases and members so that they
|
||||
will be properly destroyed if we throw. */
|
||||
@ -10593,7 +10594,7 @@ finish_destructor_body (void)
|
||||
if_stmt);
|
||||
finish_expr_stmt (exprstmt);
|
||||
finish_then_clause (if_stmt);
|
||||
finish_if_stmt ();
|
||||
finish_if_stmt (if_stmt);
|
||||
}
|
||||
}
|
||||
|
||||
@ -10616,7 +10617,7 @@ begin_function_body (void)
|
||||
operation of dwarfout.c. */
|
||||
keep_next_level (true);
|
||||
|
||||
stmt = begin_compound_stmt (/*has_no_scope=*/false);
|
||||
stmt = begin_compound_stmt (BCS_FN_BODY);
|
||||
COMPOUND_STMT_BODY_BLOCK (stmt) = 1;
|
||||
|
||||
if (processing_template_decl)
|
||||
@ -10716,10 +10717,10 @@ finish_function (int flags)
|
||||
current_eh_spec_block);
|
||||
}
|
||||
|
||||
finish_fname_decls ();
|
||||
|
||||
/* If we're saving up tree structure, tie off the function now. */
|
||||
finish_stmt_tree (&DECL_SAVED_TREE (fndecl));
|
||||
DECL_SAVED_TREE (fndecl) = pop_stmt_list (DECL_SAVED_TREE (fndecl));
|
||||
|
||||
finish_fname_decls ();
|
||||
|
||||
/* If this function can't throw any exceptions, remember that. */
|
||||
if (!processing_template_decl
|
||||
@ -10773,9 +10774,10 @@ finish_function (int flags)
|
||||
the function so we know that their lifetime always ends with a
|
||||
return; see g++.dg/opt/nrv6.C. We could be more flexible if
|
||||
we were to do this optimization in tree-ssa. */
|
||||
&& (outer = BLOCK_SUBBLOCKS (DECL_INITIAL (fndecl)))
|
||||
/* Skip the artificial function body block. */
|
||||
&& (outer = BLOCK_SUBBLOCKS (BLOCK_SUBBLOCKS (DECL_INITIAL (fndecl))),
|
||||
chain_member (r, BLOCK_VARS (outer))))
|
||||
&& (outer = BLOCK_SUBBLOCKS (outer))
|
||||
&& chain_member (r, BLOCK_VARS (outer)))
|
||||
finalize_nrv (&DECL_SAVED_TREE (fndecl), r, DECL_RESULT (fndecl));
|
||||
|
||||
current_function_return_value = NULL_TREE;
|
||||
@ -11094,10 +11096,6 @@ cxx_maybe_build_cleanup (tree decl)
|
||||
void
|
||||
finish_stmt (void)
|
||||
{
|
||||
/* Always assume this statement was not an expression statement. If
|
||||
it actually was an expression statement, its our callers
|
||||
responsibility to fix this up. */
|
||||
last_expr_type = NULL_TREE;
|
||||
}
|
||||
|
||||
/* DECL was originally constructed as a non-static member function,
|
||||
|
@ -1970,7 +1970,7 @@ start_objects (int method_type, int initp)
|
||||
DECL_GLOBAL_DTOR_P (current_function_decl) = 1;
|
||||
DECL_LANG_SPECIFIC (current_function_decl)->decl_flags.u2sel = 1;
|
||||
|
||||
body = begin_compound_stmt (/*has_no_scope=*/false);
|
||||
body = begin_compound_stmt (BCS_FN_BODY);
|
||||
|
||||
/* We cannot allow these functions to be elided, even if they do not
|
||||
have external linkage. And, there's no point in deferring
|
||||
@ -2127,7 +2127,7 @@ start_static_storage_duration_function (unsigned count)
|
||||
SF_PRE_PARSED);
|
||||
|
||||
/* Set up the scope of the outermost block in the function. */
|
||||
body = begin_compound_stmt (/*has_no_scope=*/false);
|
||||
body = begin_compound_stmt (BCS_FN_BODY);
|
||||
|
||||
/* This function must not be deferred because we are depending on
|
||||
its compilation to tell us what is TREE_SYMBOL_REFERENCED. */
|
||||
@ -2307,7 +2307,7 @@ static void
|
||||
finish_static_initialization_or_destruction (tree guard_if_stmt)
|
||||
{
|
||||
finish_then_clause (guard_if_stmt);
|
||||
finish_if_stmt ();
|
||||
finish_if_stmt (guard_if_stmt);
|
||||
|
||||
/* Now that we're done with DECL we don't need to pretend to be a
|
||||
member of its class any longer. */
|
||||
|
@ -37,6 +37,7 @@ Boston, MA 02111-1307, USA. */
|
||||
#include "except.h"
|
||||
#include "toplev.h"
|
||||
#include "tree-inline.h"
|
||||
#include "tree-iterator.h"
|
||||
|
||||
static void push_eh_cleanup (tree);
|
||||
static tree prepare_eh_type (tree);
|
||||
@ -51,7 +52,6 @@ static tree wrap_cleanups_r (tree *, int *, void *);
|
||||
static int complete_ptr_ref_or_void_ptr_p (tree, tree);
|
||||
static bool is_admissible_throw_operand (tree);
|
||||
static int can_convert_eh (tree, tree);
|
||||
static void check_handlers_1 (tree, tree);
|
||||
static tree cp_protect_cleanup_actions (void);
|
||||
|
||||
/* Sets up all the global eh stuff that needs to be initialized at the
|
||||
@ -462,6 +462,7 @@ begin_eh_spec_block (void)
|
||||
{
|
||||
tree r = build_stmt (EH_SPEC_BLOCK, NULL_TREE, NULL_TREE);
|
||||
add_stmt (r);
|
||||
EH_SPEC_STMTS (r) = push_stmt_list ();
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -470,7 +471,7 @@ finish_eh_spec_block (tree raw_raises, tree eh_spec_block)
|
||||
{
|
||||
tree raises;
|
||||
|
||||
RECHAIN_STMTS (eh_spec_block, EH_SPEC_STMTS (eh_spec_block));
|
||||
EH_SPEC_STMTS (eh_spec_block) = pop_stmt_list (EH_SPEC_STMTS (eh_spec_block));
|
||||
|
||||
/* Strip cv quals, etc, from the specification types. */
|
||||
for (raises = NULL_TREE;
|
||||
@ -874,47 +875,57 @@ can_convert_eh (tree to, tree from)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check whether any of HANDLERS are shadowed by another handler accepting
|
||||
TYPE. Note that the shadowing may not be complete; even if an exception
|
||||
of type B would be caught by a handler for A, there could be a derived
|
||||
class C for which A is an ambiguous base but B is not, so the handler
|
||||
for B would catch an exception of type C. */
|
||||
/* Check whether any of the handlers in I are shadowed by another handler
|
||||
accepting TYPE. Note that the shadowing may not be complete; even if
|
||||
an exception of type B would be caught by a handler for A, there could
|
||||
be a derived class C for which A is an ambiguous base but B is not, so
|
||||
the handler for B would catch an exception of type C. */
|
||||
|
||||
static void
|
||||
check_handlers_1 (tree master, tree handlers)
|
||||
check_handlers_1 (tree master, tree_stmt_iterator i)
|
||||
{
|
||||
tree type = TREE_TYPE (master);
|
||||
tree handler;
|
||||
|
||||
for (handler = handlers; handler; handler = TREE_CHAIN (handler))
|
||||
if (TREE_TYPE (handler)
|
||||
&& can_convert_eh (type, TREE_TYPE (handler)))
|
||||
{
|
||||
warning ("%Hexception of type `%T' will be caught",
|
||||
EXPR_LOCUS (handler), TREE_TYPE (handler));
|
||||
warning ("%H by earlier handler for `%T'",
|
||||
EXPR_LOCUS (master), type);
|
||||
break;
|
||||
}
|
||||
for (; !tsi_end_p (i); tsi_next (&i))
|
||||
{
|
||||
tree handler = tsi_stmt (i);
|
||||
if (TREE_TYPE (handler) && can_convert_eh (type, TREE_TYPE (handler)))
|
||||
{
|
||||
warning ("%Hexception of type `%T' will be caught",
|
||||
EXPR_LOCUS (handler), TREE_TYPE (handler));
|
||||
warning ("%H by earlier handler for `%T'",
|
||||
EXPR_LOCUS (master), type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Given a chain of HANDLERs, make sure that they're OK. */
|
||||
/* Given a STATEMENT_LIST of HANDLERs, make sure that they're OK. */
|
||||
|
||||
void
|
||||
check_handlers (tree handlers)
|
||||
{
|
||||
tree handler;
|
||||
int save_line = input_line;
|
||||
|
||||
for (handler = handlers; handler; handler = TREE_CHAIN (handler))
|
||||
{
|
||||
if (TREE_CHAIN (handler) == NULL_TREE)
|
||||
/* No more handlers; nothing to shadow. */;
|
||||
else if (TREE_TYPE (handler) == NULL_TREE)
|
||||
pedwarn ("%H`...' handler must be the last handler for"
|
||||
" its try block", EXPR_LOCUS (handler));
|
||||
else
|
||||
check_handlers_1 (handler, TREE_CHAIN (handler));
|
||||
}
|
||||
input_line = save_line;
|
||||
tree_stmt_iterator i;
|
||||
|
||||
/* If we don't have a STATEMENT_LIST, then we've just got one
|
||||
handler, and thus nothing to warn about. */
|
||||
if (TREE_CODE (handlers) != STATEMENT_LIST)
|
||||
return;
|
||||
|
||||
i = tsi_start (handlers);
|
||||
if (!tsi_end_p (i))
|
||||
while (1)
|
||||
{
|
||||
tree handler = tsi_stmt (i);
|
||||
tsi_next (&i);
|
||||
|
||||
/* No more handlers; nothing to shadow. */
|
||||
if (tsi_end_p (i))
|
||||
break;
|
||||
if (TREE_TYPE (handler) == NULL_TREE)
|
||||
pedwarn ("%H`...' handler must be the last handler for"
|
||||
" its try block", EXPR_LOCUS (handler));
|
||||
else
|
||||
check_handlers_1 (handler, i);
|
||||
}
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ begin_init_stmts (tree *stmt_expr_p, tree *compound_stmt_p)
|
||||
bool is_global = !building_stmt_tree ();
|
||||
|
||||
*stmt_expr_p = begin_stmt_expr ();
|
||||
*compound_stmt_p = begin_compound_stmt (/*has_no_scope=*/true);
|
||||
*compound_stmt_p = begin_compound_stmt (BCS_NO_SCOPE);
|
||||
|
||||
return is_global;
|
||||
}
|
||||
@ -826,7 +826,6 @@ static void
|
||||
construct_virtual_base (tree vbase, tree arguments)
|
||||
{
|
||||
tree inner_if_stmt;
|
||||
tree compound_stmt;
|
||||
tree exp;
|
||||
tree flag;
|
||||
|
||||
@ -847,7 +846,6 @@ construct_virtual_base (tree vbase, tree arguments)
|
||||
flag = TREE_CHAIN (DECL_ARGUMENTS (current_function_decl));
|
||||
inner_if_stmt = begin_if_stmt ();
|
||||
finish_if_stmt_cond (flag, inner_if_stmt);
|
||||
compound_stmt = begin_compound_stmt (/*has_no_scope=*/true);
|
||||
|
||||
/* Compute the location of the virtual base. If we're
|
||||
constructing virtual bases, then we must be the most derived
|
||||
@ -857,9 +855,8 @@ construct_virtual_base (tree vbase, tree arguments)
|
||||
|
||||
expand_aggr_init_1 (vbase, current_class_ref, exp, arguments,
|
||||
LOOKUP_COMPLAIN);
|
||||
finish_compound_stmt (compound_stmt);
|
||||
finish_then_clause (inner_if_stmt);
|
||||
finish_if_stmt ();
|
||||
finish_if_stmt (inner_if_stmt);
|
||||
|
||||
expand_cleanup_for_base (vbase, flag);
|
||||
}
|
||||
@ -2526,7 +2523,6 @@ build_vec_init (tree base, tree maxindex, tree init, int from_array)
|
||||
tree compound_stmt;
|
||||
int destroy_temps;
|
||||
tree try_block = NULL_TREE;
|
||||
tree try_body = NULL_TREE;
|
||||
int num_initialized_elts = 0;
|
||||
bool is_global;
|
||||
|
||||
@ -2605,7 +2601,6 @@ build_vec_init (tree base, tree maxindex, tree init, int from_array)
|
||||
&& from_array != 2)
|
||||
{
|
||||
try_block = begin_try_block ();
|
||||
try_body = begin_compound_stmt (/*has_no_scope=*/true);
|
||||
}
|
||||
|
||||
if (init != NULL_TREE && TREE_CODE (init) == CONSTRUCTOR)
|
||||
@ -2674,7 +2669,6 @@ build_vec_init (tree base, tree maxindex, tree init, int from_array)
|
||||
/* If the ITERATOR is equal to -1, then we don't have to loop;
|
||||
we've already initialized all the elements. */
|
||||
tree for_stmt;
|
||||
tree for_body;
|
||||
tree elt_init;
|
||||
|
||||
for_stmt = begin_for_stmt ();
|
||||
@ -2685,9 +2679,6 @@ build_vec_init (tree base, tree maxindex, tree init, int from_array)
|
||||
finish_for_expr (build_unary_op (PREDECREMENT_EXPR, iterator, 0),
|
||||
for_stmt);
|
||||
|
||||
/* Otherwise, loop through the elements. */
|
||||
for_body = begin_compound_stmt (/*has_no_scope=*/true);
|
||||
|
||||
if (from_array)
|
||||
{
|
||||
tree to = build1 (INDIRECT_REF, type, base);
|
||||
@ -2727,7 +2718,6 @@ build_vec_init (tree base, tree maxindex, tree init, int from_array)
|
||||
if (base2)
|
||||
finish_expr_stmt (build_unary_op (PREINCREMENT_EXPR, base2, 0));
|
||||
|
||||
finish_compound_stmt (for_body);
|
||||
finish_for_stmt (for_stmt);
|
||||
}
|
||||
|
||||
@ -2747,7 +2737,6 @@ build_vec_init (tree base, tree maxindex, tree init, int from_array)
|
||||
type = strip_array_types (type);
|
||||
}
|
||||
|
||||
finish_compound_stmt (try_body);
|
||||
finish_cleanup_try_block (try_block);
|
||||
e = build_vec_delete_1 (rval, m, type, sfk_base_destructor,
|
||||
/*use_global_delete=*/0);
|
||||
@ -2756,7 +2745,7 @@ build_vec_init (tree base, tree maxindex, tree init, int from_array)
|
||||
|
||||
/* The value of the array initialization is the array itself, RVAL
|
||||
is a pointer to the first element. */
|
||||
finish_stmt_expr_expr (rval);
|
||||
finish_stmt_expr_expr (rval, stmt_expr);
|
||||
|
||||
stmt_expr = finish_init_stmts (is_global, stmt_expr, compound_stmt);
|
||||
|
||||
|
@ -621,7 +621,7 @@ do_build_assign_ref (tree fndecl)
|
||||
tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl));
|
||||
tree compound_stmt;
|
||||
|
||||
compound_stmt = begin_compound_stmt (/*has_no_scope=*/false);
|
||||
compound_stmt = begin_compound_stmt (0);
|
||||
parm = convert_from_reference (parm);
|
||||
|
||||
if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type)
|
||||
@ -778,7 +778,7 @@ synthesize_method (tree fndecl)
|
||||
if (need_body)
|
||||
{
|
||||
tree compound_stmt;
|
||||
compound_stmt = begin_compound_stmt (/*has_no_scope=*/false);
|
||||
compound_stmt = begin_compound_stmt (BCS_FN_BODY);
|
||||
finish_compound_stmt (compound_stmt);
|
||||
}
|
||||
|
||||
|
@ -1433,8 +1433,8 @@ maybe_push_cleanup_level (tree type)
|
||||
&& current_binding_level->more_cleanups_ok == 0)
|
||||
{
|
||||
begin_scope (sk_cleanup, NULL);
|
||||
current_binding_level->statement_list = push_stmt_list ();
|
||||
clear_last_expr ();
|
||||
add_scope_stmt (/*begin_p=*/1, /*partial_p=*/1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -205,6 +205,10 @@ struct cp_binding_level GTY(())
|
||||
TREE_LIST; the TREE_VALUE is the actual declaration. */
|
||||
tree dead_vars_from_for;
|
||||
|
||||
/* STATEMENT_LIST for statements in this binding contour.
|
||||
Only used at present for SK_CLEANUP temporary bindings. */
|
||||
tree statement_list;
|
||||
|
||||
/* Binding depth at which this level began. */
|
||||
int binding_depth;
|
||||
|
||||
|
@ -1415,15 +1415,15 @@ static tree cp_parser_builtin_offsetof
|
||||
/* Statements [gram.stmt.stmt] */
|
||||
|
||||
static void cp_parser_statement
|
||||
(cp_parser *, bool);
|
||||
(cp_parser *, tree);
|
||||
static tree cp_parser_labeled_statement
|
||||
(cp_parser *, bool);
|
||||
(cp_parser *, tree);
|
||||
static tree cp_parser_expression_statement
|
||||
(cp_parser *, bool);
|
||||
(cp_parser *, tree);
|
||||
static tree cp_parser_compound_statement
|
||||
(cp_parser *, bool);
|
||||
(cp_parser *, tree, bool);
|
||||
static void cp_parser_statement_seq_opt
|
||||
(cp_parser *, bool);
|
||||
(cp_parser *, tree);
|
||||
static tree cp_parser_selection_statement
|
||||
(cp_parser *);
|
||||
static tree cp_parser_condition
|
||||
@ -2542,7 +2542,7 @@ cp_parser_primary_expression (cp_parser *parser,
|
||||
/* Start the statement-expression. */
|
||||
expr = begin_stmt_expr ();
|
||||
/* Parse the compound-statement. */
|
||||
cp_parser_compound_statement (parser, true);
|
||||
cp_parser_compound_statement (parser, expr, false);
|
||||
/* Finish up. */
|
||||
expr = finish_stmt_expr (expr, false);
|
||||
}
|
||||
@ -5615,7 +5615,7 @@ cp_parser_builtin_offsetof (cp_parser *parser)
|
||||
try-block */
|
||||
|
||||
static void
|
||||
cp_parser_statement (cp_parser* parser, bool in_statement_expr_p)
|
||||
cp_parser_statement (cp_parser* parser, tree in_statement_expr)
|
||||
{
|
||||
tree statement;
|
||||
cp_token *token;
|
||||
@ -5638,7 +5638,7 @@ cp_parser_statement (cp_parser* parser, bool in_statement_expr_p)
|
||||
case RID_CASE:
|
||||
case RID_DEFAULT:
|
||||
statement = cp_parser_labeled_statement (parser,
|
||||
in_statement_expr_p);
|
||||
in_statement_expr);
|
||||
break;
|
||||
|
||||
case RID_IF:
|
||||
@ -5675,11 +5675,11 @@ cp_parser_statement (cp_parser* parser, bool in_statement_expr_p)
|
||||
labeled-statement. */
|
||||
token = cp_lexer_peek_nth_token (parser->lexer, 2);
|
||||
if (token->type == CPP_COLON)
|
||||
statement = cp_parser_labeled_statement (parser, in_statement_expr_p);
|
||||
statement = cp_parser_labeled_statement (parser, in_statement_expr);
|
||||
}
|
||||
/* Anything that starts with a `{' must be a compound-statement. */
|
||||
else if (token->type == CPP_OPEN_BRACE)
|
||||
statement = cp_parser_compound_statement (parser, false);
|
||||
statement = cp_parser_compound_statement (parser, NULL, false);
|
||||
|
||||
/* Everything else must be a declaration-statement or an
|
||||
expression-statement. Try for the declaration-statement
|
||||
@ -5697,7 +5697,7 @@ cp_parser_statement (cp_parser* parser, bool in_statement_expr_p)
|
||||
return;
|
||||
}
|
||||
/* Look for an expression-statement instead. */
|
||||
statement = cp_parser_expression_statement (parser, in_statement_expr_p);
|
||||
statement = cp_parser_expression_statement (parser, in_statement_expr);
|
||||
}
|
||||
|
||||
/* Set the line number for the statement. */
|
||||
@ -5724,7 +5724,7 @@ cp_parser_statement (cp_parser* parser, bool in_statement_expr_p)
|
||||
an ordinary label, returns a LABEL_STMT. */
|
||||
|
||||
static tree
|
||||
cp_parser_labeled_statement (cp_parser* parser, bool in_statement_expr_p)
|
||||
cp_parser_labeled_statement (cp_parser* parser, tree in_statement_expr)
|
||||
{
|
||||
cp_token *token;
|
||||
tree statement = error_mark_node;
|
||||
@ -5792,7 +5792,7 @@ cp_parser_labeled_statement (cp_parser* parser, bool in_statement_expr_p)
|
||||
/* Require the `:' token. */
|
||||
cp_parser_require (parser, CPP_COLON, "`:'");
|
||||
/* Parse the labeled statement. */
|
||||
cp_parser_statement (parser, in_statement_expr_p);
|
||||
cp_parser_statement (parser, in_statement_expr);
|
||||
|
||||
/* Return the label, in the case of a `case' or `default' label. */
|
||||
return statement;
|
||||
@ -5809,7 +5809,7 @@ cp_parser_labeled_statement (cp_parser* parser, bool in_statement_expr_p)
|
||||
expression statement. */
|
||||
|
||||
static tree
|
||||
cp_parser_expression_statement (cp_parser* parser, bool in_statement_expr_p)
|
||||
cp_parser_expression_statement (cp_parser* parser, tree in_statement_expr)
|
||||
{
|
||||
tree statement = NULL_TREE;
|
||||
|
||||
@ -5821,12 +5821,12 @@ cp_parser_expression_statement (cp_parser* parser, bool in_statement_expr_p)
|
||||
/* Consume the final `;'. */
|
||||
cp_parser_consume_semicolon_at_end_of_statement (parser);
|
||||
|
||||
if (in_statement_expr_p
|
||||
if (in_statement_expr
|
||||
&& cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
|
||||
{
|
||||
/* This is the final expression statement of a statement
|
||||
expression. */
|
||||
statement = finish_stmt_expr_expr (statement);
|
||||
statement = finish_stmt_expr_expr (statement, in_statement_expr);
|
||||
}
|
||||
else if (statement)
|
||||
statement = finish_expr_stmt (statement);
|
||||
@ -5844,7 +5844,8 @@ cp_parser_expression_statement (cp_parser* parser, bool in_statement_expr_p)
|
||||
Returns a COMPOUND_STMT representing the statement. */
|
||||
|
||||
static tree
|
||||
cp_parser_compound_statement (cp_parser *parser, bool in_statement_expr_p)
|
||||
cp_parser_compound_statement (cp_parser *parser, tree in_statement_expr,
|
||||
bool in_try)
|
||||
{
|
||||
tree compound_stmt;
|
||||
|
||||
@ -5852,9 +5853,9 @@ cp_parser_compound_statement (cp_parser *parser, bool in_statement_expr_p)
|
||||
if (!cp_parser_require (parser, CPP_OPEN_BRACE, "`{'"))
|
||||
return error_mark_node;
|
||||
/* Begin the compound-statement. */
|
||||
compound_stmt = begin_compound_stmt (/*has_no_scope=*/false);
|
||||
compound_stmt = begin_compound_stmt (in_try ? BCS_TRY_BLOCK : 0);
|
||||
/* Parse an (optional) statement-seq. */
|
||||
cp_parser_statement_seq_opt (parser, in_statement_expr_p);
|
||||
cp_parser_statement_seq_opt (parser, in_statement_expr);
|
||||
/* Finish the compound-statement. */
|
||||
finish_compound_stmt (compound_stmt);
|
||||
/* Consume the `}'. */
|
||||
@ -5870,7 +5871,7 @@ cp_parser_compound_statement (cp_parser *parser, bool in_statement_expr_p)
|
||||
statement-seq [opt] statement */
|
||||
|
||||
static void
|
||||
cp_parser_statement_seq_opt (cp_parser* parser, bool in_statement_expr_p)
|
||||
cp_parser_statement_seq_opt (cp_parser* parser, tree in_statement_expr)
|
||||
{
|
||||
/* Scan statements until there aren't any more. */
|
||||
while (true)
|
||||
@ -5881,7 +5882,7 @@ cp_parser_statement_seq_opt (cp_parser* parser, bool in_statement_expr_p)
|
||||
break;
|
||||
|
||||
/* Parse the statement. */
|
||||
cp_parser_statement (parser, in_statement_expr_p);
|
||||
cp_parser_statement (parser, in_statement_expr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5935,35 +5936,30 @@ cp_parser_selection_statement (cp_parser* parser)
|
||||
|
||||
if (keyword == RID_IF)
|
||||
{
|
||||
tree then_stmt;
|
||||
|
||||
/* Add the condition. */
|
||||
finish_if_stmt_cond (condition, statement);
|
||||
|
||||
/* Parse the then-clause. */
|
||||
then_stmt = cp_parser_implicitly_scoped_statement (parser);
|
||||
cp_parser_implicitly_scoped_statement (parser);
|
||||
finish_then_clause (statement);
|
||||
|
||||
/* If the next token is `else', parse the else-clause. */
|
||||
if (cp_lexer_next_token_is_keyword (parser->lexer,
|
||||
RID_ELSE))
|
||||
{
|
||||
tree else_stmt;
|
||||
|
||||
/* Consume the `else' keyword. */
|
||||
cp_lexer_consume_token (parser->lexer);
|
||||
begin_else_clause (statement);
|
||||
/* Parse the else-clause. */
|
||||
else_stmt
|
||||
= cp_parser_implicitly_scoped_statement (parser);
|
||||
cp_parser_implicitly_scoped_statement (parser);
|
||||
finish_else_clause (statement);
|
||||
}
|
||||
|
||||
/* Now we're all done with the if-statement. */
|
||||
finish_if_stmt ();
|
||||
finish_if_stmt (statement);
|
||||
}
|
||||
else
|
||||
{
|
||||
tree body;
|
||||
bool in_switch_statement_p;
|
||||
|
||||
/* Add the condition. */
|
||||
@ -5972,7 +5968,7 @@ cp_parser_selection_statement (cp_parser* parser)
|
||||
/* Parse the body of the switch-statement. */
|
||||
in_switch_statement_p = parser->in_switch_statement_p;
|
||||
parser->in_switch_statement_p = true;
|
||||
body = cp_parser_implicitly_scoped_statement (parser);
|
||||
cp_parser_implicitly_scoped_statement (parser);
|
||||
parser->in_switch_statement_p = in_switch_statement_p;
|
||||
|
||||
/* Now we're all done with the switch-statement. */
|
||||
@ -6365,7 +6361,7 @@ cp_parser_implicitly_scoped_statement (cp_parser* parser)
|
||||
if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE))
|
||||
{
|
||||
/* Create a compound-statement. */
|
||||
statement = begin_compound_stmt (/*has_no_scope=*/false);
|
||||
statement = begin_compound_stmt (0);
|
||||
/* Parse the dependent-statement. */
|
||||
cp_parser_statement (parser, false);
|
||||
/* Finish the dummy compound-statement. */
|
||||
@ -6373,7 +6369,7 @@ cp_parser_implicitly_scoped_statement (cp_parser* parser)
|
||||
}
|
||||
/* Otherwise, we simply parse the statement directly. */
|
||||
else
|
||||
statement = cp_parser_compound_statement (parser, false);
|
||||
statement = cp_parser_compound_statement (parser, NULL, false);
|
||||
|
||||
/* Return the statement. */
|
||||
return statement;
|
||||
@ -6387,21 +6383,17 @@ cp_parser_implicitly_scoped_statement (cp_parser* parser)
|
||||
static void
|
||||
cp_parser_already_scoped_statement (cp_parser* parser)
|
||||
{
|
||||
/* If the token is not a `{', then we must take special action. */
|
||||
if (cp_lexer_next_token_is_not(parser->lexer, CPP_OPEN_BRACE))
|
||||
{
|
||||
tree statement;
|
||||
|
||||
/* Create a compound-statement. */
|
||||
statement = begin_compound_stmt (/*has_no_scope=*/true);
|
||||
/* Parse the dependent-statement. */
|
||||
cp_parser_statement (parser, false);
|
||||
/* Finish the dummy compound-statement. */
|
||||
finish_compound_stmt (statement);
|
||||
}
|
||||
/* Otherwise, we simply parse the statement directly. */
|
||||
else
|
||||
/* If the token is a `{', then we must take special action. */
|
||||
if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE))
|
||||
cp_parser_statement (parser, false);
|
||||
else
|
||||
{
|
||||
/* Avoid calling cp_parser_compound_statement, so that we
|
||||
don't create a new scope. Do everything else by hand. */
|
||||
cp_parser_require (parser, CPP_OPEN_BRACE, "`{'");
|
||||
cp_parser_statement_seq_opt (parser, false);
|
||||
cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
|
||||
}
|
||||
}
|
||||
|
||||
/* Declarations [gram.dcl.dcl] */
|
||||
@ -11618,7 +11610,7 @@ cp_parser_parameter_declaration (cp_parser *parser,
|
||||
static void
|
||||
cp_parser_function_body (cp_parser *parser)
|
||||
{
|
||||
cp_parser_compound_statement (parser, false);
|
||||
cp_parser_compound_statement (parser, NULL, false);
|
||||
}
|
||||
|
||||
/* Parse a ctor-initializer-opt followed by a function-body. Return
|
||||
@ -13265,7 +13257,7 @@ cp_parser_try_block (cp_parser* parser)
|
||||
|
||||
cp_parser_require_keyword (parser, RID_TRY, "`try'");
|
||||
try_block = begin_try_block ();
|
||||
cp_parser_compound_statement (parser, false);
|
||||
cp_parser_compound_statement (parser, NULL, true);
|
||||
finish_try_block (try_block);
|
||||
cp_parser_handler_seq (parser);
|
||||
finish_handler_sequence (try_block);
|
||||
@ -13341,7 +13333,7 @@ cp_parser_handler (cp_parser* parser)
|
||||
declaration = cp_parser_exception_declaration (parser);
|
||||
finish_handler_parms (declaration, handler);
|
||||
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
|
||||
cp_parser_compound_statement (parser, false);
|
||||
cp_parser_compound_statement (parser, NULL, false);
|
||||
finish_handler (handler);
|
||||
}
|
||||
|
||||
|
93
gcc/cp/pt.c
93
gcc/cp/pt.c
@ -42,6 +42,7 @@ Boston, MA 02111-1307, USA. */
|
||||
#include "toplev.h"
|
||||
#include "rtl.h"
|
||||
#include "timevar.h"
|
||||
#include "tree-iterator.h"
|
||||
|
||||
/* The type of functions taking a tree, and some additional data, and
|
||||
returning an int. */
|
||||
@ -7615,22 +7616,6 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
||||
in_decl),
|
||||
NULL_TREE);
|
||||
|
||||
case STMT_EXPR:
|
||||
/* This processing should really occur in tsubst_expr. However,
|
||||
tsubst_expr does not recurse into expressions, since it
|
||||
assumes that there aren't any statements inside them. So, we
|
||||
need to expand the STMT_EXPR here. */
|
||||
if (!processing_template_decl)
|
||||
{
|
||||
tree stmt_expr = begin_stmt_expr ();
|
||||
|
||||
tsubst_expr (STMT_EXPR_STMT (t), args,
|
||||
complain | tf_stmt_expr_cmpd, in_decl);
|
||||
return finish_stmt_expr (stmt_expr, false);
|
||||
}
|
||||
|
||||
return t;
|
||||
|
||||
case COND_EXPR:
|
||||
case MODOP_EXPR:
|
||||
case PSEUDO_DTOR_EXPR:
|
||||
@ -7752,20 +7737,26 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
||||
static tree
|
||||
tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
||||
{
|
||||
tree stmt, tmp;
|
||||
tsubst_flags_t stmt_expr
|
||||
= complain & (tf_stmt_expr_cmpd | tf_stmt_expr_body);
|
||||
/* Live only within one (recursive) call to tsubst_expr. We use
|
||||
this to pass the statement expression node from the STMT_EXPR
|
||||
to the EXPR_STMT that is its result. */
|
||||
static tree cur_stmt_expr;
|
||||
|
||||
tree stmt, tmp;
|
||||
|
||||
complain ^= stmt_expr;
|
||||
if (t == NULL_TREE || t == error_mark_node)
|
||||
return t;
|
||||
|
||||
if (!STATEMENT_CODE_P (TREE_CODE (t)))
|
||||
return tsubst_copy_and_build (t, args, complain, in_decl,
|
||||
/*function_p=*/false);
|
||||
|
||||
switch (TREE_CODE (t))
|
||||
{
|
||||
case STATEMENT_LIST:
|
||||
{
|
||||
tree_stmt_iterator i;
|
||||
for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
|
||||
tsubst_expr (tsi_stmt (i), args, complain, in_decl);
|
||||
break;
|
||||
}
|
||||
|
||||
case CTOR_INITIALIZER:
|
||||
prep_stmt (t);
|
||||
finish_mem_initializers (tsubst_initializer_list
|
||||
@ -7778,6 +7769,19 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
||||
args, complain, in_decl));
|
||||
break;
|
||||
|
||||
case STMT_EXPR:
|
||||
{
|
||||
tree old_stmt_expr = cur_stmt_expr;
|
||||
tree stmt_expr = begin_stmt_expr ();
|
||||
|
||||
cur_stmt_expr = stmt_expr;
|
||||
tsubst_expr (STMT_EXPR_STMT (t), args, complain, in_decl);
|
||||
stmt_expr = finish_stmt_expr (stmt_expr, false);
|
||||
cur_stmt_expr = old_stmt_expr;
|
||||
|
||||
return stmt_expr;
|
||||
}
|
||||
|
||||
case EXPR_STMT:
|
||||
{
|
||||
tree r;
|
||||
@ -7785,8 +7789,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
||||
prep_stmt (t);
|
||||
|
||||
r = tsubst_expr (EXPR_STMT_EXPR (t), args, complain, in_decl);
|
||||
if (stmt_expr & tf_stmt_expr_body && !TREE_CHAIN (t))
|
||||
finish_stmt_expr_expr (r);
|
||||
if (EXPR_STMT_STMT_EXPR_RESULT (t))
|
||||
finish_stmt_expr_expr (r, cur_stmt_expr);
|
||||
else
|
||||
finish_expr_stmt (r);
|
||||
break;
|
||||
@ -7861,12 +7865,9 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
||||
}
|
||||
|
||||
/* A DECL_STMT can also be used as an expression, in the condition
|
||||
clause of an if/for/while construct. If we aren't followed by
|
||||
another statement, return our decl. */
|
||||
if (TREE_CHAIN (t) == NULL_TREE)
|
||||
return decl;
|
||||
clause of an if/for/while construct. */
|
||||
return decl;
|
||||
}
|
||||
break;
|
||||
|
||||
case FOR_STMT:
|
||||
{
|
||||
@ -7916,21 +7917,17 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
||||
finish_if_stmt_cond (tsubst_expr (IF_COND (t),
|
||||
args, complain, in_decl),
|
||||
stmt);
|
||||
tsubst_expr (THEN_CLAUSE (t), args, complain, in_decl);
|
||||
finish_then_clause (stmt);
|
||||
|
||||
if (tmp = THEN_CLAUSE (t), tmp)
|
||||
if (ELSE_CLAUSE (t))
|
||||
{
|
||||
tsubst_expr (tmp, args, complain, in_decl);
|
||||
finish_then_clause (stmt);
|
||||
}
|
||||
|
||||
if (tmp = ELSE_CLAUSE (t), tmp)
|
||||
{
|
||||
begin_else_clause ();
|
||||
tsubst_expr (tmp, args, complain, in_decl);
|
||||
begin_else_clause (stmt);
|
||||
tsubst_expr (ELSE_CLAUSE (t), args, complain, in_decl);
|
||||
finish_else_clause (stmt);
|
||||
}
|
||||
|
||||
finish_if_stmt ();
|
||||
finish_if_stmt (stmt);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -7940,11 +7937,10 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
||||
if (COMPOUND_STMT_BODY_BLOCK (t))
|
||||
stmt = begin_function_body ();
|
||||
else
|
||||
stmt = begin_compound_stmt (COMPOUND_STMT_NO_SCOPE (t));
|
||||
stmt = begin_compound_stmt (COMPOUND_STMT_TRY_BLOCK (t)
|
||||
? BCS_TRY_BLOCK : 0);
|
||||
|
||||
tsubst_expr (COMPOUND_BODY (t), args,
|
||||
complain | ((stmt_expr & tf_stmt_expr_cmpd) << 1),
|
||||
in_decl);
|
||||
tsubst_expr (COMPOUND_BODY (t), args, complain, in_decl);
|
||||
|
||||
if (COMPOUND_STMT_BODY_BLOCK (t))
|
||||
finish_function_body (stmt);
|
||||
@ -8053,7 +8049,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
||||
stmt = begin_handler ();
|
||||
if (HANDLER_PARMS (t))
|
||||
{
|
||||
decl = DECL_STMT_DECL (HANDLER_PARMS (t));
|
||||
decl = HANDLER_PARMS (t);
|
||||
decl = tsubst (decl, args, complain, in_decl);
|
||||
/* Prevent instantiate_decl from trying to instantiate
|
||||
this variable. We've already done all that needs to be
|
||||
@ -8074,10 +8070,13 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!STATEMENT_CODE_P (TREE_CODE (t)))
|
||||
return tsubst_copy_and_build (t, args, complain, in_decl,
|
||||
/*function_p=*/false);
|
||||
abort ();
|
||||
}
|
||||
|
||||
return tsubst_expr (TREE_CHAIN (t), args, complain | stmt_expr, in_decl);
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* T is a postfix-expression that is not being used in a function
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "debug.h"
|
||||
#include "diagnostic.h"
|
||||
#include "cgraph.h"
|
||||
#include "tree-iterator.h"
|
||||
|
||||
/* There routines provide a modular interface to perform many parsing
|
||||
operations. They may therefore be used during actual parsing, or
|
||||
@ -60,23 +61,6 @@ static void emit_associated_thunks (tree);
|
||||
static tree finalize_nrv_r (tree *, int *, void *);
|
||||
|
||||
|
||||
/* Finish processing the COND, the SUBSTMT condition for STMT. */
|
||||
|
||||
#define FINISH_COND(COND, STMT, SUBSTMT) \
|
||||
do { \
|
||||
if (last_tree != (STMT)) \
|
||||
{ \
|
||||
RECHAIN_STMTS (STMT, SUBSTMT); \
|
||||
if (!processing_template_decl) \
|
||||
{ \
|
||||
(COND) = build_tree_list (SUBSTMT, COND); \
|
||||
(SUBSTMT) = (COND); \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
(SUBSTMT) = (COND); \
|
||||
} while (0)
|
||||
|
||||
/* Deferred Access Checking Overview
|
||||
---------------------------------
|
||||
|
||||
@ -332,45 +316,99 @@ anon_aggr_type_p (tree node)
|
||||
|
||||
/* Finish a scope. */
|
||||
|
||||
tree
|
||||
do_poplevel (void)
|
||||
static tree
|
||||
do_poplevel (tree stmt_list)
|
||||
{
|
||||
tree block = NULL_TREE;
|
||||
tree block = NULL;
|
||||
|
||||
if (stmts_are_full_exprs_p ())
|
||||
{
|
||||
tree scope_stmts = NULL_TREE;
|
||||
block = poplevel (kept_level_p (), 1, 0);
|
||||
|
||||
block = poplevel (kept_level_p (), 1, 0);
|
||||
if (!processing_template_decl)
|
||||
{
|
||||
/* This needs to come after the poplevel so that partial scopes
|
||||
are properly nested. */
|
||||
scope_stmts = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0);
|
||||
if (block)
|
||||
{
|
||||
SCOPE_STMT_BLOCK (TREE_PURPOSE (scope_stmts)) = block;
|
||||
SCOPE_STMT_BLOCK (TREE_VALUE (scope_stmts)) = block;
|
||||
}
|
||||
}
|
||||
stmt_list = pop_stmt_list (stmt_list);
|
||||
|
||||
if (!processing_template_decl)
|
||||
{
|
||||
stmt_list = c_build_bind_expr (block, stmt_list);
|
||||
/* ??? See c_end_compound_stmt re statement expressions. */
|
||||
}
|
||||
|
||||
return block;
|
||||
return stmt_list;
|
||||
}
|
||||
|
||||
/* Begin a new scope. */
|
||||
|
||||
void
|
||||
static tree
|
||||
do_pushlevel (scope_kind sk)
|
||||
{
|
||||
tree ret = push_stmt_list ();
|
||||
if (stmts_are_full_exprs_p ())
|
||||
begin_scope (sk, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Finish processing a conditional. COND contains the raw expression;
|
||||
STMT_P is a stacked statement list that will contain any other stmts
|
||||
emitting during the processing of this conditional. Place the
|
||||
resulting conditional back in STMT_P. */
|
||||
|
||||
static void
|
||||
finish_cond (tree cond, tree *stmt_p)
|
||||
{
|
||||
tree stmt = *stmt_p;
|
||||
stmt = pop_stmt_list (stmt);
|
||||
if (TREE_SIDE_EFFECTS (stmt))
|
||||
{
|
||||
if (!processing_template_decl)
|
||||
add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0);
|
||||
begin_scope (sk, NULL);
|
||||
/* If stmt is set, it will be a DECL_STMT. When processing a template,
|
||||
using this is enough, because tsubst_expr considers the result of a
|
||||
DECL_STMT to be the DECL. When generating real code, we build a
|
||||
funny little TREE_LIST thingy that's handled by the gimplifier. */
|
||||
/* ??? The object of this thingy is to get the DECL declared in the
|
||||
proper scope. Seems like this oughtn't be terribly hard with the
|
||||
new explicit uses of BIND_EXPR and such. */
|
||||
if (processing_template_decl)
|
||||
{
|
||||
stmt = expr_only (stmt);
|
||||
if (!stmt)
|
||||
abort ();
|
||||
}
|
||||
else
|
||||
stmt = build_tree_list (stmt, cond);
|
||||
}
|
||||
else
|
||||
stmt = cond;
|
||||
*stmt_p = stmt;
|
||||
}
|
||||
|
||||
/* If *COND_P specifies a conditional with a declaration, transform the
|
||||
loop such that
|
||||
while (A x = 42) { }
|
||||
for (; A x = 42;) { }
|
||||
becomes
|
||||
while (true) { A x = 42; if (!x) break; }
|
||||
for (;;) { A x = 42; if (!x) break; }
|
||||
The statement list for the loop body should have been pushed. */
|
||||
|
||||
static void
|
||||
simplify_loop_decl_cond (tree *cond_p)
|
||||
{
|
||||
tree cond = *cond_p;
|
||||
if (TREE_CODE (cond) == TREE_LIST)
|
||||
{
|
||||
tree if_stmt;
|
||||
|
||||
*cond_p = boolean_true_node;
|
||||
|
||||
if_stmt = begin_if_stmt ();
|
||||
add_stmt (TREE_PURPOSE (cond));
|
||||
cond = build_unary_op (TRUTH_NOT_EXPR, TREE_VALUE (cond), 0);
|
||||
finish_if_stmt_cond (cond, if_stmt);
|
||||
finish_break_stmt ();
|
||||
finish_then_clause (if_stmt);
|
||||
finish_if_stmt (if_stmt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Finish a goto-statement. */
|
||||
|
||||
tree
|
||||
@ -432,8 +470,12 @@ finish_expr_stmt (tree expr)
|
||||
expr = convert_to_void (expr, "statement");
|
||||
else if (!type_dependent_expression_p (expr))
|
||||
convert_to_void (build_non_dependent_expr (expr), "statement");
|
||||
|
||||
r = add_stmt (build_stmt (EXPR_STMT, expr));
|
||||
|
||||
/* Simplification of inner statement expressions, compound exprs,
|
||||
etc can result in the us already having an EXPR_STMT. */
|
||||
if (TREE_CODE (expr) != EXPR_STMT)
|
||||
expr = build_stmt (EXPR_STMT, expr);
|
||||
r = add_stmt (expr);
|
||||
}
|
||||
|
||||
finish_stmt ();
|
||||
@ -448,10 +490,12 @@ finish_expr_stmt (tree expr)
|
||||
tree
|
||||
begin_if_stmt (void)
|
||||
{
|
||||
tree r;
|
||||
do_pushlevel (sk_block);
|
||||
tree r, scope;
|
||||
scope = do_pushlevel (sk_block);
|
||||
r = build_stmt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
|
||||
TREE_CHAIN (r) = scope;
|
||||
add_stmt (r);
|
||||
IF_COND (r) = push_stmt_list ();
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -462,7 +506,8 @@ void
|
||||
finish_if_stmt_cond (tree cond, tree if_stmt)
|
||||
{
|
||||
cond = maybe_convert_cond (cond);
|
||||
FINISH_COND (cond, if_stmt, IF_COND (if_stmt));
|
||||
finish_cond (cond, &IF_COND (if_stmt));
|
||||
THEN_CLAUSE (if_stmt) = push_stmt_list ();
|
||||
}
|
||||
|
||||
/* Finish the then-clause of an if-statement, which may be given by
|
||||
@ -471,15 +516,16 @@ finish_if_stmt_cond (tree cond, tree if_stmt)
|
||||
tree
|
||||
finish_then_clause (tree if_stmt)
|
||||
{
|
||||
RECHAIN_STMTS (if_stmt, THEN_CLAUSE (if_stmt));
|
||||
THEN_CLAUSE (if_stmt) = pop_stmt_list (THEN_CLAUSE (if_stmt));
|
||||
return if_stmt;
|
||||
}
|
||||
|
||||
/* Begin the else-clause of an if-statement. */
|
||||
|
||||
void
|
||||
begin_else_clause (void)
|
||||
void
|
||||
begin_else_clause (tree if_stmt)
|
||||
{
|
||||
ELSE_CLAUSE (if_stmt) = push_stmt_list ();
|
||||
}
|
||||
|
||||
/* Finish the else-clause of an if-statement, which may be given by
|
||||
@ -488,16 +534,18 @@ begin_else_clause (void)
|
||||
void
|
||||
finish_else_clause (tree if_stmt)
|
||||
{
|
||||
RECHAIN_STMTS (if_stmt, ELSE_CLAUSE (if_stmt));
|
||||
ELSE_CLAUSE (if_stmt) = pop_stmt_list (ELSE_CLAUSE (if_stmt));
|
||||
}
|
||||
|
||||
/* Finish an if-statement. */
|
||||
|
||||
void
|
||||
finish_if_stmt (void)
|
||||
finish_if_stmt (tree if_stmt)
|
||||
{
|
||||
tree scope = TREE_CHAIN (if_stmt);
|
||||
TREE_CHAIN (if_stmt) = NULL;
|
||||
add_stmt (do_poplevel (scope));
|
||||
finish_stmt ();
|
||||
do_poplevel ();
|
||||
}
|
||||
|
||||
/* Begin a while-statement. Returns a newly created WHILE_STMT if
|
||||
@ -509,7 +557,8 @@ begin_while_stmt (void)
|
||||
tree r;
|
||||
r = build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE);
|
||||
add_stmt (r);
|
||||
do_pushlevel (sk_block);
|
||||
WHILE_BODY (r) = do_pushlevel (sk_block);
|
||||
WHILE_COND (r) = push_stmt_list ();
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -520,29 +569,8 @@ void
|
||||
finish_while_stmt_cond (tree cond, tree while_stmt)
|
||||
{
|
||||
cond = maybe_convert_cond (cond);
|
||||
if (processing_template_decl)
|
||||
/* Don't mess with condition decls in a template. */
|
||||
FINISH_COND (cond, while_stmt, WHILE_COND (while_stmt));
|
||||
else if (getdecls () == NULL_TREE)
|
||||
/* It was a simple condition; install it. */
|
||||
WHILE_COND (while_stmt) = cond;
|
||||
else
|
||||
{
|
||||
/* If there was a declaration in the condition, we can't leave it
|
||||
there; transform
|
||||
while (A x = 42) { }
|
||||
to
|
||||
while (true) { A x = 42; if (!x) break; } */
|
||||
tree if_stmt;
|
||||
WHILE_COND (while_stmt) = boolean_true_node;
|
||||
|
||||
if_stmt = begin_if_stmt ();
|
||||
cond = build_unary_op (TRUTH_NOT_EXPR, cond, 0);
|
||||
finish_if_stmt_cond (cond, if_stmt);
|
||||
finish_break_stmt ();
|
||||
finish_then_clause (if_stmt);
|
||||
finish_if_stmt ();
|
||||
}
|
||||
finish_cond (cond, &WHILE_COND (while_stmt));
|
||||
simplify_loop_decl_cond (&WHILE_COND (while_stmt));
|
||||
}
|
||||
|
||||
/* Finish a while-statement, which may be given by WHILE_STMT. */
|
||||
@ -550,8 +578,7 @@ finish_while_stmt_cond (tree cond, tree while_stmt)
|
||||
void
|
||||
finish_while_stmt (tree while_stmt)
|
||||
{
|
||||
do_poplevel ();
|
||||
RECHAIN_STMTS (while_stmt, WHILE_BODY (while_stmt));
|
||||
WHILE_BODY (while_stmt) = do_poplevel (WHILE_BODY (while_stmt));
|
||||
finish_stmt ();
|
||||
}
|
||||
|
||||
@ -563,6 +590,7 @@ begin_do_stmt (void)
|
||||
{
|
||||
tree r = build_stmt (DO_STMT, NULL_TREE, NULL_TREE);
|
||||
add_stmt (r);
|
||||
DO_BODY (r) = push_stmt_list ();
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -571,7 +599,7 @@ begin_do_stmt (void)
|
||||
void
|
||||
finish_do_body (tree do_stmt)
|
||||
{
|
||||
RECHAIN_STMTS (do_stmt, DO_BODY (do_stmt));
|
||||
DO_BODY (do_stmt) = pop_stmt_list (DO_BODY (do_stmt));
|
||||
}
|
||||
|
||||
/* Finish a do-statement, which may be given by DO_STMT, and whose
|
||||
@ -620,10 +648,9 @@ begin_for_stmt (void)
|
||||
|
||||
r = build_stmt (FOR_STMT, NULL_TREE, NULL_TREE,
|
||||
NULL_TREE, NULL_TREE);
|
||||
NEW_FOR_SCOPE_P (r) = flag_new_for_scope > 0;
|
||||
if (NEW_FOR_SCOPE_P (r))
|
||||
do_pushlevel (sk_for);
|
||||
add_stmt (r);
|
||||
|
||||
if (flag_new_for_scope > 0)
|
||||
TREE_CHAIN (r) = do_pushlevel (sk_for);
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -634,9 +661,9 @@ begin_for_stmt (void)
|
||||
void
|
||||
finish_for_init_stmt (tree for_stmt)
|
||||
{
|
||||
if (last_tree != for_stmt)
|
||||
RECHAIN_STMTS (for_stmt, FOR_INIT_STMT (for_stmt));
|
||||
do_pushlevel (sk_block);
|
||||
add_stmt (for_stmt);
|
||||
FOR_BODY (for_stmt) = do_pushlevel (sk_block);
|
||||
FOR_COND (for_stmt) = push_stmt_list ();
|
||||
}
|
||||
|
||||
/* Finish the COND of a for-statement, which may be given by
|
||||
@ -646,29 +673,9 @@ void
|
||||
finish_for_cond (tree cond, tree for_stmt)
|
||||
{
|
||||
cond = maybe_convert_cond (cond);
|
||||
if (processing_template_decl)
|
||||
/* Don't mess with condition decls in a template. */
|
||||
FINISH_COND (cond, for_stmt, FOR_COND (for_stmt));
|
||||
else if (getdecls () == NULL_TREE)
|
||||
/* It was a simple condition; install it. */
|
||||
FOR_COND (for_stmt) = cond;
|
||||
else
|
||||
{
|
||||
/* If there was a declaration in the condition, we can't leave it
|
||||
there; transform
|
||||
for (; A x = 42;) { }
|
||||
to
|
||||
for (;;) { A x = 42; if (!x) break; } */
|
||||
tree if_stmt;
|
||||
FOR_COND (for_stmt) = NULL_TREE;
|
||||
|
||||
if_stmt = begin_if_stmt ();
|
||||
cond = build_unary_op (TRUTH_NOT_EXPR, cond, 0);
|
||||
finish_if_stmt_cond (cond, if_stmt);
|
||||
finish_break_stmt ();
|
||||
finish_then_clause (if_stmt);
|
||||
finish_if_stmt ();
|
||||
}
|
||||
finish_cond (cond, &FOR_COND (for_stmt));
|
||||
if (FOR_COND (for_stmt))
|
||||
simplify_loop_decl_cond (&FOR_COND (for_stmt));
|
||||
}
|
||||
|
||||
/* Finish the increment-EXPRESSION in a for-statement, which may be
|
||||
@ -694,11 +701,16 @@ finish_for_expr (tree expr, tree for_stmt)
|
||||
void
|
||||
finish_for_stmt (tree for_stmt)
|
||||
{
|
||||
FOR_BODY (for_stmt) = do_poplevel (FOR_BODY (for_stmt));
|
||||
|
||||
/* Pop the scope for the body of the loop. */
|
||||
do_poplevel ();
|
||||
RECHAIN_STMTS (for_stmt, FOR_BODY (for_stmt));
|
||||
if (NEW_FOR_SCOPE_P (for_stmt))
|
||||
do_poplevel ();
|
||||
if (flag_new_for_scope > 0)
|
||||
{
|
||||
tree scope = TREE_CHAIN (for_stmt);
|
||||
TREE_CHAIN (for_stmt) = NULL;
|
||||
add_stmt (do_poplevel (scope));
|
||||
}
|
||||
|
||||
finish_stmt ();
|
||||
}
|
||||
|
||||
@ -724,10 +736,16 @@ finish_continue_stmt (void)
|
||||
tree
|
||||
begin_switch_stmt (void)
|
||||
{
|
||||
tree r;
|
||||
do_pushlevel (sk_block);
|
||||
tree r, scope;
|
||||
|
||||
r = build_stmt (SWITCH_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
|
||||
|
||||
scope = do_pushlevel (sk_block);
|
||||
TREE_CHAIN (r) = scope;
|
||||
|
||||
add_stmt (r);
|
||||
SWITCH_COND (r) = push_stmt_list ();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -770,9 +788,10 @@ finish_switch_cond (tree cond, tree switch_stmt)
|
||||
cond = index;
|
||||
}
|
||||
}
|
||||
FINISH_COND (cond, switch_stmt, SWITCH_COND (switch_stmt));
|
||||
finish_cond (cond, &SWITCH_COND (switch_stmt));
|
||||
SWITCH_TYPE (switch_stmt) = orig_type;
|
||||
push_switch (switch_stmt);
|
||||
SWITCH_BODY (switch_stmt) = push_stmt_list ();
|
||||
}
|
||||
|
||||
/* Finish the body of a switch-statement, which may be given by
|
||||
@ -781,10 +800,15 @@ finish_switch_cond (tree cond, tree switch_stmt)
|
||||
void
|
||||
finish_switch_stmt (tree switch_stmt)
|
||||
{
|
||||
RECHAIN_STMTS (switch_stmt, SWITCH_BODY (switch_stmt));
|
||||
tree scope;
|
||||
|
||||
SWITCH_BODY (switch_stmt) = pop_stmt_list (SWITCH_BODY (switch_stmt));
|
||||
pop_switch ();
|
||||
finish_stmt ();
|
||||
do_poplevel ();
|
||||
|
||||
scope = TREE_CHAIN (switch_stmt);
|
||||
TREE_CHAIN (switch_stmt) = NULL;
|
||||
add_stmt (do_poplevel (scope));
|
||||
}
|
||||
|
||||
/* Begin a try-block. Returns a newly-created TRY_BLOCK if
|
||||
@ -795,6 +819,7 @@ begin_try_block (void)
|
||||
{
|
||||
tree r = build_stmt (TRY_BLOCK, NULL_TREE, NULL_TREE);
|
||||
add_stmt (r);
|
||||
TRY_STMTS (r) = push_stmt_list ();
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -803,9 +828,8 @@ begin_try_block (void)
|
||||
tree
|
||||
begin_function_try_block (void)
|
||||
{
|
||||
tree r = build_stmt (TRY_BLOCK, NULL_TREE, NULL_TREE);
|
||||
tree r = begin_try_block ();
|
||||
FN_TRY_BLOCK_P (r) = 1;
|
||||
add_stmt (r);
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -814,7 +838,8 @@ begin_function_try_block (void)
|
||||
void
|
||||
finish_try_block (tree try_block)
|
||||
{
|
||||
RECHAIN_STMTS (try_block, TRY_STMTS (try_block));
|
||||
TRY_STMTS (try_block) = pop_stmt_list (TRY_STMTS (try_block));
|
||||
TRY_HANDLERS (try_block) = push_stmt_list ();
|
||||
}
|
||||
|
||||
/* Finish the body of a cleanup try-block, which may be given by
|
||||
@ -823,7 +848,7 @@ finish_try_block (tree try_block)
|
||||
void
|
||||
finish_cleanup_try_block (tree try_block)
|
||||
{
|
||||
RECHAIN_STMTS (try_block, TRY_STMTS (try_block));
|
||||
TRY_STMTS (try_block) = pop_stmt_list (TRY_STMTS (try_block));
|
||||
}
|
||||
|
||||
/* Finish an implicitly generated try-block, with a cleanup is given
|
||||
@ -841,16 +866,9 @@ finish_cleanup (tree cleanup, tree try_block)
|
||||
void
|
||||
finish_function_try_block (tree try_block)
|
||||
{
|
||||
if (TREE_CHAIN (try_block)
|
||||
&& TREE_CODE (TREE_CHAIN (try_block)) == CTOR_INITIALIZER)
|
||||
{
|
||||
/* Chain the compound statement after the CTOR_INITIALIZER. */
|
||||
TREE_CHAIN (TREE_CHAIN (try_block)) = last_tree;
|
||||
/* And make the CTOR_INITIALIZER the body of the try-block. */
|
||||
RECHAIN_STMTS (try_block, TRY_STMTS (try_block));
|
||||
}
|
||||
else
|
||||
RECHAIN_STMTS (try_block, TRY_STMTS (try_block));
|
||||
finish_try_block (try_block);
|
||||
/* FIXME : something queer about CTOR_INITIALIZER somehow following
|
||||
the try block, but moving it inside. */
|
||||
in_function_try_handler = 1;
|
||||
}
|
||||
|
||||
@ -860,7 +878,7 @@ finish_function_try_block (tree try_block)
|
||||
void
|
||||
finish_handler_sequence (tree try_block)
|
||||
{
|
||||
RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block));
|
||||
TRY_HANDLERS (try_block) = pop_stmt_list (TRY_HANDLERS (try_block));
|
||||
check_handlers (TRY_HANDLERS (try_block));
|
||||
}
|
||||
|
||||
@ -870,8 +888,7 @@ void
|
||||
finish_function_handler_sequence (tree try_block)
|
||||
{
|
||||
in_function_try_handler = 0;
|
||||
RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block));
|
||||
check_handlers (TRY_HANDLERS (try_block));
|
||||
finish_handler_sequence (try_block);
|
||||
}
|
||||
|
||||
/* Begin a handler. Returns a HANDLER if appropriate. */
|
||||
@ -880,11 +897,14 @@ tree
|
||||
begin_handler (void)
|
||||
{
|
||||
tree r;
|
||||
|
||||
r = build_stmt (HANDLER, NULL_TREE, NULL_TREE);
|
||||
add_stmt (r);
|
||||
|
||||
/* Create a binding level for the eh_info and the exception object
|
||||
cleanup. */
|
||||
do_pushlevel (sk_catch);
|
||||
HANDLER_BODY (r) = do_pushlevel (sk_catch);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -902,8 +922,7 @@ finish_handler_parms (tree decl, tree handler)
|
||||
{
|
||||
decl = pushdecl (decl);
|
||||
decl = push_template_decl (decl);
|
||||
add_decl_stmt (decl);
|
||||
RECHAIN_STMTS (handler, HANDLER_PARMS (handler));
|
||||
HANDLER_PARMS (handler) = decl;
|
||||
type = TREE_TYPE (decl);
|
||||
}
|
||||
}
|
||||
@ -923,8 +942,7 @@ finish_handler (tree handler)
|
||||
{
|
||||
if (!processing_template_decl)
|
||||
expand_end_catch_block ();
|
||||
do_poplevel ();
|
||||
RECHAIN_STMTS (handler, HANDLER_BODY (handler));
|
||||
HANDLER_BODY (handler) = do_poplevel (HANDLER_BODY (handler));
|
||||
}
|
||||
|
||||
/* Begin a compound-statement. If HAS_NO_SCOPE is true, the
|
||||
@ -932,58 +950,50 @@ finish_handler (tree handler)
|
||||
COMPOUND_STMT. */
|
||||
|
||||
tree
|
||||
begin_compound_stmt (bool has_no_scope)
|
||||
begin_compound_stmt (unsigned int flags)
|
||||
{
|
||||
tree r;
|
||||
int is_try = 0;
|
||||
tree r;
|
||||
|
||||
r = build_stmt (COMPOUND_STMT, NULL_TREE);
|
||||
if (flags & BCS_NO_SCOPE)
|
||||
{
|
||||
r = push_stmt_list ();
|
||||
STATEMENT_LIST_NO_SCOPE (r) = 1;
|
||||
|
||||
if (last_tree && TREE_CODE (last_tree) == TRY_BLOCK)
|
||||
is_try = 1;
|
||||
|
||||
add_stmt (r);
|
||||
if (has_no_scope)
|
||||
COMPOUND_STMT_NO_SCOPE (r) = 1;
|
||||
|
||||
last_expr_type = NULL_TREE;
|
||||
|
||||
if (!has_no_scope)
|
||||
do_pushlevel (is_try ? sk_try : sk_block);
|
||||
/* Normally, we try hard to keep the BLOCK for a statement-expression.
|
||||
But, if it's a statement-expression with a scopeless block, there's
|
||||
nothing to keep, and we don't want to accidentally keep a block
|
||||
*inside* the scopeless block. */
|
||||
keep_next_level (false);
|
||||
}
|
||||
else
|
||||
/* Normally, we try hard to keep the BLOCK for a
|
||||
statement-expression. But, if it's a statement-expression with
|
||||
a scopeless block, there's nothing to keep, and we don't want
|
||||
to accidentally keep a block *inside* the scopeless block. */
|
||||
keep_next_level (false);
|
||||
r = do_pushlevel (flags & BCS_TRY_BLOCK ? sk_try : sk_block);
|
||||
|
||||
if (flags & BCS_FN_BODY || processing_template_decl)
|
||||
{
|
||||
r = build (COMPOUND_STMT, NULL_TREE, r);
|
||||
COMPOUND_STMT_TRY_BLOCK (r) = (flags & BCS_TRY_BLOCK) != 0;
|
||||
COMPOUND_STMT_BODY_BLOCK (r) = (flags & BCS_FN_BODY) != 0;
|
||||
TREE_SIDE_EFFECTS (r) = 1;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Finish a compound-statement, which is given by COMPOUND_STMT. */
|
||||
|
||||
tree
|
||||
finish_compound_stmt (tree compound_stmt)
|
||||
void
|
||||
finish_compound_stmt (tree stmt)
|
||||
{
|
||||
tree r;
|
||||
tree t;
|
||||
|
||||
if (COMPOUND_STMT_NO_SCOPE (compound_stmt))
|
||||
r = NULL_TREE;
|
||||
if (TREE_CODE (stmt) == COMPOUND_STMT)
|
||||
COMPOUND_BODY (stmt) = do_poplevel (COMPOUND_BODY (stmt));
|
||||
else if (STATEMENT_LIST_NO_SCOPE (stmt))
|
||||
stmt = pop_stmt_list (stmt);
|
||||
else
|
||||
r = do_poplevel ();
|
||||
stmt = do_poplevel (stmt);
|
||||
|
||||
RECHAIN_STMTS (compound_stmt, COMPOUND_BODY (compound_stmt));
|
||||
|
||||
/* When we call finish_stmt we will lose LAST_EXPR_TYPE. But, since
|
||||
the precise purpose of that variable is store the type of the
|
||||
last expression statement within the last compound statement, we
|
||||
preserve the value. */
|
||||
t = last_expr_type;
|
||||
/* ??? See c_end_compound_stmt wrt statement expressions. */
|
||||
add_stmt (stmt);
|
||||
finish_stmt ();
|
||||
last_expr_type = t;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Finish an asm-statement, whose components are a STRING, some
|
||||
@ -1090,7 +1100,7 @@ finish_label_decl (tree name)
|
||||
void
|
||||
finish_decl_cleanup (tree decl, tree cleanup)
|
||||
{
|
||||
add_stmt (build_stmt (CLEANUP_STMT, decl, cleanup));
|
||||
push_cleanup (decl, cleanup, false);
|
||||
}
|
||||
|
||||
/* If the current scope exits with an exception, run CLEANUP. */
|
||||
@ -1098,9 +1108,7 @@ finish_decl_cleanup (tree decl, tree cleanup)
|
||||
void
|
||||
finish_eh_cleanup (tree cleanup)
|
||||
{
|
||||
tree r = build_stmt (CLEANUP_STMT, NULL_TREE, cleanup);
|
||||
CLEANUP_EH_ONLY (r) = 1;
|
||||
add_stmt (r);
|
||||
push_cleanup (NULL, cleanup, true);
|
||||
}
|
||||
|
||||
/* The MEM_INITS is a list of mem-initializers, in reverse of the
|
||||
@ -1120,14 +1128,6 @@ finish_mem_initializers (tree mem_inits)
|
||||
emit_mem_initializers (mem_inits);
|
||||
}
|
||||
|
||||
/* Returns the stack of SCOPE_STMTs for the current function. */
|
||||
|
||||
tree *
|
||||
current_scope_stmt_stack (void)
|
||||
{
|
||||
return &cfun->language->base.x_scope_stmt_stack;
|
||||
}
|
||||
|
||||
/* Finish a parenthesized expression EXPR. */
|
||||
|
||||
tree
|
||||
@ -1348,17 +1348,7 @@ finish_qualified_id_expr (tree qualifying_class, tree expr, bool done,
|
||||
tree
|
||||
begin_stmt_expr (void)
|
||||
{
|
||||
/* If we're outside a function, we won't have a statement-tree to
|
||||
work with. But, if we see a statement-expression we need to
|
||||
create one. */
|
||||
if (! cfun && !last_tree)
|
||||
begin_stmt_tree (&scope_chain->x_saved_tree);
|
||||
|
||||
last_expr_type = NULL_TREE;
|
||||
|
||||
keep_next_level (true);
|
||||
|
||||
return last_tree;
|
||||
return push_stmt_list ();
|
||||
}
|
||||
|
||||
/* Process the final expression of a statement expression. EXPR can be
|
||||
@ -1367,7 +1357,7 @@ begin_stmt_expr (void)
|
||||
expression. */
|
||||
|
||||
tree
|
||||
finish_stmt_expr_expr (tree expr)
|
||||
finish_stmt_expr_expr (tree expr, tree stmt_expr)
|
||||
{
|
||||
tree result = NULL_TREE;
|
||||
tree type = void_type_node;
|
||||
@ -1408,15 +1398,16 @@ finish_stmt_expr_expr (tree expr)
|
||||
if (expr != error_mark_node)
|
||||
{
|
||||
result = build_stmt (EXPR_STMT, expr);
|
||||
EXPR_STMT_STMT_EXPR_RESULT (result) = 1;
|
||||
add_stmt (result);
|
||||
}
|
||||
}
|
||||
|
||||
finish_stmt ();
|
||||
|
||||
/* Remember the last expression so that finish_stmt_expr can pull it
|
||||
apart. */
|
||||
last_expr_type = result ? result : void_type_node;
|
||||
/* Remember the last expression so that finish_stmt_expr
|
||||
can pull it apart. */
|
||||
TREE_TYPE (stmt_expr) = result;
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -1426,46 +1417,62 @@ finish_stmt_expr_expr (tree expr)
|
||||
representing the statement-expression. */
|
||||
|
||||
tree
|
||||
finish_stmt_expr (tree rtl_expr, bool has_no_scope)
|
||||
finish_stmt_expr (tree stmt_expr, bool has_no_scope)
|
||||
{
|
||||
tree result;
|
||||
tree result_stmt = last_expr_type;
|
||||
tree type;
|
||||
|
||||
if (!last_expr_type)
|
||||
tree result, result_stmt, type;
|
||||
tree *result_stmt_p = NULL;
|
||||
|
||||
result_stmt = TREE_TYPE (stmt_expr);
|
||||
TREE_TYPE (stmt_expr) = void_type_node;
|
||||
result = pop_stmt_list (stmt_expr);
|
||||
|
||||
if (!result_stmt || VOID_TYPE_P (result_stmt))
|
||||
type = void_type_node;
|
||||
else
|
||||
{
|
||||
if (result_stmt == void_type_node)
|
||||
/* We need to search the statement expression for the result_stmt,
|
||||
since we'll need to replace it entirely. */
|
||||
tree t;
|
||||
result_stmt_p = &result;
|
||||
while (1)
|
||||
{
|
||||
type = void_type_node;
|
||||
result_stmt = NULL_TREE;
|
||||
}
|
||||
else
|
||||
type = TREE_TYPE (EXPR_STMT_EXPR (result_stmt));
|
||||
}
|
||||
|
||||
result = build_min (STMT_EXPR, type, last_tree);
|
||||
TREE_SIDE_EFFECTS (result) = 1;
|
||||
STMT_EXPR_NO_SCOPE (result) = has_no_scope;
|
||||
|
||||
last_expr_type = NULL_TREE;
|
||||
|
||||
/* Remove the compound statement from the tree structure; it is
|
||||
now saved in the STMT_EXPR. */
|
||||
last_tree = rtl_expr;
|
||||
TREE_CHAIN (last_tree) = NULL_TREE;
|
||||
t = *result_stmt_p;
|
||||
if (t == result_stmt)
|
||||
break;
|
||||
|
||||
/* If we created a statement-tree for this statement-expression,
|
||||
remove it now. */
|
||||
if (! cfun
|
||||
&& TREE_CHAIN (scope_chain->x_saved_tree) == NULL_TREE)
|
||||
finish_stmt_tree (&scope_chain->x_saved_tree);
|
||||
switch (TREE_CODE (t))
|
||||
{
|
||||
case STATEMENT_LIST:
|
||||
{
|
||||
tree_stmt_iterator i = tsi_last (t);
|
||||
result_stmt_p = tsi_stmt_ptr (i);
|
||||
break;
|
||||
}
|
||||
case BIND_EXPR:
|
||||
result_stmt_p = &BIND_EXPR_BODY (t);
|
||||
break;
|
||||
case COMPOUND_STMT:
|
||||
result_stmt_p = &COMPOUND_BODY (t);
|
||||
break;
|
||||
case TRY_FINALLY_EXPR:
|
||||
case TRY_CATCH_EXPR:
|
||||
case CLEANUP_STMT:
|
||||
result_stmt_p = &TREE_OPERAND (t, 0);
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
type = TREE_TYPE (EXPR_STMT_EXPR (result_stmt));
|
||||
}
|
||||
|
||||
if (processing_template_decl)
|
||||
return result;
|
||||
|
||||
if (!VOID_TYPE_P (type))
|
||||
{
|
||||
result = build_min (STMT_EXPR, type, result);
|
||||
TREE_SIDE_EFFECTS (result) = 1;
|
||||
STMT_EXPR_NO_SCOPE (result) = has_no_scope;
|
||||
}
|
||||
else if (!VOID_TYPE_P (type))
|
||||
{
|
||||
/* Pull out the TARGET_EXPR that is the final expression. Put
|
||||
the target's init_expr as the final expression and then put
|
||||
@ -1474,10 +1481,24 @@ finish_stmt_expr (tree rtl_expr, bool has_no_scope)
|
||||
tree last_expr = EXPR_STMT_EXPR (result_stmt);
|
||||
|
||||
my_friendly_assert (TREE_CODE (last_expr) == TARGET_EXPR, 20030729);
|
||||
EXPR_STMT_EXPR (result_stmt) = TREE_OPERAND (last_expr, 1);
|
||||
*result_stmt_p = TREE_OPERAND (last_expr, 1);
|
||||
|
||||
if (TREE_CODE (result) == BIND_EXPR)
|
||||
{
|
||||
if (VOID_TYPE_P (TREE_TYPE (result)))
|
||||
TREE_TYPE (result) = TREE_TYPE (last_expr);
|
||||
else if (same_type_p (TREE_TYPE (result), TREE_TYPE (last_expr)))
|
||||
;
|
||||
else
|
||||
abort ();
|
||||
}
|
||||
else if (TREE_CODE (result) == STATEMENT_LIST)
|
||||
result = build (BIND_EXPR, TREE_TYPE (last_expr), NULL, result, NULL);
|
||||
|
||||
TREE_OPERAND (last_expr, 1) = result;
|
||||
result = last_expr;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -2755,11 +2776,8 @@ simplify_aggr_init_expr (tree *tp)
|
||||
|
||||
/* We want to use the value of the initialized location as the
|
||||
result. */
|
||||
call_expr = build (COMPOUND_EXPR, type,
|
||||
call_expr, slot);
|
||||
call_expr = build (COMPOUND_EXPR, type, call_expr, slot);
|
||||
|
||||
/* Replace the AGGR_INIT_EXPR with the CALL_EXPR. */
|
||||
TREE_CHAIN (call_expr) = TREE_CHAIN (aggr_init_expr);
|
||||
*tp = call_expr;
|
||||
}
|
||||
|
||||
|
@ -293,13 +293,10 @@ cxx_incomplete_type_error (tree value, tree type)
|
||||
|
||||
|
||||
/* The recursive part of split_nonconstant_init. DEST is an lvalue
|
||||
expression to which INIT should be assigned. INIT is a CONSTRUCTOR.
|
||||
PCODE is a pointer to the tail of a chain of statements being emitted.
|
||||
The return value is the new tail of that chain after new statements
|
||||
are generated. */
|
||||
expression to which INIT should be assigned. INIT is a CONSTRUCTOR. */
|
||||
|
||||
static tree *
|
||||
split_nonconstant_init_1 (tree dest, tree init, tree *pcode)
|
||||
static void
|
||||
split_nonconstant_init_1 (tree dest, tree init)
|
||||
{
|
||||
tree *pelt, elt, type = TREE_TYPE (dest);
|
||||
tree sub, code, inner_type = NULL;
|
||||
@ -331,7 +328,7 @@ split_nonconstant_init_1 (tree dest, tree init, tree *pcode)
|
||||
else
|
||||
sub = build (COMPONENT_REF, inner_type, dest, field_index);
|
||||
|
||||
pcode = split_nonconstant_init_1 (sub, value, pcode);
|
||||
split_nonconstant_init_1 (sub, value);
|
||||
}
|
||||
else if (!initializer_constant_valid_p (value, inner_type))
|
||||
{
|
||||
@ -344,11 +341,10 @@ split_nonconstant_init_1 (tree dest, tree init, tree *pcode)
|
||||
|
||||
code = build (MODIFY_EXPR, inner_type, sub, value);
|
||||
code = build_stmt (EXPR_STMT, code);
|
||||
|
||||
*pcode = code;
|
||||
pcode = &TREE_CHAIN (code);
|
||||
add_stmt (code);
|
||||
continue;
|
||||
}
|
||||
|
||||
pelt = &TREE_CHAIN (elt);
|
||||
}
|
||||
break;
|
||||
@ -359,15 +355,13 @@ split_nonconstant_init_1 (tree dest, tree init, tree *pcode)
|
||||
CONSTRUCTOR_ELTS (init) = NULL;
|
||||
code = build (MODIFY_EXPR, type, dest, init);
|
||||
code = build_stmt (EXPR_STMT, code);
|
||||
pcode = &TREE_CHAIN (code);
|
||||
add_stmt (code);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
return pcode;
|
||||
}
|
||||
|
||||
/* A subroutine of store_init_value. Splits non-constant static
|
||||
@ -382,10 +376,9 @@ split_nonconstant_init (tree dest, tree init)
|
||||
|
||||
if (TREE_CODE (init) == CONSTRUCTOR)
|
||||
{
|
||||
code = build_stmt (COMPOUND_STMT, NULL_TREE);
|
||||
split_nonconstant_init_1 (dest, init, &COMPOUND_BODY (code));
|
||||
code = build1 (STMT_EXPR, void_type_node, code);
|
||||
TREE_SIDE_EFFECTS (code) = 1;
|
||||
code = push_stmt_list ();
|
||||
split_nonconstant_init_1 (dest, init);
|
||||
code = pop_stmt_list (code);
|
||||
DECL_INITIAL (dest) = init;
|
||||
TREE_READONLY (dest) = 0;
|
||||
}
|
||||
|
@ -9015,7 +9015,7 @@ tree_expr_nonnegative_p (tree t)
|
||||
case MODIFY_EXPR:
|
||||
return tree_expr_nonnegative_p (TREE_OPERAND (t, 1));
|
||||
case BIND_EXPR:
|
||||
return tree_expr_nonnegative_p (TREE_OPERAND (t, 1));
|
||||
return tree_expr_nonnegative_p (expr_last (TREE_OPERAND (t, 1)));
|
||||
case SAVE_EXPR:
|
||||
return tree_expr_nonnegative_p (TREE_OPERAND (t, 0));
|
||||
case NON_LVALUE_EXPR:
|
||||
|
@ -754,23 +754,23 @@ gimple_build_eh_filter (tree body, tree allowed, tree failure)
|
||||
WRAPPER was already void. */
|
||||
|
||||
tree
|
||||
voidify_wrapper_expr (tree wrapper)
|
||||
voidify_wrapper_expr (tree wrapper, tree temp)
|
||||
{
|
||||
if (!VOID_TYPE_P (TREE_TYPE (wrapper)))
|
||||
{
|
||||
tree *p;
|
||||
tree temp;
|
||||
tree *p, sub = wrapper;
|
||||
|
||||
restart:
|
||||
/* Set p to point to the body of the wrapper. */
|
||||
switch (TREE_CODE (wrapper))
|
||||
switch (TREE_CODE (sub))
|
||||
{
|
||||
case BIND_EXPR:
|
||||
/* For a BIND_EXPR, the body is operand 1. */
|
||||
p = &BIND_EXPR_BODY (wrapper);
|
||||
p = &BIND_EXPR_BODY (sub);
|
||||
break;
|
||||
|
||||
default:
|
||||
p = &TREE_OPERAND (wrapper, 0);
|
||||
p = &TREE_OPERAND (sub, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -789,15 +789,22 @@ voidify_wrapper_expr (tree wrapper)
|
||||
}
|
||||
}
|
||||
|
||||
if (p && TREE_CODE (*p) == INIT_EXPR)
|
||||
if (p == NULL || IS_EMPTY_STMT (*p))
|
||||
;
|
||||
/* Look through exception handling. */
|
||||
else if (TREE_CODE (*p) == TRY_FINALLY_EXPR
|
||||
|| TREE_CODE (*p) == TRY_CATCH_EXPR)
|
||||
{
|
||||
/* The C++ frontend already did this for us. */;
|
||||
temp = TREE_OPERAND (*p, 0);
|
||||
sub = *p;
|
||||
goto restart;
|
||||
}
|
||||
else if (p && TREE_CODE (*p) == INDIRECT_REF)
|
||||
/* The C++ frontend already did this for us. */
|
||||
else if (TREE_CODE (*p) == INIT_EXPR)
|
||||
temp = TREE_OPERAND (*p, 0);
|
||||
/* If we're returning a dereference, move the dereference
|
||||
outside the wrapper. */
|
||||
else if (TREE_CODE (*p) == INDIRECT_REF)
|
||||
{
|
||||
/* If we're returning a dereference, move the dereference outside
|
||||
the wrapper. */
|
||||
tree ptr = TREE_OPERAND (*p, 0);
|
||||
temp = create_tmp_var (TREE_TYPE (ptr), "retval");
|
||||
*p = build (MODIFY_EXPR, TREE_TYPE (ptr), temp, ptr);
|
||||
@ -808,12 +815,10 @@ voidify_wrapper_expr (tree wrapper)
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = create_tmp_var (TREE_TYPE (wrapper), "retval");
|
||||
if (p && !IS_EMPTY_STMT (*p))
|
||||
{
|
||||
*p = build (MODIFY_EXPR, TREE_TYPE (temp), temp, *p);
|
||||
TREE_SIDE_EFFECTS (wrapper) = 1;
|
||||
}
|
||||
if (!temp)
|
||||
temp = create_tmp_var (TREE_TYPE (wrapper), "retval");
|
||||
*p = build (MODIFY_EXPR, TREE_TYPE (temp), temp, *p);
|
||||
TREE_SIDE_EFFECTS (wrapper) = 1;
|
||||
}
|
||||
|
||||
TREE_TYPE (wrapper) = void_type_node;
|
||||
@ -845,13 +850,14 @@ build_stack_save_restore (tree *save, tree *restore)
|
||||
/* Gimplify a BIND_EXPR. Just voidify and recurse. */
|
||||
|
||||
static enum gimplify_status
|
||||
gimplify_bind_expr (tree *expr_p, tree *pre_p)
|
||||
gimplify_bind_expr (tree *expr_p, tree temp, tree *pre_p)
|
||||
{
|
||||
tree bind_expr = *expr_p;
|
||||
tree temp = voidify_wrapper_expr (bind_expr);
|
||||
bool old_save_stack = gimplify_ctxp->save_stack;
|
||||
tree t;
|
||||
|
||||
temp = voidify_wrapper_expr (bind_expr, temp);
|
||||
|
||||
/* Mark variables seen in this bind expr. */
|
||||
for (t = BIND_EXPR_VARS (bind_expr); t ; t = TREE_CHAIN (t))
|
||||
t->decl.seen_in_bind_expr = 1;
|
||||
@ -2872,7 +2878,7 @@ gimplify_cleanup_point_expr (tree *expr_p, tree *pre_p)
|
||||
tree_stmt_iterator iter;
|
||||
tree body;
|
||||
|
||||
tree temp = voidify_wrapper_expr (*expr_p);
|
||||
tree temp = voidify_wrapper_expr (*expr_p, NULL);
|
||||
|
||||
/* We only care about the number of conditions between the innermost
|
||||
CLEANUP_POINT_EXPR and the cleanup. So save and reset the count. */
|
||||
@ -3006,12 +3012,17 @@ gimplify_target_expr (tree *expr_p, tree *pre_p, tree *post_p)
|
||||
temps list. */
|
||||
gimple_add_tmp_var (temp);
|
||||
|
||||
/* Build up the initialization and add it to pre_p. */
|
||||
init = build (MODIFY_EXPR, void_type_node, temp, init);
|
||||
ret = gimplify_expr (&init, pre_p, post_p, is_gimple_stmt, fb_none);
|
||||
if (ret == GS_ERROR)
|
||||
return GS_ERROR;
|
||||
|
||||
/* Build up the initialization and add it to pre_p. Special handling
|
||||
for BIND_EXPR can result in fewer temporaries created. */
|
||||
if (TREE_CODE (init) == BIND_EXPR)
|
||||
gimplify_bind_expr (&init, temp, pre_p);
|
||||
if (init != temp)
|
||||
{
|
||||
init = build (MODIFY_EXPR, void_type_node, temp, init);
|
||||
ret = gimplify_expr (&init, pre_p, post_p, is_gimple_stmt, fb_none);
|
||||
if (ret == GS_ERROR)
|
||||
return GS_ERROR;
|
||||
}
|
||||
append_to_statement_list (init, pre_p);
|
||||
|
||||
/* If needed, push the cleanup for the temp. */
|
||||
@ -3286,7 +3297,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
|
||||
break;
|
||||
|
||||
case BIND_EXPR:
|
||||
ret = gimplify_bind_expr (expr_p, pre_p);
|
||||
ret = gimplify_bind_expr (expr_p, NULL, pre_p);
|
||||
break;
|
||||
|
||||
case LOOP_EXPR:
|
||||
@ -3530,7 +3541,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
|
||||
/* If we are gimplifying at the statement level, we're done. Tack
|
||||
everything together and replace the original statement with the
|
||||
gimplified form. */
|
||||
if (is_statement)
|
||||
if (fallback == fb_none || is_statement)
|
||||
{
|
||||
if (internal_pre || internal_post)
|
||||
{
|
||||
|
@ -78,7 +78,6 @@ extern tree lhd_tree_inlining_walk_subtrees (tree *, int *, walk_tree_fn,
|
||||
extern int lhd_tree_inlining_cannot_inline_tree_fn (tree *);
|
||||
extern int lhd_tree_inlining_disregard_inline_limits (tree);
|
||||
extern tree lhd_tree_inlining_add_pending_fn_decls (void *, tree);
|
||||
extern int lhd_tree_inlining_tree_chain_matters_p (tree);
|
||||
extern int lhd_tree_inlining_auto_var_in_fn_p (tree, tree);
|
||||
extern tree lhd_tree_inlining_copy_res_decl_for_inlining (tree, tree, tree,
|
||||
void *, int *, tree);
|
||||
@ -151,8 +150,6 @@ extern int lhd_gimplify_expr (tree *, tree *, tree *);
|
||||
lhd_tree_inlining_disregard_inline_limits
|
||||
#define LANG_HOOKS_TREE_INLINING_ADD_PENDING_FN_DECLS \
|
||||
lhd_tree_inlining_add_pending_fn_decls
|
||||
#define LANG_HOOKS_TREE_INLINING_TREE_CHAIN_MATTERS_P \
|
||||
lhd_tree_inlining_tree_chain_matters_p
|
||||
#define LANG_HOOKS_TREE_INLINING_AUTO_VAR_IN_FN_P \
|
||||
lhd_tree_inlining_auto_var_in_fn_p
|
||||
#define LANG_HOOKS_TREE_INLINING_COPY_RES_DECL_FOR_INLINING \
|
||||
@ -175,7 +172,6 @@ extern int lhd_gimplify_expr (tree *, tree *, tree *);
|
||||
LANG_HOOKS_TREE_INLINING_CANNOT_INLINE_TREE_FN, \
|
||||
LANG_HOOKS_TREE_INLINING_DISREGARD_INLINE_LIMITS, \
|
||||
LANG_HOOKS_TREE_INLINING_ADD_PENDING_FN_DECLS, \
|
||||
LANG_HOOKS_TREE_INLINING_TREE_CHAIN_MATTERS_P, \
|
||||
LANG_HOOKS_TREE_INLINING_AUTO_VAR_IN_FN_P, \
|
||||
LANG_HOOKS_TREE_INLINING_COPY_RES_DECL_FOR_INLINING, \
|
||||
LANG_HOOKS_TREE_INLINING_ANON_AGGR_TYPE_P, \
|
||||
|
@ -365,16 +365,6 @@ lhd_tree_inlining_add_pending_fn_decls (void *vafnp ATTRIBUTE_UNUSED, tree pfn)
|
||||
return pfn;
|
||||
}
|
||||
|
||||
/* lang_hooks.tree_inlining.tree_chain_matters_p indicates whether the
|
||||
TREE_CHAIN of a language-specific tree node is relevant, i.e.,
|
||||
whether it should be walked, copied and preserved across copies. */
|
||||
|
||||
int
|
||||
lhd_tree_inlining_tree_chain_matters_p (tree t ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* lang_hooks.tree_inlining.auto_var_in_fn_p is called to determine
|
||||
whether VT is an automatic variable defined in function FT. */
|
||||
|
||||
|
@ -39,7 +39,6 @@ struct lang_hooks_for_tree_inlining
|
||||
int (*cannot_inline_tree_fn) (tree *);
|
||||
int (*disregard_inline_limits) (tree);
|
||||
tree (*add_pending_fn_decls) (void *, tree);
|
||||
int (*tree_chain_matters_p) (tree);
|
||||
int (*auto_var_in_fn_p) (tree, tree);
|
||||
tree (*copy_res_decl_for_inlining) (tree, tree, tree,
|
||||
void *, int *, tree);
|
||||
|
@ -1875,7 +1875,7 @@ build_module_descriptor (void)
|
||||
|
||||
{
|
||||
tree parms, execclass_decl, decelerator, void_list_node_1;
|
||||
tree init_function_name, init_function_decl;
|
||||
tree init_function_name, init_function_decl, compound;
|
||||
|
||||
/* Declare void __objc_execClass (void *); */
|
||||
|
||||
@ -1903,6 +1903,7 @@ build_module_descriptor (void)
|
||||
NULL_TREE),
|
||||
NULL_TREE);
|
||||
store_parm_decls ();
|
||||
compound = c_begin_compound_stmt (true);
|
||||
|
||||
init_function_decl = current_function_decl;
|
||||
TREE_PUBLIC (init_function_decl) = ! targetm.have_ctors_dtors;
|
||||
@ -1917,6 +1918,7 @@ build_module_descriptor (void)
|
||||
decelerator = build_function_call (execclass_decl, parms);
|
||||
|
||||
c_expand_expr_stmt (decelerator);
|
||||
add_stmt (c_end_compound_stmt (compound, true));
|
||||
|
||||
finish_function ();
|
||||
|
||||
@ -2687,10 +2689,7 @@ objc_enter_block (void)
|
||||
#ifdef OBJCPLUS
|
||||
block = begin_compound_stmt (0);
|
||||
#else
|
||||
block = c_begin_compound_stmt ();
|
||||
push_scope ();
|
||||
clear_last_expr ();
|
||||
add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0);
|
||||
block = c_begin_compound_stmt (1);
|
||||
#endif
|
||||
|
||||
objc_exception_block_stack = tree_cons (NULL_TREE, block,
|
||||
@ -2704,24 +2703,14 @@ static tree
|
||||
objc_exit_block (void)
|
||||
{
|
||||
tree block = TREE_VALUE (objc_exception_block_stack);
|
||||
#ifndef OBJCPLUS
|
||||
tree scope_stmt, inner;
|
||||
#endif
|
||||
objc_exception_block_stack = TREE_CHAIN (objc_exception_block_stack);
|
||||
|
||||
objc_clear_super_receiver ();
|
||||
#ifdef OBJCPLUS
|
||||
finish_compound_stmt (0, block);
|
||||
finish_compound_stmt (block);
|
||||
#else
|
||||
scope_stmt = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0);
|
||||
inner = pop_scope ();
|
||||
|
||||
SCOPE_STMT_BLOCK (TREE_PURPOSE (scope_stmt))
|
||||
= SCOPE_STMT_BLOCK (TREE_VALUE (scope_stmt))
|
||||
= inner;
|
||||
RECHAIN_STMTS (block, COMPOUND_BODY (block));
|
||||
block = c_end_compound_stmt (block, 1);
|
||||
#endif
|
||||
last_expr_type = NULL_TREE;
|
||||
objc_exception_block_stack = TREE_CHAIN (objc_exception_block_stack);
|
||||
|
||||
blk_nesting_count--;
|
||||
return block;
|
||||
@ -2804,6 +2793,15 @@ objc_build_try_enter_fragment (void)
|
||||
c_expand_expr_stmt (build_function_call
|
||||
(objc_exception_try_enter_decl, func_params));
|
||||
|
||||
#ifdef OBJCPLUS
|
||||
/* Um, C and C++ have very different statement construction functions.
|
||||
Partly because different scoping rules are in effect, but partly
|
||||
because of how their parsers are constructed. I highly recommend
|
||||
simply constructing the statements by hand here. You don't need
|
||||
any of the ancilliary tracking necessary for user parsing bits anyway. */
|
||||
#error
|
||||
#endif
|
||||
|
||||
if_stmt = c_begin_if_stmt ();
|
||||
if_nesting_count++;
|
||||
/* If <setjmp.h> has been included, the _setjmp prototype has
|
||||
@ -2865,8 +2863,7 @@ objc_build_extract_fragment (void)
|
||||
_rethrowException = objc_exception_extract(&_stackExceptionData);
|
||||
} */
|
||||
|
||||
objc_exit_block ();
|
||||
c_finish_then ();
|
||||
c_finish_then (objc_exit_block ());
|
||||
|
||||
c_expand_start_else ();
|
||||
objc_enter_block ();
|
||||
@ -2874,8 +2871,7 @@ objc_build_extract_fragment (void)
|
||||
(TREE_VALUE (objc_rethrow_exception),
|
||||
NOP_EXPR,
|
||||
objc_build_extract_expr ()));
|
||||
objc_exit_block ();
|
||||
c_finish_else ();
|
||||
c_finish_else (objc_exit_block ());
|
||||
c_expand_end_cond ();
|
||||
if_nesting_count--;
|
||||
}
|
||||
@ -2934,8 +2930,7 @@ objc_build_try_epilogue (int also_catch_prologue)
|
||||
|
||||
tree if_stmt;
|
||||
|
||||
objc_exit_block ();
|
||||
c_finish_then ();
|
||||
c_finish_then (objc_exit_block ());
|
||||
|
||||
c_expand_start_else ();
|
||||
objc_enter_block ();
|
||||
@ -3017,8 +3012,7 @@ objc_build_catch_stmt (tree catch_expr)
|
||||
|
||||
objc_catch_type = tree_cons (NULL_TREE, var_type, objc_catch_type);
|
||||
|
||||
objc_exit_block ();
|
||||
c_finish_then ();
|
||||
c_finish_then (objc_exit_block ());
|
||||
|
||||
c_expand_start_else ();
|
||||
catch_count_stack->val++;
|
||||
@ -3061,8 +3055,7 @@ objc_build_catch_epilogue (void)
|
||||
} // end TRY-CATCH scope
|
||||
*/
|
||||
|
||||
objc_exit_block ();
|
||||
c_finish_then ();
|
||||
c_finish_then (objc_exit_block ());
|
||||
|
||||
c_expand_start_else ();
|
||||
objc_enter_block ();
|
||||
@ -3075,7 +3068,8 @@ objc_build_catch_epilogue (void)
|
||||
objc_exit_block ();
|
||||
while (catch_count_stack->val--)
|
||||
{
|
||||
c_finish_else (); /* close off all the nested ifs ! */
|
||||
/* FIXME. Need to have the block of each else that was opened. */
|
||||
c_finish_else ((abort (), NULL)); /* close off all the nested ifs ! */
|
||||
c_expand_end_cond ();
|
||||
if_nesting_count--;
|
||||
}
|
||||
@ -3084,8 +3078,7 @@ objc_build_catch_epilogue (void)
|
||||
|
||||
objc_build_extract_fragment ();
|
||||
|
||||
objc_exit_block ();
|
||||
c_finish_else ();
|
||||
c_finish_else (objc_exit_block ());
|
||||
c_expand_end_cond ();
|
||||
if_nesting_count--;
|
||||
objc_exit_block ();
|
||||
@ -3116,8 +3109,7 @@ objc_build_finally_prologue (void)
|
||||
0, if_stmt);
|
||||
objc_enter_block ();
|
||||
objc_build_try_exit_fragment ();
|
||||
objc_exit_block ();
|
||||
c_finish_then ();
|
||||
c_finish_then (objc_exit_block ());
|
||||
c_expand_end_cond ();
|
||||
if_nesting_count--;
|
||||
|
||||
@ -3141,8 +3133,7 @@ objc_build_finally_epilogue (void)
|
||||
0, if_stmt);
|
||||
objc_enter_block ();
|
||||
objc_build_throw_stmt (TREE_VALUE (objc_rethrow_exception));
|
||||
objc_exit_block ();
|
||||
c_finish_then ();
|
||||
c_finish_then (objc_exit_block ());
|
||||
c_expand_end_cond ();
|
||||
if_nesting_count--;
|
||||
|
||||
|
@ -112,9 +112,6 @@ enum c_language_kind c_language = clk_objc;
|
||||
#undef LANG_HOOKS_TREE_INLINING_CONVERT_PARM_FOR_INLINING
|
||||
#define LANG_HOOKS_TREE_INLINING_CONVERT_PARM_FOR_INLINING \
|
||||
c_convert_parm_for_inlining
|
||||
#undef LANG_HOOKS_TREE_INLINING_TREE_CHAIN_MATTERS_P
|
||||
#define LANG_HOOKS_TREE_INLINING_TREE_CHAIN_MATTERS_P \
|
||||
c_tree_chain_matters_p
|
||||
|
||||
#undef LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION
|
||||
#define LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION c_expand_body
|
||||
|
@ -69,6 +69,11 @@ objc_message_selector (void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
objc_clear_super_receiver (void)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
objc_is_public (tree expr ATTRIBUTE_UNUSED, tree identifier ATTRIBUTE_UNUSED)
|
||||
{
|
||||
|
@ -1,3 +1,8 @@
|
||||
2004-06-15 Richard Henderson <rth@redhat.com>
|
||||
|
||||
* g++.dg/ext/stmtexpr1.C: XFAIL.
|
||||
* gcc.dg/20030612-1.c: XFAIL.
|
||||
|
||||
2004-06-15 Eric Christopher <echristo@redhat.com>
|
||||
|
||||
* g++.dg/charset/asm5.c: New.
|
||||
|
@ -1,4 +1,4 @@
|
||||
// { dg-do run }
|
||||
// { dg-do run { xfail *-*-* } }
|
||||
// { dg-options "" }
|
||||
|
||||
// Copyright (C) 2003 Free Software Foundation, Inc.
|
||||
|
@ -8,7 +8,7 @@ void foo()
|
||||
long x = 3;
|
||||
(void)({
|
||||
A = B + x + ((1) - 1);
|
||||
return; /* { dg-warning "statement-expressions should end with a non-void expression" } */
|
||||
return; /* { dg-warning "statement-expressions should end with a non-void expression" "" { xfail *-*-* } } */
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -80,8 +80,6 @@ tree get_call_expr_in (tree t);
|
||||
|
||||
void recalculate_side_effects (tree);
|
||||
|
||||
void append_to_statement_list (tree, tree *);
|
||||
void append_to_statement_list_force (tree, tree *);
|
||||
void append_to_compound_expr (tree, tree *);
|
||||
|
||||
/* FIXME we should deduce this from the predicate. */
|
||||
@ -116,7 +114,7 @@ tree gimple_current_bind_expr (void);
|
||||
void gimple_push_bind_expr (tree);
|
||||
void gimple_pop_bind_expr (void);
|
||||
void unshare_all_trees (tree);
|
||||
tree voidify_wrapper_expr (tree);
|
||||
tree voidify_wrapper_expr (tree, tree);
|
||||
tree gimple_build_eh_filter (tree, tree, tree);
|
||||
tree build_and_jump (tree *);
|
||||
tree alloc_stmt_list (void);
|
||||
|
@ -1657,7 +1657,7 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data)
|
||||
restoring of current_function_decl. */
|
||||
save_decl = current_function_decl;
|
||||
current_function_decl = id->node->decl;
|
||||
inline_result = voidify_wrapper_expr (expr);
|
||||
inline_result = voidify_wrapper_expr (expr, NULL);
|
||||
current_function_decl = save_decl;
|
||||
|
||||
/* If the inlined function returns a result that we care about,
|
||||
@ -1906,7 +1906,7 @@ clone_body (tree clone, tree fn, void *arg_map)
|
||||
id.cloning_p = true;
|
||||
|
||||
/* Actually copy the body. */
|
||||
TREE_CHAIN (DECL_SAVED_TREE (clone)) = copy_body (&id);
|
||||
append_to_statement_list_force (copy_body (&id), &DECL_SAVED_TREE (clone));
|
||||
}
|
||||
|
||||
/* Save duplicate of body in FN. MAP is used to pass around splay tree
|
||||
@ -2006,8 +2006,7 @@ walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_)
|
||||
interesting below this point in the tree. */
|
||||
if (!walk_subtrees)
|
||||
{
|
||||
if (code == TREE_LIST
|
||||
|| lang_hooks.tree_inlining.tree_chain_matters_p (*tp))
|
||||
if (code == TREE_LIST)
|
||||
/* But we still need to check our siblings. */
|
||||
WALK_SUBTREE_TAIL (TREE_CHAIN (*tp));
|
||||
else
|
||||
@ -2052,10 +2051,6 @@ walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_)
|
||||
WALK_SUBTREE (TREE_OPERAND (*tp, len - 1));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (lang_hooks.tree_inlining.tree_chain_matters_p (*tp))
|
||||
/* Check our siblings. */
|
||||
WALK_SUBTREE_TAIL (TREE_CHAIN (*tp));
|
||||
}
|
||||
else if (TREE_CODE_CLASS (code) == 'd')
|
||||
{
|
||||
@ -2226,8 +2221,7 @@ copy_tree_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
|
||||
|| TREE_CODE_CLASS (code) == 'c'
|
||||
|| code == TREE_LIST
|
||||
|| code == TREE_VEC
|
||||
|| code == TYPE_DECL
|
||||
|| lang_hooks.tree_inlining.tree_chain_matters_p (*tp))
|
||||
|| code == TYPE_DECL)
|
||||
{
|
||||
/* Because the chain gets clobbered when we make a copy, we save it
|
||||
here. */
|
||||
@ -2245,8 +2239,7 @@ copy_tree_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
|
||||
|
||||
/* 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
|
||||
|| lang_hooks.tree_inlining.tree_chain_matters_p (*tp))
|
||||
if (code == PARM_DECL || code == TREE_LIST)
|
||||
TREE_CHAIN (*tp) = chain;
|
||||
|
||||
/* For now, we don't update BLOCKs when we make copies. So, we
|
||||
|
@ -40,14 +40,12 @@ alloc_stmt_list (void)
|
||||
if (list)
|
||||
{
|
||||
stmt_list_cache = TREE_CHAIN (list);
|
||||
TREE_CHAIN (list) = NULL;
|
||||
TREE_SIDE_EFFECTS (list) = 0;
|
||||
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;
|
||||
}
|
||||
list = make_node (STATEMENT_LIST);
|
||||
TREE_TYPE (list) = void_type_node;
|
||||
return list;
|
||||
}
|
||||
|
||||
@ -73,8 +71,6 @@ tsi_link_before (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
|
||||
if (t == i->container)
|
||||
abort ();
|
||||
|
||||
TREE_SIDE_EFFECTS (i->container) = 1;
|
||||
|
||||
if (TREE_CODE (t) == STATEMENT_LIST)
|
||||
{
|
||||
head = STATEMENT_LIST_HEAD (t);
|
||||
@ -101,6 +97,8 @@ tsi_link_before (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
|
||||
tail = head;
|
||||
}
|
||||
|
||||
TREE_SIDE_EFFECTS (i->container) = 1;
|
||||
|
||||
cur = i->ptr;
|
||||
|
||||
/* Link it into the list. */
|
||||
@ -151,8 +149,6 @@ tsi_link_after (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
|
||||
if (t == i->container)
|
||||
abort ();
|
||||
|
||||
TREE_SIDE_EFFECTS (i->container) = 1;
|
||||
|
||||
if (TREE_CODE (t) == STATEMENT_LIST)
|
||||
{
|
||||
head = STATEMENT_LIST_HEAD (t);
|
||||
@ -179,6 +175,8 @@ tsi_link_after (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
|
||||
tail = head;
|
||||
}
|
||||
|
||||
TREE_SIDE_EFFECTS (i->container) = 1;
|
||||
|
||||
cur = i->ptr;
|
||||
|
||||
/* Link it into the list. */
|
||||
|
@ -117,4 +117,7 @@ void tsi_delink (tree_stmt_iterator *);
|
||||
tree tsi_split_statement_list_after (const tree_stmt_iterator *);
|
||||
tree tsi_split_statement_list_before (tree_stmt_iterator *);
|
||||
|
||||
void append_to_statement_list (tree, tree *);
|
||||
void append_to_statement_list_force (tree, tree *);
|
||||
|
||||
#endif /* GCC_TREE_ITERATOR_H */
|
||||
|
@ -741,10 +741,12 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
|
||||
break;
|
||||
|
||||
case TARGET_EXPR:
|
||||
dump_generic_node (buffer, TYPE_NAME (TREE_TYPE (node)), spc, flags, false);
|
||||
pp_character (buffer, '(');
|
||||
pp_string (buffer, "TARGET_EXPR <");
|
||||
dump_generic_node (buffer, TARGET_EXPR_SLOT (node), spc, flags, false);
|
||||
pp_character (buffer, ',');
|
||||
pp_space (buffer);
|
||||
dump_generic_node (buffer, TARGET_EXPR_INITIAL (node), spc, flags, false);
|
||||
pp_character (buffer, ')');
|
||||
pp_character (buffer, '>');
|
||||
break;
|
||||
|
||||
case COND_EXPR:
|
||||
|
Loading…
Reference in New Issue
Block a user