See attached patch.
This one is fairly simple. This is also the last of the meta-bug PR125515.
Regression tested on x86_64.
I will probably simplify the commit message. Thought I should comments before I
do that.
OK for mainline and later backport to 16.
Regards,
Jerry
---
When a nested implied-do array constructor called a transformational
intrinsic (e.g. RESHAPE) whose result type has allocatable components, the
argument temporaries were freed before the result's allocatable components
were deep-copied, causing a heap-use-after-free and wrong runtime values.
The root cause: in gfc_conv_procedure_call, the call to
gfc_add_block_to_block (&se->pre, &post) — which frees the allocatable
components of argument temporaries — was issued before the deep-copy loop
for the result's allocatable components. Transformational library functions
such as RESHAPE do a shallow byte-copy of the source array into the result,
so the result's component pointers alias those of the argument temporaries.
Freeing the temporaries first and then copying yielded use-after-free.
Fix: move gfc_add_block_to_block (&se->pre, &post) to after the deep-copy
loop, so that the result's allocatable components are copied while the
source storage is still live.
PR fortran/125535
Assisted by: Claude Sonnet 4.6
gcc/fortran/ChangeLog:
PR fortran/125535
* trans-expr.cc (gfc_conv_procedure_call): Move post block append
to after the deep copy of allocatable components for transformational
intrinsics, so that argument temporaries are not freed before the
result components are copied.
gcc/testsuite/ChangeLog:
PR fortran/125535
* gfortran.dg/implied_do_alloc_comp_1.f90: New test.
---From 7b0e7473fc53127f70276cdd3e33268e3b867c7b Mon Sep 17 00:00:00 2001
From: Jerry DeLisle <[email protected]>
Date: Fri, 5 Jun 2026 13:20:05 -0700
Subject: [PATCH] fortran: wrong-code for implied-do with allocatable-component
derived type and transformational intrinsic
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
When a nested implied-do array constructor called a transformational
intrinsic (e.g. RESHAPE) whose result type has allocatable components, the
argument temporaries were freed before the result's allocatable components
were deep-copied, causing a heap-use-after-free and wrong runtime values.
The root cause: in gfc_conv_procedure_call, the call to
gfc_add_block_to_block (&se->pre, &post) — which frees the allocatable
components of argument temporaries — was issued before the deep-copy loop
for the result's allocatable components. Transformational library functions
such as RESHAPE do a shallow byte-copy of the source array into the result,
so the result's component pointers alias those of the argument temporaries.
Freeing the temporaries first and then copying yielded use-after-free.
Fix: move gfc_add_block_to_block (&se->pre, &post) to after the deep-copy
loop, so that the result's allocatable components are copied while the
source storage is still live.
PR fortran/125535
Assisted by: Claude Sonnet 4.6
gcc/fortran/ChangeLog:
PR fortran/125535
* trans-expr.cc (gfc_conv_procedure_call): Move post block append
to after the deep copy of allocatable components for transformational
intrinsics, so that argument temporaries are not freed before the
result components are copied.
gcc/testsuite/ChangeLog:
PR fortran/125535
* gfortran.dg/implied_do_alloc_comp_1.f90: New test.
---
gcc/fortran/trans-expr.cc | 10 ++---
.../gfortran.dg/implied_do_alloc_comp_1.f90 | 39 +++++++++++++++++++
2 files changed, 44 insertions(+), 5 deletions(-)
create mode 100644 gcc/testsuite/gfortran.dg/implied_do_alloc_comp_1.f90
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index c808c1b3ef3..00925f2ef5a 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -9069,12 +9069,10 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
/* Follow the function call with the argument post block. */
if (byref)
{
- gfc_add_block_to_block (&se->pre, &post);
-
/* Transformational functions of derived types with allocatable
- components must have the result allocatable components copied when the
- argument is actually given. This is unnecessry for REDUCE because the
- wrapper for the OPERATION function takes care of this. */
+ components must have the result allocatable components copied
+ BEFORE the argument post block is appended. Copying the result
+ first, then freeing the argument, gives the correct order. */
arg = expr->value.function.actual;
if (result && arg && expr->rank
&& isym && isym->transformational
@@ -9102,6 +9100,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
NULL, GFC_CAF_COARRAY_NOCOARRAY);
gfc_add_expr_to_block (&se->pre, tmp);
}
+
+ gfc_add_block_to_block (&se->pre, &post);
}
else
{
diff --git a/gcc/testsuite/gfortran.dg/implied_do_alloc_comp_1.f90 b/gcc/testsuite/gfortran.dg/implied_do_alloc_comp_1.f90
new file mode 100644
index 00000000000..8f0ae4976d8
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/implied_do_alloc_comp_1.f90
@@ -0,0 +1,39 @@
+! { dg-do run }
+! Test that a nested implied-do array constructor with a derived-type
+! constructor whose argument uses an outer loop variable produces correct
+! results when the derived type has an allocatable component.
+!
+! PR fortran/125535
+
+module m
+ implicit none
+ type :: t
+ real, allocatable :: v(:)
+ end type
+contains
+ pure function make(x) result(r)
+ real, intent(in) :: x(:)
+ type(t) :: r
+ r%v = x
+ end function
+end module
+
+program implied_do_alloc_comp
+ use m
+ implicit none
+ integer, parameter :: n=3, k=2
+ type(t), allocatable :: a(:,:)
+ real :: h(k, n)
+ integer :: i, j
+
+ h(1,:) = [10., 20., 30.]
+ h(2,:) = [11., 21., 31.]
+
+ ! Nested implied-do where inner DT constructor uses outer variable i.
+ ! Without the fix this produces heap-use-after-free and wrong values.
+ a = reshape([([(make(h(:,i)), j=1,1)], i=1,n)], [1,n])
+
+ if (any(a(1,1)%v /= h(:,1))) stop 1
+ if (any(a(1,2)%v /= h(:,2))) stop 2
+ if (any(a(1,3)%v /= h(:,3))) stop 3
+end program
--
2.54.0