This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
break in statement expression in while condition fails to compile
- From: Prathamesh Kulkarni <bilbotheelffriend at gmail dot com>
- To: gcc at gcc dot gnu dot org
- Date: Tue, 10 Dec 2013 18:51:19 +0530
- Subject: break in statement expression in while condition fails to compile
- Authentication-results: sourceware.org; auth=none
The following code fails to compile with gcc-4.8.2.
int main(void)
{
while ( ({ break; 0; }) )
;
return 0;
}
foo.c:3:14: error: break statement not within loop or switch
while ( ({ break; 0; }) )
^
Is this a compile-error or is it a bug in GCC ?
clang-3.2 seems to compile it.
I came across a thread on this issue
in context of for loop, but I couldn't get a definite answer.
http://gcc.gnu.org/ml/gcc-help/2013-07/msg00100.html
I think the reason above code fails to compile is because,
c_break_label has value zero_size_node instead of NULL_TREE
when c_finish_bc_stmt() gets called.
static void
c_parser_while_statement (c_parser *parser)
{
tree block, cond, body, save_break, save_cont;
location_t loc;
gcc_assert (c_parser_next_token_is_
keyword (parser, RID_WHILE));
c_parser_consume_token (parser);
block = c_begin_compound_stmt (flag_isoc99);
loc = c_parser_peek_token (parser)->location;
cond = c_parser_paren_condition (parser);
save_break = c_break_label;
c_break_label = NULL_TREE;
save_cont = c_cont_label;
c_cont_label = NULL_TREE;
body = c_parser_c99_block_statement (parser);
c_finish_loop (loc, cond, NULL, body, c_break_label, c_cont_label, true);
add_stmt (c_end_compound_stmt (loc, block, flag_isoc99));
c_break_label = save_break;
c_cont_label = save_cont;
}
c_parser_paren_condition() is called *before* assigning
c_break_label and c_cont_label to NULL_TREE
cond = c_parser_paren_condition (parser);
save_break = c_break_label;
c_break_label = NULL_TREE;
save_cont = c_cont_label;
c_cont_label = NULL_TREE;
Instead if c_parser_paren_condition(parser) is placed
*after* setting c_break_label and c_cont_label to NULL_TREE, the above
code compiles correctly (i changed the order and built cc1 and the
above test-case compiled without error):
save_break = c_break_label;
c_break_label = NULL_TREE;
save_cont = c_cont_label;
c_cont_label = NULL_TREE;
cond = c_parser_paren_condition (parser);
I guess that's because of the following if-else sequence
in c_bc_finish_stmt(loc, label_p, is_break):
tree c_finish_bc_stmt(location_t loc, tree *label_p, bool is_break)
{
label = *label_p;
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)
printf("2nd time here\n");
else switch (TREE_INT_CST_LOW (label))
{
case 0:
if (is_break)
error_at (loc, "break statement not within loop or switch");
}
// rest of function
}
This function gets called from here (in c-parser.c):
case RID_BREAK:
c_parser_consume_token (parser);
stmt = c_finish_bc_stmt (loc, &c_break_label, true);
goto expect_semicolon;
Initially c_break_label (and c_cont_label) are set to
zero_size_node in c-decl.c in start_function()
c_break_label = c_cont_label = size_zero_node;
where size_zero_node is non-null.
so the control enters else switch() branch,
and the error "break statement not within loop or switch" gets printed.
Instead if c_parse_paren_condition() is called
after setting c_break_label (and c_cont_label) to NULL_TREE,
then control shall enter the if (!label) {} branch.
Thanks and Regards,
Prathamesh