public inbox for fortran@gcc.gnu.org
 help / color / mirror / Atom feed
* [Fortran, Patch, PR 96992] Fix Class arrays of different ranks are rejected as storage association argument
@ 2024-06-14 15:05 Andre Vehreschild
  2024-06-16 21:27 ` Harald Anlauf
  0 siblings, 1 reply; 4+ messages in thread
From: Andre Vehreschild @ 2024-06-14 15:05 UTC (permalink / raw)
  To: GCC-Patches-ML, GCC-Fortran-ML

[-- Attachment #1: Type: text/plain, Size: 661 bytes --]

Hi all,

I somehow got assigned to this PR so I fixed it. GFortran was ICEing because of
the ASSUME_RANK in a derived to class conversion. After fixing this, storage
association was producing segfaults. The "shape conversion" of the class array
as dummy argument was not initializing the dim 0 stride and with that grabbing
into the memory somewhere. This is now fixed and

regtests fine on x86_64 Fedora 39. Ok for mainline?

I assume this patch could be fixing some other PRs with class array's parameter
passing, too. If that sounds familiar, feel free to point me to them.

Regards,
	Andre
--
Andre Vehreschild * Email: vehre ad gmx dot de

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: pr96992_1.patch --]
[-- Type: text/x-patch, Size: 4701 bytes --]

From 86ac3179e1314ca1c41f52025c5a156ad7346dc1 Mon Sep 17 00:00:00 2001
From: Andre Vehreschild <vehre@gcc.gnu.org>
Date: Fri, 14 Jun 2024 16:54:37 +0200
Subject: [PATCH] Fortran: [PR96992] Fix rejecting class arrays of different
 ranks as storage association argument.

Removing the assert in trans-expr, lead to initial strides not set
which is not fixed.

	PR fortran/96992

gcc/fortran/ChangeLog:

	* trans-array.cc (gfc_trans_array_bounds): Set a starting
	stride, when descriptor expects a variable for the stride.
	(gfc_trans_dummy_array_bias): Allow storage association for
	dummy class arrays, when they are not elemental.
	* trans-expr.cc (gfc_conv_derived_to_class): Remove assert to
	allow converting derived to class type arrays with assumend
	rank.

gcc/testsuite/ChangeLog:

	* gfortran.dg/pr96992.f90: New test.
---
 gcc/fortran/trans-array.cc            |  7 ++-
 gcc/fortran/trans-expr.cc             |  2 -
 gcc/testsuite/gfortran.dg/pr96992.f90 | 61 +++++++++++++++++++++++++++
 3 files changed, 67 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/pr96992.f90

diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index b3088a892c8..9fa8bad2f35 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -6798,6 +6798,9 @@ gfc_trans_array_bounds (tree type, gfc_symbol * sym, tree * poffset,

   size = gfc_index_one_node;
   offset = gfc_index_zero_node;
+  stride = GFC_TYPE_ARRAY_STRIDE (type, 0);
+  if (stride && VAR_P (stride))
+    gfc_add_modify (pblock, stride, gfc_index_one_node);
   for (dim = 0; dim < as->rank; dim++)
     {
       /* Evaluate non-constant array bound expressions.
@@ -7134,7 +7137,9 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc,
       || (is_classarray && CLASS_DATA (sym)->attr.allocatable))
     return;

-  if (!is_classarray && sym->attr.dummy && gfc_is_nodesc_array (sym))
+  if ((!is_classarray
+       || (is_classarray && CLASS_DATA (sym)->as->type == AS_EXPLICIT))
+      && sym->attr.dummy && !sym->attr.elemental && gfc_is_nodesc_array (sym))
     {
       gfc_trans_g77_array (sym, block);
       return;
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index 0796fb75505..4bb62cfb1ad 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -903,8 +903,6 @@ gfc_conv_derived_to_class (gfc_se *parmse, gfc_expr *e,

 	  if (e->rank != class_ts.u.derived->components->as->rank)
 	    {
-	      gcc_assert (class_ts.u.derived->components->as->type
-			  == AS_ASSUMED_RANK);
 	      if (derived_array
 		  && GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (parmse->expr)))
 		{
diff --git a/gcc/testsuite/gfortran.dg/pr96992.f90 b/gcc/testsuite/gfortran.dg/pr96992.f90
new file mode 100644
index 00000000000..c56ed80f394
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr96992.f90
@@ -0,0 +1,61 @@
+! { dg-do run }
+
+! PR fortran/96992
+
+! Contributed by Thomas Koenig  <tkoenig@gcc.gnu.org>
+
+! From the standard:
+! An actual argument that represents an element sequence and
+! corresponds to a dummy argument that is an array is sequence
+! associated with the dummy argument. The rank and shape of the
+! actual argument need not agree with the rank and shape of the
+! dummy argument, but the number of elements in the dummy argument
+! shall not exceed the number of elements in the element sequence
+! of the actual argument. If the dummy argument is assumed-size,
+! the number of elements in the dummy argument is exactly
+! the number of elements in the element sequence.
+
+! Check that walking the sequence starts with an initialized stride
+! for dim == 0.
+
+module foo_mod
+  implicit none
+  type foo
+     integer :: i
+  end type foo
+contains
+  subroutine d1(x,n)
+    integer, intent(in) :: n
+    integer :: i
+    class (foo), intent(out), dimension(n) :: x
+    select type(x)
+    class is(foo)
+       x(:)%i = (/ (42 + i, i = 1, n ) /)
+    class default
+       stop 1
+    end select
+  end subroutine d1
+  subroutine d2(x,n)
+    integer, intent(in) :: n
+    integer :: i
+    class (foo), intent(in), dimension(n,n,n) :: x
+    select type (x)
+    class is (foo)
+       print *,x%i
+       if ( any( x%i /= reshape((/ (42 + i, i = 1, n ** 3 ) /), [n, n, n] ))) stop 2
+    class default
+       stop 3
+    end select
+  end subroutine d2
+end module foo_mod
+program main
+  use foo_mod
+  implicit none
+  type (foo), dimension(:), allocatable :: f
+  integer :: n
+  n = 3
+  allocate (f(n*n*n))
+  call d1(f,n*n*n)
+  call d2(f,n)
+end program main
+
--
2.45.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Fortran, Patch, PR 96992] Fix Class arrays of different ranks are rejected as storage association argument
  2024-06-14 15:05 [Fortran, Patch, PR 96992] Fix Class arrays of different ranks are rejected as storage association argument Andre Vehreschild
@ 2024-06-16 21:27 ` Harald Anlauf
  2024-06-19  7:07   ` Andre Vehreschild
  0 siblings, 1 reply; 4+ messages in thread
From: Harald Anlauf @ 2024-06-16 21:27 UTC (permalink / raw)
  To: Andre Vehreschild, GCC-Patches-ML, GCC-Fortran-ML

Hi Andre,

Am 14.06.24 um 17:05 schrieb Andre Vehreschild:
> Hi all,
>
> I somehow got assigned to this PR so I fixed it. GFortran was ICEing because of
> the ASSUME_RANK in a derived to class conversion. After fixing this, storage
> association was producing segfaults. The "shape conversion" of the class array
> as dummy argument was not initializing the dim 0 stride and with that grabbing
> into the memory somewhere. This is now fixed and
>
> regtests fine on x86_64 Fedora 39. Ok for mainline?

the patch fixes the testcase in your submission, but not the following
slight variation of the main program:

module foo_mod
   implicit none
   type foo
      integer :: i
   end type foo
contains
   subroutine d1(x,n)
     integer, intent(in) :: n
     integer :: i
     class (foo), intent(out) :: x(n)
     select type(x)
     class is(foo)
        x(:)%i = (/ (42 + i, i = 1, n ) /)
     class default
        stop 1
     end select
   end subroutine d1
   subroutine d2(x,n)
     integer, intent(in) :: n
     integer :: i
     class (foo), intent(in) :: x(n,n,n)
     select type (x)
     class is (foo)
        print *,x%i
        if ( any( x%i /= reshape((/ (42 + i, i = 1, n ** 3 ) /), [n, n,
n] ))) stop 2
     class default
        stop 3
     end select
   end subroutine d2
end module foo_mod
program main
   use foo_mod
   implicit none
   type (foo), dimension(:), allocatable :: f
   integer :: n
   n = 2
   allocate (f(n*n*n))
   ! Original testcase:
   call d1(f,n*n*n)
   call d2(f,n)                  ! OK
   call d1(f(1:n*n*n),n*n*n)
   print *, "After call d1(f(1:n*n*n:1),n*n*n):"
   print *, f%i
   call d2(f(1:n*n*n),n)         ! OK
   ! Using stride -1:
   call d1(f(n*n*n:1:-1),n*n*n)
   print *, "After call d1(f(n*n*n:1:-1),n*n*n):"
   print *, f%i
   call d2(f(n*n*n:1:-1),n)      ! not OK
   deallocate (f)
end program main

While this runs fine with the latest Intel compiler, gfortran including
your patch prints:

           43          44          45          46          47
48          49          50
  After call d1(f(1:n*n*n:1),n*n*n):
           43          44          45          46          47
48          49          50
           43          44          45          46          47
48          49          50
  After call d1(f(n*n*n:1:-1),n*n*n):
           50          49          48          47          46
45          44          43
           43           0           0          49           0
34244976           0    34238480
STOP 2

So while the negative stride (-1) in the call to d1 appears to
work as it should, it does not work properly for the call to d2.
The first array element is fine in d2, but anything else isn't.

Do you see what goes wrong here?

(This may be a more general, pre-existing issue in a different place.)

Thanks,
Harald

P.S.: regarding your commit message, I think the reference to the pr
in brackets should be moved to the end of the summary line, i.e. for

Fortran: [PR96992] Fix rejecting class arrays of different ranks as
storage association argument.

the "[PR96992" should be moved.  Makes it also easier to read.

> I assume this patch could be fixing some other PRs with class array's parameter
> passing, too. If that sounds familiar, feel free to point me to them.
>
> Regards,
> 	Andre
> --
> Andre Vehreschild * Email: vehre ad gmx dot de


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Fortran, Patch, PR 96992] Fix Class arrays of different ranks are rejected as storage association argument
  2024-06-16 21:27 ` Harald Anlauf
@ 2024-06-19  7:07   ` Andre Vehreschild
  2024-06-19 19:17     ` Harald Anlauf
  0 siblings, 1 reply; 4+ messages in thread
From: Andre Vehreschild @ 2024-06-19  7:07 UTC (permalink / raw)
  To: Harald Anlauf; +Cc: GCC-Patches-ML, GCC-Fortran-ML

[-- Attachment #1: Type: text/plain, Size: 626 bytes --]

Hi Harald,

thank you for the investigation and useful tips. I had to figure what went
wrong here, but I now figured, that the array needs repacking when a negative
stride is used (or at least a call to that routine, which then fixes "stuff").
I have added it, freeing the memory allocated potentially by pack, and also
updated the testcase to include the negative stride.

Regtests fine on x86_64-pc-linux-gnu/Fedora 39. Ok for mainline?

Regards,
	Andre

On Sun, 16 Jun 2024 23:27:46 +0200
Harald Anlauf <anlauf@gmx.de> wrote:

<< snipped for brevity >>>
--
Andre Vehreschild * Email: vehre ad gmx dot de

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: pr96992_2.patch --]
[-- Type: text/x-patch, Size: 6606 bytes --]

From c0c95afa95bb682385e47cc248f04e6eecd91e6d Mon Sep 17 00:00:00 2001
From: Andre Vehreschild <vehre@gcc.gnu.org>
Date: Fri, 14 Jun 2024 16:54:37 +0200
Subject: [PATCH] Fortran: Fix rejecting class arrays of different ranks as
 storage association argument.

Removing the assert in trans-expr, lead to initial strides not set
which is not fixed.  When the array needs repacking, this is done for
class arrays now, too.

	PR fortran/96992

gcc/fortran/ChangeLog:

	* trans-array.cc (gfc_trans_array_bounds): Set a starting
	stride, when descriptor expects a variable for the stride.
	(gfc_trans_dummy_array_bias): Allow storage association for
	dummy class arrays, when they are not elemental.
	* trans-expr.cc (gfc_conv_derived_to_class): Remove assert to
	allow converting derived to class type arrays with assumed
	rank.  Add packing when necessary.

gcc/testsuite/ChangeLog:

	* gfortran.dg/pr96992.f90: New test.
---
 gcc/fortran/trans-array.cc            |  7 ++-
 gcc/fortran/trans-expr.cc             | 31 ++++++++++++-
 gcc/testsuite/gfortran.dg/pr96992.f90 | 66 +++++++++++++++++++++++++++
 3 files changed, 101 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/pr96992.f90

diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index 24a9a51692c..573e056d7c6 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -6798,6 +6798,9 @@ gfc_trans_array_bounds (tree type, gfc_symbol * sym, tree * poffset,

   size = gfc_index_one_node;
   offset = gfc_index_zero_node;
+  stride = GFC_TYPE_ARRAY_STRIDE (type, 0);
+  if (stride && VAR_P (stride))
+    gfc_add_modify (pblock, stride, gfc_index_one_node);
   for (dim = 0; dim < as->rank; dim++)
     {
       /* Evaluate non-constant array bound expressions.
@@ -7143,7 +7146,9 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc,
       || (is_classarray && CLASS_DATA (sym)->attr.allocatable))
     return;

-  if (!is_classarray && sym->attr.dummy && gfc_is_nodesc_array (sym))
+  if ((!is_classarray
+       || (is_classarray && CLASS_DATA (sym)->as->type == AS_EXPLICIT))
+      && sym->attr.dummy && !sym->attr.elemental && gfc_is_nodesc_array (sym))
     {
       gfc_trans_g77_array (sym, block);
       return;
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index 0796fb75505..4468163e482 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -874,6 +874,7 @@ gfc_conv_derived_to_class (gfc_se *parmse, gfc_expr *e,
 	  stmtblock_t block;
 	  gfc_init_block (&block);
 	  gfc_ref *ref;
+	  tree maybetmp = NULL_TREE, origdata = NULL_TREE;

 	  parmse->ss = ss;
 	  parmse->use_offset = 1;
@@ -903,8 +904,29 @@ gfc_conv_derived_to_class (gfc_se *parmse, gfc_expr *e,

 	  if (e->rank != class_ts.u.derived->components->as->rank)
 	    {
-	      gcc_assert (class_ts.u.derived->components->as->type
-			  == AS_ASSUMED_RANK);
+	      tree desc;
+
+	      desc = parmse->expr;
+	      if (VAR_P (desc) && GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc))
+		  && !GFC_DECL_PACKED_ARRAY (desc)
+		  && !GFC_DECL_PARTIAL_PACKED_ARRAY (desc))
+		{
+		  origdata = gfc_evaluate_now (
+		    fold_convert (pvoid_type_node,
+				  gfc_conv_descriptor_data_get (desc)),
+		    &block);
+		  tmp = gfc_build_addr_expr (NULL, desc);
+		  tmp = build_call_expr (gfor_fndecl_in_pack, 1, tmp);
+		  maybetmp = gfc_evaluate_now (tmp, &block);
+		  gfc_conv_descriptor_data_set (&block, desc, maybetmp);
+		  /* Add code to free eventually allocated temporary array
+		     from pack.  */
+		  tmp = fold_build2 (NE_EXPR, boolean_type_node, maybetmp,
+				     origdata);
+		  tmp = build3_v (COND_EXPR, tmp, gfc_call_free (maybetmp),
+				  build_empty_stmt (input_location));
+		  gfc_add_expr_to_block (&parmse->post, tmp);
+		}
 	      if (derived_array
 		  && GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (parmse->expr)))
 		{
@@ -933,6 +955,11 @@ gfc_conv_derived_to_class (gfc_se *parmse, gfc_expr *e,
 	      if (derived_array && *derived_array != NULL_TREE)
 		gfc_conv_descriptor_data_set (&block, *derived_array,
 					      null_pointer_node);
+	      if (maybetmp)
+		{
+		  gfc_add_modify (&block, maybetmp, null_pointer_node);
+		  gfc_add_modify (&block, origdata, null_pointer_node);
+		}

 	      tmp = build3_v (COND_EXPR, cond_optional, tmp,
 			      gfc_finish_block (&block));
diff --git a/gcc/testsuite/gfortran.dg/pr96992.f90 b/gcc/testsuite/gfortran.dg/pr96992.f90
new file mode 100644
index 00000000000..e4b38ef35f0
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr96992.f90
@@ -0,0 +1,66 @@
+! { dg-do run }
+
+! PR fortran/96992
+
+! Contributed by Thomas Koenig  <tkoenig@gcc.gnu.org>
+
+! From the standard:
+! An actual argument that represents an element sequence and
+! corresponds to a dummy argument that is an array is sequence
+! associated with the dummy argument. The rank and shape of the
+! actual argument need not agree with the rank and shape of the
+! dummy argument, but the number of elements in the dummy argument
+! shall not exceed the number of elements in the element sequence
+! of the actual argument. If the dummy argument is assumed-size,
+! the number of elements in the dummy argument is exactly
+! the number of elements in the element sequence.
+
+! Check that walking the sequence starts with an initialized stride
+! for dim == 0.
+
+module foo_mod
+  implicit none
+  type foo
+     integer :: i
+  end type foo
+contains
+  subroutine d1(x,n)
+    integer, intent(in) :: n
+    integer :: i
+    class (foo), intent(out), dimension(n) :: x
+    select type(x)
+    class is(foo)
+       x(:)%i = (/ (42 + i, i = 1, n ) /)
+    class default
+       stop 1
+    end select
+  end subroutine d1
+  subroutine d2(x,n)
+    integer, intent(in) :: n
+    integer :: i
+    class (foo), intent(in), dimension(n,n,n) :: x
+    select type (x)
+    class is (foo)
+       if ( any( x%i /= reshape((/ (42 + i, i = 1, n ** 3 ) /), [n, n, n] ))) stop 2
+    class default
+       stop 3
+    end select
+  end subroutine d2
+end module foo_mod
+program main
+  use foo_mod
+  implicit none
+  type (foo), dimension(:), allocatable :: f
+  integer :: n,i
+  n = 3
+  allocate (f(n*n*n))
+  call d1(f,n*n*n)
+  call d2(f,n)
+
+  ! Use negative stride
+  call d1(f(n*n*n:1:-1),n*n*n)
+  if ( any( f%i /= (/ (42 + i, i = n ** 3, 1, -1 ) /) )) stop 4
+  call d2(f(n*n*n:1:-1),n)
+  deallocate (f)
+end program main
+
--
2.45.2


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Fortran, Patch, PR 96992] Fix Class arrays of different ranks are rejected as storage association argument
  2024-06-19  7:07   ` Andre Vehreschild
@ 2024-06-19 19:17     ` Harald Anlauf
  0 siblings, 0 replies; 4+ messages in thread
From: Harald Anlauf @ 2024-06-19 19:17 UTC (permalink / raw)
  To: Andre Vehreschild; +Cc: GCC-Patches-ML, GCC-Fortran-ML

Hi Andre,

Am 19.06.24 um 09:07 schrieb Andre Vehreschild:
> Hi Harald,
>
> thank you for the investigation and useful tips. I had to figure what went
> wrong here, but I now figured, that the array needs repacking when a negative
> stride is used (or at least a call to that routine, which then fixes "stuff").
> I have added it, freeing the memory allocated potentially by pack, and also
> updated the testcase to include the negative stride.

hmmm, the pack does not always get generated:

module foo_mod
   implicit none
   type foo
      integer :: i
   end type foo
contains
   subroutine d1(x,n)
     integer, intent(in) :: n
     integer :: i
     class (foo), intent(out) :: x(n)
     select type(x)
     class is(foo)
        x(:)%i = (/ (42 + i, i = 1, n ) /)
     class default
        stop 1
     end select
   end subroutine d1
   subroutine d2(x,n)
     integer, intent(in) :: n
     integer :: i
     class (foo), intent(in) :: x(n,n,n)
     select type (x)
     class is (foo)
        print *,"d2:  ", x%i
        if ( any( x%i /= reshape((/ (42 + i, i = 1, n ** 3 ) /), [n, n,
n] ))) stop 2
     class default
        stop 3
     end select
   end subroutine d2

   subroutine d3(x,n)
     integer, intent(in) :: n
     integer :: i
     class (foo), intent(inout) :: x(n)
     select type (x)
     class is (foo)
        print *,"d3_1:", x%i
        x%i = -x%i               ! Simply negate elements
        print *,"d3_2:", x%i
     class default
        stop 33
     end select
   end subroutine d3
end module foo_mod
program main
   use foo_mod
   implicit none
   type (foo), dimension(:), allocatable :: f
   integer :: n, k, m
   n = 2
   allocate (f(n*n*n))
   ! Original testcase:
   call d1(f,n*n*n)
   print *, "d1->:", f%i
   call d2(f,n)
   ! Ensure that array f is ok:
   print *, "d2->:", f%i

   ! The following shows that no appropriate internal pack is generated:
   call d1(f,n*n*n)
   print *, "d1->:", f%i
   m = n*n*n
   k = 3
   print *, "->d3:", f(1:m:k)%i
   call d3(f(1:m:k),1+(m-1)/k)
   print *, "d3->:", f(1:m:k)%i
   print *, "full:", f%i
   deallocate (f)
end program main


After the second version of your patch this prints:

  d1->:          43          44          45          46          47
     48          49          50
  d2:            43          44          45          46          47
     48          49          50
  d2->:          43          44          45          46          47
     48          49          50
  d1->:          43          44          45          46          47
     48          49          50
  ->d3:          43          46          49
  d3_1:          43          44          45
  d3_2:         -43         -44         -45
  d3->:         -43          46          49
  full:         -43         -44         -45          46          47
     48          49          50

While the print properly handles f(1:m:k)%i, passing it as
actual argument to subroutine d3 does not do pack/unpack.

Can you have another look?

Thanks,
Harald


> Regtests fine on x86_64-pc-linux-gnu/Fedora 39. Ok for mainline?
>
> Regards,
> 	Andre
>
> On Sun, 16 Jun 2024 23:27:46 +0200
> Harald Anlauf <anlauf@gmx.de> wrote:
>
> << snipped for brevity >>>
> --
> Andre Vehreschild * Email: vehre ad gmx dot de


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2024-06-19 19:17 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-06-14 15:05 [Fortran, Patch, PR 96992] Fix Class arrays of different ranks are rejected as storage association argument Andre Vehreschild
2024-06-16 21:27 ` Harald Anlauf
2024-06-19  7:07   ` Andre Vehreschild
2024-06-19 19:17     ` Harald Anlauf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).