3

I want to know how to judge if a fortran procedure pointer is associated with a specific subroutine. The following a MWE (basically based on my previous question)

# module file
module boundary
implicit none

type bc_type
  procedure(boundary_type), pointer, nopass :: bc
  ! some other type-bound parameters
end type

abstract interface
  subroutine boundary_type(i)
    integer :: i
  end subroutine
end interface

contains

subroutine boundaryA(i)
integer :: i
  print*, 'Boundary A at ',i
end subroutine

subroutine boundaryB(i)
integer :: i
  print*, 'Boundary B at ',i
end subroutine

end module

# main file
program main
use boundary
implicit none
type(bc_type) :: a    

  a%bc => boundaryA

end program

I know that the function associated can be used to judge if a procedure pointer is associated, but how can I know which subroutine is it associated with? For here, if bc associated with boundaryA or boundaryB?

I tried

associated(a%bc, boundaryA)

The compiler (gfortran 4.8.2) gives an error that 'target' argument of 'associated' intrinsic at boundaryA must be the same type and kind as 'pointer'.

If the nopass attribute is removed, the compiler gives an error that argument 'i' of 'bc' with pass(i) at 'bc' must be of the derived type 'bc_type'.

zljt3216
  • 53
  • 1
  • 5
  • It gives an error "target argument of 'associated intrinsic at boundaryA must be the same type and kind as 'pointer''". – zljt3216 Feb 25 '18 at 11:01
  • Sorry for my mistake. I actually took another example code. I have corrected it. The main difference is that now the procedure pointer is defined in a new type 'bc_type'. If nopass is removed, the compiler gives an error that argument 'i' of 'bc' with pass(i) must be of the derived type 'bc_type'. – zljt3216 Feb 25 '18 at 14:30
  • Now it's a type's component, `nopass` is required. However, I tried with gfortran 4.8.1 (closest version I have to yours) and this is accepted, as expected. Have you access to other (later) versions? – francescalus Feb 25 '18 at 14:50
  • I tried with gfortran 5.3.0 on my windows 8 system and it works perfectly. The approach in Steve's answer also works here. But both fail in gfortran 4.8.2 on my ubuntu system 4.8.2. – zljt3216 Feb 26 '18 at 01:30

1 Answers1

1

Here's one way to do it.

program main
use boundary
use, intrinsic :: iso_c_binding
implicit none
type(bc_type) :: a    

  a%bc => boundaryA

if (same_proc(c_funloc(a%bc),c_funloc(boundaryA))) print *, "boundaryA"
if (same_proc(c_funloc(a%bc),c_funloc(boundaryB))) print *, "boundaryB"

    contains
    function same_proc (a,b)
    use, intrinsic :: iso_c_binding
    logical same_proc
    type(c_funptr), intent(in) :: a,b

    same_proc = transfer(a,0_C_INTPTR_T) == transfer(b,0_C_INTPTR_T)
    end function same_proc


end program
Steve Lionel
  • 6,972
  • 18
  • 31
  • You method gives a new error saying argument 'a' to 'c_funloc' must be a procedure. (I'm using gfortran 4.8.2) Also, could you please explain more on the details of the 'same_proc' function? The iso_c_binding module, transfer function, c_funloc function are all new to me... – zljt3216 Feb 26 '18 at 01:14
  • This worked for me in Intel Fortran; could be a gfortran bug. C_FUNLOC is a C interoiperability function defined in ISO_C_BINDING - part of the Fortran 2003 standard. It takes a procedure as an argument and returns a pointer to it as a value of type C_FUNLOC. So the calls to same_proc pass the C_FUNLOC value (address of procedure) of the two procedures to compare. same_proc uses TRANSFER to "cast" those values to an address-sized integer and compares them. If they are the same, that means the C_FUNLOC values are the same. – Steve Lionel Mar 01 '18 at 00:35
  • This solution works with gfortran 7.3. @SteveLionel: Why `associated(a%bc, boundaryA)` does not work with intel compiler? It works with gfortran 7.3 but it does not work with intel 18.0.2. Should we expect this to work in future versions? Thank you. – alexis May 04 '18 at 20:11
  • 1
    @alexis , that's a very good question. I'm uncertain why I didn't suggest that earlier. It ought to work, according to the standard. I am retired from Intel so I can't predict when it might get fixed, but I will report it to Intel. – Steve Lionel May 05 '18 at 22:44