On 10/23/19 8:12 PM, Steve Kargl wrote:
        * trans-expr.c (gfc_conv_procedure_call): Evaluate args and then
        deallocate actual args assocated with intent(out) dummies.

I think the patch by itself looks fine to me – except that the saw_dealloc is not needed. You can either check "if (dealloc_blk->head)" or you can use gfc_add_block_to_block unconditionally as it handles NULL_TREE.

However, the following test case shows that expressions which can be transferred into a tree (se->expr) without needing more evaluations and a temporary (i.e. evaluating things in se->pre) do not work. – The allocated(a) check is really artificial, however, the test() call looks as if it might appear in the real world. First the dump:

    foo ((integer(kind=4)[0:] * restrict) a.data != 0B, (integer(kind=4)) MAX_EXPR <(D.3958->dim[0].ubound - D.3958->dim[0].lbound) + 1, 0>, test ((integer(kind=4)[0:] * restrict) a.data), &a);

And then the test case:

implicit none (type, external)
integer, allocatable :: a(:)
a = [1, 2]
call foo(allocated(a), size(a), test(a), a)
contains
subroutine foo(alloc, sz, tst, x)
  logical, value :: alloc, tst
  integer, value :: sz
  integer, allocatable, intent(out) :: x(:)
  if (allocated(x)) stop 1
  if (.not.alloc) stop 2
  if (sz /= 2) stop 3
  if (.not. tst) stop 4
end subroutine foo
logical function test(zz)
  integer :: zz(2)
  test = zz(2) == 2
end function test
end

Hence, I wonder whether one needs to do (pseudo code):

if (any dummy argument is allocatable + intent-out)
  force_func_eval = true
if (actual is an expression + force_func_eval)
  parmse->expr =  gfc_evaluate_now (parmse->expr, &parmse)

Such that one uses a temporary variable for those, but keeps the status quo for 
the rest.

Note, in gfc_conv_procedure_call() there are 3 blocks of
code that deal with the deallocation of actual arguments
assocated with intent(out) dummy arguments.  The patch
affects the first and third blocks.  The 2nd block, lines
6071-6111, concerns CLASS and finalization.  I use neither,
so have no idea what Fortran requires.  More importantly,
I have very little understanding of gfortran's internal
implementation for CLASS and finalization.  Someone who
cares about CLASS and finalization will need to consider
how to possibly fix a possible issue.

I wonder how to test for it. I tried to create a test case (pr92178-3.f90) but as it turns out, the deallocation happens (via zz->_vptr->_final) directly in the called function and not in the callee.

For this one, I was playing with the attached patch – but if one cannot trigger it, it might not be needed.

I have also created another test case pr92178-2.f90 which essentially does what pr92178.f90 already did (nearly same code path, covered by your patch).


The question is how to proceed from here.

Tobias

! { dg-do run }
!
! PR fortran/92178
program foo
   implicit none (type, external)

   type t0
     integer, allocatable :: X0
   end type t0

   type, extends(t0) :: t
   end type t

   type, extends(t) :: t2
   end type t2

   type(t2) :: x2
   class(t), allocatable :: aa(:)

   allocate(t2 :: aa(1))
   allocate(aa(1)%x0)
   contains
      subroutine caller(xx)
         class(t) :: xx(:)
         if (.not. allocated(xx(1)%x0)) stop 10
         if (.not. same_type_as(xx, x2)) stop 11
         call check_intentout(allocated(xx(1)%x0), same_type_as(xx, x2), xx, &
                              allocated(xx(1)%x0), same_type_as(xx, x2))
      end subroutine caller
      subroutine check_intentout(alloc1, same1, zz, alloc2, same2)
         logical, value :: alloc1, alloc2, same1, same2
         class(t0), intent(out) :: zz(:)
         if (allocated(zz(1)%x0)) stop 1
         if (.not.alloc1) stop 2
         if (.not.alloc2) stop 3
         if (.not.same1) stop 4
         if (.not.same2) stop 5
      end subroutine
end program
! { dg-do run }
!
! PR fortran/92178
program foo
   implicit none (type, external)

   type t
   end type t

   type, extends(t) :: t2
   end type t2

   type(t2) :: x2
   class(t), allocatable :: aa

   call check_intentout_false(allocated(aa), aa, &
                              allocated(aa))
   if (allocated(aa)) stop 1

   allocate(t2 :: aa)
   if (.not.allocated(aa)) stop 2
   if (.not.same_type_as(aa, x2)) stop 3
   call check_intentout_true(allocated(aa), (same_type_as(aa, x2)), aa, &
                              allocated(aa), (same_type_as(aa, x2)))
   if (allocated(aa)) stop 4

   contains
      subroutine check_intentout_false(alloc1, yy, alloc2)
         logical, value :: alloc1, alloc2
         class(t), allocatable, intent(out) :: yy
         if (allocated(yy)) stop 11
         if (alloc1) stop 12
         if (alloc2) stop 13
      end subroutine
      subroutine check_intentout_true(alloc1, same1, zz, alloc2, same2)
         logical, value :: alloc1, alloc2, same1, same2
         class(t), allocatable, intent(out) :: zz
         if (allocated(zz)) stop 21
         if (.not.alloc1) stop 22
         if (.not.alloc2) stop 23
         if (.not.same1) stop 24
         if (.not.same2) stop 25
      end subroutine
end program
diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c
index 7eba1bbd082..d44da6d02ef 100644
--- a/gcc/fortran/trans-expr.c
+++ b/gcc/fortran/trans-expr.c
@@ -5392,6 +5392,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
   gfc_component *comp = NULL;
   int arglen;
   unsigned int argc;
+  stmtblock_t dealloc_blk;
 
   arglist = NULL;
   retargs = NULL;
@@ -5432,6 +5433,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
     info = NULL;
 
   gfc_init_block (&post);
+  gfc_init_block (&dealloc_blk);
   gfc_init_interface_mapping (&mapping);
   if (!comp)
     {
@@ -5963,8 +5965,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
 			}
 		      else
 			tmp = gfc_finish_block (&block);
-
-		      gfc_add_expr_to_block (&se->pre, tmp);
+		      gfc_add_expr_to_block (&dealloc_blk, tmp);
 		    }
 
 		  if (fsym && (fsym->ts.type == BT_DERIVED
@@ -6049,6 +6050,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
 		    && (CLASS_DATA (fsym)->attr.dimension
 			|| CLASS_DATA (fsym)->attr.codimension))
 	    {
+	      gfc_se tmpse;
+
 	      /* Pass a class array.  */
 	      parmse.use_offset = 1;
 	      gfc_conv_expr_descriptor (&parmse, e);
@@ -6092,12 +6095,19 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
 		  else
 		    tmp = gfc_finish_block (&block);
 
-		  gfc_add_expr_to_block (&se->pre, tmp);
+		  gfc_add_expr_to_block (&dealloc_blk, tmp);
 		}
 
+	      /* The 'pre' part of the gfc_conv_class_to_class conversion has to
+		 come after the deallocation of INTENT_OUT, which in turn is
+		 done after all arguments have been evaluated.  */
+	      gfc_init_se (&tmpse, NULL);
+	      tmpse.expr = parmse.expr;
+	      tmpse.class_vptr = parmse.class_vptr;
+
 	      /* The conversion does not repackage the reference to a class
 	         array - _data descriptor.  */
-	      gfc_conv_class_to_class (&parmse, e, fsym->ts, false,
+	      gfc_conv_class_to_class (&tmpse, e, fsym->ts, false,
 				     fsym->attr.intent != INTENT_IN
 				     && (CLASS_DATA (fsym)->attr.class_pointer
 					 || CLASS_DATA (fsym)->attr.allocatable),
@@ -6106,6 +6116,11 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
 				     && e->symtree->n.sym->attr.optional,
 				     CLASS_DATA (fsym)->attr.class_pointer
 				     || CLASS_DATA (fsym)->attr.allocatable);
+__builtin_fprintf(stderr,"DEBUg – IS – CALLED\n");
+	      gfc_add_block_to_block (&dealloc_blk, &tmpse.pre);
+	      parmse.expr = tmpse.expr;
+	      parmse.class_vptr = tmpse.class_vptr;
+	      gfc_add_block_to_block (&parmse.post, &tmpse.post);
 	    }
 	  else
 	    {
@@ -6258,7 +6273,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
 				     void_type_node,
 				     gfc_conv_expr_present (e->symtree->n.sym),
 				       tmp, build_empty_stmt (input_location));
-		  gfc_add_expr_to_block (&se->pre, tmp);
+		  gfc_add_expr_to_block (&dealloc_blk, tmp);
 		}
 	    }
 	}
@@ -6629,6 +6644,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
 
       vec_safe_push (arglist, parmse.expr);
     }
+  gfc_add_block_to_block (&se->pre, &dealloc_blk);
   gfc_finish_interface_mapping (&mapping, &se->pre, &se->post);
 
   if (comp)

Reply via email to