Hi Mikael,

This looks fine to me. OK for mainline.

Thanks for the fix.

Paul


On Sat, 26 Jul 2025 at 20:31, Mikael Morin <morin-mik...@orange.fr> wrote:

> From: Mikael Morin <mik...@gcc.gnu.org>
>
> Regression-tested on x86_64-pc-linux-gnu.
> OK for master?
>
> -- >8 --
>
> Don't look for a class container too far after an array descriptor.
> This avoids generating a polymorphic array reference, using the virtual
> table of a parent object, to access a non-polymorphic child having a
> type unrelated to that of the parent.
>
>         PR fortran/121185
>
> gcc/fortran/ChangeLog:
>
>         * trans-expr.cc (gfc_get_class_from_expr): Give up class
>         descriptor lookup on the second COMPONENT_REF after an array
>         descriptor.
>
> gcc/testsuite/ChangeLog:
>
>         * gfortran.dg/assign_13.f90: New test.
> ---
>  gcc/fortran/trans-expr.cc               | 21 +++++++++++++++++++++
>  gcc/testsuite/gfortran.dg/assign_13.f90 | 25 +++++++++++++++++++++++++
>  2 files changed, 46 insertions(+)
>  create mode 100644 gcc/testsuite/gfortran.dg/assign_13.f90
>
> diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
> index 7c7621571ad..6cb2b677937 100644
> --- a/gcc/fortran/trans-expr.cc
> +++ b/gcc/fortran/trans-expr.cc
> @@ -714,6 +714,8 @@ gfc_get_class_from_expr (tree expr)
>  {
>    tree tmp;
>    tree type;
> +  bool array_descr_found = false;
> +  bool comp_after_descr_found = false;
>
>    for (tmp = expr; tmp; tmp = TREE_OPERAND (tmp, 0))
>      {
> @@ -725,6 +727,8 @@ gfc_get_class_from_expr (tree expr)
>         {
>           if (GFC_CLASS_TYPE_P (type))
>             return tmp;
> +         if (GFC_DESCRIPTOR_TYPE_P (type))
> +           array_descr_found = true;
>           if (type != TYPE_CANONICAL (type))
>             type = TYPE_CANONICAL (type);
>           else
> @@ -732,6 +736,23 @@ gfc_get_class_from_expr (tree expr)
>         }
>        if (VAR_P (tmp) || TREE_CODE (tmp) == PARM_DECL)
>         break;
> +
> +      /* Avoid walking up the reference chain too far.  For class arrays,
> the
> +        array descriptor is a direct component (through a pointer) of the
> class
> +        container.  So there is exactly one COMPONENT_REF between a class
> +        container and its child array descriptor.  After seeing an array
> +        descriptor, we can give up on the second COMPONENT_REF we see, if
> no
> +        class container was found until that point.  */
> +      if (array_descr_found)
> +       {
> +         if (comp_after_descr_found)
> +           {
> +             if (TREE_CODE (tmp) == COMPONENT_REF)
> +               return NULL_TREE;
> +           }
> +         else if (TREE_CODE (tmp) == COMPONENT_REF)
> +           comp_after_descr_found = true;
> +       }
>      }
>
>    if (POINTER_TYPE_P (TREE_TYPE (tmp)))
> diff --git a/gcc/testsuite/gfortran.dg/assign_13.f90
> b/gcc/testsuite/gfortran.dg/assign_13.f90
> new file mode 100644
> index 00000000000..262ade0997a
> --- /dev/null
> +++ b/gcc/testsuite/gfortran.dg/assign_13.f90
> @@ -0,0 +1,25 @@
> +! { dg-do run }
> +!
> +! PR fortran/121185
> +! The assignment to Y%X in CHECK_T was using a polymorphic array access
> on the
> +! left hand side, using the virtual table of Y.
> +
> +program p
> +  implicit none
> +  type t
> +     complex, allocatable :: x(:)
> +  end type t
> +  real :: trace = 2.
> +  type(t) :: z
> +  z%x = [1,2] * trace
> +  call check_t (z)
> +contains
> +  subroutine check_t (y)
> +    class(t) :: y
> +    ! print *, y% x
> +    if (any(y%x /= [2., 4.])) error stop 11
> +    y%x = y%x / trace
> +    ! print *, y% x
> +    if (any(y%x /= [1., 2.])) error stop 12
> +  end subroutine
> +end
> --
> 2.47.2
>
>

Reply via email to