Fix dangling references in thunks at -O0

When a thunk cannot be emitted in assembly directly, expand_thunk
generates regular GIMPLE code but unconditionally forces a tail
call to the target of the thunk.  That's theoretically OK because
the thunk essentially forwards its parameters to the target, but
in practice the RTL expander can spill parameters passed by reference
on the stack in assign_parm_setup_reg.

gcc/ChangeLog:
	* cgraphunit.c (cgraph_node::expand_thunk): Make sure to set
	cfun->tail_call_marked when forcing a tail call.
	* function.c (assign_parm_setup_reg): Always use a register to
	load a parameter passed by reference if cfun->tail_call_marked.

gcc/testsuite/ChangeLog:
	* gnat.dg/thunk1.adb: New test.
	* gnat.dg/thunk1_pkg1.ads: New helper.
	* gnat.dg/thunk1_pkg2.ads: Likewise.
	* gnat.dg/thunk1_pkg2.adb: Likewise.
This commit is contained in:
Eric Botcazou 2020-09-14 17:24:32 +02:00
parent 863e8d53eb
commit a7d8dcdf2f
6 changed files with 52 additions and 6 deletions

View file

@ -2171,7 +2171,10 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
}
}
else
gimple_call_set_tail (call, true);
{
gimple_call_set_tail (call, true);
cfun->tail_call_marked = true;
}
/* Build return value. */
if (!DECL_BY_REFERENCE (resdecl))
@ -2184,6 +2187,7 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
else
{
gimple_call_set_tail (call, true);
cfun->tail_call_marked = true;
remove_edge (single_succ_edge (bb));
}

View file

@ -3322,13 +3322,15 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
else
emit_move_insn (parmreg, validated_mem);
/* If we were passed a pointer but the actual value can safely live
in a register, retrieve it and use it directly. */
/* If we were passed a pointer but the actual value can live in a register,
retrieve it and use it directly. Note that we cannot use nominal_mode,
because it will have been set to Pmode above, we must use the actual mode
of the parameter instead. */
if (data->arg.pass_by_reference && TYPE_MODE (TREE_TYPE (parm)) != BLKmode)
{
/* We can't use nominal_mode, because it will have been set to
Pmode above. We must use the actual mode of the parm. */
if (use_register_for_decl (parm))
/* Use a stack slot for debugging purposes, except if a tail call is
involved because this would create a dangling reference. */
if (use_register_for_decl (parm) || cfun->tail_call_marked)
{
parmreg = gen_reg_rtx (TYPE_MODE (TREE_TYPE (parm)));
mark_user_reg (parmreg);

View file

@ -0,0 +1,9 @@
-- { dg-do run }
with Thunk1_Pkg1; use Thunk1_Pkg1;
procedure Thunk1 is
D: Derived;
begin
D.Op ("Message");
end;

View file

@ -0,0 +1,7 @@
with Thunk1_Pkg2; use Thunk1_Pkg2;
package Thunk1_Pkg1 is
type Derived is new Ext with null record;
end Thunk1_Pkg1;

View file

@ -0,0 +1,10 @@
package body Thunk1_Pkg2 is
procedure Op (This : in out Ext; S : String) is
begin
if S /= "Message" then
raise Program_Error;
end if;
end;
end Thunk1_Pkg2;

View file

@ -0,0 +1,14 @@
package Thunk1_Pkg2 is
type Root is tagged record
I : Integer;
end record;
type Iface is interface;
procedure Op (This : in out Iface; S : String) is abstract;
type Ext is new Root and Iface with null record;
procedure Op (This : in out Ext; S : String);
end Thunk1_Pkg2;