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;
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);
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;
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;
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;
#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
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 *);
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);
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));
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);
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);
}
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
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));
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);
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).
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);
"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,
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));
}
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
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)
/* 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)
}
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));
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);
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
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;
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;
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)
}
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)
{
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);
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);
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 *);
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);
}
\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. */
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;
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;
}
}
- /* 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. */
}
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;
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;
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
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. */
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)
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" }
}
}