- edited description
compile failure with gfortran 10 when using CCTK_PointerTo
Compiling with gfortran 10 currently fails with (among others):
COMPILING CactusExamples/DemoInterp/src/Interp1D.F
/Users/jenkins/Cactus/configs/sim/build/DemoInterp/Interp1D.f:191:37:
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 https://github.com/Unidata/netcdf-fortran/issues/212), 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)
-
reporter -
reporter Issue
#2404was marked as a duplicate of this issue. -
reporter Also see this email thread on the mailing list: http://lists.einsteintoolkit.org/pipermail/users/2020-June/007451.html
-
reporter I possible way to make our
CCTK_PointerTo
function work is described here: https://software.intel.com/en-us/forums/intel-fortran-compiler/topic/798744 -
reporter -
reporter - changed status to open
Please review.
-
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 takevoid*
as argument. https://www.ibm.com/support/knowledgecenter/SSAT4T_15.1.4/com.ibm.xlf1514.lelinux.doc/language_ref/assumedtypeobj.html 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.
-
reporter @Peter Diener being the resident Fortran expert, would you mind having a look at the pull request, please?
-
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 inarrangements/ExternalLibraries/BLAS/src/blas.F90
.The error is not too surprising as the declaration is apparently Fortran 2018 only (https://stackoverflow.com/questions/54378844/syntax-error-with-type-with-intel-fortran-compiler-2015-mac-os-x) 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. -
Yes, I’m not surprised this would fail on old compilers. I suspect it will also fail on older gfortran compilers.
-
reporter Updated the pull request to compile on both QueenBee (intel 14) and with gfortran-10 and gfortran-9.
-
reporter Still not good enough. Using
TYPE(*)
makes the function independent of the type, but not the rank of the argument. Unfortuhantely using usingTYPE(*), DIMENSION(..)
for assumed rank changes how arguments are passed andCCTK_PointerTo(a)
is no longer passed the address ofa
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. -
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 thenTYPE(*)
is Fortran 2018 so any compiler supporting the latter will support the former) requiresuse 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 whena
is a scalar.
- use Cray pointers ie
-
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? -
With the things you have tried already, I’m afraid that the only path forward I see, is to use
c_loc
fromiso_c_binding
. Maybe it’s time for cactus to require a modern enough fortran compiler thatiso_c_binding
is provided. However, using this might not be without problems, as the argument has to have thepointer
ortarget
attribute. -
Why not use Cray pointers? They essentially have C semantics (which we want) and are ubiquitous.
-
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). -
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 ofa
when passed to a C function (ptrfun0
) expecting avoid *
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. -
reporter Hmm, I may be missing an indirection step: https://software.intel.com/en-us/forums/intel-fortran-compiler/topic/270769 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 interface 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 theinterface
block inDECLARE_CCTK_FUNCTIONS
. Thetransfer
function is F90 and really is the interesting bit. Basically it andc_loc
give me a Cray pointer. -
reporter The pull request in https://bitbucket.org/cactuscode/cactus/pull-requests/97/cactus-declare-cctk_pointerto-as 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 inTestReduce
andEHFinde
issues inEOS_Omni
andGRHydro
. 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). -
reporter Please review.
-
reporter Unless objected I will apply this commit after 2020-07-13
-
reporter -
reporter - changed status to resolved
-
reporter - Log in to comment