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