On Thu, Mar 20, 2025 at 06:25:26PM +0100, Jakub Jelinek wrote:
> On Thu, Mar 20, 2025 at 10:01:02AM -0700, Andi Kleen wrote:
> > So it could be as simple as that patch?  It solves your test case at least
> > for x86.
> 
> Not sure I like this, but if others (e.g. Richi, Joseph, Jason) are ok with
> it I can live with it.  But we'd need a good documentation, ideally some
> some new warning about it (perhaps enabled in -Wextra) and testcase
> coverage.
> Looking around, clang warns for
> int foo (int *);
> int bar (int *x)
> {
>   *x = 42;
>   int a = 0;
>   [[clang::musttail]] return foo (&a);
> }
> by default (without -Wall/-Wextra) with
> warning: address of stack memory associated with local variable 'a' passed to 
> musttail function [-Wreturn-stack-address]
> Dunno if that warning is about other stuff or just that.
> If just that, perhaps we'd need multiple levels for it, diagnose passing
> those to musttail arguments by default and have in -Wextra stronger variant
> that would diagnose even the
> int baz (int *x)
> {
>   *x = 42;
>   int a = 0;
>   foo (&a);
>   [[clang::musttail]] return foo (nullptr);
> }
> case, i.e. escaped variables that are still in scope.
> That variant of the warning perhaps should suggest to users to end the
> lifetime of those variables before the musttail call.

It looks like it's reasonably easy to provide a single warning
covering both the escape and the passing case. Doing it more
fine grained would need much more code by redoing parts
of ref_may_be_used_by_stmt_p etc.

Perhaps that is good enough?

This version also fixes a memory leak in my earlier variant.

diff --git a/gcc/tree-tailcall.cc b/gcc/tree-tailcall.cc
index f97df31eb3cf..066037ed09c6 100644
--- a/gcc/tree-tailcall.cc
+++ b/gcc/tree-tailcall.cc
@@ -714,29 +714,36 @@ find_tail_calls (basic_block bb, struct tailcall **ret, 
bool only_musttail,
     {
       if (TREE_CODE (var) != PARM_DECL
          && auto_var_in_fn_p (var, cfun->decl)
-         && may_be_aliased (var)
-         && (ref_maybe_used_by_stmt_p (call, var, false)
-             || call_may_clobber_ref_p (call, var, false)))
+         && may_be_aliased (var))
        {
-         if (!VAR_P (var))
+         if (VAR_P (var)
+               && !bitmap_bit_p (local_live_vars,
+                           *live_vars->get (DECL_UID (var))))
+           continue;
+         if (ref_maybe_used_by_stmt_p (call, var, false))
            {
-             if (local_live_vars)
-               BITMAP_FREE (local_live_vars);
-             maybe_error_musttail (call,
-                                   _("call invocation refers to locals"));
-             return;
+             if (gimple_call_must_tail_p (call))
+               {
+                 warning_at (call->location, 0,
+                         "Address of local variable %qE may be used by 
musttail call",
+                                 var);
+                 continue;
+               }
            }
-         else
+         else if (call_may_clobber_ref_p (call, var, false))
            {
-             unsigned int *v = live_vars->get (DECL_UID (var));
-             if (bitmap_bit_p (local_live_vars, *v))
+             if (gimple_call_must_tail_p (call))
                {
-                 BITMAP_FREE (local_live_vars);
-                 maybe_error_musttail (call,
-                                       _("call invocation refers to locals"));
-                 return;
+                 warning_at (call->location, 0,
+                         "musttail call may clobber escaped variable %qE", 
var);
+                 continue;
                }
            }
+         else
+           continue;
+         if (local_live_vars)
+           BITMAP_FREE (local_live_vars);
+         return;
        }
     }
 

Reply via email to