* [PATCH V2 1/4] Move loop and switch tree data structures from cp/ to c-family/.
2020-08-13 16:34 [PATCH V2 0/4] Unify C and C++ handling of loops and switches Sandra Loosemore
@ 2020-08-13 16:34 ` Sandra Loosemore
2020-08-13 16:34 ` [PATCH V2 2/4] Use C-style loop lowering instead of C++-style Sandra Loosemore
` (4 subsequent siblings)
5 siblings, 0 replies; 16+ messages in thread
From: Sandra Loosemore @ 2020-08-13 16:34 UTC (permalink / raw)
To: gcc-patches
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 <sandra@codesourcery.com>
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.
---
gcc/c-family/c-common.c | 24 +++
gcc/c-family/c-common.def | 24 +++
gcc/c-family/c-common.h | 53 ++++-
gcc/c-family/c-dump.c | 38 ++++
gcc/c-family/c-gimplify.c | 408 ++++++++++++++++++++++++++++++++++++
gcc/c-family/c-pretty-print.c | 92 ++++++++-
gcc/cp/cp-gimplify.c | 469 ++++++++----------------------------------
gcc/cp/cp-objcp-common.c | 13 +-
gcc/cp/cp-tree.def | 23 ---
gcc/cp/cp-tree.h | 40 ----
gcc/cp/cxx-pretty-print.c | 78 -------
gcc/cp/dump.c | 31 ---
gcc/doc/generic.texi | 56 +++--
13 files changed, 751 insertions(+), 598 deletions(-)
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 873bea9..e16ca38 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 7ceb9a2..1954bfe 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 4fc64bc..6abfe4b 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 ffc5808..d3caacc 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 5d357d0..db930fc 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 ec0bafe..c364e1c 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);
+ }
}
\f
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index f869583..74ed9ad 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);
}
\f
/* 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 fecf866..b946332 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 31be2cf..c8fe35c 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 fc54e6b..6fe7eac 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4015,14 +4015,6 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
#define DECL_LOCAL_FUNCTION_P(NODE) \
DECL_LANG_FLAG_0 (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) \
@@ -5075,25 +5067,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)
@@ -5104,19 +5077,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 263f225..d10c18d 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 c509bad..81d2c16 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 fb98727..7373266 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
--
2.8.1
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH V2 4/4] Change C front end to emit structured loop and switch tree nodes.
2020-08-13 16:34 [PATCH V2 0/4] Unify C and C++ handling of loops and switches Sandra Loosemore
` (2 preceding siblings ...)
2020-08-13 16:34 ` [PATCH V2 3/4] Work around bootstrap failure in Fortran front end Sandra Loosemore
@ 2020-08-13 16:34 ` Sandra Loosemore
2020-08-28 16:58 ` [PING] [PATCH V2 0/4] Unify C and C++ handling of loops and switches Sandra Loosemore
2020-09-09 21:13 ` Jason Merrill
5 siblings, 0 replies; 16+ messages in thread
From: Sandra Loosemore @ 2020-08-13 16:34 UTC (permalink / raw)
To: gcc-patches
2020-08-12 Sandra Loosemore <sandra@codesourcery.com>
gcc/c
* c-decl.c (c_break_label, c_cont_label): Delete, and replace
with...
(in_statement): New.
(start_function): Adjust for above change.
(c_push_function_context, c_pop_function_context): Likewise.
* c-lang.h (struct language_function): Likewise.
* c-objc-common.h (LANG_HOOKS_BLOCK_MAY_FALLTHRU): Define.
* c-parser.c (objc_foreach_break_label, objc_foreach_continue_label):
New.
(c_parser_statement_after_labels): Adjust calls to c_finish_bc_stmt.
(c_parser_switch_statement): Adjust break/switch context handling
and calls to renamed functions.
(c_parser_while_statement): Adjust break/switch context handling and
build a WHILE_STMT.
(c_parser_do_statement): Ditto, with DO_STMT respectively.
(c_parser_for_statement): Ditto, with FOR_STMT respectively.
(c_parser_omp_for_loop): Adjust break/switch context handling.
* c-tree.h (c_break_label, c_cont_label): Delete.
(IN_SWITCH_STMT, IN_ITERATION_STMT): Define.
(IN_OMP_BLOCK, IN_OMP_FOR, IN_OBJC_FOREACH): Define.
(in_statement, switch_statement_break_seen_p): Declare.
(c_start_case, c_finish_case): Renamed to...
(c_start_switch, c_finish_switch).
(c_finish_bc_stmt): Adjust arguments.
* c-typeck.c (build_function_call_vec): Don't try to print
statements with %qE format.
(struct c_switch): Rename switch_expr field to switch_stmt.
Add break_stmt_seen_p field.
(c_start_case): Rename to c_start_switch. Build a SWITCH_STMT
instead of a SWITCH_EXPR. Update for changes to struct c_switch.
(do_case): Update for changes to struct c_switch.
(c_finish_case): Rename to c_finish_switch. Update for changes to
struct c_switch and change of representation from SWITCH_EXPR to
SWITCH_STMT.
(c_finish_loop): Delete.
(c_finish_bc_stmt): Update to reflect changes to break/continue
state representation. Build a BREAK_STMT or CONTINUE_STMT instead
of a GOTO_EXPR except for objc foreach loops.
gcc/objc
* objc-act.c (objc_start_method_definition): Update to reflect
changes to break/continue state bookkeeping in C front end.
gcc/testsuite/
* gcc.dg/gomp/block-7.c: Update expected error message wording.
---
gcc/c/c-decl.c | 18 ++-
gcc/c/c-lang.h | 3 +-
gcc/c/c-objc-common.h | 2 +
gcc/c/c-parser.c | 125 ++++++++++----------
gcc/c/c-tree.h | 21 +++-
gcc/c/c-typeck.c | 227 +++++++++++-------------------------
gcc/objc/ChangeLog | 5 +
gcc/objc/objc-act.c | 6 +-
gcc/testsuite/gcc.dg/gomp/block-7.c | 12 +-
9 files changed, 169 insertions(+), 250 deletions(-)
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index 5d6b504..c82af63 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -112,9 +112,9 @@ struct obstack parser_obstack;
static GTY(()) struct stmt_tree_s c_stmt_tree;
-/* State saving variables. */
-tree c_break_label;
-tree c_cont_label;
+/* Zero if we are not in an iteration or switch statement, otherwise
+ a bitmask. See bitmask definitions in c-tree.h. */
+unsigned char in_statement;
/* A list of decls to be made automatically visible in each file scope. */
static GTY(()) tree visible_builtins;
@@ -9160,10 +9160,8 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
warn_about_return_type = 0;
c_switch_stack = NULL;
- /* Indicate no valid break/continue context by setting these variables
- to some non-null, non-label value. We'll notice and emit the proper
- error message in c_finish_bc_stmt. */
- c_break_label = c_cont_label = size_zero_node;
+ /* Indicate no valid break/continue context. */
+ in_statement = 0;
decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, true, NULL,
&attributes, NULL, NULL, DEPRECATED_NORMAL);
@@ -10164,8 +10162,7 @@ c_push_function_context (void)
p->base.x_stmt_tree = c_stmt_tree;
c_stmt_tree.x_cur_stmt_list = vec_safe_copy (c_stmt_tree.x_cur_stmt_list);
- p->x_break_label = c_break_label;
- p->x_cont_label = c_cont_label;
+ p->x_in_statement = in_statement;
p->x_switch_stack = c_switch_stack;
p->arg_info = current_function_arg_info;
p->returns_value = current_function_returns_value;
@@ -10204,8 +10201,7 @@ c_pop_function_context (void)
c_stmt_tree = p->base.x_stmt_tree;
p->base.x_stmt_tree.x_cur_stmt_list = NULL;
- c_break_label = p->x_break_label;
- c_cont_label = p->x_cont_label;
+ in_statement = p->x_in_statement;
c_switch_stack = p->x_switch_stack;
current_function_arg_info = p->arg_info;
current_function_returns_value = p->returns_value;
diff --git a/gcc/c/c-lang.h b/gcc/c/c-lang.h
index 6d377cd..7e9a276 100644
--- a/gcc/c/c-lang.h
+++ b/gcc/c/c-lang.h
@@ -51,8 +51,7 @@ struct GTY(()) lang_decl {
struct GTY(()) language_function {
struct c_language_function base;
- tree x_break_label;
- tree x_cont_label;
+ unsigned char x_in_statement;
struct c_switch * GTY((skip)) x_switch_stack;
struct c_arg_info * GTY((skip)) arg_info;
int returns_value;
diff --git a/gcc/c/c-objc-common.h b/gcc/c/c-objc-common.h
index 9257959..76f9db7 100644
--- a/gcc/c/c-objc-common.h
+++ b/gcc/c/c-objc-common.h
@@ -56,6 +56,8 @@ along with GCC; see the file COPYING3. If not see
#define LANG_HOOKS_TYPES_COMPATIBLE_P c_types_compatible_p
#undef LANG_HOOKS_MISSING_NORETURN_OK_P
#define LANG_HOOKS_MISSING_NORETURN_OK_P c_missing_noreturn_ok_p
+#undef LANG_HOOKS_BLOCK_MAY_FALLTHRU
+#define LANG_HOOKS_BLOCK_MAY_FALLTHRU c_block_may_fallthru
#undef LANG_HOOKS_BUILTIN_FUNCTION
#define LANG_HOOKS_BUILTIN_FUNCTION c_builtin_function
#undef LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 7961cbc..4706f98 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1479,6 +1479,9 @@ struct oacc_routine_data {
location_t loc;
};
+/* Used for parsing objc foreach statements. */
+static tree objc_foreach_break_label, objc_foreach_continue_label;
+
static bool c_parser_nth_token_starts_std_attributes (c_parser *,
unsigned int);
static tree c_parser_std_attribute_specifier_sequence (c_parser *);
@@ -6221,11 +6224,11 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p,
goto expect_semicolon;
case RID_CONTINUE:
c_parser_consume_token (parser);
- stmt = c_finish_bc_stmt (loc, &c_cont_label, false);
+ stmt = c_finish_bc_stmt (loc, objc_foreach_continue_label, false);
goto expect_semicolon;
case RID_BREAK:
c_parser_consume_token (parser);
- stmt = c_finish_bc_stmt (loc, &c_break_label, true);
+ stmt = c_finish_bc_stmt (loc, objc_foreach_break_label, true);
goto expect_semicolon;
case RID_RETURN:
c_parser_consume_token (parser);
@@ -6627,7 +6630,8 @@ static void
c_parser_switch_statement (c_parser *parser, bool *if_p)
{
struct c_expr ce;
- tree block, expr, body, save_break;
+ tree block, expr, body;
+ unsigned char save_in_statement;
location_t switch_loc = c_parser_peek_token (parser)->location;
location_t switch_cond_loc;
gcc_assert (c_parser_next_token_is_keyword (parser, RID_SWITCH));
@@ -6653,9 +6657,9 @@ c_parser_switch_statement (c_parser *parser, bool *if_p)
expr = error_mark_node;
ce.original_type = error_mark_node;
}
- c_start_case (switch_loc, switch_cond_loc, expr, explicit_cast_p);
- save_break = c_break_label;
- c_break_label = NULL_TREE;
+ c_start_switch (switch_loc, switch_cond_loc, expr, explicit_cast_p);
+ save_in_statement = in_statement;
+ in_statement |= IN_SWITCH_STMT;
location_t loc_after_labels;
bool open_brace_p = c_parser_peek_token (parser)->type == CPP_OPEN_BRACE;
body = c_parser_c99_block_statement (parser, if_p, &loc_after_labels);
@@ -6663,16 +6667,8 @@ c_parser_switch_statement (c_parser *parser, bool *if_p)
if (!open_brace_p && c_parser_peek_token (parser)->type != CPP_SEMICOLON)
warn_for_multistatement_macros (loc_after_labels, next_loc, switch_loc,
RID_SWITCH);
- if (c_break_label)
- {
- location_t here = c_parser_peek_token (parser)->location;
- tree t = build1 (LABEL_EXPR, void_type_node, c_break_label);
- SET_EXPR_LOCATION (t, here);
- SWITCH_BREAK_LABEL_P (c_break_label) = 1;
- append_to_statement_list_force (t, &body);
- }
- c_finish_case (body, ce.original_type);
- c_break_label = save_break;
+ c_finish_switch (body, ce.original_type);
+ in_statement = save_in_statement;
add_stmt (c_end_compound_stmt (switch_loc, block, flag_isoc99));
c_parser_maybe_reclassify_token (parser);
}
@@ -6690,7 +6686,8 @@ static void
c_parser_while_statement (c_parser *parser, bool ivdep, unsigned short unroll,
bool *if_p)
{
- tree block, cond, body, save_break, save_cont;
+ tree block, cond, body;
+ unsigned char save_in_statement;
location_t loc;
gcc_assert (c_parser_next_token_is_keyword (parser, RID_WHILE));
token_indent_info while_tinfo
@@ -6709,10 +6706,8 @@ c_parser_while_statement (c_parser *parser, bool ivdep, unsigned short unroll,
build_int_cst (integer_type_node,
annot_expr_unroll_kind),
build_int_cst (integer_type_node, unroll));
- save_break = c_break_label;
- c_break_label = NULL_TREE;
- save_cont = c_cont_label;
- c_cont_label = NULL_TREE;
+ save_in_statement = in_statement;
+ in_statement = IN_ITERATION_STMT;
token_indent_info body_tinfo
= get_token_indent_info (c_parser_peek_token (parser));
@@ -6720,8 +6715,7 @@ c_parser_while_statement (c_parser *parser, bool ivdep, unsigned short unroll,
location_t loc_after_labels;
bool open_brace = c_parser_next_token_is (parser, CPP_OPEN_BRACE);
body = c_parser_c99_block_statement (parser, if_p, &loc_after_labels);
- c_finish_loop (loc, loc, cond, UNKNOWN_LOCATION, NULL, body,
- c_break_label, c_cont_label, true);
+ add_stmt (build_stmt (loc, WHILE_STMT, cond, body));
add_stmt (c_end_compound_stmt (loc, block, flag_isoc99));
c_parser_maybe_reclassify_token (parser);
@@ -6733,8 +6727,7 @@ c_parser_while_statement (c_parser *parser, bool ivdep, unsigned short unroll,
warn_for_multistatement_macros (loc_after_labels, next_tinfo.location,
while_tinfo.location, RID_WHILE);
- c_break_label = save_break;
- c_cont_label = save_cont;
+ in_statement = save_in_statement;
}
/* Parse a do statement (C90 6.6.5, C99 6.8.5, C11 6.8.5).
@@ -6746,7 +6739,8 @@ c_parser_while_statement (c_parser *parser, bool ivdep, unsigned short unroll,
static void
c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll)
{
- tree block, cond, body, save_break, save_cont, new_break, new_cont;
+ tree block, cond, body;
+ unsigned char save_in_statement;
location_t loc;
gcc_assert (c_parser_next_token_is_keyword (parser, RID_DO));
c_parser_consume_token (parser);
@@ -6756,17 +6750,11 @@ c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll)
"suggest braces around empty body in %<do%> statement");
block = c_begin_compound_stmt (flag_isoc99);
loc = c_parser_peek_token (parser)->location;
- save_break = c_break_label;
- c_break_label = NULL_TREE;
- save_cont = c_cont_label;
- c_cont_label = NULL_TREE;
+ save_in_statement = in_statement;
+ in_statement = IN_ITERATION_STMT;
body = c_parser_c99_block_statement (parser, NULL);
c_parser_require_keyword (parser, RID_WHILE, "expected %<while%>");
- new_break = c_break_label;
- c_break_label = save_break;
- new_cont = c_cont_label;
- c_cont_label = save_cont;
- location_t cond_loc = c_parser_peek_token (parser)->location;
+ in_statement = save_in_statement;
cond = c_parser_paren_condition (parser);
if (ivdep && cond != error_mark_node)
cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
@@ -6780,8 +6768,8 @@ c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll)
build_int_cst (integer_type_node, unroll));
if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
c_parser_skip_to_end_of_block_or_statement (parser);
- c_finish_loop (loc, cond_loc, cond, UNKNOWN_LOCATION, NULL, body,
- new_break, new_cont, false);
+
+ add_stmt (build_stmt (loc, DO_STMT, cond, body));
add_stmt (c_end_compound_stmt (loc, block, flag_isoc99));
}
@@ -6848,15 +6836,15 @@ static void
c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
bool *if_p)
{
- tree block, cond, incr, save_break, save_cont, body;
+ tree block, cond, incr, body;
+ unsigned char save_in_statement;
+ tree save_objc_foreach_break_label, save_objc_foreach_continue_label;
/* The following are only used when parsing an ObjC foreach statement. */
tree object_expression;
/* Silence the bogus uninitialized warning. */
tree collection_expression = NULL;
location_t loc = c_parser_peek_token (parser)->location;
location_t for_loc = loc;
- location_t cond_loc = UNKNOWN_LOCATION;
- location_t incr_loc = UNKNOWN_LOCATION;
bool is_foreach_statement = false;
gcc_assert (c_parser_next_token_is_keyword (parser, RID_FOR));
token_indent_info for_tinfo
@@ -6966,7 +6954,6 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
gcc_assert (!parser->objc_could_be_foreach_context);
if (!is_foreach_statement)
{
- cond_loc = c_parser_peek_token (parser)->location;
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
{
if (ivdep)
@@ -7007,7 +6994,7 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
/* Parse the increment expression (the third expression in a
for-statement). In the case of a foreach-statement, this is
the expression that follows the 'in'. */
- loc = incr_loc = c_parser_peek_token (parser)->location;
+ loc = c_parser_peek_token (parser)->location;
if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
{
if (is_foreach_statement)
@@ -7033,10 +7020,17 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
}
parens.skip_until_found_close (parser);
}
- save_break = c_break_label;
- c_break_label = NULL_TREE;
- save_cont = c_cont_label;
- c_cont_label = NULL_TREE;
+ save_in_statement = in_statement;
+ if (is_foreach_statement)
+ {
+ in_statement = IN_OBJC_FOREACH;
+ save_objc_foreach_break_label = objc_foreach_break_label;
+ save_objc_foreach_continue_label = objc_foreach_continue_label;
+ objc_foreach_break_label = create_artificial_label (loc);
+ objc_foreach_continue_label = create_artificial_label (loc);
+ }
+ else
+ in_statement = IN_ITERATION_STMT;
token_indent_info body_tinfo
= get_token_indent_info (c_parser_peek_token (parser));
@@ -7047,11 +7041,12 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
if (is_foreach_statement)
objc_finish_foreach_loop (for_loc, object_expression,
- collection_expression, body, c_break_label,
- c_cont_label);
+ collection_expression, body,
+ objc_foreach_break_label,
+ objc_foreach_continue_label);
else
- c_finish_loop (for_loc, cond_loc, cond, incr_loc, incr, body,
- c_break_label, c_cont_label, true);
+ add_stmt (build_stmt (for_loc, FOR_STMT, NULL_TREE, cond, incr,
+ body, NULL_TREE));
add_stmt (c_end_compound_stmt (for_loc, block,
flag_isoc99 || c_dialect_objc ()));
c_parser_maybe_reclassify_token (parser);
@@ -7064,8 +7059,12 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
warn_for_multistatement_macros (loc_after_labels, next_tinfo.location,
for_tinfo.location, RID_FOR);
- c_break_label = save_break;
- c_cont_label = save_cont;
+ in_statement = save_in_statement;
+ if (is_foreach_statement)
+ {
+ objc_foreach_break_label = save_objc_foreach_break_label;
+ objc_foreach_continue_label = save_objc_foreach_continue_label;
+ }
}
/* Parse an asm statement, a GNU extension. This is a full-blown asm
@@ -18031,7 +18030,8 @@ static tree
c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
tree clauses, tree *cclauses, bool *if_p)
{
- tree decl, cond, incr, save_break, save_cont, body, init, stmt, cl;
+ tree decl, cond, incr, body, init, stmt, cl;
+ unsigned char save_in_statement;
tree declv, condv, incrv, initv, ret = NULL_TREE;
tree pre_body = NULL_TREE, this_pre_body;
tree ordered_cl = NULL_TREE;
@@ -18099,6 +18099,11 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
for_loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
+ /* Forbid break/continue in the loop initializer, condition, and
+ increment expressions. */
+ save_in_statement = in_statement;
+ in_statement = IN_OMP_BLOCK;
+
for (i = 0; i < count; i++)
{
int bracecount = 0;
@@ -18272,10 +18277,7 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
if (nbraces)
if_p = NULL;
- save_break = c_break_label;
- c_break_label = size_one_node;
- save_cont = c_cont_label;
- c_cont_label = NULL_TREE;
+ in_statement = IN_OMP_FOR;
body = push_stmt_list ();
if (inscan)
@@ -18289,16 +18291,9 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
}
else
add_stmt (c_parser_c99_block_statement (parser, if_p));
- if (c_cont_label)
- {
- tree t = build1 (LABEL_EXPR, void_type_node, c_cont_label);
- SET_EXPR_LOCATION (t, loc);
- add_stmt (t);
- }
body = pop_stmt_list (body);
- c_break_label = save_break;
- c_cont_label = save_cont;
+ in_statement = save_in_statement;
while (nbraces)
{
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 10938cf..7e51859 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -547,8 +547,19 @@ extern void gen_aux_info_record (tree, int, int, int);
struct c_spot_bindings;
class c_struct_parse_info;
extern struct obstack parser_obstack;
-extern tree c_break_label;
-extern tree c_cont_label;
+/* Set to IN_ITERATION_STMT if parsing an iteration-statement,
+ to IN_OMP_BLOCK if parsing OpenMP structured block and
+ IN_OMP_FOR if parsing OpenMP loop. If parsing a switch statement,
+ this is bitwise ORed with IN_SWITCH_STMT, unless parsing an
+ iteration-statement, OpenMP block or loop within that switch. */
+#define IN_SWITCH_STMT 1
+#define IN_ITERATION_STMT 2
+#define IN_OMP_BLOCK 4
+#define IN_OMP_FOR 8
+#define IN_OBJC_FOREACH 16
+extern unsigned char in_statement;
+
+extern bool switch_statement_break_seen_p;
extern bool global_bindings_p (void);
extern tree pushdecl (tree);
@@ -714,8 +725,8 @@ extern void process_init_element (location_t, struct c_expr, bool,
extern tree build_compound_literal (location_t, tree, tree, bool,
unsigned int);
extern void check_compound_literal_type (location_t, struct c_type_name *);
-extern tree c_start_case (location_t, location_t, tree, bool);
-extern void c_finish_case (tree, tree);
+extern tree c_start_switch (location_t, location_t, tree, bool);
+extern void c_finish_switch (tree, tree);
extern tree build_asm_expr (location_t, tree, tree, tree, tree, tree, bool,
bool);
extern tree build_asm_stmt (bool, tree);
@@ -730,7 +741,7 @@ extern tree c_finish_stmt_expr (location_t, tree);
extern tree c_process_expr_stmt (location_t, tree);
extern tree c_finish_expr_stmt (location_t, tree);
extern tree c_finish_return (location_t, tree, tree);
-extern tree c_finish_bc_stmt (location_t, tree *, bool);
+extern tree c_finish_bc_stmt (location_t, tree, bool);
extern tree c_finish_goto_label (location_t, tree);
extern tree c_finish_goto_ptr (location_t, tree);
extern tree c_expr_to_decl (tree, bool *, bool *);
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 0d639b60..ad1cae6 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -3076,7 +3076,7 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
if (!(TREE_CODE (fntype) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (fntype)) == FUNCTION_TYPE))
{
- if (!flag_diagnostics_show_caret)
+ if (!flag_diagnostics_show_caret && !STATEMENT_CLASS_P (function))
error_at (loc,
"called object %qE is not a function or function pointer",
function);
@@ -10808,8 +10808,8 @@ c_finish_return (location_t loc, tree retval, tree origtype)
}
\f
struct c_switch {
- /* The SWITCH_EXPR being built. */
- tree switch_expr;
+ /* The SWITCH_STMT being built. */
+ tree switch_stmt;
/* The original type of the testing expression, i.e. before the
default conversion is applied. */
@@ -10826,6 +10826,9 @@ struct c_switch {
warnings crossing decls when branching to a case label. */
struct c_spot_bindings *bindings;
+ /* Whether the switch includes any break statements. */
+ bool break_stmt_seen_p;
+
/* The next node on the stack. */
struct c_switch *next;
@@ -10843,14 +10846,14 @@ struct c_switch {
struct c_switch *c_switch_stack;
/* Start a C switch statement, testing expression EXP. Return the new
- SWITCH_EXPR. SWITCH_LOC is the location of the `switch'.
+ SWITCH_STMT. SWITCH_LOC is the location of the `switch'.
SWITCH_COND_LOC is the location of the switch's condition.
EXPLICIT_CAST_P is true if the expression EXP has an explicit cast. */
tree
-c_start_case (location_t switch_loc,
- location_t switch_cond_loc,
- tree exp, bool explicit_cast_p)
+c_start_switch (location_t switch_loc,
+ location_t switch_cond_loc,
+ tree exp, bool explicit_cast_p)
{
tree orig_type = error_mark_node;
bool bool_cond_p = false;
@@ -10900,18 +10903,19 @@ c_start_case (location_t switch_loc,
}
}
- /* Add this new SWITCH_EXPR to the stack. */
+ /* Add this new SWITCH_STMT to the stack. */
cs = XNEW (struct c_switch);
- cs->switch_expr = build2 (SWITCH_EXPR, orig_type, exp, NULL_TREE);
- SET_EXPR_LOCATION (cs->switch_expr, switch_loc);
+ cs->switch_stmt = build_stmt (switch_loc, SWITCH_STMT, exp,
+ NULL_TREE, orig_type, NULL_TREE);
cs->orig_type = orig_type;
cs->cases = splay_tree_new (case_compare, NULL, NULL);
cs->bindings = c_get_switch_bindings ();
+ cs->break_stmt_seen_p = false;
cs->bool_cond_p = bool_cond_p;
cs->next = c_switch_stack;
c_switch_stack = cs;
- return add_stmt (cs->switch_expr);
+ return add_stmt (cs->switch_stmt);
}
/* Process a case label at location LOC. */
@@ -10947,12 +10951,12 @@ do_case (location_t loc, tree low_value, tree high_value)
}
if (c_check_switch_jump_warnings (c_switch_stack->bindings,
- EXPR_LOCATION (c_switch_stack->switch_expr),
+ EXPR_LOCATION (c_switch_stack->switch_stmt),
loc))
return NULL_TREE;
label = c_add_case_label (loc, c_switch_stack->cases,
- SWITCH_COND (c_switch_stack->switch_expr),
+ SWITCH_STMT_COND (c_switch_stack->switch_stmt),
low_value, high_value);
if (label == error_mark_node)
label = NULL_TREE;
@@ -10963,20 +10967,22 @@ do_case (location_t loc, tree low_value, tree high_value)
controlling expression of the switch, or NULL_TREE. */
void
-c_finish_case (tree body, tree type)
+c_finish_switch (tree body, tree type)
{
struct c_switch *cs = c_switch_stack;
location_t switch_location;
- SWITCH_BODY (cs->switch_expr) = body;
+ SWITCH_STMT_BODY (cs->switch_stmt) = body;
/* Emit warnings as needed. */
- switch_location = EXPR_LOCATION (cs->switch_expr);
+ switch_location = EXPR_LOCATION (cs->switch_stmt);
c_do_switch_warnings (cs->cases, switch_location,
- type ? type : TREE_TYPE (cs->switch_expr),
- SWITCH_COND (cs->switch_expr), cs->bool_cond_p);
- if (c_switch_covers_all_cases_p (cs->cases, TREE_TYPE (cs->switch_expr)))
- SWITCH_ALL_CASES_P (cs->switch_expr) = 1;
+ type ? type : SWITCH_STMT_TYPE (cs->switch_stmt),
+ SWITCH_STMT_COND (cs->switch_stmt), cs->bool_cond_p);
+ if (c_switch_covers_all_cases_p (cs->cases,
+ SWITCH_STMT_TYPE (cs->switch_stmt)))
+ SWITCH_STMT_ALL_CASES_P (cs->switch_stmt) = 1;
+ SWITCH_STMT_NO_BREAK_P (cs->switch_stmt) = !cs->break_stmt_seen_p;
/* Pop the stack. */
c_switch_stack = cs->next;
@@ -11000,110 +11006,9 @@ c_finish_if_stmt (location_t if_locus, tree cond, tree then_block,
add_stmt (stmt);
}
-/* Emit a general-purpose loop construct. START_LOCUS is the location of
- the beginning of the loop. COND is the loop condition. COND_IS_FIRST
- is false for DO loops. INCR is the FOR increment expression. BODY is
- the statement controlled by the loop. BLAB is the break label. CLAB is
- the continue label. Everything is allowed to be NULL.
- COND_LOCUS is the location of the loop condition, INCR_LOCUS is the
- location of the FOR increment expression. */
-
-void
-c_finish_loop (location_t start_locus, location_t cond_locus, tree cond,
- location_t incr_locus, tree incr, tree body, tree blab,
- tree clab, bool cond_is_first)
-{
- tree entry = NULL, exit = NULL, t;
-
- /* If the condition is zero don't generate a loop construct. */
- if (cond && integer_zerop (cond))
- {
- if (cond_is_first)
- {
- t = build_and_jump (&blab);
- SET_EXPR_LOCATION (t, start_locus);
- add_stmt (t);
- }
- }
- else
- {
- tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
-
- /* If we have an exit condition, then we build an IF with gotos either
- out of the loop, or to the top of it. If there's no exit condition,
- then we just build a jump back to the top. */
- exit = build_and_jump (&LABEL_EXPR_LABEL (top));
-
- if (cond && !integer_nonzerop (cond))
- {
- /* Canonicalize the loop condition to the end. This means
- generating a branch to the loop condition. Reuse the
- continue label, if possible. */
- if (cond_is_first)
- {
- if (incr || !clab)
- {
- entry = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
- t = build_and_jump (&LABEL_EXPR_LABEL (entry));
- }
- else
- t = build1 (GOTO_EXPR, void_type_node, clab);
- SET_EXPR_LOCATION (t, start_locus);
- add_stmt (t);
- }
-
- t = build_and_jump (&blab);
- exit = fold_build3_loc (cond_is_first ? start_locus : input_location,
- COND_EXPR, void_type_node, cond, exit, t);
- }
- else
- {
- /* For the backward-goto's location of an unconditional loop
- use the beginning of the body, or, if there is none, the
- top of the loop. */
- location_t loc = EXPR_LOCATION (expr_first (body));
- if (loc == UNKNOWN_LOCATION)
- loc = start_locus;
- SET_EXPR_LOCATION (exit, loc);
- }
-
- add_stmt (top);
- }
-
- if (body)
- add_stmt (body);
- if (clab)
- add_stmt (build1 (LABEL_EXPR, void_type_node, clab));
- if (incr)
- {
- if (MAY_HAVE_DEBUG_MARKER_STMTS && incr_locus != UNKNOWN_LOCATION)
- {
- t = build0 (DEBUG_BEGIN_STMT, void_type_node);
- SET_EXPR_LOCATION (t, incr_locus);
- add_stmt (t);
- }
- add_stmt (incr);
- }
- if (entry)
- add_stmt (entry);
- if (MAY_HAVE_DEBUG_MARKER_STMTS && cond_locus != UNKNOWN_LOCATION)
- {
- t = build0 (DEBUG_BEGIN_STMT, void_type_node);
- SET_EXPR_LOCATION (t, cond_locus);
- add_stmt (t);
- }
- if (exit)
- add_stmt (exit);
- if (blab)
- add_stmt (build1 (LABEL_EXPR, void_type_node, blab));
-}
-
tree
-c_finish_bc_stmt (location_t loc, tree *label_p, bool is_break)
+c_finish_bc_stmt (location_t loc, tree label, bool is_break)
{
- bool skip;
- tree label = *label_p;
-
/* In switch statements break is sometimes stylistically used after
a return statement. This can lead to spurious warnings about
control reaching the end of a non-void function when it is
@@ -11111,47 +11016,55 @@ c_finish_bc_stmt (location_t loc, tree *label_p, bool is_break)
language specific tree nodes; this works because
block_may_fallthru returns true when given something it does not
understand. */
- skip = !block_may_fallthru (cur_stmt_list);
+ bool skip = !block_may_fallthru (cur_stmt_list);
- if (!label)
- {
- if (!skip)
- *label_p = label = create_artificial_label (loc);
- }
- else if (TREE_CODE (label) == LABEL_DECL)
- ;
- else switch (TREE_INT_CST_LOW (label))
- {
- case 0:
- if (is_break)
+ if (is_break)
+ switch (in_statement)
+ {
+ case 0:
error_at (loc, "break statement not within loop or switch");
- else
+ return NULL_TREE;
+ case IN_OMP_BLOCK:
+ error_at (loc, "invalid exit from OpenMP structured block");
+ return NULL_TREE;
+ case IN_OMP_FOR:
+ error_at (loc, "break statement used with OpenMP for loop");
+ return NULL_TREE;
+ case IN_ITERATION_STMT:
+ case IN_OBJC_FOREACH:
+ break;
+ default:
+ gcc_assert (in_statement & IN_SWITCH_STMT);
+ c_switch_stack->break_stmt_seen_p = true;
+ break;
+ }
+ else
+ switch (in_statement & ~IN_SWITCH_STMT)
+ {
+ case 0:
error_at (loc, "continue statement not within a loop");
- return NULL_TREE;
-
- case 1:
- gcc_assert (is_break);
- error_at (loc, "break statement used with OpenMP for loop");
- return NULL_TREE;
-
- case 2:
- if (is_break)
- error ("break statement within %<#pragma simd%> loop body");
- else
- error ("continue statement within %<#pragma simd%> loop body");
- return NULL_TREE;
-
- default:
- gcc_unreachable ();
- }
+ return NULL_TREE;
+ case IN_OMP_BLOCK:
+ error_at (loc, "invalid exit from OpenMP structured block");
+ return NULL_TREE;
+ case IN_ITERATION_STMT:
+ case IN_OMP_FOR:
+ case IN_OBJC_FOREACH:
+ break;
+ default:
+ gcc_unreachable ();
+ }
if (skip)
return NULL_TREE;
-
- if (!is_break)
- add_stmt (build_predict_expr (PRED_CONTINUE, NOT_TAKEN));
-
- return add_stmt (build1 (GOTO_EXPR, void_type_node, label));
+ else if (in_statement & IN_OBJC_FOREACH)
+ {
+ /* The foreach expander produces low-level code using gotos instead
+ of a structured loop construct. */
+ gcc_assert (label);
+ return add_stmt (build_stmt (loc, GOTO_EXPR, label));
+ }
+ return add_stmt (build_stmt (loc, (is_break ? BREAK_STMT : CONTINUE_STMT)));
}
/* A helper routine for c_process_expr_stmt and c_finish_stmt_expr. */
diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog
index 5d8500c..c6ab194 100644
--- a/gcc/objc/ChangeLog
+++ b/gcc/objc/ChangeLog
@@ -1,3 +1,8 @@
+2020-07-19 Sandra Loosemore <sandra@codesourcery.com>
+
+ * objc-act.c (objc_start_method_definition): Update to reflect
+ changes to break/continue state bookkeeping in C front end.
+
2020-01-01 Jakub Jelinek <jakub@redhat.com>
Update copyright years.
diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c
index 54af1cf..31a2cf3 100644
--- a/gcc/objc/objc-act.c
+++ b/gcc/objc/objc-act.c
@@ -2050,10 +2050,8 @@ objc_start_method_definition (bool is_class_method, tree decl, tree attributes,
return false;
#ifndef OBJCPLUS
- /* Indicate no valid break/continue context by setting these variables
- to some non-null, non-label value. We'll notice and emit the proper
- error message in c_finish_bc_stmt. */
- c_break_label = c_cont_label = size_zero_node;
+ /* Indicate no valid break/continue context. */
+ in_statement = 0;
#endif
if (attributes)
diff --git a/gcc/testsuite/gcc.dg/gomp/block-7.c b/gcc/testsuite/gcc.dg/gomp/block-7.c
index 6219e7e..3e87464 100644
--- a/gcc/testsuite/gcc.dg/gomp/block-7.c
+++ b/gcc/testsuite/gcc.dg/gomp/block-7.c
@@ -6,15 +6,15 @@ void foo()
for (i = 0; i < 10; ++i)
{
#pragma omp for
- for (j = ({ continue; 0; }); // { dg-error "invalid branch to/from OpenMP structured block" }
- j < ({ continue; 10; }); // { dg-error "invalid branch to/from OpenMP structured block" }
- j += ({ continue; 1; })) // { dg-error "invalid branch to/from OpenMP structured block" }
+ for (j = ({ continue; 0; }); // { dg-error "invalid exit from OpenMP structured block" }
+ j < ({ continue; 10; }); // { dg-error "invalid exit from OpenMP structured block" }
+ j += ({ continue; 1; })) // { dg-error "invalid exit from OpenMP structured block" }
continue;
#pragma omp for
- for (j = ({ break; 0; }); // { dg-error "invalid branch to/from OpenMP structured block" }
- j < ({ break; 10; }); // { dg-error "invalid branch to/from OpenMP structured block" }
- j += ({ break; 1; })) // { dg-error "invalid branch to/from OpenMP structured block" }
+ for (j = ({ break; 0; }); // { dg-error "invalid exit from OpenMP structured block" }
+ j < ({ break; 10; }); // { dg-error "invalid exit from OpenMP structured block" }
+ j += ({ break; 1; })) // { dg-error "invalid exit from OpenMP structured block" }
break; // { dg-error "break" }
}
}
--
2.8.1
^ permalink raw reply [flat|nested] 16+ messages in thread