+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.
/* 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. */
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 *);
{ 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
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++)
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);
&& 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));
}
\f
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++;
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;
}
#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
/* 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
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:
#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,
/* 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
/* 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. */
-
-#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)
+/* 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. */
-/* 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
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);
(((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);
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. */
#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,
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
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
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);
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 */
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;
/* 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)
using_eh_for_cleanups ();
}
- add_stmt (build_stmt (CLEANUP_STMT, decl, cleanup));
+ push_cleanup (decl, cleanup, false);
}
}
}
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
{
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)))
{
}
}
- 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
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;
}
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;
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. */
{
}
-/* 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
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;
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 *);
/* Go ahead and gimplify for now. */
push_context ();
+ gimplify_cleanup_stmts (fndecl);
gimplify_function_tree (fndecl);
pop_context ();
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:
c = t1 + b;
b = b + 1; <-- POST */
- for (stmt = *stmt_p; stmt && stmt != error_mark_node; stmt = next)
- {
- tree pre, post;
- int saved_stmts_are_full_exprs_p;
- location_t stmt_locus;
- enum gimplify_status ret;
-
- /* 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;
+ /* 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;
+ pre = NULL_TREE;
+ post = NULL_TREE;
- next = TREE_CHAIN (stmt);
+ switch (TREE_CODE (stmt))
+ {
+ case COMPOUND_STMT:
+ stmt = COMPOUND_BODY (stmt);
+ ret = GS_OK;
+ break;
- switch (TREE_CODE (stmt))
- {
- case COMPOUND_STMT:
- stmt = COMPOUND_BODY (stmt);
- ret = GS_OK;
- break;
+ case FOR_STMT:
+ ret = gimplify_for_stmt (&stmt, &pre);
+ break;
- case SCOPE_STMT:
- ret = gimplify_block (&stmt, &next);
- break;
+ case WHILE_STMT:
+ ret = gimplify_while_stmt (&stmt);
+ break;
- case FOR_STMT:
- ret = gimplify_for_stmt (&stmt, &next);
- break;
+ case DO_STMT:
+ ret = gimplify_do_stmt (&stmt);
+ break;
- case WHILE_STMT:
- ret = gimplify_while_stmt (&stmt);
- break;
+ case IF_STMT:
+ ret = gimplify_if_stmt (&stmt);
+ break;
- case DO_STMT:
- ret = gimplify_do_stmt (&stmt);
- break;
+ case SWITCH_STMT:
+ ret = gimplify_switch_stmt (&stmt);
+ break;
- case IF_STMT:
- ret = gimplify_if_stmt (&stmt);
- break;
+ case EXPR_STMT:
+ ret = gimplify_expr_stmt (&stmt);
+ break;
- case SWITCH_STMT:
- ret = gimplify_switch_stmt (&stmt);
- break;
+ case RETURN_STMT:
+ ret = gimplify_return_stmt (&stmt);
+ break;
- case EXPR_STMT:
- ret = gimplify_expr_stmt (&stmt);
- break;
+ case DECL_STMT:
+ ret = gimplify_decl_stmt (&stmt);
+ break;
- case RETURN_STMT:
- ret = gimplify_return_stmt (&stmt);
- break;
+ case LABEL_STMT:
+ stmt = build1 (LABEL_EXPR, void_type_node, LABEL_STMT_LABEL (stmt));
+ ret = GS_OK;
+ break;
- case DECL_STMT:
- ret = gimplify_decl_stmt (&stmt);
- break;
+ case GOTO_STMT:
+ stmt = build1 (GOTO_EXPR, void_type_node, GOTO_DESTINATION (stmt));
+ ret = GS_OK;
+ break;
- case LABEL_STMT:
- stmt = build1 (LABEL_EXPR, void_type_node, LABEL_STMT_LABEL (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 GOTO_STMT:
- stmt = build1 (GOTO_EXPR, void_type_node, GOTO_DESTINATION (stmt));
- ret = GS_OK;
- break;
+ case CONTINUE_STMT:
+ stmt = build_bc_goto (bc_continue);
+ 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 BREAK_STMT:
+ stmt = build_bc_goto (bc_break);
+ ret = GS_OK;
+ break;
- case CONTINUE_STMT:
- stmt = build_bc_goto (bc_continue);
- 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;
- case BREAK_STMT:
- stmt = build_bc_goto (bc_break);
+ default:
+ if (lang_gimplify_stmt && (*lang_gimplify_stmt) (&stmt))
+ {
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 ();
- }
+ fprintf (stderr, "unhandled statement node in c_gimplify_stmt:\n");
+ debug_tree (stmt);
+ abort ();
+ break;
+ }
- /* PRE and POST now contain a list of statements for all the
- side-effects in STMT. */
+ switch (ret)
+ {
+ case GS_ERROR:
+ goto cont;
+ case GS_OK:
+ gimplify_stmt (&stmt);
+ break;
+ case GS_ALL_DONE:
+ break;
+ default:
+ abort ();
+ }
- append_to_statement_list (stmt, &pre);
- append_to_statement_list (post, &pre);
- annotate_all_with_locus (&pre, stmt_locus);
+ /* PRE and POST now contain a list of statements for all the
+ side-effects in STMT. */
- 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;
- }
- append_to_statement_list (stmt, &outer_pre);
- *stmt_p = outer_pre;
+ 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;
}
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;
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 = c_build_bind_expr (block, TREE_CHAIN (*stmt_p));
- *stmt_p = bind;
- input_location = stmt_locus;
+ bind = body;
- 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.
{
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);
}
}
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;
}
tree stmt, then_, else_;
stmt = *stmt_p;
- restart:
then_ = THEN_CLAUSE (stmt);
else_ = ELSE_CLAUSE (stmt);
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;
}
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
#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
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)
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 ();
}
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,
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 ();
}
%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
| '(' 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 '.'
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
;
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:
'(' '{'
{ 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. */
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--; }
;
/* 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);
{ 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"); }
$<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--; }
;
| 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); }
#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
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
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;
}
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);
#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. */
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;
}
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
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);
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
#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. */
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);
}
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");
/* 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);
}
+\f
+/* 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;
+}
+\f
+/* 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;
+}
+\f
+/* 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;
+}
+\f
+/* 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;
+}
+\f
+/* 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;
+}
+\f
/* Build a binary-operation expression without default conversions.
CODE is the kind of expression to build.
This function differs from `build' in several ways:
+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
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. */
{
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.
-
- 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);
+ 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 expression
+ which the caller is responsible for attaching to
+ the statement tree. */
}
else
{
/* 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))
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);
}
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);
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);
}
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.
*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;
}
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);
#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
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)
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)
{
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.
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.
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).
#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) \
/* 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'. */
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. */
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);
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);
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);
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);
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);
/* 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++ */
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);
}
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)
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);
}
/* 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:
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 ();
/* 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;
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);
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);
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;
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
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. */
if_stmt);
finish_expr_stmt (exprstmt);
finish_then_clause (if_stmt);
- finish_if_stmt ();
+ finish_if_stmt (if_stmt);
}
}
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)
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
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;
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,
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
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. */
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. */
#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);
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
{
tree r = build_stmt (EH_SPEC_BLOCK, NULL_TREE, NULL_TREE);
add_stmt (r);
+ EH_SPEC_STMTS (r) = push_stmt_list ();
return r;
}
{
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;
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);
+ }
}
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;
}
construct_virtual_base (tree vbase, tree arguments)
{
tree inner_if_stmt;
- tree compound_stmt;
tree exp;
tree flag;
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
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);
}
tree compound_stmt;
int destroy_temps;
tree try_block = NULL_TREE;
- tree try_body = NULL_TREE;
int num_initialized_elts = 0;
bool is_global;
&& 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)
/* 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 ();
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);
if (base2)
finish_expr_stmt (build_unary_op (PREINCREMENT_EXPR, base2, 0));
- finish_compound_stmt (for_body);
finish_for_stmt (for_stmt);
}
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);
/* 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);
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)
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);
}
&& 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);
}
}
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;
/* 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
/* 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);
}
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;
case RID_CASE:
case RID_DEFAULT:
statement = cp_parser_labeled_statement (parser,
- in_statement_expr_p);
+ in_statement_expr);
break;
case RID_IF:
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
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. */
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;
/* 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;
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;
/* 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);
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;
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 `}'. */
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)
break;
/* Parse the statement. */
- cp_parser_statement (parser, in_statement_expr_p);
+ cp_parser_statement (parser, in_statement_expr);
}
}
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. */
/* 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. */
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. */
}
/* 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;
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))
+ /* 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
{
- 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);
+ /* 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, "`}'");
}
- /* Otherwise, we simply parse the statement directly. */
- else
- cp_parser_statement (parser, false);
}
/* Declarations [gram.dcl.dcl] */
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
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);
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);
}
#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. */
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:
static tree
tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
{
+ /* 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;
- tsubst_flags_t stmt_expr
- = complain & (tf_stmt_expr_cmpd | tf_stmt_expr_body);
- 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
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;
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;
}
/* 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:
{
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)
- {
- tsubst_expr (tmp, args, complain, in_decl);
- finish_then_clause (stmt);
- }
-
- if (tmp = ELSE_CLAUSE (t), tmp)
+ if (ELSE_CLAUSE (t))
{
- 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;
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);
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
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
#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
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
---------------------------------
/* 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 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)
{
- if (!processing_template_decl)
- add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0);
- begin_scope (sk, NULL);
+ 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
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 ();
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;
}
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
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
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
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;
}
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. */
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 ();
}
{
tree r = build_stmt (DO_STMT, NULL_TREE, NULL_TREE);
add_stmt (r);
+ DO_BODY (r) = push_stmt_list ();
return r;
}
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
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;
}
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
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
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 ();
}
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;
}
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
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
{
tree r = build_stmt (TRY_BLOCK, NULL_TREE, NULL_TREE);
add_stmt (r);
+ TRY_STMTS (r) = push_stmt_list ();
return r;
}
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;
}
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
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
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;
}
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));
}
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. */
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;
}
{
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);
}
}
{
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
COMPOUND_STMT. */
tree
-begin_compound_stmt (bool has_no_scope)
+begin_compound_stmt (unsigned int flags)
{
- tree r;
- int is_try = 0;
-
- r = build_stmt (COMPOUND_STMT, NULL_TREE);
-
- 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;
+ tree r;
- last_expr_type = NULL_TREE;
+ if (flags & BCS_NO_SCOPE)
+ {
+ r = push_stmt_list ();
+ STATEMENT_LIST_NO_SCOPE (r) = 1;
- 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 ();
-
- RECHAIN_STMTS (compound_stmt, COMPOUND_BODY (compound_stmt));
+ stmt = do_poplevel (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
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. */
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
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
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
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;
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;
}
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;
+ t = *result_stmt_p;
+ if (t == result_stmt)
+ break;
+
+ 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 ();
+ }
}
- else
- type = TREE_TYPE (EXPR_STMT_EXPR (result_stmt));
+ 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;
-
- /* 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);
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
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;
}
/* 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;
}
\f
/* 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;
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))
{
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;
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
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;
}
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:
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;
}
}
}
- 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);
}
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;
/* 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;
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. */
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. */
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:
/* 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)
{
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);
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 \
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, \
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. */
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);
{
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 *); */
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;
decelerator = build_function_call (execclass_decl, parms);
c_expand_expr_stmt (decelerator);
+ add_stmt (c_end_compound_stmt (compound, true));
finish_function ();
#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,
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;
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
_rethrowException = objc_exception_extract(&_stackExceptionData);
} */
- objc_exit_block ();
- c_finish_then ();
+ c_finish_then (objc_exit_block ());
c_expand_start_else ();
objc_enter_block ();
(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--;
}
tree if_stmt;
- objc_exit_block ();
- c_finish_then ();
+ c_finish_then (objc_exit_block ());
c_expand_start_else ();
objc_enter_block ();
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++;
} // end TRY-CATCH scope
*/
- objc_exit_block ();
- c_finish_then ();
+ c_finish_then (objc_exit_block ());
c_expand_start_else ();
objc_enter_block ();
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--;
}
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 ();
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--;
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--;
#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
return 0;
}
+void
+objc_clear_super_receiver (void)
+{
+}
+
int
objc_is_public (tree expr ATTRIBUTE_UNUSED, tree identifier ATTRIBUTE_UNUSED)
{
+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.
-// { dg-do run }
+// { dg-do run { xfail *-*-* } }
// { dg-options "" }
// Copyright (C) 2003 Free Software Foundation, Inc.
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 *-*-* } } */
});
}
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. */
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);
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,
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
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
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')
{
|| 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. */
/* 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
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;
}
if (t == i->container)
abort ();
- TREE_SIDE_EFFECTS (i->container) = 1;
-
if (TREE_CODE (t) == STATEMENT_LIST)
{
head = STATEMENT_LIST_HEAD (t);
tail = head;
}
+ TREE_SIDE_EFFECTS (i->container) = 1;
+
cur = i->ptr;
/* Link it into the list. */
if (t == i->container)
abort ();
- TREE_SIDE_EFFECTS (i->container) = 1;
-
if (TREE_CODE (t) == STATEMENT_LIST)
{
head = STATEMENT_LIST_HEAD (t);
tail = head;
}
+ TREE_SIDE_EFFECTS (i->container) = 1;
+
cur = i->ptr;
/* Link it into the list. */
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 */
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: