After parsing an unconditional "while"- or "for"-loop, the C front-end generates a backward-goto statement and implicitly sets its location to the current input_location. But in some cases the parser peeks ahead first, such that input_location already points to the line after the loop and the generated backward-goto gets the wrong line number.
One way this can occur is with a loop body consisting of an "if" statement, because then the parser peeks for an optional "else" before finishing the loop. Another way occurs since r223098 ("Implement -Wmisleading-indentation"), even with a loop body enclosed in braces. This is because the check for misleading indentation always peeks ahead one token as well. This patch adds a new parameter to c_finish_loop that expclitly specifies the location to be used for the loop iteration. All calls to c_finish_loop are adjusted accordingly. gcc/c/ChangeLog: PR debug/67192 * c-typeck.c (c_finish_loop): Replace implicit use of input_location by new parameter iter_locus. * c-tree.h (c_finish_loop): Adjust prototype. * c-array-notation.c (fix_builtin_array_notation_fn): Explicitly pass input_location as the new parameter to c_finish_loop. (build_array_notation_expr): Likewise. (fix_conditional_array_notations_1): Likewise. (fix_array_notation_expr): Likewise. (fix_array_notation_call_expr): Likewise. * c-parser.c (c_parser_while_statement): Choose iter_locus depending on whether the loop body is enclosed in braces, and pass it to c_finish_loop. (c_parser_for_statement): Likewise. (c_parser_do_statement): Use the final semicolon's location for iter_locus and pass it to c_finish_loop. gcc/testsuite/ChangeLog: PR debug/67192 * gcc.dg/guality/pr67192.c: New test. --- gcc/c/c-array-notation.c | 15 ++++--- gcc/c/c-parser.c | 13 ++++-- gcc/c/c-tree.h | 2 +- gcc/c/c-typeck.c | 17 +++++--- gcc/testsuite/gcc.dg/guality/pr67192.c | 79 ++++++++++++++++++++++++++++++++++ 5 files changed, 109 insertions(+), 17 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/guality/pr67192.c diff --git a/gcc/c/c-array-notation.c b/gcc/c/c-array-notation.c index 3de7569..c457eee2 100644 --- a/gcc/c/c-array-notation.c +++ b/gcc/c/c-array-notation.c @@ -591,7 +591,8 @@ fix_builtin_array_notation_fn (tree an_builtin_fn, tree *new_var) for (ii = 0; ii < rank; ii++) { tree new_loop = push_stmt_list (); - c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr, + c_finish_loop (location, input_location, an_loop_info[ii].cmp, + an_loop_info[ii].incr, body, NULL_TREE, NULL_TREE, true); body = pop_stmt_list (new_loop); } @@ -879,8 +880,8 @@ build_array_notation_expr (location_t location, tree lhs, tree lhs_origtype, append_to_statement_list_force (lhs_an_loop_info[ii].incr, &incr_list); if (rhs_rank && rhs_an_loop_info[ii].incr) append_to_statement_list_force (rhs_an_loop_info[ii].incr, &incr_list); - c_finish_loop (location, cond_expr[ii], incr_list, body, NULL_TREE, - NULL_TREE, true); + c_finish_loop (location, input_location, cond_expr[ii], + incr_list, body, NULL_TREE, NULL_TREE, true); body = pop_stmt_list (new_loop); } append_to_statement_list_force (body, &loop_with_init); @@ -1004,7 +1005,8 @@ fix_conditional_array_notations_1 (tree stmt) { tree new_loop = push_stmt_list (); add_stmt (an_loop_info[ii].ind_init); - c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr, + c_finish_loop (location, input_location, an_loop_info[ii].cmp, + an_loop_info[ii].incr, body, NULL_TREE, NULL_TREE, true); body = pop_stmt_list (new_loop); } @@ -1107,7 +1109,7 @@ fix_array_notation_expr (location_t location, enum tree_code code, { tree new_loop = push_stmt_list (); add_stmt (an_loop_info[ii].ind_init); - c_finish_loop (location, an_loop_info[ii].cmp, + c_finish_loop (location, input_location, an_loop_info[ii].cmp, an_loop_info[ii].incr, body, NULL_TREE, NULL_TREE, true); body = pop_stmt_list (new_loop); @@ -1193,7 +1195,8 @@ fix_array_notation_call_expr (tree arg) { tree new_loop = push_stmt_list (); add_stmt (an_loop_info[ii].ind_init); - c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr, + c_finish_loop (location, input_location, an_loop_info[ii].cmp, + an_loop_info[ii].incr, body, NULL_TREE, NULL_TREE, true); body = pop_stmt_list (new_loop); } diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 704ebc6..69e0a9c 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -5438,13 +5438,16 @@ c_parser_while_statement (c_parser *parser, bool ivdep) token_indent_info body_tinfo = get_token_indent_info (c_parser_peek_token (parser)); + bool is_braced = c_parser_next_token_is (parser, CPP_OPEN_BRACE); body = c_parser_c99_block_statement (parser); + location_t iter_loc = is_braced ? input_location : loc; token_indent_info next_tinfo = get_token_indent_info (c_parser_peek_token (parser)); warn_for_misleading_indentation (while_tinfo, body_tinfo, next_tinfo); - c_finish_loop (loc, cond, NULL, body, c_break_label, c_cont_label, true); + c_finish_loop (loc, iter_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; @@ -5490,7 +5493,8 @@ c_parser_do_statement (c_parser *parser, bool ivdep) annot_expr_ivdep_kind)); if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) c_parser_skip_to_end_of_block_or_statement (parser); - c_finish_loop (loc, cond, NULL, body, new_break, new_cont, false); + c_finish_loop (loc, input_location, cond, NULL, body, new_break, + new_cont, false); add_stmt (c_end_compound_stmt (loc, block, flag_isoc99)); } @@ -5727,7 +5731,9 @@ c_parser_for_statement (c_parser *parser, bool ivdep) token_indent_info body_tinfo = get_token_indent_info (c_parser_peek_token (parser)); + bool is_braced = c_parser_next_token_is (parser, CPP_OPEN_BRACE); body = c_parser_c99_block_statement (parser); + location_t iter_loc = is_braced ? input_location : loc; token_indent_info next_tinfo = get_token_indent_info (c_parser_peek_token (parser)); @@ -5736,7 +5742,8 @@ c_parser_for_statement (c_parser *parser, bool ivdep) if (is_foreach_statement) objc_finish_foreach_loop (loc, object_expression, collection_expression, body, c_break_label, c_cont_label); else - c_finish_loop (loc, cond, incr, body, c_break_label, c_cont_label, true); + c_finish_loop (loc, iter_loc, cond, incr, body, c_break_label, + c_cont_label, true); add_stmt (c_end_compound_stmt (loc, block, flag_isoc99 || c_dialect_objc ())); c_break_label = save_break; c_cont_label = save_cont; diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index bee03d3..9c13672 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -630,7 +630,7 @@ extern int c_types_compatible_p (tree, tree); extern tree c_begin_compound_stmt (bool); extern tree c_end_compound_stmt (location_t, tree, bool); extern void c_finish_if_stmt (location_t, tree, tree, tree, bool); -extern void c_finish_loop (location_t, tree, tree, tree, tree, tree, bool); +extern void c_finish_loop (location_t, location_t, tree, tree, tree, tree, tree, bool); extern tree c_begin_stmt_expr (void); extern tree c_finish_stmt_expr (location_t, tree); extern tree c_process_expr_stmt (location_t, tree); diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index bc43602..e4b5471 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -9810,14 +9810,16 @@ 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. */ +/* Emit a general-purpose loop construct. START_LOCUS is the location + of the beginning of the loop. ITER_LOCUS is the location of the + loop iteration. 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. */ void -c_finish_loop (location_t start_locus, tree cond, tree incr, tree body, +c_finish_loop (location_t start_locus, location_t iter_locus, + tree cond, tree incr, tree body, tree blab, tree clab, bool cond_is_first) { tree entry = NULL, exit = NULL, t; @@ -9843,6 +9845,7 @@ c_finish_loop (location_t start_locus, tree cond, tree incr, tree body, 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)); + SET_EXPR_LOCATION (exit, iter_locus); if (cond && !integer_nonzerop (cond)) { @@ -9867,7 +9870,7 @@ c_finish_loop (location_t start_locus, tree cond, tree incr, tree body, exit = fold_build3_loc (start_locus, COND_EXPR, void_type_node, cond, exit, t); else - exit = fold_build3_loc (input_location, + exit = fold_build3_loc (iter_locus, COND_EXPR, void_type_node, cond, exit, t); } diff --git a/gcc/testsuite/gcc.dg/guality/pr67192.c b/gcc/testsuite/gcc.dg/guality/pr67192.c new file mode 100644 index 0000000..faef853 --- /dev/null +++ b/gcc/testsuite/gcc.dg/guality/pr67192.c @@ -0,0 +1,79 @@ +/* PR debug/67192 */ +/* { dg-do run } */ +/* { dg-options "-g -Wmisleading-indentation" } */ + +volatile int cnt = 0; + +__attribute__((noinline, noclone)) static int +last (void) +{ + return ++cnt % 5 == 0; +} + +__attribute__((noinline, noclone)) static void +do_it (void) +{ + asm volatile ("" : : "r" (&cnt) : "memory"); +} + +__attribute__((noinline, noclone)) static void +f1 (void) +{ + for (;; do_it()) + if (last ()) + break; + do_it (); /* { dg-final { gdb-test 25 "cnt" "5" } } */ +} + +__attribute__((noinline, noclone)) static void +f2 (void) +{ + while (1) + if (last ()) + break; + else + do_it (); + do_it (); /* { dg-final { gdb-test 36 "cnt" "10" } } */ +} + +__attribute__((noinline, noclone)) static void +f3 (void) +{ + for (;; do_it()) + { + if (last ()) + break; + } + do_it (); /* { dg-final { gdb-test 47 "cnt" "15" } } */ +} + +__attribute__((noinline, noclone)) static void +f4 (void) +{ + while (1) + { + if (last ()) + break; + do_it (); + } + do_it (); /* { dg-final { gdb-test 59 "cnt" "20" } } */ +} + +void (*volatile fnp1) (void) = f1; +void (*volatile fnp2) (void) = f2; +void (*volatile fnp3) (void) = f3; +void (*volatile fnp4) (void) = f4; + +int +main () +{ + asm volatile ("" : : "r" (&fnp1) : "memory"); + asm volatile ("" : : "r" (&fnp2) : "memory"); + asm volatile ("" : : "r" (&fnp3) : "memory"); + asm volatile ("" : : "r" (&fnp4) : "memory"); + fnp1 (); + fnp2 (); + fnp3 (); + fnp4 (); + return 0; +} -- 2.3.0