From 3696a50beeb73f4ded8a584e76ee16f0bde109b9 Mon Sep 17 00:00:00 2001 From: Sandra Loosemore Date: Sat, 19 Sep 2020 07:32:35 -0700 Subject: [PATCH] Change C front end to emit structured loop and switch tree nodes. 2020-08-12 Sandra Loosemore 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/objc-act.c | 6 +- gcc/testsuite/gcc.dg/gomp/block-7.c | 12 +- 8 files changed, 164 insertions(+), 250 deletions(-) diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 190c00bd435..8204db2a16e 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; @@ -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; diff --git a/gcc/c/c-lang.h b/gcc/c/c-lang.h index 6d377cde8f4..7e9a276f861 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 925795986e7..76f9db7cc55 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 a8bc301ffad..2e6775aefe7 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 % 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 %"); - 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) { diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 10938cf0857..7e51859b7e0 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 bb27099bfe1..dd3e30958ac 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 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) } 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/objc-act.c b/gcc/objc/objc-act.c index 54af1cff533..31a2cf3753f 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 6219e7e4662..3e8746406be 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.30.2