https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58123

Aldy Hernandez <aldyh at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|UNCONFIRMED                 |NEW
   Last reconfirmed|                            |2015-02-18
     Ever confirmed|0                           |1

--- Comment #7 from Aldy Hernandez <aldyh at gcc dot gnu.org> ---
Confirmed.

There are a few curious things with this bug.

First, the reason we jump to line 11 is because the EH code, as it expands
try/finally blocks, can't find the location of the destructor calls, so it uses
the location of the enclosing TRY block.  So for something like this:

try {
  foo();
} finally {
  C::~C (&var);
}

...lower_try_finally_onedest(), will set the location of the destructor call to
the try location:

      if (LOCATION_LOCUS (gimple_location (stmt)) == UNKNOWN_LOCATION)
    {
      tree block = gimple_block (stmt);
      gimple_set_location (stmt, gimple_location (tf->try_finally_expr));
      gimple_set_block (stmt, block);
    }

Putting this aside for a second, my question is, do we really want a debugging
experience where we jump from back from the end of scope, back to the
declaration of the class?  Because one way of fixing this would be to get rid
of the above code that pushes the try location onto finally statements that are
locationless.  Then we could hit "next" on the debugger and go from line 8 -> 9
-> 10 -> 11 -> 12, without backtracking to some definition.

Second, the reason we don't have a location for the destructor call is
apparently by design, so we don't do this jumping around I am arguing against. 
 The patch for PR debug/49951 specifically removes the location of the
destructor so we don't jump around:

  /* build_delete sets the location of the destructor call to the
     current location, even though the destructor is going to be
     called later, at the end of the current scope.  This can lead to
     a "jumpy" behaviour for users of debuggers when they step around
     the end of the block.  So let's unset the location of the
     destructor call instead.  */
  if (cleanup != NULL && EXPR_P (cleanup))
    SET_EXPR_LOCATION (cleanup, UNKNOWN_LOCATION);

But alas, as I explain above, the try/finally code fills in the missing
location for the destructor with the location of the try.

Third, be that as it may with the above two points, the TRY location is
actually wrong in the trees:

      [a.cc:11:40] try      <-- ***THIS SHOULD BE LINE 8***
        {
          [a.cc:9:14] C::C ([a.cc:9:14] &b);
          [a.cc:9:14] try
            {
              [a.cc:10:14] C::C ([a.cc:10:14] &c);
              [a.cc:10:14] try
                {
                  [a.cc:11:22] D.2371 = C::m ([a.cc:11:22] &a);
                  [a.cc:11:30] D.2372 = C::m ([a.cc:11:30] &b);
                  [a.cc:11:25] D.2373 = D.2371 + D.2372;
                  [a.cc:11:38] D.2374 = C::m ([a.cc:11:38] &c);
                  [a.cc:11:39] D.2370 = D.2373 + D.2374;
                  [a.cc:11:39] goto <D.2375>;
                }
              finally
                {
                  C::~C (&c);
                }
            }
          finally
            {
              C::~C (&b);
            }
        }
      finally
        {
          C::~C (&a);
        }

This is actually a problem in the gimplifier.  The code gimplifying the
TRY_FINALLY_EXPR has:

        if (LOCATION_LOCUS (saved_location) != UNKNOWN_LOCATION)
          gimple_set_location (try_, saved_location);
        else
          gimple_set_location (try_, EXPR_LOCATION (save_expr));

which means we are preferring the saved_location (gathered generically from
input_location) over the TRY_FINALLY_EXPR's location.

IMO, this should be (untested):

diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 1353ada..d822913 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -8244,10 +8244,10 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p,
gimple_seq *post_p,
                      TREE_CODE (*expr_p) == TRY_FINALLY_EXPR
                      ? GIMPLE_TRY_FINALLY
                      : GIMPLE_TRY_CATCH);
-        if (LOCATION_LOCUS (saved_location) != UNKNOWN_LOCATION)
-          gimple_set_location (try_, saved_location);
-        else
+        if (EXPR_HAS_LOCATION (save_expr))
           gimple_set_location (try_, EXPR_LOCATION (save_expr));
+        else if (LOCATION_LOCUS (saved_location) != UNKNOWN_LOCATION)
+          gimple_set_location (try_, saved_location);
         if (TREE_CODE (*expr_p) == TRY_CATCH_EXPR)
           gimple_try_set_catch_is_cleanup (try_,
                            TRY_CATCH_IS_CLEANUP (*expr_p));

This prefers the TRY_FINALLY_EXPR's location if available, else it uses the
input_location upon entry.

With this untested patch, we do the jumpy thing Jan was expecting-- going back
to line 8.  But I question whether we want this at all.  Instead, do we even
want to fill in unknown location finally statements with the location of the
try block?

It seems like there are two possible solutions (a) avoid filling in missing
locations with the try block's location (b) fix the gimplifier to use the
TRY_FINALLY_EXPR's location if available.

Either way, I think the gimplifier is wrong and should be fixed with (b)
independently of this problem.

Jason, Jakub?

Reply via email to