See attached 1 of 5 patch
Regression tested on x86_64
Regards,
Jerry
---
fortran: [PR49802]-1 Add a deep copy mode to
gfc_conv_subref_array_arg
This is the shared infrastructure the rest of the PR49802 series builds
on. It changes no behaviour for any existing caller.
gfc_conv_subref_array_arg gains a DEEP_COPY argument, defaulting to
false, which it passes on to gfc_trans_scalar_assign so that the
temporary is given allocatable components of its own rather than
sharing those of the actual argument. The components are freed again
once the call has returned. Only INTENT_IN is supported, since writing
the temporary back would leave the actual argument holding the freed
component pointers.
Two latent problems in the pass_optional path are fixed at the same
time. The pointer was assigned the address of the descriptor rather
than the descriptor, and the string length was not copied back out of
the private gfc_se, so a CHARACTER actual argument reached
gfc_conv_missing_dummy with none. Neither is reachable today: the only
caller that passes SYM, and so the only one that can set pass_optional,
is gfc_conv_array_parameter, which also sets check_contiguous. Both
are exercised by the last patch of this series, where an absent
optional actual argument is passed to a VALUE dummy.
PR fortran/49802
gcc/fortran/ChangeLog:
* trans.h (gfc_conv_subref_array_arg): Add DEEP_COPY argument.
* trans-expr.cc (gfc_conv_subref_array_arg): Take DEEP_COPY and
pass it on to gfc_trans_scalar_assign; deallocate the allocatable
components of the temporary after the call. Dereference the
descriptor when setting the pointer for an optional argument that
is not also checked for contiguity, and pass the string length
back to the caller's gfc_se.
---From f495a81c795eb7c36928146bf1edcaba3b641c41 Mon Sep 17 00:00:00 2001
From: Jerry DeLisle <[email protected]>
Date: Sun, 23 Aug 2026 18:27:40 -0700
Subject: [PATCH 1/5] fortran: [PR49802]-1 Add a deep copy mode to
gfc_conv_subref_array_arg
This is the shared infrastructure the rest of the PR49802 series builds
on. It changes no behaviour for any existing caller.
gfc_conv_subref_array_arg gains a DEEP_COPY argument, defaulting to
false, which it passes on to gfc_trans_scalar_assign so that the
temporary is given allocatable components of its own rather than
sharing those of the actual argument. The components are freed again
once the call has returned. Only INTENT_IN is supported, since writing
the temporary back would leave the actual argument holding the freed
component pointers.
Two latent problems in the pass_optional path are fixed at the same
time. The pointer was assigned the address of the descriptor rather
than the descriptor, and the string length was not copied back out of
the private gfc_se, so a CHARACTER actual argument reached
gfc_conv_missing_dummy with none. Neither is reachable today: the only
caller that passes SYM, and so the only one that can set pass_optional,
is gfc_conv_array_parameter, which also sets check_contiguous. Both
are exercised by the last patch of this series, where an absent
optional actual argument is passed to a VALUE dummy.
PR fortran/49802
gcc/fortran/ChangeLog:
* trans.h (gfc_conv_subref_array_arg): Add DEEP_COPY argument.
* trans-expr.cc (gfc_conv_subref_array_arg): Take DEEP_COPY and
pass it on to gfc_trans_scalar_assign; deallocate the allocatable
components of the temporary after the call. Dereference the
descriptor when setting the pointer for an optional argument that
is not also checked for contiguity, and pass the string length
back to the caller's gfc_se.
---
gcc/fortran/trans-expr.cc | 26 ++++++++++++++++++++++----
gcc/fortran/trans.h | 3 ++-
2 files changed, 24 insertions(+), 5 deletions(-)
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index a881ca24983..960026692a2 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -5558,7 +5558,8 @@ void
gfc_conv_subref_array_arg (gfc_se *se, gfc_expr * expr, int g77,
sym_intent intent, bool formal_ptr,
const gfc_symbol *fsym, const char *proc_name,
- gfc_symbol *sym, bool check_contiguous)
+ gfc_symbol *sym, bool check_contiguous,
+ bool deep_copy)
{
gfc_se lse;
gfc_se rse;
@@ -5670,7 +5671,7 @@ gfc_conv_subref_array_arg (gfc_se *se, gfc_expr * expr, int g77,
if (intent != INTENT_OUT)
{
- tmp = gfc_trans_scalar_assign (&lse, &rse, expr->ts, false, false);
+ tmp = gfc_trans_scalar_assign (&lse, &rse, expr->ts, deep_copy, false);
gfc_add_expr_to_block (&body, tmp);
gcc_assert (rse.ss == gfc_ss_terminator);
gfc_trans_scalarizing_loops (&loop, &body);
@@ -5802,6 +5803,19 @@ gfc_conv_subref_array_arg (gfc_se *se, gfc_expr * expr, int g77,
class_array_fcn:
+ /* A deep copy allocated fresh components for the temporary; free them
+ again once the call has returned, before the temporary itself goes.
+ Only INTENT_IN is supported, as writing the temporary back would leave
+ the actual argument holding the freed component pointers. */
+ gcc_assert (!deep_copy || intent == INTENT_IN);
+ if (deep_copy && expr->ts.type == BT_DERIVED
+ && expr->ts.u.derived->attr.alloc_comp)
+ {
+ tmp = gfc_deallocate_alloc_comp (expr->ts.u.derived, parmse->expr,
+ dimen);
+ gfc_add_expr_to_block (&parmse->post, tmp);
+ }
+
gfc_add_block_to_block (&parmse->post, &loop.post);
gfc_cleanup_loop (&loop);
@@ -5967,8 +5981,11 @@ class_array_fcn:
}
else
{
- /* pointer = pramse->expr; . */
- gfc_add_modify (&parmse->pre, pointer, parmse->expr);
+ /* pointer = parmse->expr; . */
+ tmp = (GFC_DESCRIPTOR_TYPE_P (type)
+ ? build_fold_indirect_ref_loc (input_location, parmse->expr)
+ : parmse->expr);
+ gfc_add_modify (&parmse->pre, pointer, tmp);
pre_stmts = gfc_finish_block (&parmse->pre);
}
@@ -6050,6 +6067,7 @@ class_array_fcn:
gcc_assert (!pass_optional);
}
se->expr = pointer;
+ se->string_length = parmse->string_length;
}
return;
diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h
index 408acf081f1..e529ce795b9 100644
--- a/gcc/fortran/trans.h
+++ b/gcc/fortran/trans.h
@@ -564,7 +564,8 @@ void gfc_conv_subref_array_arg (gfc_se *, gfc_expr *, int, sym_intent, bool,
const gfc_symbol *fsym = NULL,
const char *proc_name = NULL,
gfc_symbol *sym = NULL,
- bool check_contiguous = false);
+ bool check_contiguous = false,
+ bool deep_copy = false);
void gfc_conv_is_contiguous_expr (gfc_se *, gfc_expr *);
--
2.55.0