Commit 9def91e9 by Jakub Jelinek

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  <jakub@redhat.com>

	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.
parent 37482edc
2020-03-19 Jakub Jelinek <jakub@redhat.com>
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 <jakub@redhat.com> 2020-03-17 Jakub Jelinek <jakub@redhat.com>
PR c/94172 PR c/94172
......
...@@ -9851,7 +9851,7 @@ temp_pop_parm_decls (void) ...@@ -9851,7 +9851,7 @@ temp_pop_parm_decls (void)
This is called after parsing the body of the function definition. */ This is called after parsing the body of the function definition. */
void void
finish_function (void) finish_function (location_t end_loc)
{ {
tree fndecl = current_function_decl; tree fndecl = current_function_decl;
...@@ -9947,7 +9947,7 @@ finish_function (void) ...@@ -9947,7 +9947,7 @@ finish_function (void)
/* Store the end of the function, so that we get good line number /* Store the end of the function, so that we get good line number
info for the epilogue. */ info for the epilogue. */
cfun->function_end_locus = input_location; cfun->function_end_locus = end_loc;
/* Finalize the ELF visibility for the function. */ /* Finalize the ELF visibility for the function. */
c_determine_visibility (fndecl); c_determine_visibility (fndecl);
......
...@@ -1487,8 +1487,8 @@ static struct c_expr c_parser_braced_init (c_parser *, tree, bool, ...@@ -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_initelt (c_parser *, struct obstack *);
static void c_parser_initval (c_parser *, struct c_expr *, static void c_parser_initval (c_parser *, struct c_expr *,
struct obstack *); struct obstack *);
static tree c_parser_compound_statement (c_parser *); static tree c_parser_compound_statement (c_parser *, location_t * = NULL);
static void c_parser_compound_statement_nostart (c_parser *); static location_t c_parser_compound_statement_nostart (c_parser *);
static void c_parser_label (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 (c_parser *, bool *, location_t * = NULL);
static void c_parser_statement_after_labels (c_parser *, bool *, static void c_parser_statement_after_labels (c_parser *, bool *,
...@@ -1583,8 +1583,7 @@ static void c_parser_objc_at_synthesize_declaration (c_parser *); ...@@ -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 void c_parser_objc_at_dynamic_declaration (c_parser *);
static bool c_parser_objc_diagnose_bad_element_prefix static bool c_parser_objc_diagnose_bad_element_prefix
(c_parser *, struct c_declspecs *); (c_parser *, struct c_declspecs *);
static location_t c_parser_parse_rtl_body (c_parser *, char *);
static void c_parser_parse_rtl_body (c_parser *parser, char *start_with_pass);
/* Parse a translation unit (C90 6.7, C99 6.9, C11 6.9). /* 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, ...@@ -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); c_finish_oacc_routine (oacc_routine_data, current_function_decl, true);
DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
= c_parser_peek_token (parser)->location; = c_parser_peek_token (parser)->location;
location_t endloc;
/* If the definition was marked with __RTL, use the RTL parser now, /* If the definition was marked with __RTL, use the RTL parser now,
consuming the function body. */ consuming the function body. */
if (specs->declspec_il == cdil_rtl) 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, /* Normally, store_parm_decls sets next_is_function_body,
anticipating a function body. We need a push_scope/pop_scope 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, ...@@ -2486,7 +2486,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
push_scope (); push_scope ();
pop_scope (); pop_scope ();
finish_function (); finish_function (endloc);
return; return;
} }
/* If the definition was marked with __GIMPLE then parse the /* 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, ...@@ -2499,9 +2499,11 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
specs->declspec_il, specs->declspec_il,
specs->entry_bb_count); specs->entry_bb_count);
in_late_binary_op = saved; in_late_binary_op = saved;
struct function *fun = DECL_STRUCT_FUNCTION (current_function_decl);
endloc = fun->function_start_locus;
} }
else else
fnbody = c_parser_compound_statement (parser); fnbody = c_parser_compound_statement (parser, &endloc);
tree fndecl = current_function_decl; tree fndecl = current_function_decl;
if (nested) if (nested)
{ {
...@@ -2512,7 +2514,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, ...@@ -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. */ by initializer_constant_valid_p. See gcc.dg/nested-fn-2.c. */
DECL_STATIC_CHAIN (decl) = 1; DECL_STATIC_CHAIN (decl) = 1;
add_stmt (fnbody); add_stmt (fnbody);
finish_function (); finish_function (endloc);
c_pop_function_context (); c_pop_function_context ();
add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl)); 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, ...@@ -2520,7 +2522,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
{ {
if (fnbody) if (fnbody)
add_stmt (fnbody); add_stmt (fnbody);
finish_function (); finish_function (endloc);
} }
/* Get rid of the empty stmt list for GIMPLE/RTL. */ /* Get rid of the empty stmt list for GIMPLE/RTL. */
if (specs->declspec_il != cdil_none) if (specs->declspec_il != cdil_none)
...@@ -5599,7 +5601,7 @@ c_parser_initval (c_parser *parser, struct c_expr *after, ...@@ -5599,7 +5601,7 @@ c_parser_initval (c_parser *parser, struct c_expr *after,
cancellation-point-directive */ cancellation-point-directive */
static tree static tree
c_parser_compound_statement (c_parser *parser) c_parser_compound_statement (c_parser *parser, location_t *endlocp)
{ {
tree stmt; tree stmt;
location_t brace_loc; location_t brace_loc;
...@@ -5613,7 +5615,9 @@ c_parser_compound_statement (c_parser *parser) ...@@ -5613,7 +5615,9 @@ c_parser_compound_statement (c_parser *parser)
return error_mark_node; return error_mark_node;
} }
stmt = c_begin_compound_stmt (true); 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); return c_end_compound_stmt (brace_loc, stmt, true);
} }
...@@ -5622,7 +5626,7 @@ c_parser_compound_statement (c_parser *parser) ...@@ -5622,7 +5626,7 @@ c_parser_compound_statement (c_parser *parser)
used for parsing both compound statements and statement expressions used for parsing both compound statements and statement expressions
(which follow different paths to handling the opening). */ (which follow different paths to handling the opening). */
static void static location_t
c_parser_compound_statement_nostart (c_parser *parser) c_parser_compound_statement_nostart (c_parser *parser)
{ {
bool last_stmt = false; bool last_stmt = false;
...@@ -5631,9 +5635,10 @@ c_parser_compound_statement_nostart (c_parser *parser) ...@@ -5631,9 +5635,10 @@ c_parser_compound_statement_nostart (c_parser *parser)
location_t label_loc = UNKNOWN_LOCATION; /* Quiet warning. */ location_t label_loc = UNKNOWN_LOCATION; /* Quiet warning. */
if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) 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); c_parser_consume_token (parser);
return; return endloc;
} }
mark_valid_location_for_stdc_pragma (true); mark_valid_location_for_stdc_pragma (true);
if (c_parser_next_token_is_keyword (parser, RID_LABEL)) if (c_parser_next_token_is_keyword (parser, RID_LABEL))
...@@ -5674,8 +5679,9 @@ c_parser_compound_statement_nostart (c_parser *parser) ...@@ -5674,8 +5679,9 @@ c_parser_compound_statement_nostart (c_parser *parser)
{ {
mark_valid_location_for_stdc_pragma (save_valid_for_pragma); mark_valid_location_for_stdc_pragma (save_valid_for_pragma);
c_parser_error (parser, "expected declaration or statement"); c_parser_error (parser, "expected declaration or statement");
location_t endloc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser); c_parser_consume_token (parser);
return; return endloc;
} }
while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE)) while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE))
{ {
...@@ -5773,7 +5779,7 @@ c_parser_compound_statement_nostart (c_parser *parser) ...@@ -5773,7 +5779,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
{ {
mark_valid_location_for_stdc_pragma (save_valid_for_pragma); mark_valid_location_for_stdc_pragma (save_valid_for_pragma);
c_parser_error (parser, "expected declaration or statement"); 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)) else if (c_parser_next_token_is_keyword (parser, RID_ELSE))
{ {
...@@ -5781,7 +5787,7 @@ c_parser_compound_statement_nostart (c_parser *parser) ...@@ -5781,7 +5787,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
{ {
mark_valid_location_for_stdc_pragma (save_valid_for_pragma); mark_valid_location_for_stdc_pragma (save_valid_for_pragma);
error_at (loc, "expected %<}%> before %<else%>"); error_at (loc, "expected %<}%> before %<else%>");
return; return c_parser_peek_token (parser)->location;
} }
else else
{ {
...@@ -5804,9 +5810,11 @@ c_parser_compound_statement_nostart (c_parser *parser) ...@@ -5804,9 +5810,11 @@ c_parser_compound_statement_nostart (c_parser *parser)
} }
if (last_label) if (last_label)
error_at (label_loc, "label at end of compound statement"); error_at (label_loc, "label at end of compound statement");
location_t endloc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser); c_parser_consume_token (parser);
/* Restore the value we started with. */ /* Restore the value we started with. */
mark_valid_location_for_stdc_pragma (save_valid_for_pragma); mark_valid_location_for_stdc_pragma (save_valid_for_pragma);
return endloc;
} }
/* Parse all consecutive labels, possibly preceded by standard /* Parse all consecutive labels, possibly preceded by standard
...@@ -21725,13 +21733,13 @@ c_parse_file (void) ...@@ -21725,13 +21733,13 @@ c_parse_file (void)
Take ownership of START_WITH_PASS, if non-NULL. */ Take ownership of START_WITH_PASS, if non-NULL. */
void location_t
c_parser_parse_rtl_body (c_parser *parser, char *start_with_pass) c_parser_parse_rtl_body (c_parser *parser, char *start_with_pass)
{ {
if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
{ {
free (start_with_pass); free (start_with_pass);
return; return c_parser_peek_token (parser)->location;
} }
location_t start_loc = 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) ...@@ -21753,7 +21761,7 @@ c_parser_parse_rtl_body (c_parser *parser, char *start_with_pass)
case CPP_EOF: case CPP_EOF:
error_at (start_loc, "no closing brace"); error_at (start_loc, "no closing brace");
free (start_with_pass); free (start_with_pass);
return; return c_parser_peek_token (parser)->location;
default: default:
break; break;
} }
...@@ -21771,12 +21779,13 @@ c_parser_parse_rtl_body (c_parser *parser, char *start_with_pass) ...@@ -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)) if (!read_rtl_function_body_from_file_range (start_loc, end_loc))
{ {
free (start_with_pass); free (start_with_pass);
return; return end_loc;
} }
/* Run the backend on the cfun created above, transferring ownership of /* Run the backend on the cfun created above, transferring ownership of
START_WITH_PASS. */ START_WITH_PASS. */
run_rtl_passes (start_with_pass); run_rtl_passes (start_with_pass);
return end_loc;
} }
#include "gt-c-c-parser.h" #include "gt-c-c-parser.h"
...@@ -580,7 +580,7 @@ extern bool c_check_switch_jump_warnings (struct c_spot_bindings *, ...@@ -580,7 +580,7 @@ extern bool c_check_switch_jump_warnings (struct c_spot_bindings *,
location_t, location_t); location_t, location_t);
extern void finish_decl (tree, location_t, tree, tree, tree); extern void finish_decl (tree, location_t, tree, tree, tree);
extern tree finish_enum (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, extern tree finish_struct (location_t, tree, tree, tree,
class c_struct_parse_info *); class c_struct_parse_info *);
extern tree c_simulate_enum_decl (location_t, const char *, extern tree c_simulate_enum_decl (location_t, const char *,
......
2020-03-19 Jakub Jelinek <jakub@redhat.com>
PR gcov-profile/94029
* gcc.misc-tests/gcov-pr94029.c: New test.
2020-03-19 Jan Hubicka <hubicka@ucw.cz> 2020-03-19 Jan Hubicka <hubicka@ucw.cz>
PR ipa/92372 PR ipa/92372
......
/* 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 } } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment