diff mbox series

c: Fix up cfun->function_end_locus from the C FE [PR94029]

Message ID 20200319084923.GN2156@tucnak
State New
Headers show
Series c: Fix up cfun->function_end_locus from the C FE [PR94029] | expand

Commit Message

Jeff Law via Gcc-patches March 19, 2020, 8:49 a.m. UTC
Hi!

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.

Both patches successfully bootstrapped/regtested on x86_64-linux and
i686-linux, ok for trunk (which one)?

	Jakub
2020-03-19  Jakub Jelinek  <jakub@redhat.com>

	PR gcov-profile/94029
	* c-parser.c (c_parser_compound_statement_nostart): Set
	input_location to the locus of closing CPP_CLOSE_BRACE.

	* gcc.misc-tests/gcov-pr94029.c: New test.
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.

--- gcc/c/c-tree.h.jj	2020-03-17 22:31:56.586909614 +0100
+++ gcc/c/c-tree.h	2020-03-18 13:54:56.207538538 +0100
@@ -580,7 +580,7 @@ extern bool c_check_switch_jump_warnings
 					  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 *,
--- gcc/c/c-parser.c.jj	2020-03-18 13:36:22.006021310 +0100
+++ gcc/c/c-parser.c	2020-03-18 13:57:45.576034113 +0100
@@ -1487,8 +1487,8 @@ static struct c_expr c_parser_braced_ini
 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_
 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
 	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
 	  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
 				      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
 	     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
 	{
 	  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, stru
      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 *p
       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 *p
    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_p
   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_p
     {
       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_p
 	{
 	  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_p
             {
 	      mark_valid_location_for_stdc_pragma (save_valid_for_pragma);
 	      error_at (loc, "expected %<}%> before %<else%>");
-              return;
+	      return c_parser_peek_token (parser)->location;
             }
           else
             {
@@ -5804,9 +5810,11 @@ c_parser_compound_statement_nostart (c_p
     }
   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 *parse
 	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 *parse
   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"
--- gcc/c/c-decl.c.jj	2020-03-17 22:31:56.589909571 +0100
+++ gcc/c/c-decl.c	2020-03-18 13:55:22.560148860 +0100
@@ -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);
--- gcc/testsuite/gcc.misc-tests/gcov-pr94029.c.jj	2020-03-18 13:41:02.192871170 +0100
+++ gcc/testsuite/gcc.misc-tests/gcov-pr94029.c	2020-03-18 13:41:02.192871170 +0100
@@ -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 } } */

Comments

Joseph Myers March 19, 2020, 9:38 p.m. UTC | #1
On Thu, 19 Mar 2020, Jakub Jelinek via Gcc-patches wrote:

> The second instead propagates the location_t from the parsing of the
> outermost compound statement (the function body) to finish_function.
> 
> Both patches successfully bootstrapped/regtested on x86_64-linux and
> i686-linux, ok for trunk (which one)?

The second patch is OK.
diff mbox series

Patch

--- gcc/c/c-parser.c.jj	2020-03-18 12:47:20.749483242 +0100
+++ gcc/c/c-parser.c	2020-03-18 13:12:25.182276999 +0100
@@ -5631,7 +5631,9 @@  c_parser_compound_statement_nostart (c_p
   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);
+      c_token *token = c_parser_peek_token (parser);
+      add_debug_begin_stmt (token->location);
+      c_parser_set_source_position_from_token (token);
       c_parser_consume_token (parser);
       return;
     }
@@ -5804,6 +5806,7 @@  c_parser_compound_statement_nostart (c_p
     }
   if (last_label)
     error_at (label_loc, "label at end of compound statement");
+  c_parser_set_source_position_from_token (c_parser_peek_token (parser));
   c_parser_consume_token (parser);
   /* Restore the value we started with.  */
   mark_valid_location_for_stdc_pragma (save_valid_for_pragma);
--- gcc/testsuite/gcc.misc-tests/gcov-pr94029.c.jj	2020-03-18 13:20:10.371407269 +0100
+++ gcc/testsuite/gcc.misc-tests/gcov-pr94029.c	2020-03-18 13:20:46.736870237 +0100
@@ -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 } } */