Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
Announcements
Welcome to the Intel Community. If you get an answer you like, please mark it as an Accepted Solution to help others. Thank you!

Unlimited polymorphic and C pointers

Jacob_Williams
New Contributor I
232 Views

I'm trying to create a c_ptr to an allocated class(*),pointer variable, and then convert it back later into a Fortran pointer. Here is a toy example:

program test

    use iso_c_binding

    implicit none

    type :: blah
        integer :: i = 0
    end type blah

    class(*),pointer :: p,q
    type(c_ptr) :: cp

    allocate(p,source=blah(999))
    cp = c_loc(p)

    allocate(blah :: q)      ! (*) either of these
    !allocate(q,mold=blah()) !
    call c_f_pointer(cp,q)

    select type (q)  ! works as long as (*) is present, otherwise crash
    type is (blah)
        write(*,*) 'q%i:',q%i
    end select

end program test

If I don't have the allocate(blah :: q), the c_f_pointer call seems to works, but then it crashes when I try to access anything in the variable. So, my question is: is this the right way to do this? My concern is that it's a memory leak (it seems like the memory grabbed in this allocation would be lost when I call c_f_pointer? But I'm not sure). I'm using ifort 17.0.2.

0 Kudos
7 Replies
Steve_Lionel
Black Belt Retired Employee
232 Views

This will never work. When you do C_LOC, you lose ALL of the extra info that is kept with a polymorphic entity, and there is no way to reconstruct it. At best you could convert back to a pointer of fixed type.

Ideally, the compiler would complain about the use of a polymorphic pointer in the call to C_F_POINTER, but the current implementation doesn't allow for that and the standard doesn't require a check.

 

Jacob_Williams
New Contributor I
232 Views

So, this would be good?:

program test2

    use iso_c_binding

    implicit none

    type :: blah
        integer :: i = 0
    end type blah

    class(*),pointer :: p
    type(c_ptr)  :: cp
    type(blah),pointer :: q

    allocate(p,source=blah(999))

    cp = c_loc(p)
    call c_f_pointer(cp,q)

    write(*,*) 'q%i:',q%i

end program test2

It seems to run fine.

Neil_Carlson
Beginner
232 Views

Can C_LOC be applied to a polymorphic variable?  My understanding had been "no",  but looking at the standard just now, I'm not so sure.  If it isn't allowed, you can wrap the pointer in a type, and apply c_loc to a variable of that type.  I've used this trick before.

FortranFan
Honored Contributor II
232 Views

Neil Carlson wrote:

Can C_LOC be applied to a polymorphic variable?  My understanding had been "no",  but looking at the standard just now, I'm not so sure. ..

The standard revision that is "in the works" i.e., N2118 toward Fortran 2015 which, by the way, strives to include via TS 29113 further (some read this as enhanced) interoperability with C, explains on the dummy argument X in the C_LOC(X) function,

It shall either be a variable with interoperable type and kind type parameters, or
be a nonpolymorphic variable with no length type parameters.

I infer that to mean X can be a polymorphic variable whose dynamic instance is an interoperable type with interoperable kind type parameters; otherwise, X will have to be a nonpolymorphic variable with no length type parameters.

So in the example above from Message #3, if the type of blah were to be interoperable (which it is not, at least in principle), then the C_LOC(p) instruction will be standard-conforming.  That is my quick take on it.

Neil_Carlson
Beginner
232 Views

What you inferred is exactly what led me to have doubts, but it is an inference and not clearly right (to me at least), though I hope it is.

Boxing the polymorphic pointer has the advantage of preserving the extra metadata that one loses when applying c_loc directly to the pointer. For example

program main

  use iso_c_binding

  type box
    class(*), pointer :: p => null()
  end type
  type(box), target  :: pbox
  type(box), pointer :: qbox
  type(c_ptr) :: cp
  
  allocate(pbox%p, source=1)
  cp = c_loc(pbox)
  call c_f_pointer(cp, qbox)
  
  select type (q => qbox%p)
  type is (integer)
    print *, 'got integer', q
  class default
    print *, 'lost dynamic type'
  end select

end program

 

Jacob_Williams
New Contributor I
232 Views

The "box" method also works for me (it also has the advantage of also working on gfortran, which the other two do not). So, the theory is that this is OK because box is a nonpolymorphic variable with no length type parameters (even though it does contain a polymorphic variable?)

 

 

Steve_Lionel
Black Belt Retired Employee
232 Views

FortranFan's "inference" is exactly what the standard intends to say - the argummt shall either be interoperable (which clss(*) is not) or s non-polymorphic variable. Non-standard. As I said, it would be nice if ifort complained about this. I have little doubt that some other compilers do.

Reply