From 9def91e9f2a7051c9c146f16c1a10d1b25d33b47 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 19 Mar 2020 22:56:20 +0100 Subject: [PATCH] c: Fix up cfun->function_end_locus from the C FE [PR94029] On the following testcase we ICE because while DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus = c_parser_peek_token (parser)->location; and similarly DECL_SOURCE_LOCATION (fndecl) is set from some token's location, the end is set as: /* Store the end of the function, so that we get good line number info for the epilogue. */ cfun->function_end_locus = input_location; and the thing is that input_location is only very rarely set in the C FE (the primary spot that changes it is the cb_line_change/fe_file_change). Which means, e.g. for pretty much all C functions that are on a single line, function_start_locus column is > than function_end_locus column, and the testcase even has smaller line in function_end_locus because cb_line_change isn't performed while parsing multi-line arguments of a function-like macro. Attached are two possible fixes to achieve what the C++ FE does, in particular that cfun->function_end_locus is the locus of the closing } of the function. The first one updates input_location when we see a closing } of a compound statement (though any, not just the function body) and thus input_location in the finish_function call is what we need. The second instead propagates the location_t from the parsing of the outermost compound statement (the function body) to finish_function. The second one is this version. 2020-03-19 Jakub Jelinek PR gcov-profile/94029 * c-tree.h (finish_function): Add location_t argument defaulted to input_location. * c-parser.c (c_parser_compound_statement): Add endlocp argument and set it to the locus of closing } if non-NULL. (c_parser_compound_statement_nostart): Return locus of closing }. (c_parser_parse_rtl_body): Likewise. (c_parser_declaration_or_fndef): Propagate locus of closing } to finish_function. * c-decl.c (finish_function): Add end_loc argument, use it instead of input_location to set function_end_locus. * gcc.misc-tests/gcov-pr94029.c: New test. --- gcc/c/ChangeLog | 14 ++++++ gcc/c/c-decl.c | 4 +- gcc/c/c-parser.c | 51 ++++++++++++--------- gcc/c/c-tree.h | 2 +- gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/gcc.misc-tests/gcov-pr94029.c | 14 ++++++ 6 files changed, 66 insertions(+), 24 deletions(-) create mode 100644 gcc/testsuite/gcc.misc-tests/gcov-pr94029.c diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 25f8f5b6b7b..c0b65a5b91d 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,17 @@ +2020-03-19 Jakub Jelinek + + PR gcov-profile/94029 + * c-tree.h (finish_function): Add location_t argument defaulted to + input_location. + * c-parser.c (c_parser_compound_statement): Add endlocp argument and + set it to the locus of closing } if non-NULL. + (c_parser_compound_statement_nostart): Return locus of closing }. + (c_parser_parse_rtl_body): Likewise. + (c_parser_declaration_or_fndef): Propagate locus of closing } to + finish_function. + * c-decl.c (finish_function): Add end_loc argument, use it instead of + input_location to set function_end_locus. + 2020-03-17 Jakub Jelinek PR c/94172 diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index ed5163dd465..80fe3186759 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -9851,7 +9851,7 @@ temp_pop_parm_decls (void) This is called after parsing the body of the function definition. */ void -finish_function (void) +finish_function (location_t end_loc) { tree fndecl = current_function_decl; @@ -9947,7 +9947,7 @@ finish_function (void) /* Store the end of the function, so that we get good line number info for the epilogue. */ - cfun->function_end_locus = input_location; + cfun->function_end_locus = end_loc; /* Finalize the ELF visibility for the function. */ c_determine_visibility (fndecl); diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 1e8f2f7108d..4b068a938fb 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1487,8 +1487,8 @@ static struct c_expr c_parser_braced_init (c_parser *, tree, bool, static void c_parser_initelt (c_parser *, struct obstack *); static void c_parser_initval (c_parser *, struct c_expr *, struct obstack *); -static tree c_parser_compound_statement (c_parser *); -static void c_parser_compound_statement_nostart (c_parser *); +static tree c_parser_compound_statement (c_parser *, location_t * = NULL); +static location_t c_parser_compound_statement_nostart (c_parser *); static void c_parser_label (c_parser *); static void c_parser_statement (c_parser *, bool *, location_t * = NULL); static void c_parser_statement_after_labels (c_parser *, bool *, @@ -1583,8 +1583,7 @@ static void c_parser_objc_at_synthesize_declaration (c_parser *); static void c_parser_objc_at_dynamic_declaration (c_parser *); static bool c_parser_objc_diagnose_bad_element_prefix (c_parser *, struct c_declspecs *); - -static void c_parser_parse_rtl_body (c_parser *parser, char *start_with_pass); +static location_t c_parser_parse_rtl_body (c_parser *, char *); /* Parse a translation unit (C90 6.7, C99 6.9, C11 6.9). @@ -2472,12 +2471,13 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, c_finish_oacc_routine (oacc_routine_data, current_function_decl, true); DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus = c_parser_peek_token (parser)->location; + location_t endloc; /* If the definition was marked with __RTL, use the RTL parser now, consuming the function body. */ if (specs->declspec_il == cdil_rtl) { - c_parser_parse_rtl_body (parser, specs->gimple_or_rtl_pass); + endloc = c_parser_parse_rtl_body (parser, specs->gimple_or_rtl_pass); /* Normally, store_parm_decls sets next_is_function_body, anticipating a function body. We need a push_scope/pop_scope @@ -2486,7 +2486,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, push_scope (); pop_scope (); - finish_function (); + finish_function (endloc); return; } /* If the definition was marked with __GIMPLE then parse the @@ -2499,9 +2499,11 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, specs->declspec_il, specs->entry_bb_count); in_late_binary_op = saved; + struct function *fun = DECL_STRUCT_FUNCTION (current_function_decl); + endloc = fun->function_start_locus; } else - fnbody = c_parser_compound_statement (parser); + fnbody = c_parser_compound_statement (parser, &endloc); tree fndecl = current_function_decl; if (nested) { @@ -2512,7 +2514,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, by initializer_constant_valid_p. See gcc.dg/nested-fn-2.c. */ DECL_STATIC_CHAIN (decl) = 1; add_stmt (fnbody); - finish_function (); + finish_function (endloc); c_pop_function_context (); add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl)); } @@ -2520,7 +2522,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, { if (fnbody) add_stmt (fnbody); - finish_function (); + finish_function (endloc); } /* Get rid of the empty stmt list for GIMPLE/RTL. */ if (specs->declspec_il != cdil_none) @@ -5599,7 +5601,7 @@ c_parser_initval (c_parser *parser, struct c_expr *after, cancellation-point-directive */ static tree -c_parser_compound_statement (c_parser *parser) +c_parser_compound_statement (c_parser *parser, location_t *endlocp) { tree stmt; location_t brace_loc; @@ -5613,7 +5615,9 @@ c_parser_compound_statement (c_parser *parser) return error_mark_node; } stmt = c_begin_compound_stmt (true); - c_parser_compound_statement_nostart (parser); + location_t end_loc = c_parser_compound_statement_nostart (parser); + if (endlocp) + *endlocp = end_loc; return c_end_compound_stmt (brace_loc, stmt, true); } @@ -5622,7 +5626,7 @@ c_parser_compound_statement (c_parser *parser) used for parsing both compound statements and statement expressions (which follow different paths to handling the opening). */ -static void +static location_t c_parser_compound_statement_nostart (c_parser *parser) { bool last_stmt = false; @@ -5631,9 +5635,10 @@ c_parser_compound_statement_nostart (c_parser *parser) location_t label_loc = UNKNOWN_LOCATION; /* Quiet warning. */ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) { - add_debug_begin_stmt (c_parser_peek_token (parser)->location); + location_t endloc = c_parser_peek_token (parser)->location; + add_debug_begin_stmt (endloc); c_parser_consume_token (parser); - return; + return endloc; } mark_valid_location_for_stdc_pragma (true); if (c_parser_next_token_is_keyword (parser, RID_LABEL)) @@ -5674,8 +5679,9 @@ c_parser_compound_statement_nostart (c_parser *parser) { mark_valid_location_for_stdc_pragma (save_valid_for_pragma); c_parser_error (parser, "expected declaration or statement"); + location_t endloc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); - return; + return endloc; } while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE)) { @@ -5773,7 +5779,7 @@ c_parser_compound_statement_nostart (c_parser *parser) { mark_valid_location_for_stdc_pragma (save_valid_for_pragma); c_parser_error (parser, "expected declaration or statement"); - return; + return c_parser_peek_token (parser)->location; } else if (c_parser_next_token_is_keyword (parser, RID_ELSE)) { @@ -5781,7 +5787,7 @@ c_parser_compound_statement_nostart (c_parser *parser) { mark_valid_location_for_stdc_pragma (save_valid_for_pragma); error_at (loc, "expected %<}%> before %"); - return; + return c_parser_peek_token (parser)->location; } else { @@ -5804,9 +5810,11 @@ c_parser_compound_statement_nostart (c_parser *parser) } if (last_label) error_at (label_loc, "label at end of compound statement"); + location_t endloc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); /* Restore the value we started with. */ mark_valid_location_for_stdc_pragma (save_valid_for_pragma); + return endloc; } /* Parse all consecutive labels, possibly preceded by standard @@ -21725,13 +21733,13 @@ c_parse_file (void) Take ownership of START_WITH_PASS, if non-NULL. */ -void +location_t c_parser_parse_rtl_body (c_parser *parser, char *start_with_pass) { if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) { free (start_with_pass); - return; + return c_parser_peek_token (parser)->location; } location_t start_loc = c_parser_peek_token (parser)->location; @@ -21753,7 +21761,7 @@ c_parser_parse_rtl_body (c_parser *parser, char *start_with_pass) case CPP_EOF: error_at (start_loc, "no closing brace"); free (start_with_pass); - return; + return c_parser_peek_token (parser)->location; default: break; } @@ -21771,12 +21779,13 @@ c_parser_parse_rtl_body (c_parser *parser, char *start_with_pass) if (!read_rtl_function_body_from_file_range (start_loc, end_loc)) { free (start_with_pass); - return; + return end_loc; } /* Run the backend on the cfun created above, transferring ownership of START_WITH_PASS. */ run_rtl_passes (start_with_pass); + return end_loc; } #include "gt-c-c-parser.h" diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 364d7e03398..2015827dbb1 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -580,7 +580,7 @@ extern bool c_check_switch_jump_warnings (struct c_spot_bindings *, location_t, location_t); extern void finish_decl (tree, location_t, tree, tree, tree); extern tree finish_enum (tree, tree, tree); -extern void finish_function (void); +extern void finish_function (location_t = input_location); extern tree finish_struct (location_t, tree, tree, tree, class c_struct_parse_info *); extern tree c_simulate_enum_decl (location_t, const char *, diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index cce16031845..bde605d2b2f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2020-03-19 Jakub Jelinek + + PR gcov-profile/94029 + * gcc.misc-tests/gcov-pr94029.c: New test. + 2020-03-19 Jan Hubicka PR ipa/92372 diff --git a/gcc/testsuite/gcc.misc-tests/gcov-pr94029.c b/gcc/testsuite/gcc.misc-tests/gcov-pr94029.c new file mode 100644 index 00000000000..84d9b9b2749 --- /dev/null +++ b/gcc/testsuite/gcc.misc-tests/gcov-pr94029.c @@ -0,0 +1,14 @@ +/* PR gcov-profile/94029 */ +/* { dg-options "-ftest-coverage" } */ +/* { dg-do compile } */ + +#define impl_test(name) void test_##name() { } +impl_test(t1 +) impl_test(t2) + +int main() +{ + return 0; +} + +/* { dg-final { run-gcov remove-gcda gcov-pr94029.c } } */ -- 2.30.2