Starting with ifort 17.0.0 code using (a certain definition of) procedure pointers does not compile anymore. It works with ifort <= 16.0.4 (tested e.g. with ifort 16.0.4, 12.1.0). The problem is reproducible for both, Linux and Windows.
module impl_list__ implicit none type, public :: Node_t integer :: val procedure(), nopass, pointer :: cloneProc_int end type interface subroutine NodeCloner( tgt, src ) import Node_t type(Node_t), pointer, intent(out) :: tgt type(Node_t), intent(in) :: src end subroutine end interface procedure(), pointer :: cloneProc => null() type(Node_t) :: node end module subroutine func() use impl_list__ implicit none procedure(NodeCloner), pointer :: cloneNode, cloneNode_int cloneNode_int => node%cloneProc_int cloneNode => cloneProc end subroutine
Here are my different tests with different compilers:
~/winhpc> gfortran --version GNU Fortran 5.2.0 Copyright (C) 2015 Free Software Foundation, Inc. ~/winhpc> gcc -c list_test_v2.f90 list_test_v2.f90:29:17: cloneNode => cloneProc 1 Error: Explicit interface required for ‘cloneproc’ at (1): pointer argument ~/winhpc> ifort --version ifort (IFORT) 16.0.4 20160811 Copyright (C) 1985-2016 Intel Corporation. All rights reserved. ~/winhpc> ifort -c list_test_v2.f90 ~/winhpc> ifort --version ifort (IFORT) 17.0.0 20160721 Copyright (C) 1985-2016 Intel Corporation. All rights reserved. ~/winhpc> ifort -c list_test_v2.f90 list_test_v2.f90(28): error #6138: An explicit interface is required in this context. [CLONENODE_INT] cloneNode_int => node%cloneProc_int ----^ list_test_v2.f90(29): error #6138: An explicit interface is required in this context. [CLONENODE] cloneNode => cloneProc ----^ compilation aborted for list_test_v2.f90 (code 1) ~/winhpc> ifort --version ifort (IFORT) 12.1.0 20111011 Copyright (C) 1985-2011 Intel Corporation. All rights reserved. ~/winhpc> ifort -c list_test_v2.f90
The code tests the use of two procedure pointers. One is stored inside a user defined type, the other is defined within the module. gfortran in all version accepts the pointer inside the user defined type but not the one defined directly in the module. Ifort before version 17.0.0 accepts both pointers. The compilation fails for both pointers if the version is 17.0.0 or newer (also tested 17.0.2).
Is this an intended behavior? If so, what would be the correct way to handle such pointers? Otherwise, is this a bug?
I would argue that the gfortran you're using has a bug in that it doesn't complain about both pointer assignments. Both of the procedure pointer targets here have implicit interface (that's what PROCEDURE() gets you), and the pointers in question have explicit interface. The standard says:
If the pointer object has an explicit interface, its characteristics shall be the same as the pointer target except that the pointer target may be pure even if the pointer object is not pure and the pointer target may be an elemental intrinsic procedure even if the pointer object is not elemental.
Maybe you can fudge something with C_FUNLOC and C_F_PROCPOINTER, though you're still violating the rule that the interfaces must match.
Or you could use explicit interfaces everywhere (a better approach).
Same problem here ... which I had to "fix" for ifort 17 with C_F_PROCPOINTER.
Steve, so this means it used to be a bug in earlier ifort versions accepting this assignment and from now it's just illegal to do such casts, right?
But then what is the suggested "Fortran-way" to store a generic procedure pointer and to cast it once before doing the call? Of course it would be the cleaner approach (here I'd say "cleaner", not "better") to use explicit interfaces everywhere. However in reality this is simply not possible without making the number of necessary interface definitions explode - what a nightmare! So in order to avoid that, yes sir, I prefer the fudge-way using C_F_PROCPOINTER, and I think it's kind of strange that I've to apply the C-compatibility module to work around a shortcoming of the language (as I understand it).
Well I see that since Fortran is trying to go the object-oriented way and considering the consequent use of classes it would not be necessary to do such unclean casts, but again, real life is different: honestly, up to now one just can't rely on OOP-features in Fortran since the compilers still have too many bugs or things that are not yet supported. In software projects where it's necessary to share code with others this is a real show-stopper and I can't force others to update their compiler-licenses just to compile my code.
Therefore, for me there's still no choice but to stick with poor-mans OOP - although it appears to be kind of illegal now.
Yes, it was a bug before that this error was not detected.
If you insist on operating with the blade guard removed, then don't use explicit interfaces for the procedure pointer. Just don't come back here complaining when things go awry because you made an argument match error.
Or as I suggested earlier, use C_LOC to store the pointer and C_F_PROCPOINTER to assign it. That's a little better as you'll be able to use an explicit interface for the pointer. I see "OOP" tossed around everywhere, but everybody seems to have a different notion of what it means. It would be better to work within the framework of the language, as fussy as you might think it if you are used to the exposed blade of C and C++.
Thanks for the clarification! Of course you're right, removing the guards means that I'm responsible for doing the call right and I'd be better off using explicit interfaces. Sorry if it sounded rude! I just wanted to explain the reasons for doing it anyways. Integrating legacy code suitably for multiple compilers can be challenging sometimes!
I think the relevant restriction in the standard is actually the paragraph following the one that Steve's quoted - "If the characteristics of the pointer object or the pointer target are such that an explicit interface is required, both the pointer object and the pointer target shall have an explicit interface" (F2008 184.108.40.206p4). As the gfortran error message in the original post identifies, the characteristics of the pointer object include a dummy argument that has the pointer attribute, hence the pointer object requires an explicit interface, hence both sides of the pointer assignment require an explicit interface.
In the absence of a characteristic of a procedure that requires an explicit interface, having an explicit interface for the pointer side of an procedure pointer assignment does not require the target side to also have an explicit interface. What's required is for the characteristics to match, explicitness of the interface of a procedure is separate to its characteristics.
Its hard to answer "what is the correct way to handle such pointers" without knowing more about what the programmer is trying to do.
Edit to also note that applying C_FUNLOC to procedures that are not interoperable requires Fortran 2015. If you are concerned about broad support for your code, writing to a standard that has not yet been published is questionable.