title: Fortran procedure pointer to subroutines in derived type
body: <p>In Fortran, I need a procedure pointer inside a derived type that can point to one of several subroutines. This problem seems to be common on SO:</p>
  
  <p><a href="https://stackoverflow.com/questions/34167276/fortran-save-procedure-as-property-in-derived-type">Fortran save procedure as property in derived type</a></p>
  
  <p><a href="https://stackoverflow.com/questions/21343488/type-bound-procedure-overloading-in-fortran-2003">Type bound procedure overloading in Fortran 2003</a></p>
  
  <p><a href="https://stackoverflow.com/questions/27705554/there-is-no-matching-specific-subroutine-for-this-type-bound-generic-subroutine">There is no matching specific subroutine for this type bound generic subroutine call</a></p>
  
  <p><a href="https://stackoverflow.com/questions/11383605/generic-type-bound-procedures-with-procedure-arguments">Generic type-bound procedures with procedure arguments</a></p>
  
  <p><a href="https://stackoverflow.com/questions/24001272/type-bound-procedure-as-arguments">Type bound procedure as arguments</a></p>
  
  <p>to name a few. The answer to this question for <em>functions</em> is provided very nicely in the first reference.</p>
  
  <p>However, I'm still not clear on a methodology to develop such code well in the case that the type-bound procedure pointer is pointing to a subroutine. The difficulty seems to be that there is no type associated with what is returned (since nothing is really "returned").</p>
  
  <p>I would also like to point out the nuance that, although a simple solution may exist in a more recent standard of fortran (2003,2008), this solution may not work on all compilers, which may be problematic in the future. So I'm interested in compiler-friendly solutions.</p>
  
  <p>I have a small code (shown below) that currently works, but in my big code, I'm getting an internal compiler error (also shown below) in the file where I use procedure pointers in derived types. My question is: what can I do to the code below to</p>
  
  <p>1) Strictly use explicit interfaces</p>
  
  <p>2) Maximize information passed to the compiler</p>
  
  <p>3) Ensure the code is portable between as many compilers as possible (i.e. use fortran 90 / 95 standards).</p>
  
  <p>To what degree can the above be satisfied (1 being most important)? Is it possible to satisfy all of these criteria above? I know that's "satisfy all of these criteria" is subjective, but I would argue that the answer is 'yes' for the same question regarding functions instead of subroutines.</p>
  
  <pre><code> gcc version 5.1.0 (i686-posix-dwarf-rev0, Built by MinGW-W64 project)
  </code></pre>
  
  <p>The small code:</p>
  
  <pre><code>  module subs_mod
    implicit none
    public :: add,mult
    contains
    subroutine add(x,y,z)
      implicit none
      integer,intent(inout) :: x
      integer,intent(in) :: y,z
      x = y+z
    end subroutine
    subroutine mult(x,y,z)
      implicit none
      integer,intent(inout) :: x
      integer,intent(in) :: y,z
      x = y*z
    end subroutine
    end module
  
    module type_A_mod
    use subs_mod
    implicit none
    public :: type_A,init,operate
    type type_A
      procedure(),pointer,nopass :: op
    end type
    contains
    subroutine init(A,op)
      implicit none
      external :: op
      type(type_A),intent(inout) :: A
      A%op =&gt; op
    end subroutine
    subroutine operate(A,x,y,z)
      implicit none
      type(type_A),intent(in) :: A
      integer,intent(inout) :: x
      integer,intent(in) :: y,z
      call A%op(x,y,z)
    end subroutine
    end module
  
    program test
    use type_A_mod
    use subs_mod
    implicit none
    type(type_A) :: A
    integer :: x
    call init(A,mult)
    call operate(A,x,3,5)
    write(*,*) 'x = ',x
    end program
  </code></pre>
  
  <p>Compiler error in big code:</p>
  
  <pre><code>    f951.exe: internal compiler error: Segmentation fault
      libbacktrace could not find executable to open
      Please submit a full bug report,
      with preprocessed source if appropriate.
      See &lt;http://sourceforge.net/projects/mingw-w64&gt; for instructions.
  </code></pre>
  
  <p><em>UPDATE</em></p>
  
  <p>Here's a small modification that gives the compiler more information, but I have not tried this on the big code. However, it seems arbitrary, and I have no idea if it will help or not.</p>
  
  <pre><code>  ...
    function add(x,y,z) result(TF)
    ...
      logical :: TF
      x = y+z
      TF = .true.
    end function
    function mult(x,y,z) result(TF)
    ...
      logical :: TF
      x = y*z
      TF = .true.
    end function
    end module
  
    module type_A_mod
    ...
    type type_A
      procedure(logical),pointer,nopass :: op
    end type
    ...
    subroutine init(A,op)
      implicit none
      logical,external :: op
    ...
    end subroutine
    subroutine operate(A,x,y,z)
    ...
      logical :: TF
      TF = A%op(x,y,z)
    end subroutine
    end module
  
    program test
    ...
    end program
  </code></pre>
  
  <p><strong>SOLUTION COMMENTS</strong>
  Just to comment on the solution (provided by @IanH): there was one additional wrinkle, and that was that I had some derived types entering the abstract interface, which according to <a href="ftp://ftp.nag.co.uk/sc22wg5/n1551-n1600/n1579.pdf" rel="nofollow noreferrer">The New Features of Fortran 2003</a>, the <code>Import</code> statement should be included to make the abstract interface aware of any entering derived types. Here is a small working example, which, applied to the big code, mitigates the internal compiler error I was having :)</p>
  
  <pre><code>  module DT_mod
    implicit none
    private
    public :: DT
    type DT
      integer :: i
    end type
    contains
    end module
  
    module subs_mod
    use DT_mod
    implicit none
    private
    public :: add,mult,op_int
  
    abstract interface
    subroutine op_int(d,x,y,z)
      import :: DT
      implicit none
      type(DT),intent(inout) :: d
      integer,intent(inout) :: x
      integer,intent(in) :: y,z
    end subroutine
    end interface
  
    contains
    subroutine add(d,x,y,z)
      implicit none
      type(DT),intent(inout) :: d
      integer,intent(inout) :: x
      integer,intent(in) :: y,z
      x = y+z
      d%i = 1
    end subroutine
    subroutine mult(d,x,y,z)
      implicit none
      type(DT),intent(inout) :: d
      integer,intent(inout) :: x
      integer,intent(in) :: y,z
      x = y*z
      d%i = 2
    end subroutine
    end module
  
    module type_A_mod
    use DT_mod
    use subs_mod
    implicit none
    private
    public :: type_A,init,operate
    type type_A
      procedure(op_int),pointer,nopass :: op
    end type
    contains
    subroutine init(A,op)
      implicit none
      procedure(op_int) :: op
      type(type_A),intent(inout) :: A
      A%op =&gt; op
    end subroutine
    subroutine operate(A,d,x,y,z)
      implicit none
      type(DT),intent(inout) :: d
      type(type_A),intent(in) :: A
      integer,intent(inout) :: x
      integer,intent(in) :: y,z
      call A%op(d,x,y,z)
    end subroutine
    end module
  
    program test
    use type_A_mod
    use subs_mod
    use DT_mod
    implicit none
    type(type_A) :: A
    type(DT) :: d
    integer :: x,y,z
    y = 3; z = 5
    call init(A,mult)
    call operate(A,d,x,y,z)
    write(*,*) 'x,y,x = ',y,z,x
    write(*,*) 'd%i = ',d%i
    end program
  </code></pre>
  
  <p>Any help is greatly appreciated.</p>