diff mbox series

[fortran] PR109345 - [12/13/14/15 Regression] class(*) variable that is a string array is not handled correctly

Message ID CAGkQGiKc_5NCrsHrLswHzEFg2TkG4Zc22Of=Wy8bv8fBUzXfvA@mail.gmail.com
State New
Headers show
Series [fortran] PR109345 - [12/13/14/15 Regression] class(*) variable that is a string array is not handled correctly | expand

Commit Message

Paul Richard Thomas Nov. 10, 2024, 1:52 p.m. UTC
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

Comments

Harald Anlauf Nov. 10, 2024, 8:28 p.m. UTC | #1
Hi Paul,

this looks good to me for mainline as well as backports ...

... except that the PR number should be corrected (109345 instead of 
109435) in the testcase and the commit message (Change.logs).

Thanks for the patch!

Harald

Am 10.11.24 um 14:52 schrieb Paul Richard Thomas:
> 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
>
Paul Richard Thomas Nov. 11, 2024, 9:20 a.m. UTC | #2
>
> Hi Harald,
>

Thanks for the review!


> ... except that the PR number should be corrected (109345 instead of
> 109435) in the testcase and the commit message (Change.logs).
>
> Dyslexics of the world untie!

Paul
diff mbox series

Patch

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  <lchilutti@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
+