https://gcc.gnu.org/g:e22d80d4f0f8d33f538c1a4bad07b2c819a6d55c
commit r15-5083-ge22d80d4f0f8d33f538c1a4bad07b2c819a6d55c Author: Paul Thomas <pa...@gcc.gnu.org> Date: Mon Nov 11 12:21:57 2024 +0000 Fortran: Fix elemental array refs in SELECT TYPE [PR109345] 2024-11-10 Paul Thomas <pa...@gcc.gnu.org> gcc/fortran PR fortran/109345 * trans-array.cc (gfc_get_array_span): Unlimited polymorphic expressions are now treated separately since the span need not be the same as the element size. gcc/testsuite/ PR fortran/109345 * gfortran.dg/character_workout_1.f90: Cut trailing whitespace. * gfortran.dg/pr109345.f90: New test. Diff: --- gcc/fortran/trans-array.cc | 44 +++++++++---- gcc/testsuite/gfortran.dg/character_workout_1.f90 | 8 +-- gcc/testsuite/gfortran.dg/pr109345.f90 | 77 +++++++++++++++++++++++ 3 files changed, 113 insertions(+), 16 deletions(-) diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc index a52bde90bd2c..e888b737bec3 100644 --- a/gcc/fortran/trans-array.cc +++ b/gcc/fortran/trans-array.cc @@ -962,6 +962,8 @@ tree gfc_get_array_span (tree desc, gfc_expr *expr) { tree tmp; + gfc_symbol *sym = expr->expr_type == EXPR_VARIABLE + ? expr->symtree->n.sym : NULL; if (is_pointer_array (desc) || (get_CFI_desc (NULL, expr, &desc, NULL) @@ -983,25 +985,43 @@ gfc_get_array_span (tree desc, gfc_expr *expr) desc = build_fold_indirect_ref_loc (input_location, desc); tmp = gfc_conv_descriptor_span_get (desc); } + else if (UNLIMITED_POLY (expr) + || (sym && UNLIMITED_POLY (sym))) + { + /* Treat unlimited polymorphic expressions separately because + the element size need not be the same as the span. Obtain + the class container, which is simplified here by their being + no component references. */ + if (sym && sym->attr.dummy) + { + tmp = gfc_get_symbol_decl (sym); + tmp = GFC_DECL_SAVED_DESCRIPTOR (tmp); + if (INDIRECT_REF_P (tmp)) + tmp = TREE_OPERAND (tmp, 0); + } + else + { + gcc_assert (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc))); + tmp = TREE_OPERAND (desc, 0); + } + tmp = gfc_class_data_get (tmp); + tmp = gfc_conv_descriptor_span_get (tmp); + } else if (TREE_CODE (desc) == COMPONENT_REF && GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc)) && GFC_CLASS_TYPE_P (TREE_TYPE (TREE_OPERAND (desc, 0)))) { - /* The descriptor is a class _data field and so use the vtable - size for the receiving span field. */ - tmp = gfc_get_vptr_from_expr (desc); + /* The descriptor is a class _data field. Use the vtable size + since it is guaranteed to have been set and is always OK for + class array descriptors that are not unlimited. */ + tmp = gfc_class_vptr_get (TREE_OPERAND (desc, 0)); tmp = gfc_vptr_size_get (tmp); } - else if (expr && expr->expr_type == EXPR_VARIABLE - && expr->symtree->n.sym->ts.type == BT_CLASS - && expr->ref->type == REF_COMPONENT - && expr->ref->next->type == REF_ARRAY - && expr->ref->next->next == NULL - && CLASS_DATA (expr->symtree->n.sym)->attr.dimension) + else if (sym && sym->ts.type == BT_CLASS && sym->attr.dummy) { - /* Dummys come in sometimes with the descriptor detached from - the class field or declaration. */ - tmp = gfc_class_vptr_get (expr->symtree->n.sym->backend_decl); + /* Class dummys usually requires extraction from the saved + descriptor, which gfc_class_vptr_get does for us. */ + tmp = gfc_class_vptr_get (sym->backend_decl); tmp = gfc_vptr_size_get (tmp); } else diff --git a/gcc/testsuite/gfortran.dg/character_workout_1.f90 b/gcc/testsuite/gfortran.dg/character_workout_1.f90 index 98133b48960a..8f8bdbf00690 100644 --- a/gcc/testsuite/gfortran.dg/character_workout_1.f90 +++ b/gcc/testsuite/gfortran.dg/character_workout_1.f90 @@ -1,7 +1,7 @@ ! { dg-do run } ! ! Tests fix for PR100120/100816/100818/100819/100821 -! +! program main_p @@ -27,10 +27,10 @@ program main_p character(len=m, kind=k), pointer :: pm(:) character(len=e, kind=k), pointer :: pe(:) character(len=:, kind=k), pointer :: pd(:) - + class(*), pointer :: su class(*), pointer :: pu(:) - + integer :: i, j nullify(s1, sm, se, sd, su) @@ -41,7 +41,7 @@ program main_p cm(i)(j:j) = char(i*m+j+c-m, kind=k) end do end do - + s1 => c1(n) if(.not.associated(s1)) stop 1 if(.not.associated(s1, c1(n))) stop 2 diff --git a/gcc/testsuite/gfortran.dg/pr109345.f90 b/gcc/testsuite/gfortran.dg/pr109345.f90 new file mode 100644 index 000000000000..cff9aaa987a0 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr109345.f90 @@ -0,0 +1,77 @@ +! { dg-do run } +! +! Test the fix for PR109345 in which array references in the SELECT TYPE +! block below failed because the descriptor span was not set correctly. +! +! Contributed by Lauren Chilutti <lchilu...@gmail.com> +! +program test + implicit none + type :: t + character(len=12, kind=4) :: str_array(4) + integer :: i + end type + character(len=12, kind=1), target :: str_array(4) + character(len=12, kind=4), target :: str_array4(4) + type(t) :: str_t (4) + integer :: i + + str_array(:) = "" + str_array(1) = "12345678" + str_array(2) = "@ABCDEFG" +! Original failing test + call foo (str_array) + + str_array4(:) = "" + str_array4(1) = "12345678" + str_array4(2) = "@ABCDEFG" + str_t = [(t(str_array4, i), i = 1, 4)] +! Test character(kind=4) + call foo (str_t(2)%str_array) +! Test component references + call foo (str_t%str_array(1), .true.) +! Test component references and that array offset is correct. + call foo (str_t(2:3)%i) + +contains + subroutine foo (var, flag) + class(*), intent(in) :: var(:) + integer(kind=4) :: i + logical, optional :: flag + select type (var) + type is (character(len=*, kind=1)) + if (len (var) /= 12) stop 1 +! Scalarised array references worked. + if (any (var /= str_array)) stop 2 + do i = 1, size(var) +! Elemental array references did not work. + if (trim (var(i)) /= trim (str_array(i))) stop 3 + enddo + + type is (character(len=*, kind=4)) + if (len (var) /= 12) stop 4 +! Scalarised array references worked. + if (any (var /= var(1))) then + if (any (var /= str_array4)) stop 5 + else + if (any (var /= str_array4(1))) stop 6 + end if + do i = 1, size(var) +! Elemental array references did not work. + if (var(i) /= var(1)) then + if (present (flag)) stop 7 + if (trim (var(i)) /= trim (str_array4(i))) stop 8 + else + if (trim (var(i)) /= trim (str_array4(1))) stop 9 + end if + enddo + + type is (integer(kind=4)) + if (any(var /= [2,3])) stop 10 + do i = 1, size (var) + if (var(i) /= i+1) stop 11 + end do + end select + end +end +