From: Sandra Loosemore Date: Sat, 19 Sep 2020 14:32:35 +0000 (-0700) Subject: Move loop and switch tree data structures from cp/ to c-family/. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=cba079f354a55363916759f6f186f92c5616b98a;p=gcc.git Move loop and switch tree data structures from cp/ to c-family/. This patch moves the definitions for DO_STMT, FOR_STMT, WHILE_STMT, SWITCH_STMT, BREAK_STMT, and CONTINUE_STMT from the C++ front end to c-family. This includes the genericizers, pretty-printers, and dump support as well as the tree definitions and accessors. Some related code for OMP_FOR and similar OMP constructs is also moved. 2020-08-12 Sandra Loosemore gcc/c-family/ * c-common.c (c_block_may_fallthrough): New, split from cxx_block_may_fallthrough in the cp front end. (c_common_init_ts): Move handling of loop and switch-related statements here from the cp front end. * c-common.def (FOR_STMT, WHILE_STMT, DO_STMT): Move here from cp front end. (BREAK_STMT, CONTINUE_STMT, SWITCH_STMT): Likewise. * c-common.h (c_block_may_fallthru): Declare. (bc_state_t): Move here from cp front end. (save_bc_state, restore_bc_state): Declare. (c_genericize_control_stmt): Declare. (WHILE_COND, WHILE_BODY): Likewise. (DO_COND, DO_BODY): Likewise. (FOR_INIT_STMT, FOR_COND, FOR_EXPR, FOR_BODY, FOR_SCOPE): Likewise. (SWITCH_STMT_COND, SWITCH_STMT_BODY): Likewise. (SWITCH_STMT_TYPE, SWITCH_STMT_SCOPE): Likewise. (SWITCH_STMT_ALL_CASES_P, SWITCH_STMT_NO_BREAK_P): Likewise. (LABEL_DECL_BREAK, LABEL_DECL_CONTINUE): Likewise. * c-dump.c (dump_stmt): Copy from cp front end. (c_dump_tree): Move code to handle structured loop and switch tree nodes here from cp front end. * c-gimplify.c: Adjust includes. (enum bc_t, bc_label, begin_bc_block, finish_bc_block): Move from cp front end. (save_bc_state, restore_bc_state): New functions using old code from cp front end. (get_bc_label, expr_loc_or_loc): Move from cp front end. (genericize_c_loop): Move from cp front end. (genericize_for_stmt, genericize_while_stmt): Likewise. (genericize_do_stmt, genericize_switch_stmt): Likewise. (genericize_continue_stmt, genericize_break_stmt): Likewise. (genericize_omp_for_stmt): Likewise. (c_genericize_control_stmt): New function using code split from cp front end. (c_genericize_control_r): New. (c_genericize): Call walk_tree with c_genericize_control_r. * c-pretty-print.c (c_pretty_printer::statement): Move code to handle structured loop and switch tree nodes here from cp front end. gcc/cp/ * cp-gimplify.c (enum bc_t, bc_label): Move to c-family. (begin_bc_block, finish_bc_block, get_bc_label): Likewise. (genericize_cp_loop): Likewise. (genericize_for_stmt, genericize_while_stmt): Likewise. (genericize_do_stmt, genericize_switch_stmt): Likewise. (genericize_continue_stmt, genericize_break_stmt): Likewise. (genericize_omp_for_stmt): Likewise. (cp_genericize_r): Call c_genericize_control_stmt instead of above functions directly. (cp_genericize): Call save_bc_state and restore_bc_state instead of manipulating bc_label directly. * cp-objcp-common.c (cxx_block_may_fallthru): Defer to c_block_may_fallthru instead of handling SWITCH_STMT here. (cp_common_init_ts): Move handling of loop and switch-related statements to c-family. * cp-tree.def (FOR_STMT, WHILE_STMT, DO_STMT): Move to c-family. (BREAK_STMT, CONTINUE_STMT, SWITCH_STMT): Likewise. * cp-tree.h (LABEL_DECL_BREAK, LABEL_DECL_CONTINUE): Likewise. (WHILE_COND, WHILE_BODY): Likewise. (DO_COND, DO_BODY): Likewise. (FOR_INIT_STMT, FOR_COND, FOR_EXPR, FOR_BODY, FOR_SCOPE): Likewise. (SWITCH_STMT_COND, SWITCH_STMT_BODY): Likewise. (SWITCH_STMT_TYPE, SWITCH_STMT_SCOPE): Likewise. (SWITCH_STMT_ALL_CASES_P, SWITCH_STMT_NO_BREAK_P): Likewise. * cxx-pretty-print.c (cxx_pretty_printer::statement): Move code to handle structured loop and switch tree nodes to c-family. * dump.c (cp_dump_tree): Likewise. gcc/ * doc/generic.texi (Basic Statements): Document SWITCH_EXPR here, not SWITCH_STMT. (Statements for C and C++): Rename node to reflect what the introduction already says about sharing between C and C++ front ends. Copy-edit and correct documentation for structured loops and switch. --- diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 873bea9e2b2..e16ca3894bc 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -5007,6 +5007,24 @@ c_switch_covers_all_cases_p (splay_tree cases, tree type) 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. @@ -8126,6 +8144,12 @@ c_common_init_ts (void) 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 diff --git a/gcc/c-family/c-common.def b/gcc/c-family/c-common.def index 7ceb9a22bd4..1954bfe1f80 100644 --- a/gcc/c-family/c-common.def +++ b/gcc/c-family/c-common.def @@ -55,6 +55,30 @@ DEFTREECODE (USERDEF_LITERAL, "userdef_literal", tcc_exceptional, 3) 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 diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 4fc64bc4aa6..6abfe4b1a31 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1008,6 +1008,7 @@ extern int case_compare (splay_tree_key, splay_tree_key); 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); @@ -1115,7 +1116,15 @@ class substring_loc; 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); @@ -1279,6 +1288,48 @@ extern tree build_userdef_literal (tree suffix_id, tree value, 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. */ diff --git a/gcc/c-family/c-dump.c b/gcc/c-family/c-dump.c index ffc580871b9..d3caacc87a1 100644 --- a/gcc/c-family/c-dump.c +++ b/gcc/c-family/c-dump.c @@ -26,6 +26,13 @@ along with GCC; see the file COPYING3. If not see /* 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) { @@ -42,6 +49,37 @@ 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; } diff --git a/gcc/c-family/c-gimplify.c b/gcc/c-family/c-gimplify.c index 5d357d0f17e..db930fc5ee5 100644 --- a/gcc/c-family/c-gimplify.c +++ b/gcc/c-family/c-gimplify.c @@ -30,6 +30,8 @@ along with GCC; see the file COPYING3. If not see #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" @@ -107,6 +109,399 @@ ubsan_walk_array_refs_r (tree *tp, int *walk_subtrees, void *data) /* 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. */ @@ -128,6 +523,19 @@ c_genericize (tree fndecl) 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) diff --git a/gcc/c-family/c-pretty-print.c b/gcc/c-family/c-pretty-print.c index ec0bafe1010..c364e1c4a4d 100644 --- a/gcc/c-family/c-pretty-print.c +++ b/gcc/c-family/c-pretty-print.c @@ -2364,15 +2364,97 @@ c_pretty_printer::expression (tree e) /* 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); + } } diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index b2befa7148d..bc8a03c7b41 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -49,66 +49,6 @@ static tree cp_fold_r (tree *, int *, void *); 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 @@ -231,228 +171,6 @@ genericize_if_stmt (tree *stmt_p) *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 @@ -1565,7 +1283,8 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) 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; @@ -1636,103 +1355,10 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) 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. */ @@ -1868,6 +1494,84 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) } 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; @@ -2033,11 +1737,8 @@ cp_genericize (tree fndecl) 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. */ @@ -2047,11 +1748,7 @@ cp_genericize (tree fndecl) /* 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); } /* Build code to apply FN to each member of ARG1 and ARG2. FN may be diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c index 852a34dbc5f..e1397b7b710 100644 --- a/gcc/cp/cp-objcp-common.c +++ b/gcc/cp/cp-objcp-common.c @@ -314,13 +314,8 @@ cxx_block_may_fallthru (const_tree stmt) 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); } } @@ -478,20 +473,14 @@ cp_common_init_ts (void) 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); diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index 6eabe0d6d8f..a188576013b 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -300,35 +300,12 @@ DEFTREECODE (CLEANUP_STMT, "cleanup_stmt", tcc_statement, 3) 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) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 08976d8527c..71353814973 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4028,14 +4028,6 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #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) \ @@ -5088,25 +5080,6 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) 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) @@ -5117,19 +5090,6 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #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) diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c index 263f225a492..d10c18db039 100644 --- a/gcc/cp/cxx-pretty-print.c +++ b/gcc/cp/cxx-pretty-print.c @@ -2019,73 +2019,6 @@ cxx_pretty_printer::statement (tree t) } 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); @@ -2109,17 +2042,6 @@ cxx_pretty_printer::statement (tree t) 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: diff --git a/gcc/cp/dump.c b/gcc/cp/dump.c index c509badee81..81d2c16d5db 100644 --- a/gcc/cp/dump.c +++ b/gcc/cp/dump.c @@ -280,25 +280,6 @@ cp_dump_tree (void* dump_info, tree t) 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)); @@ -307,18 +288,6 @@ cp_dump_tree (void* dump_info, tree 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; diff --git a/gcc/doc/generic.texi b/gcc/doc/generic.texi index fb98727928a..7373266c69f 100644 --- a/gcc/doc/generic.texi +++ b/gcc/doc/generic.texi @@ -2032,14 +2032,19 @@ These nodes represent conditional exits from the nearest enclosing 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 @@ -2713,7 +2718,7 @@ should submit your patches for inclusion in GCC@. * 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 @@ -3256,8 +3261,8 @@ This predicate holds if the function an overloaded @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 @@ -3299,15 +3304,13 @@ This predicate holds if the function an overloaded @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 @@ -3332,7 +3335,7 @@ In template functions, the same nodes are used, but sometimes in 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 @@ -3361,7 +3364,7 @@ void process_stmt (stmt) @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 @@ -3418,9 +3421,10 @@ the initialization statement for the loop. The @code{FOR_COND} is the 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 @@ -3441,8 +3445,6 @@ evaluated, the statement should be executed. Then, the @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 @@ -3454,6 +3456,8 @@ The @code{THEN_CLAUSE} represents the statement given by the @code{then} 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 @@ -3470,6 +3474,14 @@ 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. +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