Move loop and switch tree data structures from cp/ to c-family/.
authorSandra Loosemore <sandra@codesourcery.com>
Sat, 19 Sep 2020 14:32:35 +0000 (07:32 -0700)
committerSandra Loosemore <sandra@codesourcery.com>
Sat, 19 Sep 2020 20:54:16 +0000 (13:54 -0700)
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.

13 files changed:
gcc/c-family/c-common.c
gcc/c-family/c-common.def
gcc/c-family/c-common.h
gcc/c-family/c-dump.c
gcc/c-family/c-gimplify.c
gcc/c-family/c-pretty-print.c
gcc/cp/cp-gimplify.c
gcc/cp/cp-objcp-common.c
gcc/cp/cp-tree.def
gcc/cp/cp-tree.h
gcc/cp/cxx-pretty-print.c
gcc/cp/dump.c
gcc/doc/generic.texi

index 873bea9e2b2f17d8b39b56f6cbffaf1b7c883d77..e16ca3894bc70022274712b3d9aad50635662211 100644 (file)
@@ -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
index 7ceb9a22bd4401f12dc1d8b66d7fe56e4de4a842..1954bfe1f808f92342d5dc6940cb9cc0cf8758d5 100644 (file)
@@ -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
index 4fc64bc4aa64d4409b73bc532bd9db5ef7f7de5b..6abfe4b1a312ef1edefcc7bf98145b4b810cae0f 100644 (file)
@@ -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.  */
index ffc580871b9fe526a8589e66c80622ef6880077d..d3caacc87a1f732060fd5f5016ad46c9f2826f11 100644 (file)
@@ -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;
     }
index 5d357d0f17e1cf534ec6e971ec2f0ae8fc4032e0..db930fc5ee5aeb568e0d1ca03d667e59bed7c638 100644 (file)
@@ -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)
index ec0bafe10105ac43a647660d58d0d083ab97ddaa..c364e1c4a4dd7e93830f6cf7d0770a722c28491d 100644 (file)
@@ -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
index b2befa7148da1702607b2cae8078ff9f6ac7d463..bc8a03c7b41aa4982d20e166bf3703205ec825fb 100644 (file)
@@ -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
index 852a34dbc5f2cacfec84c3cc551b02a7b59a00de..e1397b7b7104a05f7c8aa60d6017adb11f046a9a 100644 (file)
@@ -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);
index 6eabe0d6d8f1ffbc063812bf2c256fe3bd0c0495..a188576013b0b260a9f8a9b846f1d8f4abbf347e 100644 (file)
@@ -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)
index 08976d8527c4b09d7c2307db0c494fdc1229416f..713538149735d206dc4902f45e4649f5deb5b327 100644 (file)
@@ -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)
 
index 263f225a492e27a5b103430f675c2b9499d98b2d..d10c18db0398a6d3f97d59b58881ee9dcbd01820 100644 (file)
@@ -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:
index c509badee8151af87d730cf5a9996d698761c81a..81d2c16d5db1d1fb1274286dd45f74f8fd8f0137 100644 (file)
@@ -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;
index fb98727928af112f3825e9c12ee47fa49c84dfa0..7373266c69f393139dabe21437aa8b3c2b5b0b4a 100644 (file)
@@ -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