compile failure with gfortran 10 when using CCTK_PointerTo

Issue #2403 resolved
Roland Haas created an issue

Compiling with gfortran 10 currently fails with (among others):

COMPILING CactusExamples/DemoInterp/src/Interp1D.F

  183 |       interp_coords(1) = CCTK_PointerTo(xcoord)
      |                                        2
  191 |       out_arrays(2) = CCTK_PointerTo(compinterp1)
      |                                     1
Error: Type mismatch between actual argument at (1) and actual argument at (2) (COMPLEX(8)/REAL(8)).

and there seems to be little we can do about this since CCTK_PointerTo does have to accept all kinds of arguments. The same issue should also affect things like eg MPI_Send which takes pointers to arbitrary arrays.

This can be turned into a warning by adding -fallow-argument-mismatch to F90FLAGS (see, though the option only exists for gfortran 10 so cannot be added to the default set of flags.

If the issue indeed also affects MPI I would expect that the next version of gfortran no longer produces the warning.

Comments (25)

  1. Roland Haas reporter

    Might be good to have a test case that checks that the return value of the Fortran function returns the same value as the C function would and that the expected pointer shows up in the function’s argument list. To make sure the Fortran compiler still passes just a plain pointer and not something else.

    It should since the type(*) construct seems to be explicitly designed to handle C functions that take void* as argument. says:

    To facilitate the interoperability with formal parameters of type void* in C procedures, assumed-type arguments are introduced in Fortran. Assumed-type arguments are entities that are declared with the TYPE(*) specifier.

  2. Roland Haas reporter

    @Peter Diener being the resident Fortran expert, would you mind having a look at the pull request, please?

  3. Roland Haas reporter

    The patch fails on QueenBee ( ifort (IFORT) 14.0.2 20140120) with:

    /home/rhaas/ET_Turing/arrangements/CactusNumerical/SummationByParts/src/Derivatives2_mixed.F90(11): erro
    r #5082: Syntax error, found '::' when expecting one of: , <END-OF-STATEMENT> ;
      type(*) :: a
    /home/rhaas/ET_Turing/arrangements/CactusNumerical/SummationByParts/src/Derivatives2_mixed.F90(11): erro
    r #6622: This statement is invalid in an INTERFACE block.
      type(*) :: a
    /home/rhaas/ET_Turing/arrangements/CactusNumerical/SummationByParts/src/Derivatives2_mixed.F90(11): erro
    r #6404: This name does not have a type, and must have an explicit type.   [A]
      integer*8 function CCTK_PointerTo (a)
    compilation aborted for /home/rhaas/ET_Turing/configs/sim/build/SummationByParts/Derivatives2_mixed.f90
    (code 1)
    make[3]: *** [Derivatives2_mixed.F90.o] Error 1

    adding -stand f03 which is the newest Fortran standard that the help text says it supports gives other errors in arrangements/ExternalLibraries/BLAS/src/blas.F90.

    The error is not too surprising as the declaration is apparently Fortran 2018 only ( and only supported in ifort 2016 and up, making it even more annoying that gfortran-10 makes it an error with default parameters.

    So a configure test for type(*) may be required.

  4. Peter Diener

    Yes, I’m not surprised this would fail on old compilers. I suspect it will also fail on older gfortran compilers.

  5. Roland Haas reporter

    Updated the pull request to compile on both QueenBee (intel 14) and with gfortran-10 and gfortran-9.

  6. Roland Haas reporter

    Still not good enough. Using TYPE(*) makes the function independent of the type, but not the rank of the argument. Unfortuhantely using using TYPE(*), DIMENSION(..) for assumed rank changes how arguments are passed and CCTK_PointerTo(a) is no longer passed the address of a as its first argument. So far the best I could come up with is to overload (assuming that all compilers that check for the types are at least F90 compilers) CCTK_PointerTo on the Fortran side for up to 7 dimensions (that being the max allowed until Fortran 2008):

      interface CCTK_PointerTo
        CCTK_POINTER function CCTK_PointerTo0(a)
          type(*) :: a
        end function
        CCTK_POINTER function CCTK_PointerTo1(a)
          type(*),dimension(:) :: a
        end function
        CCTK_POINTER function CCTK_PointerTo2(a)
          type(*),dimension(:,:) :: a
        end function
        CCTK_POINTER function CCTK_PointerTo3(a)
          type(*),dimension(:,:,:) :: a
        end function
        CCTK_POINTER function CCTK_PointerTo4(a)
          type(*),dimension(:,:,:,:) :: a
        end function
        CCTK_POINTER function CCTK_PointerTo5(a)
          type(*),dimension(:,:,:,:,:) :: a
        end function
        CCTK_POINTER function CCTK_PointerTo6(a)
          type(*),dimension(:,:,:,:,:,:) :: a
        end function
        CCTK_POINTER function CCTK_PointerTo7(a)
          type(*),dimension(:,:,:,:,:,:,:) :: a
        end function
      end interface

    then on the C side of things provide 8 identical CCTK_PointerTo functions.

  7. Roland Haas reporter

    Things I cannot / do not want to do in cases like gfortran-10 where the compiler checks types / ranks of arguments:

    • use Cray pointers ie loc (not required by Cactus, only the ET)
    • use c_loc (is Fortran 2003, but then TYPE(*) is Fortran 2018 so any compiler supporting the latter will support the former) requires use iso_c_binding which I suspect will reveal all kinds of problems with using Fortran modules
    • C preprocessor tricks like #define CCTK_PointerTo(a) CCTKi_PointerTo((a)(1)) because it will fail when a is a scalar.

  8. Roland Haas reporter

    Nope, having one routine per rank does not work either. Apparently once one has

        CCTK_POINTER function CCTK_PointerTo2(a)
          type(*),dimension(:,:) :: a
        end function

    ie two assumed dimensions (and it must be assumed, the compiler will not let me have fixed dimension but assumed type) then the first argument seen by the C code is no longer the pointer to the first element of the array (but a pointer to something else). Next t o try is the c_loc function I guess. @Peter Diener do you have any suggestions what I could try instead?

  9. Peter Diener

    With the things you have tried already, I’m afraid that the only path forward I see, is to use c_loc from iso_c_binding. Maybe it’s time for cactus to require a modern enough fortran compiler that iso_c_binding is provided. However, using this might not be without problems, as the argument has to have the pointer or target attribute.

  10. Erik Schnetter

    Why not use Cray pointers? They essentially have C semantics (which we want) and are ubiquitous.

  11. Roland Haas reporter

    Mostly because I was trying for something that does not require compiler options. Cray pointers tend to require compiler options to be enabled (e.g. -fcray-pointer in gfortran) . The ET requires them (and sets options for them in simfactory) but Cactus never did (and cannot set compiler options only defaults which are then overwritten by user supplied option lists).

  12. Roland Haas reporter

    Ok. c_loc is also odd. I just tried it like so using an older Intel compiler (on Caltech’s bethe worksttion):

        integer*8 function ptrfun(a)
          use iso_c_binding, only: c_loc, c_ptr
          implicit none
          integer, TARGET, dimension(1) :: a
          external :: ptrfun0
          integer*8 :: ptrfun0
          type(c_ptr) :: ptr
          ptr = c_loc(a)
          ptrfun = ptrfun0(ptr)
          print *, "funret", ptrfun
        end function

    and whatever ptr ends up being is not the address of the first element of a when passed to a C function (ptrfun0) expecting a void * pointer. Which has me very confused given that this would seem to be exactly what I am supposed to do. I will tinker around a bit more later. Though for this week I am unlikely to have much more time I can spend on this.

  13. Roland Haas reporter

    Hmm, I may be missing an indirection step: looks like passing a c_ptr to a C function passes a pointer to a pointer and I need to add a “value” somewhere in its interface declaration.

    This seems to work:

    integer*8 function CCTK_PointerTo(a)
      use iso_c_binding, only: c_loc, c_ptr, c_intptr_t
      implicit none
      type(*), dimension(..), TARGET :: a
      type(c_ptr) :: ptr
      integer(kind=c_intptr_t) :: address
      ptr = c_loc(a)
      address = transfer(ptr, address)
      CCTK_PointerTo = address
    end function
    subroutine fortfun(a, b, c)
      implicit none
      integer*8 function CCTK_PointerTo(a)
        implicit none
        type(*), dimension(..), TARGET :: a
      end function
      end interface
      integer, dimension(2), TARGET :: a
      real :: b
      integer, dimension(2,3) :: c
      integer*8 :: p
      p = CCTK_PointerTo(a(1))
      print *, "fa1: ", p
      p = CCTK_PointerTo(a(2))
      print *, "fa2: ", p
      p = CCTK_PointerTo(b)
      print *, "fb: ", p
      p = CCTK_PointerTo(c)
      print *, "fc: ", p
    end subroutine

    which requires an F90 in the flesh for CCTK_PointerTo as well as the interface block in DECLARE_CCTK_FUNCTIONS. The transfer function is F90 and really is the interesting bit. Basically it and c_loc give me a Cray pointer.

  14. Roland Haas reporter

    The pull request in now lets me compile (and use) CCTK_PointerTo on both QB2 (as a standin for a system with an older Intel compiler) and gfortran-10.

    This does not yet let me compile or run the full toolkit to to similar issues like the CCTK_Reduce like functions one and, once that one is fixed in TestReduce and EHFinde issues in EOS_Omni and GRHydro. I will open separate tickets for them. As far as I can tell these will require fixes to Cactus using code and cannot be made to work by changes only to the flesh (since it affects subroutines rather than functions and Fortran does not require any interface like section for subroutines so the flesh has no way to hook in any possible solution to user code).

  15. Roland Haas reporter

    Actually approved by @Erik Schnetter on 2020‑06‑04 (even before the “please review”).

    Applied as git hash 1e362daf "Cactus: skip trying to find intrinsic module files" of cactus

  16. Log in to comment