Link list of blocks?

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Link list of blocks?

Steve Kargl
All,

PR fortran/92178 was submitted today, and it points to
a problem in argument evaluation.  Consider,

  implicit none
  integer, allocatable :: a(:)
  allocate(a, source=[1])
  call assign(a, (a(1)))
  print *, allocated(a)
  contains
     subroutine assign(a, b)
       integer, allocatable, intent(out) :: a(:)
       integer,              value  :: b
    end subroutine
end program

gfc_conv_procedure_call() in trans-expr.c has a large for-loop
for argument evaluation (lines: 5478-6638).  In pseudo-code
gfortran does,

  evaluate(a)
  deallocate(a)
  evaluate((a(1))

The 2nd argument evaluation causes the resulting executable to
segfault as 'a' is deallocated and a(1) is gone.  The preferred,
if not correct, ordering is

  evaluate(a)
  evaluate((a(1))
  deallocate(a)

There are 3 blocks of lines (5924-5981, 6071-6111, and 6242-6273)
that do deallocation for INTENT(OUT) dummy arguments.  Each builds
the deallocation in a block and immediately adds it to the outer
block.  To fix the bug, it seems that adding the deallocation
blocks to a linked list, then after all arguments are processed
(after the massive for-loop) the linked list is walked and the
deallocation can be added.

Anyone do something like this?  Anyone, including lurkers on
this list, want to earn the respect of gfortran community by
actually fixing this?

--
Steve
Reply | Threaded
Open this post in threaded view
|

Re: Link list of blocks?

Steve Kargl
On Tue, Oct 22, 2019 at 07:39:10PM -0700, Steve Kargl wrote:

>
> PR fortran/92178 was submitted today, and it points to
> a problem in argument evaluation.  Consider,
>
>   implicit none
>   integer, allocatable :: a(:)
>   allocate(a, source=[1])
>   call assign(a, (a(1)))
>   print *, allocated(a)
>   contains
>      subroutine assign(a, b)
>        integer, allocatable, intent(out) :: a(:)
>        integer,              value  :: b
>     end subroutine
> end program
>
> gfc_conv_procedure_call() in trans-expr.c has a large for-loop
> for argument evaluation (lines: 5478-6638).  In pseudo-code
> gfortran does,
>
>   evaluate(a)
>   deallocate(a)
>   evaluate((a(1))
>
> The 2nd argument evaluation causes the resulting executable to
> segfault as 'a' is deallocated and a(1) is gone.  The preferred,
> if not correct, ordering is
>
>   evaluate(a)
>   evaluate((a(1))
>   deallocate(a)
>
> There are 3 blocks of lines (5924-5981, 6071-6111, and 6242-6273)
> that do deallocation for INTENT(OUT) dummy arguments.  Each builds
> the deallocation in a block and immediately adds it to the outer
> block.  To fix the bug, it seems that adding the deallocation
> blocks to a linked list, then after all arguments are processed
> (after the massive for-loop) the linked list is walked and the
> deallocation can be added.
>
> Anyone do something like this?  Anyone, including lurkers on
> this list, want to earn the respect of gfortran community by
> actually fixing this?
>

Well, I have determined that I can create a stmtblock,
add the deallocations to this new block, and then add
this new block to the outer block to get the ordering
that I think is correct.  My current patch fixes the
bug in the PR!

Unfortunately, I know zero, zip, nada, about CLASS and
finalization.  The patch has two regressions with
gfortran.dg/class_array_16.f90 and gfortran.dg/finalize_12.f90.
There are two possibilities: (1) my patch is correct and
the two testcase are bogus; and, (2) my patch is partially
correct, but CLASS and finalization require special casing.

A casual scan of bugzilla shows 878 open bug reports.  grep
also shows that the subject lines contain [OOP] in 73,
CLASS in 46, and 12 with finaliz.  One might conclude that
my (1) above is the correct possibility.

--
Steve