Hi All,

The failing testcase came about because the array reference in the TYPE IS
block required the correct value of the span. The fix separates out
unlimited polymorphic expressions in gfc_get_array_span and ensures that
the value returned is the originating array span, rather than the element
size. This is done by extracting the class container and then the class
data.

The other tweak in gfc_get_array_span makes the logic rather clearer by
identifying class dummy references as being the only cases where 'desc' is
not a component of a class container.

OK for mainline and backporting to the affected, active branches after a
couple of weeks?

Paul
diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index a52bde90bd2..e888b737bec 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 98133b48960..8f8bdbf0069 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/pr109435.f90 b/gcc/testsuite/gfortran.dg/pr109435.f90
new file mode 100644
index 00000000000..7326c2e71a5
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr109435.f90
@@ -0,0 +1,77 @@
+! { dg-do run }
+!
+! Test the fix for PR109435 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
+

Attachment: Change.Logs
Description: Binary data

Reply via email to