This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

break in statement expression in while condition fails to compile


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]