Hi Mikael,

The patch applies cleanly, regtests and fixes the problem, as advertised.
It does likewise on 15-branch.

Good for mainline and, I would suggest, backporting.

Thanks for the patch.

Paul


On Wed, 30 Jul 2025 at 10:04, Mikael Morin <morin-mik...@orange.fr> wrote:

> From: Mikael Morin <mik...@gcc.gnu.org>
>
> This one may look like a collection of obscure random changes.
> It started with the removal of an isolated array descriptor offset
> update, and the chain of regression fixes that followed completed it to
> the below.  I have even found a testcase that is fixed by it.
>
> Regression-tested on x86_64-pc-linux-gnu.
> OK for master?
>
> -- >8 --
>
> There is code in gfc_conv_procedure_call that, for polymorphic
> functions, initializes the scalarization array descriptor
> information and forcedfully sets loop bounds.  This code is changing
> the decisions made by the scalarizer behind his back, and the test shows
> an example where the consequences are (badly) visible.  In the test, for
> one of the actual arguments to an elemental subroutine, an offset to the
> loop variable is missing to access the array, as it was the one
> originally chosen to set the loop bounds from.
>
> This could theoretically be fixed by just clearing the array of choice
> for the loop bounds.  This change takes instead the harder path of
> adding the missing information to the scalarizer's knowledge so that its
> decision doesn't need to be forced to something else after the fact.
> The array descriptor information initialisation for polymorphic
> functions is moved to gfc_add_loop_ss_code (after the function call
> generation), and the loop bounds initialization to a new function called
> after that.
>
> As the array chosen to set the loop bounds from is no longer forced
> to be the polymorphic function result, we have to let the scalarizer set
> a delta for polymorphic function results.  For regular non-polymorphic
> function result arrays, they are zero-based and the temporary creation
> makes the loop zero-based as well, so we can continue to skip the delta
> calculation.
>
> In the cases where a temporary is created to store the result of the
> array function, the creation of the temporary shifts the loop bounds
> to be zero-based.  As there was no delta for polymorphic result arrays,
> the function result descriptor offset was set to zero in that case for
> a zero-based array reference to be correct.  Now that the scalarizer
> sets a delta, those forced offset updates have to go because they can
> make the descriptor invalid and cause erroneous array references.
>
> gcc/fortran/ChangeLog:
>
>         * trans-expr.cc (gfc_conv_subref_array_arg): Remove offset
>         update.
>         (gfc_conv_procedure_call): For polymorphic functions, move the
>         scalarizer descriptor information...
>         * trans-array.cc (gfc_add_loop_ss_code): ... here, and evaluate
>         the bounds to fresh variables.
>         (get_class_info_from_ss): Remove offset update.
>         (gfc_conv_ss_startstride): Don't set a zero value for function
>         result upper bounds.
>         (late_set_loop_bounds): New.
>         (gfc_conv_loop_setup): If the bounds of a function result have
>         been set, and no other array provided loop bounds for a
>         dimension, use the function result bounds as loop bounds for
>         that dimension.
>         (gfc_set_delta): Don't skip delta setting for polymorphic
>         function results.
>
> gcc/testsuite/ChangeLog:
>
>         * gfortran.dg/class_elemental_1.f90: New test.
> ---
>  gcc/fortran/trans-array.cc                    | 113 ++++++++++++++----
>  gcc/fortran/trans-expr.cc                     |  35 +-----
>  .../gfortran.dg/class_elemental_1.f90         |  34 ++++++
>  3 files changed, 128 insertions(+), 54 deletions(-)
>  create mode 100644 gcc/testsuite/gfortran.dg/class_elemental_1.f90
>
> diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
> index 0f7637dd535..9a738bd5204 100644
> --- a/gcc/fortran/trans-array.cc
> +++ b/gcc/fortran/trans-array.cc
> @@ -1426,12 +1426,6 @@ get_class_info_from_ss (stmtblock_t * pre, gfc_ss
> *ss, tree *eltype,
>           tmp2 = gfc_class_len_get (class_expr);
>           gfc_add_modify (pre, tmp, tmp2);
>         }
> -
> -      if (rhs_function)
> -       {
> -         tmp = gfc_class_data_get (class_expr);
> -         gfc_conv_descriptor_offset_set (pre, tmp, gfc_index_zero_node);
> -       }
>      }
>    else if (rhs_ss->info->data.array.descriptor)
>     {
> @@ -3372,18 +3366,48 @@ gfc_add_loop_ss_code (gfc_loopinfo * loop, gfc_ss
> * ss, bool subscript,
>           break;
>
>         case GFC_SS_FUNCTION:
> -         /* Array function return value.  We call the function and save
> its
> -            result in a temporary for use inside the loop.  */
> -         gfc_init_se (&se, NULL);
> -         se.loop = loop;
> -         se.ss = ss;
> -         if (gfc_is_class_array_function (expr))
> -           expr->must_finalize = 1;
> -         gfc_conv_expr (&se, expr);
> -         gfc_add_block_to_block (&outer_loop->pre, &se.pre);
> -         gfc_add_block_to_block (&outer_loop->post, &se.post);
> -         gfc_add_block_to_block (&outer_loop->post, &se.finalblock);
> -         ss_info->string_length = se.string_length;
> +         {
> +           /* Array function return value.  We call the function and save
> its
> +              result in a temporary for use inside the loop.  */
> +           gfc_init_se (&se, NULL);
> +           se.loop = loop;
> +           se.ss = ss;
> +           bool class_func = gfc_is_class_array_function (expr);
> +           if (class_func)
> +             expr->must_finalize = 1;
> +           gfc_conv_expr (&se, expr);
> +           gfc_add_block_to_block (&outer_loop->pre, &se.pre);
> +           if (class_func
> +               && se.expr
> +               && GFC_CLASS_TYPE_P (TREE_TYPE (se.expr)))
> +             {
> +               tree tmp = gfc_class_data_get (se.expr);
> +               info->descriptor = tmp;
> +               info->data = gfc_conv_descriptor_data_get (tmp);
> +               info->offset = gfc_conv_descriptor_offset_get (tmp);
> +               for (gfc_ss *s = ss; s; s = s->parent)
> +                 for (int n = 0; n < s->dimen; n++)
> +                   {
> +                     int dim = s->dim[n];
> +                     tree tree_dim = gfc_rank_cst[dim];
> +
> +                     tree start = gfc_conv_descriptor_lbound_get (tmp,
> tree_dim);
> +                     start = gfc_evaluate_now (start, &outer_loop->pre);
> +                     info->start[dim] = start;
> +
> +                     tree end = gfc_conv_descriptor_ubound_get (tmp,
> tree_dim);
> +                     end = gfc_evaluate_now (end, &outer_loop->pre);
> +                     info->end[dim] = end;
> +
> +                     tree stride = gfc_conv_descriptor_stride_get (tmp,
> tree_dim);
> +                     stride = gfc_evaluate_now (stride, &outer_loop->pre);
> +                     info->stride[dim] = stride;
> +                   }
> +             }
> +           gfc_add_block_to_block (&outer_loop->post, &se.post);
> +           gfc_add_block_to_block (&outer_loop->post, &se.finalblock);
> +           ss_info->string_length = se.string_length;
> +         }
>           break;
>
>         case GFC_SS_CONSTRUCTOR:
> @@ -5383,7 +5407,8 @@ done:
>               int dim = ss->dim[n];
>
>               info->start[dim]  = gfc_index_zero_node;
> -             info->end[dim]    = gfc_index_zero_node;
> +             if (ss_info->type != GFC_SS_FUNCTION)
> +               info->end[dim]    = gfc_index_zero_node;
>               info->stride[dim] = gfc_index_one_node;
>             }
>           break;
> @@ -6068,6 +6093,46 @@ set_loop_bounds (gfc_loopinfo *loop)
>  }
>
>
> +/* Last attempt to set the loop bounds, in case they depend on an
> allocatable
> +   function result.  */
> +
> +static void
> +late_set_loop_bounds (gfc_loopinfo *loop)
> +{
> +  int n, dim;
> +  gfc_array_info *info;
> +  gfc_ss **loopspec;
> +
> +  loopspec = loop->specloop;
> +
> +  for (n = 0; n < loop->dimen; n++)
> +    {
> +      /* Set the extents of this range.  */
> +      if (loop->from[n] == NULL_TREE
> +         || loop->to[n] == NULL_TREE)
> +       {
> +         /* We should have found the scalarization loop specifier.  If
> not,
> +            that's bad news.  */
> +         gcc_assert (loopspec[n]);
> +
> +         info = &loopspec[n]->info->data.array;
> +         dim = loopspec[n]->dim[n];
> +
> +         if (loopspec[n]->info->type == GFC_SS_FUNCTION
> +             && info->start[dim]
> +             && info->end[dim])
> +           {
> +             loop->from[n] = info->start[dim];
> +             loop->to[n] = info->end[dim];
> +           }
> +       }
> +    }
> +
> +  for (loop = loop->nested; loop; loop = loop->next)
> +    late_set_loop_bounds (loop);
> +}
> +
> +
>  /* Initialize the scalarization loop.  Creates the loop variables.
> Determines
>     the range of the loop variables.  Creates a temporary if required.
>     Also generates code for scalar expressions which have been
> @@ -6086,6 +6151,8 @@ gfc_conv_loop_setup (gfc_loopinfo * loop, locus *
> where)
>       allocating the temporary.  */
>    gfc_add_loop_ss_code (loop, loop->ss, false, where);
>
> +  late_set_loop_bounds (loop);
> +
>    tmp_ss = loop->temp_ss;
>    /* If we want a temporary then create it.  */
>    if (tmp_ss != NULL)
> @@ -6142,9 +6209,11 @@ gfc_set_delta (gfc_loopinfo *loop)
>        gfc_ss_type ss_type;
>
>        ss_type = ss->info->type;
> -      if (ss_type != GFC_SS_SECTION
> -         && ss_type != GFC_SS_COMPONENT
> -         && ss_type != GFC_SS_CONSTRUCTOR)
> +      if (!(ss_type == GFC_SS_SECTION
> +           || ss_type == GFC_SS_COMPONENT
> +           || ss_type == GFC_SS_CONSTRUCTOR
> +           || (ss_type == GFC_SS_FUNCTION
> +               && gfc_is_class_array_function (ss->info->expr))))
>         continue;
>
>        info = &ss->info->data.array;
> diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
> index 0db7ba3fd52..bfc38add72d 100644
> --- a/gcc/fortran/trans-expr.cc
> +++ b/gcc/fortran/trans-expr.cc
> @@ -5485,16 +5485,6 @@ gfc_conv_subref_array_arg (gfc_se *se, gfc_expr *
> expr, int g77,
>    /* Translate the expression.  */
>    gfc_conv_expr (&rse, expr);
>
> -  /* Reset the offset for the function call since the loop
> -     is zero based on the data pointer.  Note that the temp
> -     comes first in the loop chain since it is added second.  */
> -  if (gfc_is_class_array_function (expr))
> -    {
> -      tmp = loop.ss->loop_chain->info->data.array.descriptor;
> -      gfc_conv_descriptor_offset_set (&loop.pre, tmp,
> -                                     gfc_index_zero_node);
> -    }
> -
>    gfc_conv_tmp_array_ref (&lse);
>
>    if (intent != INTENT_OUT)
> @@ -8864,28 +8854,9 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol *
> sym,
>           && se->expr && GFC_CLASS_TYPE_P (TREE_TYPE (se->expr))
>           && expr->must_finalize)
>         {
> -         int n;
> -         if (se->ss && se->ss->loop)
> -           {
> -             gfc_add_block_to_block (&se->ss->loop->pre, &se->pre);
> -             se->expr = gfc_evaluate_now (se->expr, &se->ss->loop->pre);
> -             tmp = gfc_class_data_get (se->expr);
> -             info->descriptor = tmp;
> -             info->data = gfc_conv_descriptor_data_get (tmp);
> -             info->offset = gfc_conv_descriptor_offset_get (tmp);
> -             for (n = 0; n < se->ss->loop->dimen; n++)
> -               {
> -                 tree dim = gfc_rank_cst[n];
> -                 se->ss->loop->to[n] = gfc_conv_descriptor_ubound_get
> (tmp, dim);
> -                 se->ss->loop->from[n] = gfc_conv_descriptor_lbound_get
> (tmp, dim);
> -               }
> -           }
> -         else
> -           {
> -             /* TODO Eliminate the doubling of temporaries. This
> -                one is necessary to ensure no memory leakage.  */
> -             se->expr = gfc_evaluate_now (se->expr, &se->pre);
> -           }
> +         /* TODO Eliminate the doubling of temporaries. This
> +            one is necessary to ensure no memory leakage.  */
> +         se->expr = gfc_evaluate_now (se->expr, &se->pre);
>
>           /* Finalize the result, if necessary.  */
>           attr = expr->value.function.esym
> diff --git a/gcc/testsuite/gfortran.dg/class_elemental_1.f90
> b/gcc/testsuite/gfortran.dg/class_elemental_1.f90
> new file mode 100644
> index 00000000000..43ebd041917
> --- /dev/null
> +++ b/gcc/testsuite/gfortran.dg/class_elemental_1.f90
> @@ -0,0 +1,34 @@
> +! { dg-do run }
> +!
> +! The polymorphic function result as actual argument used to force the
> loop
> +! bounds around the elemental call, altering access to the other arrays.
> +
> +program p
> +  implicit none
> +  type :: t
> +    integer :: i
> +  end type
> +  type :: u
> +    integer :: i, a
> +  end type
> +  type(u) :: accum(5)
> +  integer :: a(3:7), k
> +  a = [ (k*k, k=1,5) ]
> +  call s(accum, f(), a)
> +  ! print *, accum%i
> +  ! print *, accum%a
> +  if (any(accum%i /= accum%a)) error stop 1
> +contains
> +  elemental subroutine s(l, c, a)
> +    type(u)  , intent(out) :: l
> +    class(t) , intent(in)  :: c
> +    integer  , intent(in)  :: a
> +    l%i = c%i
> +    l%a = a
> +  end subroutine
> +  function f()
> +    class(t), allocatable :: f(:)
> +    allocate(f(-1:3))
> +    f%i = [ (k*k, k=1,5) ]
> +  end function
> +end program
> --
> 2.47.2
>
>

Reply via email to