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;
}
}