J3/06-352r2 To: J3 Date: November 15, 2006 From: Stan Whitlock / Aleksandar Donev Subject: BIND(C) for internal procedures References: J3/06-143, J3/06-202 Discussion: __________ We now internal procedures to be passed as actual arguments or to be the targets of procedure pointers. The next step in orderly and respectful integration is to extend this to work with C Interop, that is, a should be allowed for internal procedures, and also such procedures should be allowed as actual arguments to C_FUNLOC. We should spell out that an internal procedure must not be invoked after the host instance ceases to exist. We should not allow binding labels for internal procedures since the host environment of the internal procedure (required in order to execute it) may not be established until runtime (and thus not known to the linker). This is achieved by not allowing a NAME= specifier and explaining that there is no binding label for internal procedures. This is similar to how we require NAME="" to be specified for PRIVATE module procedures, instead of saying they have no binding label. Note that no edits are needed for C_FUNLOC: Once we allow internal procedures to be interoperable, they can be actual arguments to C_FUNLOC. Edits against 06-007r1: __________ [309:8+] Add a new paragraph: "The program shall not invoke an internal procedure when its host scoping unit is not active." [310:1-] Add a new note: "Note 12.20a An internal procedure may not be invoked using a procedure pointer from either Fortran or C after the host instance completes execution. While the host instance is active, however, the internal procedure may be invoked from outside of the host procedure scoping unit if that internal procedure was passed as an actual argument or is the target of a procedure pointer. Assuming there exists a library procedure, written either in Fortran or C and callable from either Fortran or C, that calculates the integral of an arbitrary function f(x) over the interval [a,b]: INTERFACE FUNCTION INTEGRATE(F,A,B) RESULT(INTEGRAL) BIND(C) USE ISO_C_BINDING INTERFACE FUNCTION F(X) BIND(C) ! Integrand USE ISO_C_BINDING REAL(KIND=C_FLOAT), VALUE :: X REAL(KIND=C_FLOAT) :: F END FUNCTION END INTERFACE REAL(KIND=C_FLOAT), VALUE :: A, B ! Bounds REAL(KIND=C_FLOAT) :: INTEGRAL END FUNCTION INTEGRATE END INTERFACE one can write f(x) as an internal procedure with access to any host instance local variables necessary to actually calculate f(x): FUNCTION MY_INTEGRATION(N,A,B) RESULT(INTEGRAL) ! Integrate f(x)=x^n over [a,b] USE ISO_C_BINDING INTEGER, INTENT(IN) :: N REAL, INTENT(IN) :: A, B REAL :: INTEGRAL INTEGRAL=INTEGRATE(MY_F,REAL(A,C_FLOAT),REAL(B,C_FLOAT)) ! This will call the internal function MY_F to calculate f(x) ! The above interface of INTEGRATE must be explicit and available CONTAINS FUNCTION MY_F(X) BIND(C,NAME="") ! Integrand USE ISO_C_BINDING REAL(KIND=C_FLOAT), VALUE :: X REAL(KIND=C_FLOAT) :: MY_F MY_F=X**N ! N is taken from the host instance of MY_INTEGRATION END FUNCTION END FUNCTION MY_INTEGRATION The function INTEGRATE should not save a function pointer to MY_F and use it after INTEGRATE has finished execution, because the host instance of MY_F may no longer exist. If such a pointer is saved, then it may only be used to invoke MY_F during the execution of the host instance of MY_INTEGRATION." {end note 12.20a} [326:21] Replace constraint C1240 (R1227) with: C1240 (R1227) If a is specified for an internal procedure, the NAME= specifier shall appear and it shall specify that the procedure has no binding label (15.4.1). [481:10] Replace: "the procedure is not a dummy procedure or procedure pointer" with "the procedure is not a dummy procedure, an internal procedure, or a procedure pointer" [503:11+] Add a new item (21) to the list: "(21) Any variable of type C_FUNPTR whose target is an internal procedure becomes undefined when execution of the host instance of the internal procedure is completed by execution of a RETURN or END statement" ______________