This is the mail archive of the fortran@gcc.gnu.org mailing list for the GNU Fortran project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Status of allocatable components


Erik,

Thanks for posting this. It indicates how nearly we are there. I will just add a few comments below:

* The "automatic deallocation&allocation if necessary" on assignments
is the main thing left to be done.


Are you working on this? If so, that would be great because....

* I have probably forgotten something.


... I thought to provide the modifications that are needed to the derived type constructor.

I attach the current (partly a bit ugly) version of the patch (someday,
I will clean things up and write some kind of explanation for it), and a
testcase.


I would find an explanation useful! Coming back to this after a couple of months makes me feel as if I am in the throes of a sever bout of memory loss.



Paul,

Changes I've made since last time: I've messed (= probably broken
something) a bit with the deallocation of scalar INTENT(OUT) arguments
in trans-expr.c (gfc_conv_function_call), and tried to make sure
function results aren't deallocated until after they have been used.


Yes, noted; see below for what I am now finding with the iso_varying_string testsuite.

+
+#if 0
+ case (SCALAR):
+/* This is horrible! FIXME. Problem with(eg.) vst_5.f95:205 */
+ goto get_me_out_of_here;
+#endif
+
+ case (SCALAR_POINTER):
+ tmp = build_fold_indirect_ref (tmp);
+ break;
+ case (ARRAY):
+ tmp = parmse.expr;
+ break;
+ }
+ tmp = deallocate_alloc_comp (e->ts.derived, tmp, parm_rank);
+ if (e->symtree->n.sym->result)
+ /* Don't deallocate function results until they have been used. */
+ gfc_add_expr_to_block (&se->post, tmp);
+ else
+ gfc_add_expr_to_block (&se->pre, tmp);
+ }
+
+get_me_out_of_here:
+


Your activities have made this kludge even more necessary for the IVS testcases. I think that what you have done is correct and I am on to the reasons for it - or, at least, I have found that concatenation is the primary cause of the ICEs; eg. when concatenating two iso_varying_strings when one has zero length. The operation explicitly references outside of the allocated domain. Other compilers seem able to handle this, so I suspect that there is some trick that we are missing here. I can partially get round it by modifying the fortran in the iso_varying_string module. Whether this is a bug in the module or in gfortran, I do not rightly know yet.

/* Allocatable arrays need to be freed when they go out of scope. */
+
+ /* Paul had deledted this from here ... */
+ if (sym->ts.type == BT_DERIVED && sym->ts.derived->attr.alloc_comp
+ && !(sym->attr.function || sym->attr.result))
+ {
+ int rank;
+ rank = sym->as ? sym->as->rank : 0;
+ tmp = deallocate_alloc_comp (sym->ts.derived, descriptor, rank);
+ gfc_add_expr_to_block (&fnblock, tmp);
+ }
+ /* ... to here! */
+


Rats! This was a desperate attempt to get to the bottom of the problem above. I never restored the code after the attempt - sorry!



! { dg-do run}
! { dg-options "-O2 -fdump-tree-original" }
!
! Check some basic functionality of allocatable components, including that they
! are nullified when created and automatically deallocated when
! 1. A variable goes out of scope
! 2. INTENT(OUT) dummies
! 3. Function results
!
module alloc_m

implicit none

   type :: alloc1
       real, allocatable :: x(:)
   end type alloc1

end module alloc_m


program alloc


use alloc_m

implicit none

   type :: alloc2
       type(alloc1), allocatable :: a1(:)
       integer, allocatable :: a2(:)
   end type alloc2

   type(alloc2) :: b
   integer :: i
   type(alloc2), allocatable :: c(:)

   if (allocated(b%a2) .OR. allocated(b%a1)) then
       write (0, *) 'main - 1'
       call abort()
   end if

   ! 3 calls to _gfortran_deallocate (INTENT(OUT) dummy)
   call allocate_alloc2(b)
   call check_alloc2(b)

   do i = 1, size(b%a1)
       ! 1 call to _gfortran_deallocate
       deallocate(b%a1(i)%x)
   end do

   ! 3 calls to _gfortran_deallocate (INTENT(OUT) dummy)
   call allocate_alloc2(b)

   call check_alloc2(return_alloc2())
   ! 3 calls to _gfortran_deallocate (function result)

   allocate(c(1))
   ! 3 calls to _gfortran_deallocate (INTENT(OUT) dummy)
   call allocate_alloc2(c(1))
   ! 4 calls to _gfortran_deallocate
   deallocate(c)

! 7 calls to _gfortran_deallocate (b (3) and c(4) goes aout of scope)

contains

   subroutine allocate_alloc2(b)
       type(alloc2), intent(out) :: b
       integer :: i

       if (allocated(b%a2) .OR. allocated(b%a1)) then
           write (0, *) 'allocate_alloc2 - 1'
           call abort()
       end if

       allocate (b%a2(3))
       b%a2 = [ 1, 2, 3 ]

allocate (b%a1(3))

       do i = 1, 3
           if (allocated(b%a1(i)%x)) then
               write (0, *) 'allocate_alloc2 - 2', i
               call abort()
           end if
           allocate (b%a1(i)%x(3))
           b%a1(i)%x = i + [ 1.0, 2.0, 3.0 ]
       end do

end subroutine allocate_alloc2


type(alloc2) function return_alloc2() result(b) if (allocated(b%a2) .OR. allocated(b%a1)) then write (0, *) 'return_alloc2 - 1' call abort() end if

       allocate (b%a2(3))
       b%a2 = [ 1, 2, 3 ]

allocate (b%a1(3))

       do i = 1, 3
           if (allocated(b%a1(i)%x)) then
               write (0, *) 'return_alloc2 - 2', i
               call abort()
           end if
           allocate (b%a1(i)%x(3))
           b%a1(i)%x = i + [ 1.0, 2.0, 3.0 ]
       end do
   end function return_alloc2


subroutine check_alloc2(b) type(alloc2), intent(in) :: b

       if (.NOT.(allocated(b%a2) .AND. allocated(b%a1))) then
           write (0, *) 'check_alloc2 - 1'
           call abort()
       end if
       if (any(b%a2 /= [ 1, 2, 3 ])) then
           write (0, *) 'check_alloc2 - 2'
           call abort()
       end if
       do i = 1, 3
           if (.NOT.allocated(b%a1(i)%x)) then
               write (0, *) 'check_alloc2 - 3', i
               call abort()
           end if
           if (any(b%a1(i)%x /= i + [ 1.0, 2.0, 3.0 ])) then
               write (0, *) 'check_alloc2 - 4', i
               call abort()
           end if
       end do
   end subroutine check_alloc2

end program alloc
! { dg-final { scan-tree-dump-times "deallocate" 24 "original" } }
! { dg-final { cleanup-tree-dump "original" } }


This is very good. If any of you out there are intersted in testing this patch, take a look at the code that the testcase produces! - I should explain that Erik has done all the tidy stuff; my contribution on the automatic deallocation is what produces the byte pollution...

Erik, in conclusion; you do assignments and I do constructors?

Best regards

Paul


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]