return true;
}
+/* Return true if stmt can fall through. Used by block_may_fallthru
+ default case. */
+
+bool
+c_block_may_fallthru (const_tree stmt)
+{
+ switch (TREE_CODE (stmt))
+ {
+ case SWITCH_STMT:
+ return (!SWITCH_STMT_ALL_CASES_P (stmt)
+ || !SWITCH_STMT_NO_BREAK_P (stmt)
+ || block_may_fallthru (SWITCH_STMT_BODY (stmt)));
+
+ default:
+ return true;
+ }
+}
+
/* Finish an expression taking the address of LABEL (an
IDENTIFIER_NODE). Returns an expression for the address.
MARK_TS_EXP (SIZEOF_EXPR);
MARK_TS_EXP (C_MAYBE_CONST_EXPR);
MARK_TS_EXP (EXCESS_PRECISION_EXPR);
+ MARK_TS_EXP (BREAK_STMT);
+ MARK_TS_EXP (CONTINUE_STMT);
+ MARK_TS_EXP (DO_STMT);
+ MARK_TS_EXP (FOR_STMT);
+ MARK_TS_EXP (SWITCH_STMT);
+ MARK_TS_EXP (WHILE_STMT);
}
/* Build a user-defined numeric literal out of an integer constant type VALUE
or for the purpose of -Wsizeof-pointer-memaccess warning. */
DEFTREECODE (SIZEOF_EXPR, "sizeof_expr", tcc_expression, 1)
+/* Used to represent a `for' statement. The operands are
+ FOR_INIT_STMT, FOR_COND, FOR_EXPR, FOR_BODY, and FOR_SCOPE,
+ respectively. */
+DEFTREECODE (FOR_STMT, "for_stmt", tcc_statement, 5)
+
+/* Used to represent a 'while' statement. The operands are WHILE_COND
+ and WHILE_BODY, respectively. */
+DEFTREECODE (WHILE_STMT, "while_stmt", tcc_statement, 2)
+
+/* Used to represent a 'do' statement. The operands are DO_COND and
+ DO_BODY, respectively. */
+DEFTREECODE (DO_STMT, "do_stmt", tcc_statement, 2)
+
+/* Used to represent a 'break' statement. */
+DEFTREECODE (BREAK_STMT, "break_stmt", tcc_statement, 0)
+
+/* Used to represent a 'continue' statement. */
+DEFTREECODE (CONTINUE_STMT, "continue_stmt", tcc_statement, 0)
+
+/* Used to represent a 'switch' statement. The operands are
+ SWITCH_STMT_COND, SWITCH_STMT_BODY, SWITCH_STMT_TYPE, and
+ SWITCH_STMT_SCOPE, respectively. */
+DEFTREECODE (SWITCH_STMT, "switch_stmt", tcc_statement, 4)
+
/*
Local variables:
mode:c
extern tree c_add_case_label (location_t, splay_tree, tree, tree, tree);
extern bool c_switch_covers_all_cases_p (splay_tree, tree);
+extern bool c_block_may_fallthru (const_tree);
extern tree build_function_call (location_t, tree, tree);
extern const char *c_get_substring_location (const substring_loc &substr_loc,
location_t *out_loc);
-/* In c-gimplify.c */
+/* In c-gimplify.c. */
+typedef struct bc_state
+{
+ tree bc_label[2];
+} bc_state_t;
+extern void save_bc_state (bc_state_t *);
+extern void restore_bc_state (bc_state_t *);
+extern tree c_genericize_control_stmt (tree *, int *, void *,
+ walk_tree_fn, walk_tree_lh);
extern void c_genericize (tree);
extern int c_gimplify_expr (tree *, gimple_seq *, gimple_seq *);
extern tree c_build_bind_expr (location_t, tree, tree);
enum overflow_type overflow,
tree num_string);
+
+/* WHILE_STMT accessors. These give access to the condition of the
+ while statement and the body of the while statement, respectively. */
+#define WHILE_COND(NODE) TREE_OPERAND (WHILE_STMT_CHECK (NODE), 0)
+#define WHILE_BODY(NODE) TREE_OPERAND (WHILE_STMT_CHECK (NODE), 1)
+
+/* DO_STMT accessors. These give access to the condition of the do
+ statement and the body of the do statement, respectively. */
+#define DO_COND(NODE) TREE_OPERAND (DO_STMT_CHECK (NODE), 0)
+#define DO_BODY(NODE) TREE_OPERAND (DO_STMT_CHECK (NODE), 1)
+
+/* FOR_STMT accessors. These give access to the init statement,
+ condition, update expression, and body of the for statement,
+ respectively. */
+#define FOR_INIT_STMT(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 0)
+#define FOR_COND(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 1)
+#define FOR_EXPR(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 2)
+#define FOR_BODY(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 3)
+#define FOR_SCOPE(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 4)
+
+#define SWITCH_STMT_COND(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 0)
+#define SWITCH_STMT_BODY(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 1)
+#define SWITCH_STMT_TYPE(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 2)
+#define SWITCH_STMT_SCOPE(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 3)
+/* True if there are case labels for all possible values of switch cond, either
+ because there is a default: case label or because the case label ranges cover
+ all values. */
+#define SWITCH_STMT_ALL_CASES_P(NODE) \
+ TREE_LANG_FLAG_0 (SWITCH_STMT_CHECK (NODE))
+/* True if the body of a switch stmt contains no BREAK_STMTs. */
+#define SWITCH_STMT_NO_BREAK_P(NODE) \
+ TREE_LANG_FLAG_2 (SWITCH_STMT_CHECK (NODE))
+
+
+/* Nonzero if NODE is the target for genericization of 'break' stmts. */
+#define LABEL_DECL_BREAK(NODE) \
+ DECL_LANG_FLAG_0 (LABEL_DECL_CHECK (NODE))
+
+/* Nonzero if NODE is the target for genericization of 'continue' stmts. */
+#define LABEL_DECL_CONTINUE(NODE) \
+ DECL_LANG_FLAG_1 (LABEL_DECL_CHECK (NODE))
+
extern bool convert_vector_to_array_for_subscript (location_t, tree *, tree);
/* Possibe cases of scalar_to_vector conversion. */
/* Dump any C-specific tree codes and attributes of common codes. */
+static void
+dump_stmt (dump_info_p di, const_tree t)
+{
+ if (EXPR_HAS_LOCATION (t))
+ dump_int (di, "line", EXPR_LINENO (t));
+}
+
bool
c_dump_tree (void *dump_info, tree t)
{
dump_string (di, "bitfield");
break;
+ case BREAK_STMT:
+ case CONTINUE_STMT:
+ dump_stmt (di, t);
+ break;
+
+ case DO_STMT:
+ dump_stmt (di, t);
+ dump_child ("body", DO_BODY (t));
+ dump_child ("cond", DO_COND (t));
+ break;
+
+ case FOR_STMT:
+ dump_stmt (di, t);
+ dump_child ("init", FOR_INIT_STMT (t));
+ dump_child ("cond", FOR_COND (t));
+ dump_child ("expr", FOR_EXPR (t));
+ dump_child ("body", FOR_BODY (t));
+ break;
+
+ case SWITCH_STMT:
+ dump_stmt (di, t);
+ dump_child ("cond", SWITCH_STMT_COND (t));
+ dump_child ("body", SWITCH_STMT_BODY (t));
+ break;
+
+ case WHILE_STMT:
+ dump_stmt (di, t);
+ dump_child ("cond", WHILE_COND (t));
+ dump_child ("body", WHILE_BODY (t));
+ break;
+
default:
break;
}
#include "function.h"
#include "basic-block.h"
#include "tree.h"
+#include "tree-iterator.h"
+#include "predict.h"
#include "gimple.h"
#include "cgraph.h"
#include "c-pretty-print.h"
/* Gimplification of statement trees. */
+/* Local declarations. */
+
+enum bc_t { bc_break = 0, bc_continue = 1 };
+
+/* Stack of labels which are targets for "break" or "continue",
+ linked through TREE_CHAIN. */
+static tree bc_label[2];
+
+/* Begin a scope which can be exited by a break or continue statement. BC
+ indicates which.
+
+ Just creates a label with location LOCATION and pushes it into the current
+ context. */
+
+static tree
+begin_bc_block (enum bc_t bc, location_t location)
+{
+ tree label = create_artificial_label (location);
+ DECL_CHAIN (label) = bc_label[bc];
+ bc_label[bc] = label;
+ if (bc == bc_break)
+ LABEL_DECL_BREAK (label) = true;
+ else
+ LABEL_DECL_CONTINUE (label) = true;
+ return label;
+}
+
+/* Finish a scope which can be exited by a break or continue statement.
+ LABEL was returned from the most recent call to begin_bc_block. BLOCK is
+ an expression for the contents of the scope.
+
+ If we saw a break (or continue) in the scope, append a LABEL_EXPR to
+ BLOCK. Otherwise, just forget the label. */
+
+static void
+finish_bc_block (tree *block, enum bc_t bc, tree label)
+{
+ gcc_assert (label == bc_label[bc]);
+
+ if (TREE_USED (label))
+ append_to_statement_list (build1 (LABEL_EXPR, void_type_node, label),
+ block);
+
+ bc_label[bc] = DECL_CHAIN (label);
+ DECL_CHAIN (label) = NULL_TREE;
+}
+
+/* Allow saving and restoring break/continue state. */
+
+void
+save_bc_state (bc_state_t *state)
+{
+ state->bc_label[bc_break] = bc_label[bc_break];
+ state->bc_label[bc_continue] = bc_label[bc_continue];
+ bc_label[bc_break] = NULL_TREE;
+ bc_label[bc_continue] = NULL_TREE;
+}
+
+void
+restore_bc_state (bc_state_t *state)
+{
+ gcc_assert (bc_label[bc_break] == NULL);
+ gcc_assert (bc_label[bc_continue] == NULL);
+ bc_label[bc_break] = state->bc_label[bc_break];
+ bc_label[bc_continue] = state->bc_label[bc_continue];
+}
+
+/* Get the LABEL_EXPR to represent a break or continue statement
+ in the current block scope. BC indicates which. */
+
+static tree
+get_bc_label (enum bc_t bc)
+{
+ tree label = bc_label[bc];
+ gcc_assert (label);
+
+ /* Mark the label used for finish_bc_block. */
+ TREE_USED (label) = 1;
+ return label;
+}
+
+/* Return the location from EXPR, or OR_LOC if the former is unknown. */
+
+location_t
+expr_loc_or_loc (const_tree expr, location_t or_loc)
+{
+ tree t = CONST_CAST_TREE (expr);
+ location_t loc = UNKNOWN_LOCATION;
+ if (t)
+ loc = EXPR_LOCATION (t);
+ if (loc == UNKNOWN_LOCATION)
+ loc = or_loc;
+ return loc;
+}
+
+/* Build a generic representation of one of the C loop forms. COND is the
+ loop condition or NULL_TREE. BODY is the (possibly compound) statement
+ controlled by the loop. INCR is the increment expression of a for-loop,
+ or NULL_TREE. COND_IS_FIRST indicates whether the condition is
+ evaluated before the loop body as in while and for loops, or after the
+ loop body as in do-while loops. */
+
+static void
+genericize_c_loop (tree *stmt_p, location_t start_locus, tree cond, tree body,
+ tree incr, bool cond_is_first, int *walk_subtrees,
+ void *data, walk_tree_fn func, walk_tree_lh lh)
+{
+ tree blab, clab;
+ tree exit = NULL;
+ tree stmt_list = NULL;
+ tree debug_begin = NULL;
+
+ protected_set_expr_location_if_unset (incr, start_locus);
+
+ walk_tree_1 (&cond, func, data, NULL, lh);
+ walk_tree_1 (&incr, func, data, NULL, lh);
+
+ blab = begin_bc_block (bc_break, start_locus);
+ clab = begin_bc_block (bc_continue, start_locus);
+
+ walk_tree_1 (&body, func, data, NULL, lh);
+ *walk_subtrees = 0;
+
+ if (MAY_HAVE_DEBUG_MARKER_STMTS
+ && (!cond || !integer_zerop (cond)))
+ {
+ debug_begin = build0 (DEBUG_BEGIN_STMT, void_type_node);
+ SET_EXPR_LOCATION (debug_begin, expr_loc_or_loc (cond, start_locus));
+ }
+
+ if (cond && TREE_CODE (cond) != INTEGER_CST)
+ {
+ /* If COND is constant, don't bother building an exit. If it's false,
+ we won't build a loop. If it's true, any exits are in the body. */
+ location_t cloc = expr_loc_or_loc (cond, start_locus);
+ exit = build1_loc (cloc, GOTO_EXPR, void_type_node,
+ get_bc_label (bc_break));
+ exit = fold_build3_loc (cloc, COND_EXPR, void_type_node, cond,
+ build_empty_stmt (cloc), exit);
+ }
+
+ if (exit && cond_is_first)
+ {
+ append_to_statement_list (debug_begin, &stmt_list);
+ debug_begin = NULL_TREE;
+ append_to_statement_list (exit, &stmt_list);
+ }
+ append_to_statement_list (body, &stmt_list);
+ finish_bc_block (&stmt_list, bc_continue, clab);
+ if (incr)
+ {
+ if (MAY_HAVE_DEBUG_MARKER_STMTS)
+ {
+ tree d = build0 (DEBUG_BEGIN_STMT, void_type_node);
+ SET_EXPR_LOCATION (d, expr_loc_or_loc (incr, start_locus));
+ append_to_statement_list (d, &stmt_list);
+ }
+ append_to_statement_list (incr, &stmt_list);
+ }
+ append_to_statement_list (debug_begin, &stmt_list);
+ if (exit && !cond_is_first)
+ append_to_statement_list (exit, &stmt_list);
+
+ if (!stmt_list)
+ stmt_list = build_empty_stmt (start_locus);
+
+ tree loop;
+ if (cond && integer_zerop (cond))
+ {
+ if (cond_is_first)
+ loop = fold_build3_loc (start_locus, COND_EXPR,
+ void_type_node, cond, stmt_list,
+ build_empty_stmt (start_locus));
+ else
+ loop = stmt_list;
+ }
+ else
+ {
+ location_t loc = start_locus;
+ if (!cond || integer_nonzerop (cond))
+ loc = EXPR_LOCATION (expr_first (body));
+ if (loc == UNKNOWN_LOCATION)
+ loc = start_locus;
+ loop = build1_loc (loc, LOOP_EXPR, void_type_node, stmt_list);
+ }
+
+ stmt_list = NULL;
+ append_to_statement_list (loop, &stmt_list);
+ finish_bc_block (&stmt_list, bc_break, blab);
+ if (!stmt_list)
+ stmt_list = build_empty_stmt (start_locus);
+
+ *stmt_p = stmt_list;
+}
+
+/* Genericize a FOR_STMT node *STMT_P. */
+
+static void
+genericize_for_stmt (tree *stmt_p, int *walk_subtrees, void *data,
+ walk_tree_fn func, walk_tree_lh lh)
+{
+ tree stmt = *stmt_p;
+ tree expr = NULL;
+ tree loop;
+ tree init = FOR_INIT_STMT (stmt);
+
+ if (init)
+ {
+ walk_tree_1 (&init, func, data, NULL, lh);
+ append_to_statement_list (init, &expr);
+ }
+
+ genericize_c_loop (&loop, EXPR_LOCATION (stmt), FOR_COND (stmt),
+ FOR_BODY (stmt), FOR_EXPR (stmt), 1, walk_subtrees,
+ data, func, lh);
+ append_to_statement_list (loop, &expr);
+ if (expr == NULL_TREE)
+ expr = loop;
+ *stmt_p = expr;
+}
+
+/* Genericize a WHILE_STMT node *STMT_P. */
+
+static void
+genericize_while_stmt (tree *stmt_p, int *walk_subtrees, void *data,
+ walk_tree_fn func, walk_tree_lh lh)
+{
+ tree stmt = *stmt_p;
+ genericize_c_loop (stmt_p, EXPR_LOCATION (stmt), WHILE_COND (stmt),
+ WHILE_BODY (stmt), NULL_TREE, 1, walk_subtrees,
+ data, func, lh);
+}
+
+/* Genericize a DO_STMT node *STMT_P. */
+
+static void
+genericize_do_stmt (tree *stmt_p, int *walk_subtrees, void *data,
+ walk_tree_fn func, walk_tree_lh lh)
+{
+ tree stmt = *stmt_p;
+ genericize_c_loop (stmt_p, EXPR_LOCATION (stmt), DO_COND (stmt),
+ DO_BODY (stmt), NULL_TREE, 0, walk_subtrees,
+ data, func, lh);
+}
+
+/* Genericize a SWITCH_STMT node *STMT_P by turning it into a SWITCH_EXPR. */
+
+static void
+genericize_switch_stmt (tree *stmt_p, int *walk_subtrees, void *data,
+ walk_tree_fn func, walk_tree_lh lh)
+{
+ tree stmt = *stmt_p;
+ tree break_block, body, cond, type;
+ location_t stmt_locus = EXPR_LOCATION (stmt);
+
+ body = SWITCH_STMT_BODY (stmt);
+ if (!body)
+ body = build_empty_stmt (stmt_locus);
+ cond = SWITCH_STMT_COND (stmt);
+ type = SWITCH_STMT_TYPE (stmt);
+
+ walk_tree_1 (&cond, func, data, NULL, lh);
+
+ break_block = begin_bc_block (bc_break, stmt_locus);
+
+ walk_tree_1 (&body, func, data, NULL, lh);
+ walk_tree_1 (&type, func, data, NULL, lh);
+ *walk_subtrees = 0;
+
+ if (TREE_USED (break_block))
+ SWITCH_BREAK_LABEL_P (break_block) = 1;
+ finish_bc_block (&body, bc_break, break_block);
+ *stmt_p = build2_loc (stmt_locus, SWITCH_EXPR, type, cond, body);
+ SWITCH_ALL_CASES_P (*stmt_p) = SWITCH_STMT_ALL_CASES_P (stmt);
+ gcc_checking_assert (!SWITCH_STMT_NO_BREAK_P (stmt)
+ || !TREE_USED (break_block));
+}
+
+/* Genericize a CONTINUE_STMT node *STMT_P. */
+
+static void
+genericize_continue_stmt (tree *stmt_p)
+{
+ tree stmt_list = NULL;
+ tree pred = build_predict_expr (PRED_CONTINUE, NOT_TAKEN);
+ tree label = get_bc_label (bc_continue);
+ location_t location = EXPR_LOCATION (*stmt_p);
+ tree jump = build1_loc (location, GOTO_EXPR, void_type_node, label);
+ append_to_statement_list_force (pred, &stmt_list);
+ append_to_statement_list (jump, &stmt_list);
+ *stmt_p = stmt_list;
+}
+
+/* Genericize a BREAK_STMT node *STMT_P. */
+
+static void
+genericize_break_stmt (tree *stmt_p)
+{
+ tree label = get_bc_label (bc_break);
+ location_t location = EXPR_LOCATION (*stmt_p);
+ *stmt_p = build1_loc (location, GOTO_EXPR, void_type_node, label);
+}
+
+/* Genericize a OMP_FOR node *STMT_P. */
+
+static void
+genericize_omp_for_stmt (tree *stmt_p, int *walk_subtrees, void *data,
+ walk_tree_fn func, walk_tree_lh lh)
+{
+ tree stmt = *stmt_p;
+ location_t locus = EXPR_LOCATION (stmt);
+ tree clab = begin_bc_block (bc_continue, locus);
+
+ walk_tree_1 (&OMP_FOR_BODY (stmt), func, data, NULL, lh);
+ if (TREE_CODE (stmt) != OMP_TASKLOOP)
+ walk_tree_1 (&OMP_FOR_CLAUSES (stmt), func, data, NULL, lh);
+ walk_tree_1 (&OMP_FOR_INIT (stmt), func, data, NULL, lh);
+ walk_tree_1 (&OMP_FOR_COND (stmt), func, data, NULL, lh);
+ walk_tree_1 (&OMP_FOR_INCR (stmt), func, data, NULL, lh);
+ walk_tree_1 (&OMP_FOR_PRE_BODY (stmt), func, data, NULL, lh);
+ *walk_subtrees = 0;
+
+ finish_bc_block (&OMP_FOR_BODY (stmt), bc_continue, clab);
+}
+
+
+/* Lower structured control flow tree nodes, such as loops. The
+ STMT_P, WALK_SUBTREES, and DATA arguments are as for the walk_tree_fn
+ type. FUNC and LH are language-specific functions passed to walk_tree_1
+ for node visiting and traversal, respectively; they are used to do
+ subtree processing in a language-dependent way. */
+
+tree
+c_genericize_control_stmt (tree *stmt_p, int *walk_subtrees, void *data,
+ walk_tree_fn func, walk_tree_lh lh)
+{
+ tree stmt = *stmt_p;
+
+ switch (TREE_CODE (stmt))
+ {
+ case FOR_STMT:
+ genericize_for_stmt (stmt_p, walk_subtrees, data, func, lh);
+ break;
+
+ case WHILE_STMT:
+ genericize_while_stmt (stmt_p, walk_subtrees, data, func, lh);
+ break;
+
+ case DO_STMT:
+ genericize_do_stmt (stmt_p, walk_subtrees, data, func, lh);
+ break;
+
+ case SWITCH_STMT:
+ genericize_switch_stmt (stmt_p, walk_subtrees, data, func, lh);
+ break;
+
+ case CONTINUE_STMT:
+ genericize_continue_stmt (stmt_p);
+ break;
+
+ case BREAK_STMT:
+ genericize_break_stmt (stmt_p);
+ break;
+
+ case OMP_FOR:
+ case OMP_SIMD:
+ case OMP_DISTRIBUTE:
+ case OMP_LOOP:
+ case OMP_TASKLOOP:
+ case OACC_LOOP:
+ genericize_omp_for_stmt (stmt_p, walk_subtrees, data, func, lh);
+ break;
+
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+
+/* Wrapper for c_genericize_control_stmt to allow it to be used as a walk_tree
+ callback. This is appropriate for C; C++ calls c_genericize_control_stmt
+ directly. */
+
+static tree
+c_genericize_control_r (tree *stmt_p, int *walk_subtrees, void *data)
+{
+ c_genericize_control_stmt (stmt_p, walk_subtrees, data,
+ c_genericize_control_r, NULL);
+ return NULL;
+}
+
/* Convert the tree representation of FNDECL from C frontend trees to
GENERIC. */
walk_tree_without_duplicates (&DECL_SAVED_TREE (fndecl),
do_warn_duplicated_branches_r, NULL);
+ /* Genericize loops and other structured control constructs. The C++
+ front end has already done this in lang-specific code. */
+ if (!c_dialect_cxx ())
+ {
+ bc_state_t save_state;
+ push_cfun (DECL_STRUCT_FUNCTION (fndecl));
+ save_bc_state (&save_state);
+ walk_tree (&DECL_SAVED_TREE (fndecl), c_genericize_control_r,
+ NULL, NULL);
+ restore_bc_state (&save_state);
+ pop_cfun ();
+ }
+
/* Dump the C-specific tree IR. */
dump_orig = get_dump_info (TDI_original, &local_dump_flags);
if (dump_orig)
/* Statements. */
void
-c_pretty_printer::statement (tree stmt)
+c_pretty_printer::statement (tree t)
{
- if (stmt == NULL)
+ if (t == NULL)
return;
- if (pp_needs_newline (this))
- pp_newline_and_indent (this, 0);
+ switch (TREE_CODE (t))
+ {
+
+ case SWITCH_STMT:
+ pp_c_ws_string (this, "switch");
+ pp_space (this);
+ pp_c_left_paren (this);
+ expression (SWITCH_STMT_COND (t));
+ pp_c_right_paren (this);
+ pp_indentation (this) += 3;
+ pp_needs_newline (this) = true;
+ statement (SWITCH_STMT_BODY (t));
+ pp_newline_and_indent (this, -3);
+ break;
+
+ /* iteration-statement:
+ while ( expression ) statement
+ do statement while ( expression ) ;
+ for ( expression(opt) ; expression(opt) ; expression(opt) ) statement
+ for ( declaration expression(opt) ; expression(opt) ) statement */
+ case WHILE_STMT:
+ pp_c_ws_string (this, "while");
+ pp_space (this);
+ pp_c_left_paren (this);
+ expression (WHILE_COND (t));
+ pp_c_right_paren (this);
+ pp_newline_and_indent (this, 3);
+ statement (WHILE_BODY (t));
+ pp_indentation (this) -= 3;
+ pp_needs_newline (this) = true;
+ break;
+
+ case DO_STMT:
+ pp_c_ws_string (this, "do");
+ pp_newline_and_indent (this, 3);
+ statement (DO_BODY (t));
+ pp_newline_and_indent (this, -3);
+ pp_c_ws_string (this, "while");
+ pp_space (this);
+ pp_c_left_paren (this);
+ expression (DO_COND (t));
+ pp_c_right_paren (this);
+ pp_c_semicolon (this);
+ pp_needs_newline (this) = true;
+ break;
- dump_generic_node (this, stmt, pp_indentation (this), TDF_NONE, true);
+ case FOR_STMT:
+ pp_c_ws_string (this, "for");
+ pp_space (this);
+ pp_c_left_paren (this);
+ if (FOR_INIT_STMT (t))
+ statement (FOR_INIT_STMT (t));
+ else
+ pp_c_semicolon (this);
+ pp_needs_newline (this) = false;
+ pp_c_whitespace (this);
+ if (FOR_COND (t))
+ expression (FOR_COND (t));
+ pp_c_semicolon (this);
+ pp_needs_newline (this) = false;
+ pp_c_whitespace (this);
+ if (FOR_EXPR (t))
+ expression (FOR_EXPR (t));
+ pp_c_right_paren (this);
+ pp_newline_and_indent (this, 3);
+ statement (FOR_BODY (t));
+ pp_indentation (this) -= 3;
+ pp_needs_newline (this) = true;
+ break;
+
+ /* jump-statement:
+ goto identifier;
+ continue ;
+ return expression(opt) ; */
+ case BREAK_STMT:
+ case CONTINUE_STMT:
+ pp_string (this, TREE_CODE (t) == BREAK_STMT ? "break" : "continue");
+ pp_c_semicolon (this);
+ pp_needs_newline (this) = true;
+ break;
+
+ default:
+ if (pp_needs_newline (this))
+ pp_newline_and_indent (this, 0);
+ dump_generic_node (this, t, pp_indentation (this), TDF_NONE, true);
+ }
}
\f
static void cp_genericize_tree (tree*, bool);
static tree cp_fold (tree);
-/* Local declarations. */
-
-enum bc_t { bc_break = 0, bc_continue = 1 };
-
-/* Stack of labels which are targets for "break" or "continue",
- linked through TREE_CHAIN. */
-static tree bc_label[2];
-
-/* Begin a scope which can be exited by a break or continue statement. BC
- indicates which.
-
- Just creates a label with location LOCATION and pushes it into the current
- context. */
-
-static tree
-begin_bc_block (enum bc_t bc, location_t location)
-{
- tree label = create_artificial_label (location);
- DECL_CHAIN (label) = bc_label[bc];
- bc_label[bc] = label;
- if (bc == bc_break)
- LABEL_DECL_BREAK (label) = true;
- else
- LABEL_DECL_CONTINUE (label) = true;
- return label;
-}
-
-/* Finish a scope which can be exited by a break or continue statement.
- LABEL was returned from the most recent call to begin_bc_block. BLOCK is
- an expression for the contents of the scope.
-
- If we saw a break (or continue) in the scope, append a LABEL_EXPR to
- BLOCK. Otherwise, just forget the label. */
-
-static void
-finish_bc_block (tree *block, enum bc_t bc, tree label)
-{
- gcc_assert (label == bc_label[bc]);
-
- if (TREE_USED (label))
- append_to_statement_list (build1 (LABEL_EXPR, void_type_node, label),
- block);
-
- bc_label[bc] = DECL_CHAIN (label);
- DECL_CHAIN (label) = NULL_TREE;
-}
-
-/* Get the LABEL_EXPR to represent a break or continue statement
- in the current block scope. BC indicates which. */
-
-static tree
-get_bc_label (enum bc_t bc)
-{
- tree label = bc_label[bc];
-
- /* Mark the label used for finish_bc_block. */
- TREE_USED (label) = 1;
- return label;
-}
-
/* Genericize a TRY_BLOCK. */
static void
*stmt_p = stmt;
}
-/* Build a generic representation of one of the C loop forms. COND is the
- loop condition or NULL_TREE. BODY is the (possibly compound) statement
- controlled by the loop. INCR is the increment expression of a for-loop,
- or NULL_TREE. COND_IS_FIRST indicates whether the condition is
- evaluated before the loop body as in while and for loops, or after the
- loop body as in do-while loops. */
-
-static void
-genericize_cp_loop (tree *stmt_p, location_t start_locus, tree cond, tree body,
- tree incr, bool cond_is_first, int *walk_subtrees,
- void *data)
-{
- tree blab, clab;
- tree exit = NULL;
- tree stmt_list = NULL;
- tree debug_begin = NULL;
-
- protected_set_expr_location_if_unset (incr, start_locus);
-
- cp_walk_tree (&cond, cp_genericize_r, data, NULL);
- cp_walk_tree (&incr, cp_genericize_r, data, NULL);
-
- blab = begin_bc_block (bc_break, start_locus);
- clab = begin_bc_block (bc_continue, start_locus);
-
- cp_walk_tree (&body, cp_genericize_r, data, NULL);
- *walk_subtrees = 0;
-
- if (MAY_HAVE_DEBUG_MARKER_STMTS
- && (!cond || !integer_zerop (cond)))
- {
- debug_begin = build0 (DEBUG_BEGIN_STMT, void_type_node);
- SET_EXPR_LOCATION (debug_begin, cp_expr_loc_or_loc (cond, start_locus));
- }
-
- if (cond && TREE_CODE (cond) != INTEGER_CST)
- {
- /* If COND is constant, don't bother building an exit. If it's false,
- we won't build a loop. If it's true, any exits are in the body. */
- location_t cloc = cp_expr_loc_or_loc (cond, start_locus);
- exit = build1_loc (cloc, GOTO_EXPR, void_type_node,
- get_bc_label (bc_break));
- exit = fold_build3_loc (cloc, COND_EXPR, void_type_node, cond,
- build_empty_stmt (cloc), exit);
- }
-
- if (exit && cond_is_first)
- {
- append_to_statement_list (debug_begin, &stmt_list);
- debug_begin = NULL_TREE;
- append_to_statement_list (exit, &stmt_list);
- }
- append_to_statement_list (body, &stmt_list);
- finish_bc_block (&stmt_list, bc_continue, clab);
- if (incr)
- {
- if (MAY_HAVE_DEBUG_MARKER_STMTS)
- {
- tree d = build0 (DEBUG_BEGIN_STMT, void_type_node);
- SET_EXPR_LOCATION (d, cp_expr_loc_or_loc (incr, start_locus));
- append_to_statement_list (d, &stmt_list);
- }
- append_to_statement_list (incr, &stmt_list);
- }
- append_to_statement_list (debug_begin, &stmt_list);
- if (exit && !cond_is_first)
- append_to_statement_list (exit, &stmt_list);
-
- if (!stmt_list)
- stmt_list = build_empty_stmt (start_locus);
-
- tree loop;
- if (cond && integer_zerop (cond))
- {
- if (cond_is_first)
- loop = fold_build3_loc (start_locus, COND_EXPR,
- void_type_node, cond, stmt_list,
- build_empty_stmt (start_locus));
- else
- loop = stmt_list;
- }
- else
- {
- location_t loc = start_locus;
- if (!cond || integer_nonzerop (cond))
- loc = EXPR_LOCATION (expr_first (body));
- if (loc == UNKNOWN_LOCATION)
- loc = start_locus;
- loop = build1_loc (loc, LOOP_EXPR, void_type_node, stmt_list);
- }
-
- stmt_list = NULL;
- append_to_statement_list (loop, &stmt_list);
- finish_bc_block (&stmt_list, bc_break, blab);
- if (!stmt_list)
- stmt_list = build_empty_stmt (start_locus);
-
- *stmt_p = stmt_list;
-}
-
-/* Genericize a FOR_STMT node *STMT_P. */
-
-static void
-genericize_for_stmt (tree *stmt_p, int *walk_subtrees, void *data)
-{
- tree stmt = *stmt_p;
- tree expr = NULL;
- tree loop;
- tree init = FOR_INIT_STMT (stmt);
-
- if (init)
- {
- cp_walk_tree (&init, cp_genericize_r, data, NULL);
- append_to_statement_list (init, &expr);
- }
-
- genericize_cp_loop (&loop, EXPR_LOCATION (stmt), FOR_COND (stmt),
- FOR_BODY (stmt), FOR_EXPR (stmt), 1, walk_subtrees, data);
- append_to_statement_list (loop, &expr);
- if (expr == NULL_TREE)
- expr = loop;
- *stmt_p = expr;
-}
-
-/* Genericize a WHILE_STMT node *STMT_P. */
-
-static void
-genericize_while_stmt (tree *stmt_p, int *walk_subtrees, void *data)
-{
- tree stmt = *stmt_p;
- genericize_cp_loop (stmt_p, EXPR_LOCATION (stmt), WHILE_COND (stmt),
- WHILE_BODY (stmt), NULL_TREE, 1, walk_subtrees, data);
-}
-
-/* Genericize a DO_STMT node *STMT_P. */
-
-static void
-genericize_do_stmt (tree *stmt_p, int *walk_subtrees, void *data)
-{
- tree stmt = *stmt_p;
- genericize_cp_loop (stmt_p, EXPR_LOCATION (stmt), DO_COND (stmt),
- DO_BODY (stmt), NULL_TREE, 0, walk_subtrees, data);
-}
-
-/* Genericize a SWITCH_STMT node *STMT_P by turning it into a SWITCH_EXPR. */
-
-static void
-genericize_switch_stmt (tree *stmt_p, int *walk_subtrees, void *data)
-{
- tree stmt = *stmt_p;
- tree break_block, body, cond, type;
- location_t stmt_locus = EXPR_LOCATION (stmt);
-
- body = SWITCH_STMT_BODY (stmt);
- if (!body)
- body = build_empty_stmt (stmt_locus);
- cond = SWITCH_STMT_COND (stmt);
- type = SWITCH_STMT_TYPE (stmt);
-
- cp_walk_tree (&cond, cp_genericize_r, data, NULL);
-
- break_block = begin_bc_block (bc_break, stmt_locus);
-
- cp_walk_tree (&body, cp_genericize_r, data, NULL);
- cp_walk_tree (&type, cp_genericize_r, data, NULL);
- *walk_subtrees = 0;
-
- if (TREE_USED (break_block))
- SWITCH_BREAK_LABEL_P (break_block) = 1;
- finish_bc_block (&body, bc_break, break_block);
- *stmt_p = build2_loc (stmt_locus, SWITCH_EXPR, type, cond, body);
- SWITCH_ALL_CASES_P (*stmt_p) = SWITCH_STMT_ALL_CASES_P (stmt);
- gcc_checking_assert (!SWITCH_STMT_NO_BREAK_P (stmt)
- || !TREE_USED (break_block));
-}
-
-/* Genericize a CONTINUE_STMT node *STMT_P. */
-
-static void
-genericize_continue_stmt (tree *stmt_p)
-{
- tree stmt_list = NULL;
- tree pred = build_predict_expr (PRED_CONTINUE, NOT_TAKEN);
- tree label = get_bc_label (bc_continue);
- location_t location = EXPR_LOCATION (*stmt_p);
- tree jump = build1_loc (location, GOTO_EXPR, void_type_node, label);
- append_to_statement_list_force (pred, &stmt_list);
- append_to_statement_list (jump, &stmt_list);
- *stmt_p = stmt_list;
-}
-
-/* Genericize a BREAK_STMT node *STMT_P. */
-
-static void
-genericize_break_stmt (tree *stmt_p)
-{
- tree label = get_bc_label (bc_break);
- location_t location = EXPR_LOCATION (*stmt_p);
- *stmt_p = build1_loc (location, GOTO_EXPR, void_type_node, label);
-}
-
-/* Genericize a OMP_FOR node *STMT_P. */
-
-static void
-genericize_omp_for_stmt (tree *stmt_p, int *walk_subtrees, void *data)
-{
- tree stmt = *stmt_p;
- location_t locus = EXPR_LOCATION (stmt);
- tree clab = begin_bc_block (bc_continue, locus);
-
- cp_walk_tree (&OMP_FOR_BODY (stmt), cp_genericize_r, data, NULL);
- if (TREE_CODE (stmt) != OMP_TASKLOOP)
- cp_walk_tree (&OMP_FOR_CLAUSES (stmt), cp_genericize_r, data, NULL);
- cp_walk_tree (&OMP_FOR_INIT (stmt), cp_genericize_r, data, NULL);
- cp_walk_tree (&OMP_FOR_COND (stmt), cp_genericize_r, data, NULL);
- cp_walk_tree (&OMP_FOR_INCR (stmt), cp_genericize_r, data, NULL);
- cp_walk_tree (&OMP_FOR_PRE_BODY (stmt), cp_genericize_r, data, NULL);
- *walk_subtrees = 0;
-
- finish_bc_block (&OMP_FOR_BODY (stmt), bc_continue, clab);
-}
-
/* Hook into the middle of gimplifying an OMP_FOR node. */
static enum gimplify_status
break;
}
if (TREE_CODE (stmt) == OMP_TASKLOOP)
- genericize_omp_for_stmt (stmt_p, walk_subtrees, data);
+ c_genericize_control_stmt (stmt_p, walk_subtrees, data,
+ cp_genericize_r, cp_walk_subtrees);
else
cp_walk_tree (&OMP_BODY (stmt), cp_genericize_r, data, NULL);
wtd->omp_ctx = omp_ctx.outer;
gcc_assert (!CONVERT_EXPR_VBASE_PATH (stmt));
break;
- case FOR_STMT:
- genericize_for_stmt (stmt_p, walk_subtrees, data);
- break;
-
- case WHILE_STMT:
- genericize_while_stmt (stmt_p, walk_subtrees, data);
- break;
-
- case DO_STMT:
- genericize_do_stmt (stmt_p, walk_subtrees, data);
- break;
-
- case SWITCH_STMT:
- genericize_switch_stmt (stmt_p, walk_subtrees, data);
- break;
-
- case CONTINUE_STMT:
- genericize_continue_stmt (stmt_p);
- break;
-
- case BREAK_STMT:
- genericize_break_stmt (stmt_p);
- break;
-
case SPACESHIP_EXPR:
*stmt_p = genericize_spaceship (*stmt_p);
break;
- case OMP_DISTRIBUTE:
- /* Need to explicitly instantiate copy ctors on class iterators of
- composite distribute parallel for. */
- if (OMP_FOR_INIT (*stmt_p) == NULL_TREE)
- {
- tree *data[4] = { NULL, NULL, NULL, NULL };
- tree inner = walk_tree (&OMP_FOR_BODY (*stmt_p),
- find_combined_omp_for, data, NULL);
- if (inner != NULL_TREE
- && TREE_CODE (inner) == OMP_FOR)
- {
- for (int i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (inner)); i++)
- if (OMP_FOR_ORIG_DECLS (inner)
- && TREE_CODE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner),
- i)) == TREE_LIST
- && TREE_PURPOSE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner),
- i)))
- {
- tree orig = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner), i);
- /* Class iterators aren't allowed on OMP_SIMD, so the only
- case we need to solve is distribute parallel for. */
- gcc_assert (TREE_CODE (inner) == OMP_FOR
- && data[1]);
- tree orig_decl = TREE_PURPOSE (orig);
- tree c, cl = NULL_TREE;
- for (c = OMP_FOR_CLAUSES (inner);
- c; c = OMP_CLAUSE_CHAIN (c))
- if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE
- || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE)
- && OMP_CLAUSE_DECL (c) == orig_decl)
- {
- cl = c;
- break;
- }
- if (cl == NULL_TREE)
- {
- for (c = OMP_PARALLEL_CLAUSES (*data[1]);
- c; c = OMP_CLAUSE_CHAIN (c))
- if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE
- && OMP_CLAUSE_DECL (c) == orig_decl)
- {
- cl = c;
- break;
- }
- }
- if (cl)
- {
- orig_decl = require_complete_type (orig_decl);
- tree inner_type = TREE_TYPE (orig_decl);
- if (orig_decl == error_mark_node)
- continue;
- if (TYPE_REF_P (TREE_TYPE (orig_decl)))
- inner_type = TREE_TYPE (inner_type);
-
- while (TREE_CODE (inner_type) == ARRAY_TYPE)
- inner_type = TREE_TYPE (inner_type);
- get_copy_ctor (inner_type, tf_warning_or_error);
- }
- }
- }
- }
- /* FALLTHRU */
- case OMP_FOR:
- case OMP_SIMD:
- case OMP_LOOP:
- case OACC_LOOP:
- genericize_omp_for_stmt (stmt_p, walk_subtrees, data);
- break;
-
case PTRMEM_CST:
/* By the time we get here we're handing off to the back end, so we don't
need or want to preserve PTRMEM_CST anymore. */
}
break;
+ case OMP_DISTRIBUTE:
+ /* Need to explicitly instantiate copy ctors on class iterators of
+ composite distribute parallel for. */
+ if (OMP_FOR_INIT (*stmt_p) == NULL_TREE)
+ {
+ tree *data[4] = { NULL, NULL, NULL, NULL };
+ tree inner = walk_tree (&OMP_FOR_BODY (*stmt_p),
+ find_combined_omp_for, data, NULL);
+ if (inner != NULL_TREE
+ && TREE_CODE (inner) == OMP_FOR)
+ {
+ for (int i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (inner)); i++)
+ if (OMP_FOR_ORIG_DECLS (inner)
+ && TREE_CODE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner),
+ i)) == TREE_LIST
+ && TREE_PURPOSE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner),
+ i)))
+ {
+ tree orig = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner), i);
+ /* Class iterators aren't allowed on OMP_SIMD, so the only
+ case we need to solve is distribute parallel for. */
+ gcc_assert (TREE_CODE (inner) == OMP_FOR
+ && data[1]);
+ tree orig_decl = TREE_PURPOSE (orig);
+ tree c, cl = NULL_TREE;
+ for (c = OMP_FOR_CLAUSES (inner);
+ c; c = OMP_CLAUSE_CHAIN (c))
+ if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE
+ || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE)
+ && OMP_CLAUSE_DECL (c) == orig_decl)
+ {
+ cl = c;
+ break;
+ }
+ if (cl == NULL_TREE)
+ {
+ for (c = OMP_PARALLEL_CLAUSES (*data[1]);
+ c; c = OMP_CLAUSE_CHAIN (c))
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE
+ && OMP_CLAUSE_DECL (c) == orig_decl)
+ {
+ cl = c;
+ break;
+ }
+ }
+ if (cl)
+ {
+ orig_decl = require_complete_type (orig_decl);
+ tree inner_type = TREE_TYPE (orig_decl);
+ if (orig_decl == error_mark_node)
+ continue;
+ if (TYPE_REF_P (TREE_TYPE (orig_decl)))
+ inner_type = TREE_TYPE (inner_type);
+
+ while (TREE_CODE (inner_type) == ARRAY_TYPE)
+ inner_type = TREE_TYPE (inner_type);
+ get_copy_ctor (inner_type, tf_warning_or_error);
+ }
+ }
+ }
+ }
+ /* FALLTHRU */
+
+ case FOR_STMT:
+ case WHILE_STMT:
+ case DO_STMT:
+ case SWITCH_STMT:
+ case CONTINUE_STMT:
+ case BREAK_STMT:
+ case OMP_FOR:
+ case OMP_SIMD:
+ case OMP_LOOP:
+ case OACC_LOOP:
+ /* These cases are handled by shared code. */
+ c_genericize_control_stmt (stmt_p, walk_subtrees, data,
+ cp_genericize_r, cp_walk_subtrees);
+ break;
+
default:
if (IS_TYPE_OR_DECL_P (stmt))
*walk_subtrees = 0;
return;
/* Allow cp_genericize calls to be nested. */
- tree save_bc_label[2];
- save_bc_label[bc_break] = bc_label[bc_break];
- save_bc_label[bc_continue] = bc_label[bc_continue];
- bc_label[bc_break] = NULL_TREE;
- bc_label[bc_continue] = NULL_TREE;
+ bc_state_t save_state;
+ save_bc_state (&save_state);
/* We do want to see every occurrence of the parms, so we can't just use
walk_tree's hash functionality. */
/* Do everything else. */
c_genericize (fndecl);
-
- gcc_assert (bc_label[bc_break] == NULL);
- gcc_assert (bc_label[bc_continue] == NULL);
- bc_label[bc_break] = save_bc_label[bc_break];
- bc_label[bc_continue] = save_bc_label[bc_continue];
+ restore_bc_state (&save_state);
}
\f
/* Build code to apply FN to each member of ARG1 and ARG2. FN may be
return true;
return block_may_fallthru (ELSE_CLAUSE (stmt));
- case SWITCH_STMT:
- return (!SWITCH_STMT_ALL_CASES_P (stmt)
- || !SWITCH_STMT_NO_BREAK_P (stmt)
- || block_may_fallthru (SWITCH_STMT_BODY (stmt)));
-
default:
- return true;
+ return c_block_may_fallthru (stmt);
}
}
MARK_TS_TYPE_NON_COMMON (TYPE_PACK_EXPANSION);
/* Statements. */
- MARK_TS_EXP (BREAK_STMT);
MARK_TS_EXP (CLEANUP_STMT);
- MARK_TS_EXP (CONTINUE_STMT);
- MARK_TS_EXP (DO_STMT);
MARK_TS_EXP (EH_SPEC_BLOCK);
- MARK_TS_EXP (FOR_STMT);
MARK_TS_EXP (HANDLER);
MARK_TS_EXP (IF_STMT);
MARK_TS_EXP (OMP_DEPOBJ);
MARK_TS_EXP (RANGE_FOR_STMT);
- MARK_TS_EXP (SWITCH_STMT);
MARK_TS_EXP (TRY_BLOCK);
MARK_TS_EXP (USING_STMT);
- MARK_TS_EXP (WHILE_STMT);
/* Random expressions. */
MARK_TS_EXP (ADDRESSOF_EXPR);
and COND_EXPR for the benefit of templates. */
DEFTREECODE (IF_STMT, "if_stmt", tcc_statement, 4)
-/* Used to represent a `for' statement. The operands are
- FOR_INIT_STMT, FOR_COND, FOR_EXPR, and FOR_BODY, respectively. */
-DEFTREECODE (FOR_STMT, "for_stmt", tcc_statement, 5)
-
/* Used to represent a range-based `for' statement. The operands are
RANGE_FOR_DECL, RANGE_FOR_EXPR, RANGE_FOR_BODY, RANGE_FOR_SCOPE,
RANGE_FOR_UNROLL, and RANGE_FOR_INIT_STMT, respectively. Only used in
templates. */
DEFTREECODE (RANGE_FOR_STMT, "range_for_stmt", tcc_statement, 6)
-/* Used to represent a 'while' statement. The operands are WHILE_COND
- and WHILE_BODY, respectively. */
-DEFTREECODE (WHILE_STMT, "while_stmt", tcc_statement, 2)
-
-/* Used to represent a 'do' statement. The operands are DO_BODY and
- DO_COND, respectively. */
-DEFTREECODE (DO_STMT, "do_stmt", tcc_statement, 2)
-
-/* Used to represent a 'break' statement. */
-DEFTREECODE (BREAK_STMT, "break_stmt", tcc_statement, 0)
-
-/* Used to represent a 'continue' statement. */
-DEFTREECODE (CONTINUE_STMT, "continue_stmt", tcc_statement, 0)
-
-/* Used to represent a 'switch' statement. The operands are
- SWITCH_STMT_COND, SWITCH_STMT_BODY, SWITCH_STMT_TYPE, and
- SWITCH_STMT_SCOPE, respectively. */
-DEFTREECODE (SWITCH_STMT, "switch_stmt", tcc_statement, 4)
-
/* Used to represent an expression statement. Use `EXPR_STMT_EXPR' to
obtain the expression. */
DEFTREECODE (EXPR_STMT, "expr_stmt", tcc_expression, 1)
#define DECL_LOCAL_DECL_P(NODE) \
DECL_LANG_FLAG_0 (VAR_OR_FUNCTION_DECL_CHECK (NODE))
-/* Nonzero if NODE is the target for genericization of 'break' stmts. */
-#define LABEL_DECL_BREAK(NODE) \
- DECL_LANG_FLAG_0 (LABEL_DECL_CHECK (NODE))
-
-/* Nonzero if NODE is the target for genericization of 'continue' stmts. */
-#define LABEL_DECL_CONTINUE(NODE) \
- DECL_LANG_FLAG_1 (LABEL_DECL_CHECK (NODE))
-
/* Nonzero if NODE is the target for genericization of 'return' stmts
in constructors/destructors of targetm.cxx.cdtor_returns_this targets. */
#define LABEL_DECL_CDTOR(NODE) \
building an IF_STMT; IF_STMT_EXTRA_ARGS is used after it is complete. */
#define IF_STMT_EXTRA_ARGS(NODE) IF_SCOPE (NODE)
-/* WHILE_STMT accessors. These give access to the condition of the
- while statement and the body of the while statement, respectively. */
-#define WHILE_COND(NODE) TREE_OPERAND (WHILE_STMT_CHECK (NODE), 0)
-#define WHILE_BODY(NODE) TREE_OPERAND (WHILE_STMT_CHECK (NODE), 1)
-
-/* DO_STMT accessors. These give access to the condition of the do
- statement and the body of the do statement, respectively. */
-#define DO_COND(NODE) TREE_OPERAND (DO_STMT_CHECK (NODE), 0)
-#define DO_BODY(NODE) TREE_OPERAND (DO_STMT_CHECK (NODE), 1)
-
-/* FOR_STMT accessors. These give access to the init statement,
- condition, update expression, and body of the for statement,
- respectively. */
-#define FOR_INIT_STMT(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 0)
-#define FOR_COND(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 1)
-#define FOR_EXPR(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 2)
-#define FOR_BODY(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 3)
-#define FOR_SCOPE(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 4)
-
/* RANGE_FOR_STMT accessors. These give access to the declarator,
expression, body, and scope of the statement, respectively. */
#define RANGE_FOR_DECL(NODE) TREE_OPERAND (RANGE_FOR_STMT_CHECK (NODE), 0)
#define RANGE_FOR_INIT_STMT(NODE) TREE_OPERAND (RANGE_FOR_STMT_CHECK (NODE), 5)
#define RANGE_FOR_IVDEP(NODE) TREE_LANG_FLAG_6 (RANGE_FOR_STMT_CHECK (NODE))
-#define SWITCH_STMT_COND(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 0)
-#define SWITCH_STMT_BODY(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 1)
-#define SWITCH_STMT_TYPE(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 2)
-#define SWITCH_STMT_SCOPE(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 3)
-/* True if there are case labels for all possible values of switch cond, either
- because there is a default: case label or because the case label ranges cover
- all values. */
-#define SWITCH_STMT_ALL_CASES_P(NODE) \
- TREE_LANG_FLAG_0 (SWITCH_STMT_CHECK (NODE))
-/* True if the body of a switch stmt contains no BREAK_STMTs. */
-#define SWITCH_STMT_NO_BREAK_P(NODE) \
- TREE_LANG_FLAG_2 (SWITCH_STMT_CHECK (NODE))
-
/* STMT_EXPR accessor. */
#define STMT_EXPR_STMT(NODE) TREE_OPERAND (STMT_EXPR_CHECK (NODE), 0)
}
break;
- case SWITCH_STMT:
- pp_cxx_ws_string (this, "switch");
- pp_space (this);
- pp_cxx_left_paren (this);
- expression (SWITCH_STMT_COND (t));
- pp_cxx_right_paren (this);
- pp_indentation (this) += 3;
- pp_needs_newline (this) = true;
- statement (SWITCH_STMT_BODY (t));
- pp_newline_and_indent (this, -3);
- break;
-
- /* iteration-statement:
- while ( expression ) statement
- do statement while ( expression ) ;
- for ( expression(opt) ; expression(opt) ; expression(opt) ) statement
- for ( declaration expression(opt) ; expression(opt) ) statement */
- case WHILE_STMT:
- pp_cxx_ws_string (this, "while");
- pp_space (this);
- pp_cxx_left_paren (this);
- expression (WHILE_COND (t));
- pp_cxx_right_paren (this);
- pp_newline_and_indent (this, 3);
- statement (WHILE_BODY (t));
- pp_indentation (this) -= 3;
- pp_needs_newline (this) = true;
- break;
-
- case DO_STMT:
- pp_cxx_ws_string (this, "do");
- pp_newline_and_indent (this, 3);
- statement (DO_BODY (t));
- pp_newline_and_indent (this, -3);
- pp_cxx_ws_string (this, "while");
- pp_space (this);
- pp_cxx_left_paren (this);
- expression (DO_COND (t));
- pp_cxx_right_paren (this);
- pp_cxx_semicolon (this);
- pp_needs_newline (this) = true;
- break;
-
- case FOR_STMT:
- pp_cxx_ws_string (this, "for");
- pp_space (this);
- pp_cxx_left_paren (this);
- if (FOR_INIT_STMT (t))
- statement (FOR_INIT_STMT (t));
- else
- pp_cxx_semicolon (this);
- pp_needs_newline (this) = false;
- pp_cxx_whitespace (this);
- if (FOR_COND (t))
- expression (FOR_COND (t));
- pp_cxx_semicolon (this);
- pp_needs_newline (this) = false;
- pp_cxx_whitespace (this);
- if (FOR_EXPR (t))
- expression (FOR_EXPR (t));
- pp_cxx_right_paren (this);
- pp_newline_and_indent (this, 3);
- statement (FOR_BODY (t));
- pp_indentation (this) -= 3;
- pp_needs_newline (this) = true;
- break;
-
case RANGE_FOR_STMT:
pp_cxx_ws_string (this, "for");
pp_space (this);
pp_needs_newline (this) = true;
break;
- /* jump-statement:
- goto identifier;
- continue ;
- return expression(opt) ; */
- case BREAK_STMT:
- case CONTINUE_STMT:
- pp_string (this, TREE_CODE (t) == BREAK_STMT ? "break" : "continue");
- pp_cxx_semicolon (this);
- pp_needs_newline (this) = true;
- break;
-
/* expression-statement:
expression(opt) ; */
case EXPR_STMT:
dump_child ("else", ELSE_CLAUSE (t));
break;
- case BREAK_STMT:
- case CONTINUE_STMT:
- dump_stmt (di, t);
- break;
-
- case DO_STMT:
- dump_stmt (di, t);
- dump_child ("body", DO_BODY (t));
- dump_child ("cond", DO_COND (t));
- break;
-
- case FOR_STMT:
- dump_stmt (di, t);
- dump_child ("init", FOR_INIT_STMT (t));
- dump_child ("cond", FOR_COND (t));
- dump_child ("expr", FOR_EXPR (t));
- dump_child ("body", FOR_BODY (t));
- break;
-
case RANGE_FOR_STMT:
dump_stmt (di, t);
dump_child ("init", RANGE_FOR_INIT_STMT (t));
dump_child ("body", RANGE_FOR_BODY (t));
break;
- case SWITCH_STMT:
- dump_stmt (di, t);
- dump_child ("cond", SWITCH_STMT_COND (t));
- dump_child ("body", SWITCH_STMT_BODY (t));
- break;
-
- case WHILE_STMT:
- dump_stmt (di, t);
- dump_child ("cond", WHILE_COND (t));
- dump_child ("body", WHILE_BODY (t));
- break;
-
case STMT_EXPR:
dump_child ("stmt", STMT_EXPR_STMT (t));
break;
nonzero, then the loop should be exited. An @code{EXIT_EXPR} will only
appear within a @code{LOOP_EXPR}.
-@item SWITCH_STMT
+@item SWITCH_EXPR
-Used to represent a @code{switch} statement. The @code{SWITCH_STMT_COND}
-is the expression on which the switch is occurring. See the documentation
-for an @code{IF_STMT} for more information on the representation used
-for the condition. The @code{SWITCH_STMT_BODY} is the body of the switch
-statement. The @code{SWITCH_STMT_TYPE} is the original type of switch
-expression as given in the source, before any compiler conversions.
+Used to represent a @code{switch} statement. The @code{SWITCH_COND}
+is the expression on which the switch is occurring. The
+@code{SWITCH_BODY} is the body of the switch statement.
+@code{SWITCH_ALL_CASES_P} is true if the switch includes a default
+label or the case label ranges cover all possible values of the
+condition expression.
+
+Note that @code{TREE_TYPE} for a @code{SWITCH_EXPR} represents the
+original type of switch expression as given in the source, before any
+compiler conversions, instead of the type of the switch expression
+itself (which is not meaningful).
@item CASE_LABEL_EXPR
* Namespaces:: Namespaces.
* Classes:: Classes.
* Functions for C++:: Overloading and accessors for C++.
-* Statements for C++:: Statements specific to C and C++.
+* Statements for C and C++:: Statements specific to C and C++.
* C++ Expressions:: From @code{typeid} to @code{throw}.
@end menu
@c Function Bodies
@c ---------------------------------------------------------------------
-@node Statements for C++
-@subsection Statements for C++
+@node Statements for C and C++
+@subsection Statements for C and C++
@cindex statements
@tindex BREAK_STMT
@tindex CLEANUP_STMT
@findex WHILE_BODY
@findex WHILE_COND
-A function that has a definition in the current translation unit will
-have a non-@code{NULL} @code{DECL_INITIAL}. However, back ends should not make
+A function that has a definition in the current translation unit has
+a non-@code{NULL} @code{DECL_INITIAL}. However, back ends should not make
use of the particular value given by @code{DECL_INITIAL}.
-The @code{DECL_SAVED_TREE} macro will give the complete body of the
+The @code{DECL_SAVED_TREE} gives the complete body of the
function.
-@subsubsection Statements
-
There are tree nodes corresponding to all of the source-level
statement constructs, used within the C and C++ frontends. These are
enumerated here, together with a list of the various macros that can
slightly different ways.
Many of the statements have substatements. For example, a @code{while}
-loop will have a body, which is itself a statement. If the substatement
+loop has a body, which is itself a statement. If the substatement
is @code{NULL_TREE}, it is considered equivalent to a statement
consisting of a single @code{;}, i.e., an expression statement in which
the expression has been omitted. A substatement may in fact be a list
@end smallexample
In other words, while the @code{then} clause of an @code{if} statement
in C++ can be only one statement (although that one statement may be a
-compound statement), the intermediate representation will sometimes use
+compound statement), the intermediate representation sometimes uses
several statements chained together.
@table @code
termination condition. The @code{FOR_EXPR} is the expression executed
right before the @code{FOR_COND} on each loop iteration; often, this
expression increments a counter. The body of the loop is given by
-@code{FOR_BODY}. Note that @code{FOR_INIT_STMT} and @code{FOR_BODY}
-return statements, while @code{FOR_COND} and @code{FOR_EXPR} return
-expressions.
+@code{FOR_BODY}. @code{FOR_SCOPE} holds the scope of the @code{for}
+statement (used in the C++ front end only). Note that
+@code{FOR_INIT_STMT} and @code{FOR_BODY} return statements, while
+@code{FOR_COND} and @code{FOR_EXPR} return expressions.
@item HANDLER
@code{TREE_VALUE} should be used as the conditional expression itself.
This representation is used to handle C++ code like this:
-C++ distinguishes between this and @code{COND_EXPR} for handling templates.
-
@smallexample
if (int i = 7) @dots{}
@end smallexample
condition, while the @code{ELSE_CLAUSE} represents the statement given
by the @code{else} condition.
+C++ distinguishes between this and @code{COND_EXPR} for handling templates.
+
@item SUBOBJECT
In a constructor, these nodes are used to mark the point at which a
for the condition. The @code{SWITCH_STMT_BODY} is the body of the switch
statement. The @code{SWITCH_STMT_TYPE} is the original type of switch
expression as given in the source, before any compiler conversions.
+The @code{SWITCH_STMT_SCOPE} is the statement scope (used in the
+C++ front end only).
+
+There are also two boolean flags used with @code{SWITCH_STMT}.
+@code{SWITCH_STMT_ALL_CASES_P} is true if the switch includes a default label
+or the case label ranges cover all possible values of the condition
+expression. @code{SWITCH_STMT_NO_BREAK_P} is true if there are no
+@code{break} statements in the switch.
@item TRY_BLOCK
Used to represent a @code{try} block. The body of the try block is