From 827e5af19a214323c70ee5879dc8f14f4f44ad8d 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 | 3 ++ gcc/testsuite/gcc.misc-tests/gcov-pr94029.c | 14 ++++++ 6 files changed, 64 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 1c3ca1b47096..4ff242de551c 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,6 +1,20 @@ 2020-04-07 Jakub Jelinek Backported from mainline + 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 350e08e22c2e..caa2b75ac6d5 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -9597,7 +9597,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; @@ -9693,7 +9693,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 aafe8d1740bc..5ffa61935a4f 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1402,8 +1402,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 *, @@ -1498,8 +1498,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). @@ -2323,12 +2322,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 @@ -2337,7 +2337,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 @@ -2349,9 +2349,11 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, c_parser_parse_gimple_body (parser, specs->gimple_or_rtl_pass, specs->declspec_il); 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) { @@ -2362,7 +2364,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)); } @@ -2370,7 +2372,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) @@ -4965,7 +4967,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; @@ -4979,7 +4981,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); } @@ -4988,7 +4992,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; @@ -4997,9 +5001,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)) @@ -5040,8 +5045,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)) { @@ -5122,7 +5128,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)) { @@ -5130,7 +5136,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 { @@ -5152,9 +5158,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. */ @@ -19920,13 +19928,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; @@ -19948,7 +19956,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; } @@ -19966,7 +19974,7 @@ 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; } /* If a pass name was provided for START_WITH_PASS, run the backend @@ -19974,6 +19982,7 @@ c_parser_parse_rtl_body (c_parser *parser, char *start_with_pass) ownership of START_WITH_PASS. */ if (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 147a7e867aae..4642d6824526 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -562,7 +562,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, struct c_struct_parse_info *); extern struct c_arg_info *build_arg_info (void); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 7b15ef6a9382..650b86833876 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -3,6 +3,9 @@ Backported from mainline 2020-03-19 Jakub Jelinek + PR gcov-profile/94029 + * gcc.misc-tests/gcov-pr94029.c: New test. + PR tree-optimization/94211 * gcc.dg/pr94211.c: New test. 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 000000000000..84d9b9b2749a --- /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.47.2