Change C front end to emit structured loop and switch tree nodes.
authorSandra Loosemore <sandra@codesourcery.com>
Sat, 19 Sep 2020 14:32:35 +0000 (07:32 -0700)
committerSandra Loosemore <sandra@codesourcery.com>
Sat, 19 Sep 2020 20:54:16 +0000 (13:54 -0700)
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
gcc/c/c-lang.h
gcc/c/c-objc-common.h
gcc/c/c-parser.c
gcc/c/c-tree.h
gcc/c/c-typeck.c
gcc/objc/objc-act.c
gcc/testsuite/gcc.dg/gomp/block-7.c

index 190c00bd435e8e221912cf9c1b1a80855887418b..8204db2a16ea5febe398ce2435c4744d0826ef16 100644 (file)
@@ -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;
@@ -9163,10 +9163,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);
@@ -10167,8 +10165,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;
@@ -10207,8 +10204,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;
index 6d377cde8f4c6414027a385ea9f4d9365bdde15b..7e9a276f86158d3d66ada7c04579679800f78ae7 100644 (file)
@@ -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;
index 925795986e785366fe5ee610c4dd1ce0e249e15e..76f9db7cc552a8970c0b6963a2d488f257ba6b74 100644 (file)
@@ -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
index a8bc301ffadf4ef566b0b6653555be4df65d4a55..2e6775aefe74d5c356c4c0472856408b2ad353d7 100644 (file)
@@ -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
@@ -18038,7 +18037,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;
@@ -18106,6 +18106,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;
@@ -18279,10 +18284,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)
@@ -18296,16 +18298,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)
     {
index 10938cf08570137cb210838f3c90827032253b3b..7e51859b7e09ec6a2a8a96be713126981a0d1414 100644 (file)
@@ -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 *);
index bb27099bfe1ccf51ec8b03d73a008e6b22e70809..dd3e30958aca1607151543d4456e3e71f4dc837f 100644 (file)
@@ -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.  */
index 54af1cff53365ace2856fbf4f5f5b900d2766aeb..31a2cf3753fb34a72d35cdbf5dd7f753e8f91659 100644 (file)
@@ -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)
index 6219e7e46622376c06a91d2415ac3d16b85d9824..3e8746406be028cb35a9cbe418f9fd9b21915719 100644 (file)
@@ -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" }
     }
 }