public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH V2 0/4] Unify C and C++ handling of loops and switches
@ 2020-08-13 16:34 Sandra Loosemore
  2020-08-13 16:34 ` [PATCH V2 1/4] Move loop and switch tree data structures from cp/ to c-family/ Sandra Loosemore
                   ` (5 more replies)
  0 siblings, 6 replies; 16+ messages in thread
From: Sandra Loosemore @ 2020-08-13 16:34 UTC (permalink / raw)
  To: gcc-patches

This is a revised version of the patch set originally posted
last November:

https://gcc.gnu.org/pipermail/gcc-patches/2019-November/534142.html

In addition to generally updating and rebasing the patches to reflect
other changes on mainline in the meantime, for this version I have
switched to using the C lowering strategy (directly to goto form)
rather than the C++ one (to LOOP_EXPR) because of regressions in the C
optimization tests.  Besides the ones previously noted in the original
patch submission, there were a bunch of new ones since November.  Some
of them were trivial to fix (e.g., flipping branch probabilities to
reflect the different sense of the loop exit condition in the
C++-style output), but I wasn't making much progress on others and
eventually decided to pursue the "plan B" of using the C-style output
everywhere, as discussed here:

https://gcc.gnu.org/pipermail/gcc-patches/2019-December/536536.html

The only regression I ran into with this was a bootstrap failure
building the Fortran front end from a new -Wmaybe-uninitialized error.
This might be a false positive but part 3 of the new series works
around it by adding an assertion to give g++ a hint.  Unfortunately I
had no luck in trying to reduce this to a standalone test case, but I
did observe that the failure went away when I compiled that file with
debugging enabled.  :-S  I could file a PR to look into this further if
the workaround is good enough for now.

-Sandra


Sandra Loosemore (4):
  Move loop and switch tree data structures from cp/ to c-family/.
  Use C-style loop lowering instead of C++-style.
  Work around bootstrap failure in Fortran front end.
  Change C front end to emit structured loop and switch tree nodes.

 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           | 422 ++++++++++++++++++++++++++++++++
 gcc/c-family/c-pretty-print.c       |  92 ++++++-
 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/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 +++--
 gcc/fortran/interface.c             |   4 +
 gcc/objc/ChangeLog                  |   5 +
 gcc/objc/objc-act.c                 |   6 +-
 gcc/testsuite/gcc.dg/gomp/block-7.c |  12 +-
 23 files changed, 938 insertions(+), 848 deletions(-)

-- 
2.8.1


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [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 2/4] Use C-style loop lowering instead of C++-style.
  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 ` [PATCH V2 1/4] Move loop and switch tree data structures from cp/ to c-family/ Sandra Loosemore
@ 2020-08-13 16:34 ` Sandra Loosemore
  2020-08-13 16:34 ` [PATCH V2 3/4] Work around bootstrap failure in Fortran front end Sandra Loosemore
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: Sandra Loosemore @ 2020-08-13 16:34 UTC (permalink / raw)
  To: gcc-patches

The C and C++ front ends used to use the same strategy of lowering
loops to gotos with the end test canonicalized to the bottom of the
loop.  In 2014 the C++ front end was changed to emit LOOP_EXPRs
instead (commit 1a45860e7757ee054f6bf98bee4ebe5c661dfb90).

As part of the unification of the C and C++ loop handling, it's
desirable to use the same lowering strategy for both languages.
Applying the C++ strategy to C caused a number of regressions in C
optimization tests, related to flipping the sense of the COND_EXPR for
the exit test and changes in block ordering in the output code.  Many
of these regressions just require updating regexps in the test cases
but a few appear to be genuine optimization failures.  Since it
appears the optimizers handle the C code better than C++ code, let's
go back to using the C strategy for both languages.  The rationale for
the 2014 C++ patch (support for constexpr evaluation) has been solved
in other ways meanwhile.

2020-08-12  Sandra Loosemore  <sandra@codesourcery.com>

	gcc/c-family/
	* c-gimplify.c (genericize_c_loop): Rewrite to match
	c_finish_loop in c-typeck.c.
---
 gcc/c-family/c-gimplify.c | 110 ++++++++++++++++++++++++++--------------------
 1 file changed, 62 insertions(+), 48 deletions(-)

diff --git a/gcc/c-family/c-gimplify.c b/gcc/c-family/c-gimplify.c
index db930fc..8b326c9 100644
--- a/gcc/c-family/c-gimplify.c
+++ b/gcc/c-family/c-gimplify.c
@@ -217,9 +217,10 @@ genericize_c_loop (tree *stmt_p, location_t start_locus, tree cond, tree body,
 		   void *data, walk_tree_fn func, walk_tree_lh lh)
 {
   tree blab, clab;
-  tree exit = NULL;
+  tree entry = NULL, exit = NULL, t;
   tree stmt_list = NULL;
-  tree debug_begin = NULL;
+  location_t cond_locus = expr_loc_or_loc (cond, start_locus);
+  location_t incr_locus = expr_loc_or_loc (incr, start_locus);
 
   protected_set_expr_location_if_unset (incr, start_locus);
 
@@ -232,35 +233,68 @@ genericize_c_loop (tree *stmt_p, location_t start_locus, tree cond, tree body,
   walk_tree_1 (&body, func, data, NULL, lh);
   *walk_subtrees = 0;
 
-  if (MAY_HAVE_DEBUG_MARKER_STMTS
-      && (!cond || !integer_zerop (cond)))
+  /* If condition is zero don't generate a loop construct.  */
+  if (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_is_first)
+	{
+	  t = build1_loc (start_locus, GOTO_EXPR, void_type_node,
+			  get_bc_label (bc_break));
+	  append_to_statement_list (t, &stmt_list);
+	}
     }
-
-  if (cond && TREE_CODE (cond) != INTEGER_CST)
+  else
     {
-      /* 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);
-    }
+      /* Expand to gotos.  */
+      tree top = build1 (LABEL_EXPR, void_type_node,
+			 create_artificial_label (start_locus));
 
-  if (exit && cond_is_first)
-    {
-      append_to_statement_list (debug_begin, &stmt_list);
-      debug_begin = NULL_TREE;
-      append_to_statement_list (exit, &stmt_list);
+      /* 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 = build1 (GOTO_EXPR, void_type_node, 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 there is no incr expression.  */
+	  if (cond_is_first)
+	    {
+	      if (incr)
+		{
+		  entry = build1 (LABEL_EXPR, void_type_node,
+				  create_artificial_label (start_locus));
+		  t = build1_loc (start_locus, GOTO_EXPR, void_type_node,
+				  LABEL_EXPR_LABEL (entry));
+		}
+	      else
+		t = build1_loc (start_locus, GOTO_EXPR, void_type_node,
+				get_bc_label (bc_continue));
+	      append_to_statement_list (t, &stmt_list);
+	    }
+
+	  t = build1 (GOTO_EXPR, void_type_node, get_bc_label (bc_break));
+	  exit = fold_build3_loc (cond_locus,
+				  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_loc_or_loc (expr_first (body),
+					    start_locus);
+	  SET_EXPR_LOCATION (exit, loc);
+	}
+      append_to_statement_list (top, &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)
+      if (MAY_HAVE_DEBUG_MARKER_STMTS && incr_locus != UNKNOWN_LOCATION)
 	{
 	  tree d = build0 (DEBUG_BEGIN_STMT, void_type_node);
 	  SET_EXPR_LOCATION (d, expr_loc_or_loc (incr, start_locus));
@@ -268,35 +302,15 @@ genericize_c_loop (tree *stmt_p, location_t start_locus, tree cond, tree body,
 	}
       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);
+  append_to_statement_list (entry, &stmt_list);
 
-  if (!stmt_list)
-    stmt_list = build_empty_stmt (start_locus);
-
-  tree loop;
-  if (cond && integer_zerop (cond))
+  if (MAY_HAVE_DEBUG_MARKER_STMTS && cond_locus != UNKNOWN_LOCATION)
     {
-      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);
+      tree d = build0 (DEBUG_BEGIN_STMT, void_type_node);
+      SET_EXPR_LOCATION (d, cond_locus);
+      append_to_statement_list (d, &stmt_list);
     }
-
-  stmt_list = NULL;
-  append_to_statement_list (loop, &stmt_list);
+  append_to_statement_list (exit, &stmt_list);
   finish_bc_block (&stmt_list, bc_break, blab);
   if (!stmt_list)
     stmt_list = build_empty_stmt (start_locus);
-- 
2.8.1


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH V2 3/4] Work around bootstrap failure in Fortran front end.
  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 ` [PATCH V2 1/4] Move loop and switch tree data structures from cp/ to c-family/ Sandra Loosemore
  2020-08-13 16:34 ` [PATCH V2 2/4] Use C-style loop lowering instead of C++-style Sandra Loosemore
@ 2020-08-13 16:34 ` Sandra Loosemore
       [not found]   ` <7d3fbcd3-759b-10bc-d620-83de53e027fd@moene.org>
  2020-08-13 16:34 ` [PATCH V2 4/4] Change C front end to emit structured loop and switch tree nodes Sandra Loosemore
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 16+ messages in thread
From: Sandra Loosemore @ 2020-08-13 16:34 UTC (permalink / raw)
  To: gcc-patches

Switching the C++ front end to lower loops the same was as the C front
end triggered this error when bootstrapping the Fortran front end:

/path/to/gcc/fortran/interface.c:3546:12: error: '*new_arg' may be used uninitialized [-Werror=maybe-uninitialized]
 3546 |   new_arg[i]->next = NULL;
      |   ~~~~~~~~~^

Work around this by adding an assertion, which seems appropriate for
documentation and good coding practices anyway.

2020-08-12  Sandra Loosemore  <sandra@codesourcery.com>

	gcc/fortran/
	* interface.c (gfc_compare_actual_formal): Add assertion after
	main processing loop to silence maybe-uninitialized error.
---
 gcc/fortran/interface.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/gcc/fortran/interface.c b/gcc/fortran/interface.c
index 7985fc7..9fea94c 100644
--- a/gcc/fortran/interface.c
+++ b/gcc/fortran/interface.c
@@ -3527,6 +3527,10 @@ gfc_compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal,
 	}
     }
 
+  /* We should have handled the cases where the formal arglist is null
+     already.  */
+  gcc_assert (n > 0);
+
   /* The argument lists are compatible.  We now relink a new actual
      argument list with null arguments in the right places.  The head
      of the list remains the head.  */
-- 
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

* Re: Fwd: [PATCH V2 3/4] Work around bootstrap failure in Fortran front end.
       [not found]   ` <7d3fbcd3-759b-10bc-d620-83de53e027fd@moene.org>
@ 2020-08-15 18:24     ` Thomas Koenig
  0 siblings, 0 replies; 16+ messages in thread
From: Thomas Koenig @ 2020-08-15 18:24 UTC (permalink / raw)
  To: Toon Moene, fortran, gcc-patches; +Cc: sandra

Hi,

the change looks good to me, OK for master.

Regards

	Thomas
> This arose from work by Sandra on "Unify C and C++ handling of loops and 
> switches"
> 
> Kind regards,
> Toon.
> 
> -------- Forwarded Message --------
> Subject: [PATCH V2 3/4] Work around bootstrap failure in Fortran front end.
> Date: Thu, 13 Aug 2020 10:34:31 -0600
> From: Sandra Loosemore <sandra@codesourcery.com>
> To: gcc-patches@gcc.gnu.org
> 
> Switching the C++ front end to lower loops the same was as the C front
> end triggered this error when bootstrapping the Fortran front end:
> 
> /path/to/gcc/fortran/interface.c:3546:12: error: '*new_arg' may be used 
> uninitialized [-Werror=maybe-uninitialized]
>   3546 |   new_arg[i]->next = NULL;
>        |   ~~~~~~~~~^
> 
> Work around this by adding an assertion, which seems appropriate for
> documentation and good coding practices anyway.
> 
> 2020-08-12  Sandra Loosemore  <sandra@codesourcery.com>
> 
>      gcc/fortran/
>      * interface.c (gfc_compare_actual_formal): Add assertion after
>      main processing loop to silence maybe-uninitialized error.
> ---
>   gcc/fortran/interface.c | 4 ++++
>   1 file changed, 4 insertions(+)
> 
> diff --git a/gcc/fortran/interface.c b/gcc/fortran/interface.c
> index 7985fc7..9fea94c 100644
> --- a/gcc/fortran/interface.c
> +++ b/gcc/fortran/interface.c
> @@ -3527,6 +3527,10 @@ gfc_compare_actual_formal (gfc_actual_arglist 
> **ap, gfc_formal_arglist *formal,
>       }
>       }
>   +  /* We should have handled the cases where the formal arglist is null
> +     already.  */
> +  gcc_assert (n > 0);
> +
>     /* The argument lists are compatible.  We now relink a new actual
>        argument list with null arguments in the right places.  The head
>        of the list remains the head.  */


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PING] [PATCH V2 0/4] Unify C and C++ handling of loops and switches
  2020-08-13 16:34 [PATCH V2 0/4] Unify C and C++ handling of loops and switches Sandra Loosemore
                   ` (3 preceding siblings ...)
  2020-08-13 16:34 ` [PATCH V2 4/4] Change C front end to emit structured loop and switch tree nodes Sandra Loosemore
@ 2020-08-28 16:58 ` Sandra Loosemore
  2020-09-09 17:38   ` [PING^2] " Sandra Loosemore
  2020-09-09 21:13 ` Jason Merrill
  5 siblings, 1 reply; 16+ messages in thread
From: Sandra Loosemore @ 2020-08-28 16:58 UTC (permalink / raw)
  To: gcc-patches

Ping!  Only the fix for the Fortran bootstrap failure in part 3 has been 
reviewed.

-Sandra


https://gcc.gnu.org/pipermail/gcc-patches/2020-August/551927.html

On 8/13/20 10:34 AM, Sandra Loosemore wrote:
> This is a revised version of the patch set originally posted
> last November:
> 
> https://gcc.gnu.org/pipermail/gcc-patches/2019-November/534142.html
> 
> In addition to generally updating and rebasing the patches to reflect
> other changes on mainline in the meantime, for this version I have
> switched to using the C lowering strategy (directly to goto form)
> rather than the C++ one (to LOOP_EXPR) because of regressions in the C
> optimization tests.  Besides the ones previously noted in the original
> patch submission, there were a bunch of new ones since November.  Some
> of them were trivial to fix (e.g., flipping branch probabilities to
> reflect the different sense of the loop exit condition in the
> C++-style output), but I wasn't making much progress on others and
> eventually decided to pursue the "plan B" of using the C-style output
> everywhere, as discussed here:
> 
> https://gcc.gnu.org/pipermail/gcc-patches/2019-December/536536.html
> 
> The only regression I ran into with this was a bootstrap failure
> building the Fortran front end from a new -Wmaybe-uninitialized error.
> This might be a false positive but part 3 of the new series works
> around it by adding an assertion to give g++ a hint.  Unfortunately I
> had no luck in trying to reduce this to a standalone test case, but I
> did observe that the failure went away when I compiled that file with
> debugging enabled.  :-S  I could file a PR to look into this further if
> the workaround is good enough for now.
> 
> -Sandra
> 
> 
> Sandra Loosemore (4):
>    Move loop and switch tree data structures from cp/ to c-family/.
>    Use C-style loop lowering instead of C++-style.
>    Work around bootstrap failure in Fortran front end.
>    Change C front end to emit structured loop and switch tree nodes.
> 
>   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           | 422 ++++++++++++++++++++++++++++++++
>   gcc/c-family/c-pretty-print.c       |  92 ++++++-
>   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/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 +++--
>   gcc/fortran/interface.c             |   4 +
>   gcc/objc/ChangeLog                  |   5 +
>   gcc/objc/objc-act.c                 |   6 +-
>   gcc/testsuite/gcc.dg/gomp/block-7.c |  12 +-
>   23 files changed, 938 insertions(+), 848 deletions(-)
> 


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PING^2] [PATCH V2 0/4] Unify C and C++ handling of loops and switches
  2020-08-28 16:58 ` [PING] [PATCH V2 0/4] Unify C and C++ handling of loops and switches Sandra Loosemore
@ 2020-09-09 17:38   ` Sandra Loosemore
  0 siblings, 0 replies; 16+ messages in thread
From: Sandra Loosemore @ 2020-09-09 17:38 UTC (permalink / raw)
  To: gcc-patches; +Cc: Joseph Myers, jason, Nathan Sidwell

Ping again on this patch series:
https://gcc.gnu.org/pipermail/gcc-patches/2020-August/551927.html

These patches just missed making it into GCC 10 last year -- although 
there seemed to be agreement in principle, they needed a bit more work 
to resolve test regressions.  Now that we are heading into fall again, I 
am worried that they may miss GCC 11 as well if they need further 
re-working but I don't get feedback until very late in the release 
cycle, or any feedback at all.  :-(  I also have a set of OpenACC 
patches for identifying loops in kernels regions that depend on these; 
I'll be posting those shortly and I hope to get those into GCC 11 as well.

-Sandra
> On 8/13/20 10:34 AM, Sandra Loosemore wrote:
>> This is a revised version of the patch set originally posted
>> last November:
>>
>> https://gcc.gnu.org/pipermail/gcc-patches/2019-November/534142.html
>>
>> In addition to generally updating and rebasing the patches to reflect
>> other changes on mainline in the meantime, for this version I have
>> switched to using the C lowering strategy (directly to goto form)
>> rather than the C++ one (to LOOP_EXPR) because of regressions in the C
>> optimization tests.  Besides the ones previously noted in the original
>> patch submission, there were a bunch of new ones since November.  Some
>> of them were trivial to fix (e.g., flipping branch probabilities to
>> reflect the different sense of the loop exit condition in the
>> C++-style output), but I wasn't making much progress on others and
>> eventually decided to pursue the "plan B" of using the C-style output
>> everywhere, as discussed here:
>>
>> https://gcc.gnu.org/pipermail/gcc-patches/2019-December/536536.html
>>
>> The only regression I ran into with this was a bootstrap failure
>> building the Fortran front end from a new -Wmaybe-uninitialized error.
>> This might be a false positive but part 3 of the new series works
>> around it by adding an assertion to give g++ a hint.  Unfortunately I
>> had no luck in trying to reduce this to a standalone test case, but I
>> did observe that the failure went away when I compiled that file with
>> debugging enabled.  :-S  I could file a PR to look into this further if
>> the workaround is good enough for now.
>>
>> -Sandra
>>
>>
>> Sandra Loosemore (4):
>>    Move loop and switch tree data structures from cp/ to c-family/.
>>    Use C-style loop lowering instead of C++-style.
>>    Work around bootstrap failure in Fortran front end.
>>    Change C front end to emit structured loop and switch tree nodes.
>>
>>   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           | 422 
>> ++++++++++++++++++++++++++++++++
>>   gcc/c-family/c-pretty-print.c       |  92 ++++++-
>>   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/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 +++--
>>   gcc/fortran/interface.c             |   4 +
>>   gcc/objc/ChangeLog                  |   5 +
>>   gcc/objc/objc-act.c                 |   6 +-
>>   gcc/testsuite/gcc.dg/gomp/block-7.c |  12 +-
>>   23 files changed, 938 insertions(+), 848 deletions(-)
>>
> 


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH V2 0/4] Unify C and C++ handling of loops and switches
  2020-08-13 16:34 [PATCH V2 0/4] Unify C and C++ handling of loops and switches Sandra Loosemore
                   ` (4 preceding siblings ...)
  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
  2020-09-10  0:20   ` Sandra Loosemore
  2020-09-10 13:36   ` David Malcolm
  5 siblings, 2 replies; 16+ messages in thread
From: Jason Merrill @ 2020-09-09 21:13 UTC (permalink / raw)
  To: Sandra Loosemore, gcc-patches

On 8/13/20 12:34 PM, Sandra Loosemore wrote:
> This is a revised version of the patch set originally posted
> last November:
> 
> https://gcc.gnu.org/pipermail/gcc-patches/2019-November/534142.html
> 
> In addition to generally updating and rebasing the patches to reflect
> other changes on mainline in the meantime, for this version I have
> switched to using the C lowering strategy (directly to goto form)
> rather than the C++ one (to LOOP_EXPR) because of regressions in the C
> optimization tests.  Besides the ones previously noted in the original
> patch submission, there were a bunch of new ones since November.  Some
> of them were trivial to fix (e.g., flipping branch probabilities to
> reflect the different sense of the loop exit condition in the
> C++-style output), but I wasn't making much progress on others and
> eventually decided to pursue the "plan B" of using the C-style output
> everywhere, as discussed here:
> 
> https://gcc.gnu.org/pipermail/gcc-patches/2019-December/536536.html
> 
> The only regression I ran into with this was a bootstrap failure
> building the Fortran front end from a new -Wmaybe-uninitialized error.
> This might be a false positive but part 3 of the new series works
> around it by adding an assertion to give g++ a hint.  Unfortunately I
> had no luck in trying to reduce this to a standalone test case, but I
> did observe that the failure went away when I compiled that file with
> debugging enabled.  :-S  I could file a PR to look into this further if
> the workaround is good enough for now.

My impression from Jeff's analysis in January and David's in March was 
that many of the testsuite changes were from the C++ approach actually 
providing better results, so the reversal here surprises me.  Can you 
talk more about the regressions you're seeing?

Jason


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH V2 0/4] Unify C and C++ handling of loops and switches
  2020-09-09 21:13 ` Jason Merrill
@ 2020-09-10  0:20   ` Sandra Loosemore
  2020-09-17 14:32     ` Jason Merrill
  2020-09-10 13:36   ` David Malcolm
  1 sibling, 1 reply; 16+ messages in thread
From: Sandra Loosemore @ 2020-09-10  0:20 UTC (permalink / raw)
  To: Jason Merrill, gcc-patches

On 9/9/20 3:13 PM, Jason Merrill wrote:
> 
> My impression from Jeff's analysis in January and David's in March was 
> that many of the testsuite changes were from the C++ approach actually 
> providing better results, so the reversal here surprises me.  Can you 
> talk more about the regressions you're seeing?

I spent most of my time earlier in the summer looking at the 3 
regressions I originally saw last fall.  Unfortunately I could get no 
traction at all on the 2 FSA-related ones.  :-(  For the 
gcc.dg/tree-ssa/ssa-dce-3.c regression, I tracked it down to some code 
in the cddce1 pass being sensitive to the ordering of basic blocks in 
the input code;  I filed PR96487 for that.

I was also having a bunch of problems with -Wimplicit-fallthrough 
failures triggered by the C++ front end loop expansion sometimes 
flipping the sense of the end test conditional (through the use of 
fold_build3_loc to build it).  It seemed to me that the code that 
handles COND_EXPRs for those warnings is sensitive to the order of 
blocks as well, and has asymmetric assumptions that the code for the 
"if" branch is emitted inline before the "else" branch.  I tried some 
experiments with generalizing it to recognize the branches in either 
order, but that did not fix the regressions, so maybe the problem was 
somewhere else entirely, or a combination of two different bugs.  :-(

Anyway it seemed to me that the patches would not be accepted if I 
resubmitted them in a form that still caused regressions, and switching 
back to the C way of expanding to GOTO form directly instead of via 
LOOP_EXPR did that.

-Sandra

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH V2 0/4] Unify C and C++ handling of loops and switches
  2020-09-09 21:13 ` Jason Merrill
  2020-09-10  0:20   ` Sandra Loosemore
@ 2020-09-10 13:36   ` David Malcolm
  2020-09-10 16:06     ` Sandra Loosemore
  1 sibling, 1 reply; 16+ messages in thread
From: David Malcolm @ 2020-09-10 13:36 UTC (permalink / raw)
  To: Jason Merrill, Sandra Loosemore, gcc-patches

On Wed, 2020-09-09 at 17:13 -0400, Jason Merrill wrote:
> On 8/13/20 12:34 PM, Sandra Loosemore wrote:
> > This is a revised version of the patch set originally posted
> > last November:
> > 
> > https://gcc.gnu.org/pipermail/gcc-patches/2019-November/534142.html
> > 
> > In addition to generally updating and rebasing the patches to
> > reflect
> > other changes on mainline in the meantime, for this version I have
> > switched to using the C lowering strategy (directly to goto form)
> > rather than the C++ one (to LOOP_EXPR) because of regressions in
> > the C
> > optimization tests.  Besides the ones previously noted in the
> > original
> > patch submission, there were a bunch of new ones since
> > November.  Some
> > of them were trivial to fix (e.g., flipping branch probabilities to
> > reflect the different sense of the loop exit condition in the
> > C++-style output), but I wasn't making much progress on others and
> > eventually decided to pursue the "plan B" of using the C-style
> > output
> > everywhere, as discussed here:
> > 
> > https://gcc.gnu.org/pipermail/gcc-patches/2019-December/536536.html
> > 
> > The only regression I ran into with this was a bootstrap failure
> > building the Fortran front end from a new -Wmaybe-uninitialized
> > error.
> > This might be a false positive but part 3 of the new series works
> > around it by adding an assertion to give g++ a hint.  Unfortunately
> > I
> > had no luck in trying to reduce this to a standalone test case, but
> > I
> > did observe that the failure went away when I compiled that file
> > with
> > debugging enabled.  :-S  I could file a PR to look into this
> > further if
> > the workaround is good enough for now.
> 
> My impression from Jeff's analysis in January and David's in March 

For reference, these seem to have been:
  https://gcc.gnu.org/pipermail/gcc-patches/2020-January/539207.html
and:
  https://gcc.gnu.org/pipermail/gcc-patches/2020-March/542018.html
respectively.

In the latter I said:

> I think that what's happened is that your patch improves the location
> information for the gimple stmts, and this uncovers a bug in how I 
> wrote the test.

which is presumably what Jason's getting at.

BTW, in terms of analyzer issues, my big rewrite of analyzer state-
tracking landed in master a month ago, on 2020-08-13 as
808f4dfeb3a95f50f15e71148e5c1067f90a126d, and changed the behavior of
gcc.dg/analyzer/explode-2.c, which was one of the ones an earlier
version of Sandra's patch also affected.

Sandra: was the most recent patch you posted tested against a
relatively recent source tree?  (i.e. since that 2020-08-13 patch?). 
That said, I don't want the analyzer to stand in the way of
improvements to the frontends, so let me know if I can help with any
analyzer testsuite regressions.

Thanks
Dave

> was 
> that many of the testsuite changes were from the C++ approach
> actually 
> providing better results, so the reversal here surprises me.  Can
> you 
> talk more about the regressions you're seeing?



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH V2 0/4] Unify C and C++ handling of loops and switches
  2020-09-10 13:36   ` David Malcolm
@ 2020-09-10 16:06     ` Sandra Loosemore
  0 siblings, 0 replies; 16+ messages in thread
From: Sandra Loosemore @ 2020-09-10 16:06 UTC (permalink / raw)
  To: David Malcolm, Jason Merrill, gcc-patches

On 9/10/20 7:36 AM, David Malcolm wrote:

> BTW, in terms of analyzer issues, my big rewrite of analyzer state-
> tracking landed in master a month ago, on 2020-08-13 as
> 808f4dfeb3a95f50f15e71148e5c1067f90a126d, and changed the behavior of
> gcc.dg/analyzer/explode-2.c, which was one of the ones an earlier
> version of Sandra's patch also affected.

In case I failed to make this explicit previously: my 2020-08-13 patch 
did not trigger the analyzer regressions in C that the version from last 
fall did, because it retains the existing form of C lowering for loops.

> Sandra: was the most recent patch you posted tested against a
> relatively recent source tree?  (i.e. since that 2020-08-13 patch?).
> That said, I don't want the analyzer to stand in the way of
> improvements to the frontends, so let me know if I can help with any
> analyzer testsuite regressions.

I did not prepare a rebased patch set against mainline head, but I did 
just rebase, rebuild, and retest these patches earlier this week in 
conjunction with the OpenACC kernels loop annotation patches that depend 
on them, that I just posted yesterday.  I didn't see any analyzer 
regressions in those test results either.

-Sandra

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH V2 0/4] Unify C and C++ handling of loops and switches
  2020-09-10  0:20   ` Sandra Loosemore
@ 2020-09-17 14:32     ` Jason Merrill
  2020-09-17 22:51       ` Joseph Myers
                         ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: Jason Merrill @ 2020-09-17 14:32 UTC (permalink / raw)
  To: Sandra Loosemore, gcc-patches

On 9/9/20 8:20 PM, Sandra Loosemore wrote:
> On 9/9/20 3:13 PM, Jason Merrill wrote:
>>
>> My impression from Jeff's analysis in January and David's in March was 
>> that many of the testsuite changes were from the C++ approach actually 
>> providing better results, so the reversal here surprises me.  Can you 
>> talk more about the regressions you're seeing?
> 
> I spent most of my time earlier in the summer looking at the 3 
> regressions I originally saw last fall.  Unfortunately I could get no 
> traction at all on the 2 FSA-related ones.  :-(  For the 
> gcc.dg/tree-ssa/ssa-dce-3.c regression, I tracked it down to some code 
> in the cddce1 pass being sensitive to the ordering of basic blocks in 
> the input code;  I filed PR96487 for that.
> 
> I was also having a bunch of problems with -Wimplicit-fallthrough 
> failures triggered by the C++ front end loop expansion sometimes 
> flipping the sense of the end test conditional (through the use of 
> fold_build3_loc to build it).  It seemed to me that the code that 
> handles COND_EXPRs for those warnings is sensitive to the order of 
> blocks as well, and has asymmetric assumptions that the code for the 
> "if" branch is emitted inline before the "else" branch.  I tried some 
> experiments with generalizing it to recognize the branches in either 
> order, but that did not fix the regressions, so maybe the problem was 
> somewhere else entirely, or a combination of two different bugs.  :-(
> 
> Anyway it seemed to me that the patches would not be accepted if I 
> resubmitted them in a form that still caused regressions, and switching 
> back to the C way of expanding to GOTO form directly instead of via 
> LOOP_EXPR did that.

We discussed this in a team meeting the other day, and agreed that it's 
probably simpler to switch back to gotos for C++ than fix up all the 
optimizers.  And that there probably isn't much benefit to the 
middle-end to retain the higher level representation longer.

Though the patch needed to the Fortran compiler sounds like a regression 
from this change.  Has someone looked at where that's coming from?

Have you done any benchmark comparison for C++ tests with this change? 
If not, please plan to monitor the lnt.opensuse.org benchmark results 
for impact after the change is committed.

The C++ changes are OK.  A C maintainer will need to sign off on the 
changes there.

Jason


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH V2 0/4] Unify C and C++ handling of loops and switches
  2020-09-17 14:32     ` Jason Merrill
@ 2020-09-17 22:51       ` Joseph Myers
  2020-09-17 22:57       ` Jeff Law
  2020-09-18  2:14       ` Sandra Loosemore
  2 siblings, 0 replies; 16+ messages in thread
From: Joseph Myers @ 2020-09-17 22:51 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Sandra Loosemore, gcc-patches

On Thu, 17 Sep 2020, Jason Merrill via Gcc-patches wrote:

> The C++ changes are OK.  A C maintainer will need to sign off on the changes
> there.

The C front-end changes are OK.

Note: for a long time there used to be actual (undesired) semantic 
differences between the C and C++ loop handling, but that was fixed with a 
testcase added (see bug 44715), so I'm not expecting this patch to change 
C semantics at all.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH V2 0/4] Unify C and C++ handling of loops and switches
  2020-09-17 14:32     ` Jason Merrill
  2020-09-17 22:51       ` Joseph Myers
@ 2020-09-17 22:57       ` Jeff Law
  2020-09-18  2:14       ` Sandra Loosemore
  2 siblings, 0 replies; 16+ messages in thread
From: Jeff Law @ 2020-09-17 22:57 UTC (permalink / raw)
  To: Jason Merrill, Sandra Loosemore, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2528 bytes --]


On 9/17/20 8:32 AM, Jason Merrill wrote:
> On 9/9/20 8:20 PM, Sandra Loosemore wrote:
>> On 9/9/20 3:13 PM, Jason Merrill wrote:
>>>
>>> My impression from Jeff's analysis in January and David's in March
>>> was that many of the testsuite changes were from the C++ approach
>>> actually providing better results, so the reversal here surprises
>>> me.  Can you talk more about the regressions you're seeing?
>>
>> I spent most of my time earlier in the summer looking at the 3
>> regressions I originally saw last fall.  Unfortunately I could get no
>> traction at all on the 2 FSA-related ones.  :-(  For the
>> gcc.dg/tree-ssa/ssa-dce-3.c regression, I tracked it down to some
>> code in the cddce1 pass being sensitive to the ordering of basic
>> blocks in the input code;  I filed PR96487 for that.
>>
>> I was also having a bunch of problems with -Wimplicit-fallthrough
>> failures triggered by the C++ front end loop expansion sometimes
>> flipping the sense of the end test conditional (through the use of
>> fold_build3_loc to build it).  It seemed to me that the code that
>> handles COND_EXPRs for those warnings is sensitive to the order of
>> blocks as well, and has asymmetric assumptions that the code for the
>> "if" branch is emitted inline before the "else" branch.  I tried some
>> experiments with generalizing it to recognize the branches in either
>> order, but that did not fix the regressions, so maybe the problem was
>> somewhere else entirely, or a combination of two different bugs.  :-(
>>
>> Anyway it seemed to me that the patches would not be accepted if I
>> resubmitted them in a form that still caused regressions, and
>> switching back to the C way of expanding to GOTO form directly
>> instead of via LOOP_EXPR did that.
>
> We discussed this in a team meeting the other day, and agreed that
> it's probably simpler to switch back to gotos for C++ than fix up all
> the optimizers.  And that there probably isn't much benefit to the
> middle-end to retain the higher level representation longer.

Right.  I would expect all of Richi's work through the years in loop
discovery and canonicalization to eliminate most, if not all, of the
benefit of LOOP_EXPR.  Ultimately I think we just pick one style and use
it in both places.    So I'm not going to object to this patch.



> The C++ changes are OK.  A C maintainer will need to sign off on the
> changes there.

And Joseph just signed off on the C bits.



>
> Jason
>

[-- Attachment #2: pEpkey.asc --]
[-- Type: application/pgp-keys, Size: 1763 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH V2 0/4] Unify C and C++ handling of loops and switches
  2020-09-17 14:32     ` Jason Merrill
  2020-09-17 22:51       ` Joseph Myers
  2020-09-17 22:57       ` Jeff Law
@ 2020-09-18  2:14       ` Sandra Loosemore
  2 siblings, 0 replies; 16+ messages in thread
From: Sandra Loosemore @ 2020-09-18  2:14 UTC (permalink / raw)
  To: Jason Merrill, gcc-patches

On 9/17/20 8:32 AM, Jason Merrill wrote:

> We discussed this in a team meeting the other day, and agreed that it's 
> probably simpler to switch back to gotos for C++ than fix up all the 
> optimizers.  And that there probably isn't much benefit to the 
> middle-end to retain the higher level representation longer.

When I looked into the history of the C++ change to use LOOP_EXPR, it 
seemed the primary motivation was to allow the constexpr evaluator to 
recognize loops and the optimization benefits were only lightly tested. 
But now the constexpr evaluator doesn't need LOOP_EXPR, and meanwhile I 
think the loop infrastructure and loop optimization test cases have been 
tuned for the C-style output.

> Though the patch needed to the Fortran compiler sounds like a regression 
> from this change.  Has someone looked at where that's coming from?

I tried, but wasn't able to come up with a self-contained test case 
small enough that I could actually analyze what it was doing, but that 
still triggered the warning.  In fact I am still unsure whether it is a 
bug that we weren't diagnosing that warning before, rather than that it 
showed up now.  :-S  As a programmer looking at that code, I thought the 
warning was justifiable, at least.

> Have you done any benchmark comparison for C++ tests with this change? 
> If not, please plan to monitor the lnt.opensuse.org benchmark results 
> for impact after the change is committed.

I haven't done any benchmarking myself, but yes, I will keep an eye on 
those benchmark results.

> The C++ changes are OK.  A C maintainer will need to sign off on the 
> changes there.

Thanks for the review!

-Sandra

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2020-09-18  2:14 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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 ` [PATCH V2 1/4] Move loop and switch tree data structures from cp/ to c-family/ Sandra Loosemore
2020-08-13 16:34 ` [PATCH V2 2/4] Use C-style loop lowering instead of C++-style Sandra Loosemore
2020-08-13 16:34 ` [PATCH V2 3/4] Work around bootstrap failure in Fortran front end Sandra Loosemore
     [not found]   ` <7d3fbcd3-759b-10bc-d620-83de53e027fd@moene.org>
2020-08-15 18:24     ` Fwd: " Thomas Koenig
2020-08-13 16:34 ` [PATCH V2 4/4] Change C front end to emit structured loop and switch tree nodes 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 17:38   ` [PING^2] " Sandra Loosemore
2020-09-09 21:13 ` Jason Merrill
2020-09-10  0:20   ` Sandra Loosemore
2020-09-17 14:32     ` Jason Merrill
2020-09-17 22:51       ` Joseph Myers
2020-09-17 22:57       ` Jeff Law
2020-09-18  2:14       ` Sandra Loosemore
2020-09-10 13:36   ` David Malcolm
2020-09-10 16:06     ` Sandra Loosemore

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).