Richard already approved this, but FWIW also looks goods to me. Except I can't
say anything about the testcases, since I don't know Ada at all :).
Thanks for the patch,
Filip Kastl
On Wed 2026-07-01 09:47:46, Eric Botcazou wrote:
> Hi,
>
> this is a regression present on mainline, 16, 15 and 14 branches introduced
> by
> the fix for PR tree-optimization/112653 (PTA and return). What happens is
> that DSE incorrectly eliminates a call to __builtin_memcpy, whose destination
> is obtained from (an equivalent of) malloc and is ultimately returned from
> the
> function. But this happens only when the dynamic allocation is conditional.
>
> The difference between the unconditional and conditional cases is:
>
> ESCAPED_RETURN = { ESCAPED NONLOCAL HEAP(30) }
>
> vs
>
> ESCAPED_RETURN = { ANYTHING }
>
> The proposed fix is to apply in set_uids_in_ptset the same treatment to
> ANYTHING in the escaped return case as in the escaped case.
>
> Tested on x86-64/Linux, OK for all affected branches?
>
>
> 2026-07-01 Eric Botcazou <[email protected]>
>
> * tree-ssa-structalias.cc (set_uids_in_ptset): If ANYTHING is
> present in the ESCAPED_RETURN solution, record that the global
> solution has an escaped heap if FROM contains a heap variable.
>
>
> 2026-07-01 Eric Botcazou <[email protected]>
>
> * gnat.dg/opt109.adb: New test.
> * gnat.dg/opt109_pkg.ads, gnat.dg/opt109_pkg.adb: New helper.
>
> --
> Eric Botcazou
> diff --git a/gcc/tree-ssa-structalias.cc b/gcc/tree-ssa-structalias.cc
> index ab6658a0981..8a22d6b3ce9 100644
> --- a/gcc/tree-ssa-structalias.cc
> +++ b/gcc/tree-ssa-structalias.cc
> @@ -745,12 +745,15 @@ static void
> set_uids_in_ptset (bitmap into, bitmap from, struct pt_solution *pt,
> tree fndecl)
> {
> + const varinfo_t escaped_vi = get_varinfo (var_rep[escaped_id]);
> + const varinfo_t escaped_return_vi = get_varinfo
> (var_rep[escaped_return_id]);
> + const bool everything_escaped
> + = escaped_vi->solution && bitmap_bit_p (escaped_vi->solution,
> anything_id);
> + const bool everything_escaped_return
> + = escaped_return_vi->solution
> + && bitmap_bit_p (escaped_return_vi->solution, anything_id);
> unsigned int i;
> bitmap_iterator bi;
> - varinfo_t escaped_vi = get_varinfo (var_rep[escaped_id]);
> - varinfo_t escaped_return_vi = get_varinfo (var_rep[escaped_return_id]);
> - bool everything_escaped
> - = escaped_vi->solution && bitmap_bit_p (escaped_vi->solution,
> anything_id);
>
> EXECUTE_IF_SET_IN_BITMAP (from, 0, i, bi)
> {
> @@ -766,8 +769,10 @@ set_uids_in_ptset (bitmap into, bitmap from, struct
> pt_solution *pt,
> pt->vars_contains_escaped = true;
> pt->vars_contains_escaped_heap |= vi->is_heap_var;
> }
> - if (escaped_return_vi->solution
> - && bitmap_bit_p (escaped_return_vi->solution, i))
> +
> + if (everything_escaped_return
> + || (escaped_return_vi->solution
> + && bitmap_bit_p (escaped_return_vi->solution, i)))
> pt->vars_contains_escaped_heap |= vi->is_heap_var;
>
> if (vi->is_restrict_var)
> -- { dg-do run }
> -- { dg-options "-O" }
>
> with Opt109_Pkg; use Opt109_Pkg;
>
> procedure Opt109 is
> S : constant String := "Hello World!";
> R : constant Rec := F (S);
> begin
> if R.B.Data.all /= S then
> raise Program_Error;
> end if;
> end;
> package body Opt109_Pkg is
>
> function F (Value : String) return Rec is
> begin
> if Value'Length > Max then
> return Result : Rec (Is_Small => False) do
> Result.B.Data := new String'(Value);
> end return;
> else
> return Result : Rec (Is_Small => True) do
> Result.S.Data (Value'Length + 1 .. Max) := (others => ' ');
> end return;
> end if;
> end;
>
> end Opt109_Pkg;
> with System;
>
> package Opt109_Pkg is
>
> Max : constant Natural := 7;
> subtype Small_String_Size is Natural range 0 .. Max;
>
> type Small_String is record
> Is_Small : Boolean;
> Length : Small_String_Size;
> Data : aliased String (1 .. Max);
> end record;
>
> type Big_String_Access is access all String;
>
> type Big_String is record
> Data : Big_String_Access := null;
> end record;
>
> for Big_String use record
> Data at 0 range 0 .. System.Word_Size - 1;
> end record;
>
> type Rec (Is_Small : Boolean := True) is record
> case Is_Small is
> when True => S : Small_String;
> when False => B : Big_String;
> end case;
> end record with Unchecked_Union;
>
> function F (Value : String) return Rec;
>
> end Opt109_Pkg;