Procedure statement

When working with OpenGL under MS Windows, the post version 1.2 subroutines and functions
can be used only via the function pointer route. That is: first, obtain a function pointer
of the procedure by calling wglGetProcAddress. Next, have an abstract interface
and obtain the procedure via the procedure statement with the pointer attribute.
Then use C_F_PROCPOINTER to have the subroutine of function properly working.
I try to have these two action in one single function:

  LOGICAL FUNCTION make_func(name, proc)
  CHARACTER(LEN=*),INTENT(in)       :: name
  PROCEDURE(),POINTER,INTENT(inout) :: proc
!
  TYPE(C_FUNPTR) :: fptr
!
  make_func = .TRUE.
!
  fptr = wglGetProcAddress(name)
  IF(.NOT.C_ASSOCIATED(fptr)) THEN
    write(*,*) 'a function pointer could not be obtained'
    make_func = .FALSE.
  ELSE
    CALL C_F_PROCPOINTER(fptr, proc)
    IF(.NOT.ASSOCIATED(proc)) THEN
      write(*,*) 'the procedure could not be obtained'
      make_func = .FALSE.
    END IF
  END IF
  RETURN
  END FUNCTION make_func

In the main demo program this function is called twice to have the
subroutine example_sub and the function example_fun working:

  LOGICAL :: bResult
!
  bResult = make_func("example_sub"//C_NULL_CHAR, example_sub)
  write(*,*) 'bresult', bresult
!
  bResult = make_func("example_fun"//C_NULL_CHAR, example_fun)
  write(*,*) 'bresult', bresult

!
Intel works as expected. But the gfortran complains during compilation at the
line where this subroutine is called for the example_fun:

Error: Interface mismatch in dummy procedure 'proc' at (1): 'example_fun' is not a subroutine

What is going on here? Is it valid Fortran or not? And if not,
how to modiy the make_func function to have it properly working?
Keep in mind that OpenGL have many hundreds of procedures that must be
obtained and it is very, very pleasant to have only one function to do the job.

Robert

For whatever it’s worth, I think what you show conforms and Intel Fortran has it right. But it’s one of those grey areas where opinions of compiler implementations may differ and this may require further clarification in terms of the Fortran standard. I suggest you first file a report at GCC Bugzilla to get the opinion from gfortran volunteers on this. You can follow-up based on their feedback.

In the meantime, you may want to keep in mind other options with your run-time loading of Windows DLL scenario. See what Winteractor recommends, or what other solutions have been posted by contributors such as GitHub. You may find your make_func function convenient, but your use of the implicit interface option with procedure() characteristic of your dummy argument proc appears questionable, it likely poses a vulnerability making others hesitant to use your solution (I wouldn’t). Fortran offers certain facilities to make things clearer and safer, yes it may appear verbose and tedious. But when using Fortran, you may find it better to follow those steps.

FortranFan, thanks for your reply.In the mean time I have found in MFE (edition 2018; page 286) a hint on how to solve the problem: ignore the IMPLICIT none line. And that did help! The example went fine so does the OpenGL programs. We can say that the problem is solved, but the puzzle definitely not. And I am very uncomfortable that the IMPLICIT none must be dropped. Are you able to shed some more light on the issue?

Robert

Ps. I planned to send a Fortran file with the demo program, but the site seems to not ccept that. Any idea to handle this?

Without the implicit none, the compiler is not trying to do interface checking, i.e. it does not try to make sure that the way you call a procedure matches the way the procedure is defined/should be called. I’m guessing the empty parens in procedure() defaults to meaning a subroutine with no arguments, and thus trying to pass a function pointer doesn’t conform to the interface.

In Fortran subroutine vs function, the number and types of arguments (and in many cases their names) define the procedure’s interface (i.e. its type if it is a procedure argument or procedure pointer). Trying to pass around procedure pointers in Fortran requires them to have explicit interfaces, or the compiler won’t really know how to call it. Some compilers will let you turn off that checking, but at that point you’re wading pretty deep into undefined behavior territory.

Hi Robert @robert1,
The following excerpts from the standard interpretation document (18-007r1) are perhaps relevant. Only section 15.5.2.9 refers to dummy procedures specifically but it doesn’t seem to directly address the case when the dummy procedure has no explicit interface but is not referenced as either a function or a subroutine.

I would lean towards saying that gfortran is incorrect to assume proc is a subroutine in the absence of any interface, however I may be missing a piece of the puzzle standard in this interpretation.

Section 15.4.3.6 (pg 298):

R1512 procedure-declaration-stmt is PROCEDURE ( [ proc-interface ] ) [ [ , proc-attr-spec ] ... :: ] proc-decl-list

4 If proc-interface does not appear, the procedure declaration statement does not specify whether the declared procedure entities are subroutines or functions.

9 If procedure-entity-name has an implicit interface and is explicitly typed or referenced as a function, initial-proc-target shall be a function. If procedure-entity-name has an implicit interface and is referenced as a subroutine, initial-proc-target shall be a subroutine.

Section 15.5.2.9 (pg 309)

2 If the interface of a dummy procedure is implicit and either the dummy argument is explicitly typed or referenced as a function, it shall not be referenced as a subroutine and any corresponding actual argument shall be a function, function procedure pointer, or dummy procedure…

3 If the interface of a dummy procedure is implicit and a reference to it appears as a subroutine reference, any corresponding actual argument shall be a subroutine, subroutine procedure pointer, or dummy procedure.

@robert1 ,

As I mentioned earlier, you may want to inquire with GCC/gfortran volunteers via GCC Bugzilla regarding the current implementation in gfortran of Fortran 2018 feature around implicit none (type, external). A workaround with gfortran can be implicit none (type) what may then retain what you view is provided by implicit none.

But yes, I agree with your discomfort. As I suggested earlier upthread, my recommendation will be to avoid working with implicit interfaces. You appear to seek certain convenience with your
make_func procedure but you’re introducing significant vulnerability in the process. Letting go of convenience for now and resorting to explicit instructions even if they appear verbose will be more in line with the current ethos of Fortran.

Thank all of you. I have learned from your observations and remarks that it is best to drop the idea of having a single “make_func” for the job. It will take some work but then I will be on a more solid ground. Again, thank you for the kind help.
Robert