We just remarked that there is a coverage inaccuracy in C/C++ for something as 
simple as:

void
foo (int i)
{
  if (i > 1)
    return;

  bar ();
}

The return line is always reported as covered, even at -O0.  That's because 
the return is used as the "representative return" for the entire function 
and then reused for the fallthru as-is.   The interesting thing is that this 
doesn't happen in Ada for an equivalent code, because the Ada compiler always 
adds a final return to functions:

void
foo (int i)
{
  if (i > 1)
    return;

  bar ();
  return;
}

In this case of 2 or more returns, the machinery in gimple-low.c properly 
clears the location on the representative return:

          /* Remove the line number from the representative return statement.
             It now fills in for many such returns.  Failure to remove this
             will result in incorrect results for coverage analysis.  */
          gimple_set_location (tmp_rs.stmt, UNKNOWN_LOCATION);

Hence the attached patch, which does the same when a representative return is 
reused for the fallthru.

Tested on x86_64-suse-linux, applied on the mainline as obvious.


2014-11-10  Eric Botcazou  <ebotca...@adacore.com>

        * gimple-low.c (lower_function_body): Clear the location of the first
        inserted representative return if it also fills in for the fallthru.


2014-11-10  Eric Botcazou  <ebotca...@adacore.com>

        * gcc.misc-tests/gcov-15.c: New test.


-- 
Eric Botcazou
Index: gimple-low.c
===================================================================
--- gimple-low.c	(revision 217259)
+++ gimple-low.c	(working copy)
@@ -129,7 +129,8 @@ lower_function_body (void)
   /* If the function falls off the end, we need a null return statement.
      If we've already got one in the return_statements vector, we don't
      need to do anything special.  Otherwise build one by hand.  */
-  if (gimple_seq_may_fallthru (lowered_body)
+  bool may_fallthru = gimple_seq_may_fallthru (lowered_body);
+  if (may_fallthru
       && (data.return_statements.is_empty ()
 	  || (gimple_return_retval (data.return_statements.last().stmt)
 	      != NULL)))
@@ -138,6 +139,7 @@ lower_function_body (void)
       gimple_set_location (x, cfun->function_end_locus);
       gimple_set_block (x, DECL_INITIAL (current_function_decl));
       gsi_insert_after (&i, x, GSI_CONTINUE_LINKING);
+      may_fallthru = false;
     }
 
   /* If we lowered any return statements, emit the representative
@@ -148,6 +150,14 @@ lower_function_body (void)
       x = gimple_build_label (t.label);
       gsi_insert_after (&i, x, GSI_CONTINUE_LINKING);
       gsi_insert_after (&i, t.stmt, GSI_CONTINUE_LINKING);
+      if (may_fallthru)
+	{
+	  /* Remove the line number from the representative return statement.
+	     It now fills in for the fallthru too.  Failure to remove this
+	     will result in incorrect results for coverage analysis.  */
+	  gimple_set_location (t.stmt, UNKNOWN_LOCATION);
+	  may_fallthru = false;
+	}
     }
 
   /* Once the old body has been lowered, replace it with the new
/* { dg-options "-fprofile-arcs -ftest-coverage" } */
/* { dg-do run { target native } } */

void
bar (void)
{}

void
foo (int i)
{
  if (i > 1)  /* count(1) */
    return;   /* count(#####) */

  bar ();      /* count(1) */
}

int
main (void)
{
  foo (0);
  return 0;
}

/* { dg-final { run-gcov gcov-15.c } } */

Reply via email to