weird F2003 pointer error

I'm trying to convert my OpenKIM model as QUIP potential code to the
new API and F2003 pointers. I have a routine which I'm going to
register as a get_neigh method. I'm using a kim buffer to store some
data that needs to be communicated. Relevant source is below. When I
try to compile it, I get the following errors:

/Users/bernstei/src/work/QUIP/source/QUIP/QUIP_Core/IPModel_KIM.f95:287.23:

  p_neigh_list = c_loc(buf%neigh_list)

                       1

Error: Argument 'buf' to 'c_loc' at (1) must be an associated scalar POINTER

/Users/bernstei/src/work/QUIP/source/QUIP/QUIP_Core/IPModel_KIM.f95:288.22:

  p_neigh_rij = c_loc(buf%neigh_rij)

                      1

Error: Argument 'buf' to 'c_loc' at (1) must be an associated scalar POINTER

I have no idea why those calls to c_loc are invalid. This is with
gfortran 4.8.2 on OS X.

Any ideas?

                      thanks,
                      Noam

!!!!! start of code !!!!!!!

type quip_kim_buffer

  integer :: kim_iterator_current_i = -1

  type(Atoms), pointer :: kim_at => null()

  integer(c_int), pointer :: neigh_list(:slight_smile: => null()

  real(c_double), pointer :: neigh_rij(:,:slight_smile: => null()

end type quip_kim_buffer

function quip_neighbour_iterator(pkim, iterator_mode, request, atom,
nneigh, p_neigh_list, p_neigh_rij) bind(c) result(outval)

  type(c_ptr) :: pkim

  integer(c_int) :: iterator_mode, request, atom, nneigh

  type(c_ptr) :: p_neigh_list

  type(c_ptr) :: p_neigh_rij

  integer(c_int) :: outval ! result

  type(quip_kim_buffer), pointer :: buf; type(c_ptr) :: p_buf

  integer :: kim_error

  integer :: ji

  real(dp) :: drij(3)

  p_buf = kim_api_get_model_buffer(pkim, kim_error)

  if (kim_error < KIM_STATUS_OK) then

    call system_abort("quip_neighbor_iterator failed to get kim buffer
with error "//kim_error)

  endif

  call c_f_pointer(p_buf, buf)

  if (iterator_mode == 1) then ! locator mode

    if (request < 1 .or. request > buf%kim_at%N) then

      outval = KIM_STATUS_NEIGH_INVALID_REQUEST

      return

    endif

    atom = request

  else if (iterator_mode == 0) then ! iterator mode

    if (request == 0) then

       buf%kim_iterator_current_i = 1

       outval = KIM_STATUS_NEIGH_ITER_INIT_OK

       return

    else if (request == 1) then

      if (buf%kim_iterator_current_i > buf%kim_at%N) then

        outval = KIM_STATUS_NEIGH_ITER_PAST_END

        return

      endif

      atom = buf%kim_iterator_current_i

      buf%kim_iterator_current_i = buf%kim_iterator_current_i + 1

    else ! other iterator requests

      outval = KIM_STATUS_NEIGH_INVALID_REQUEST

      return

    endif

  else ! other mode

    outval = KIM_STATUS_NEIGH_INVALID_MODE

    return

  endif

  nneigh = n_neighbours(buf%kim_at, atom)

  if (associated(buf%neigh_list)) then

    if (size(buf%neigh_list) < nneigh) deallocate(buf%neigh_list)

  endif

  if (.not. associated(buf%neigh_list)) allocate(buf%neigh_list(nneigh))

  if (associated(buf%neigh_rij)) then

    if (size(buf%neigh_rij,2) < nneigh) deallocate(buf%neigh_rij)

  endif

  if (.not. associated(buf%neigh_rij)) allocate(buf%neigh_rij(3,nneigh))

  p_neigh_list = c_loc(buf%neigh_list)

  p_neigh_rij = c_loc(buf%neigh_rij)

  do ji=1, nneigh

      buf%neigh_list(ji) = neighbour(buf%kim_at, atom, ji, diff = drij)

      buf%neigh_rij(1:3,ji) = drij

  end do

  outval = KIM_STATUS_OK

end function quip_neighbour_iterator

I also don't see anything wrong, but I have two suggestions to try:

1) Maybe? the derived type can only contain interoperable things.?. So you might try removing the kim_at and see if it still complains.

2) it might work if you ask for the c_loc of the first element of the array instead of the "whole array":

   p_neigh_list = c_loc(buf%neigh_list(1))
   p_neigh_rij = c_loc(buf%neigh_rij(1,1))

Although it doesn't seem like you should need to do this, it might work. (I don't know enought about Fortran to know if this is proper, or only acceptable, or bad practice....)

Ryan

Hi Noam,

I think

c_loc(buf%neigh_list(1))

should work. There is a nasty bug in older gfortran versions that lead to a segfault of the compiler if you omited the index. Bug was apparently just fixed in gcc 4.9. See here:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=40963

This suggestion worked, and thanks also to Lars for pointing it out as well. The definition of c_loc in sec 15.1.2.5 seems to allow it, and example C.10.2.1 definitely does c_loc(allocatable_array), not c_loc(allocatable_array(1)), which would make me think that my original syntax should be allowed. Then again, it is only 11 years after the date of the standard, so who could expect a full implementation?

Noam