Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Internal procedures and C_FUNLOC

296 views
Skip to first unread message

Richard Townsend

unread,
Feb 20, 2021, 12:47:10 PM2/20/21
to
Hi folks --

In Modern Fortran Explained (Metcalf, Reid & Cohen), section 19.3 the argument of C_FUNLOC is described as being "permitted to be a procedure that is interoperable (see section 19.9) or a pointer associated with such a procedure".

Looking at section 19.9 of MR&C, I then see the words "[an interoperable] procedure may be an external or module procedure, but is not permitted to be an internal procedure".

Looking through sec 15.3.7 of the F2008 standard, it seems there is nothing stipulating that internal procedures are viewed in a different light than module and external procedures.

However, in 15 2.3.6 (describing C_FUNLOC) the following appears: "The result is a value that can be used as an actual CPTR argument in a call to C F POINTER where FPTR has attributes that would allow the pointer assignment FPTR => X." Is it this clause that effectively prohibits creating a C_FUNPTR to an internal procedure (and then passing it in a call to a C routine)?

Many thanks,

Rich

Steve Lionel

unread,
Feb 20, 2021, 1:29:16 PM2/20/21
to
On 2/20/2021 12:47 PM, Richard Townsend wrote:
> Looking through sec 15.3.7 of the F2008 standard, it seems there is nothing stipulating that internal procedures are viewed in a different light than module and external procedures.
>
> However, in 15 2.3.6 (describing C_FUNLOC) the following appears: "The result is a value that can be used as an actual CPTR argument in a call to C F POINTER where FPTR has attributes that would allow the pointer assignment FPTR => X." Is it this clause that effectively prohibits creating a C_FUNPTR to an internal procedure (and then passing it in a call to a C routine)?

An interesting question:

One of the requirements for a Fortran procedure to be interoperable is:

(1) the interface has the BIND attribute,
(18.3.6p2)

The BIND attribute is a proc-language-binding-spec.

In F2003, there is:

C1237 (R1225) A proc-language-binding-spec shall not be specified for an
internal procedure.

which blocks this combination. This constraint disappeared in F2008 (and
does not reappear in F2018.)

Whatever the answer ends up being, it can't be restricted to the
description of C_FUNLOC. I will have to research this some more.
--
Steve Lionel
ISO/IEC JTC1/SC22/WG5 (Fortran) Convenor
Retired Intel Fortran developer/support
Email: firstname at firstnamelastname dot com
Twitter: @DoctorFortran
LinkedIn: https://www.linkedin.com/in/stevelionel
Blog: https://stevelionel.com/drfortran
WG5: https://wg5-fortran.org

Steve Lionel

unread,
Feb 20, 2021, 7:05:37 PM2/20/21
to
On 2/20/2021 12:47 PM, Richard Townsend wrote:
> Looking through sec 15.3.7 of the F2008 standard, it seems there is nothing stipulating that internal procedures are viewed in a different light than module and external procedures.
>
> However, in 15 2.3.6 (describing C_FUNLOC) the following appears: "The result is a value that can be used as an actual CPTR argument in a call to C F POINTER where FPTR has attributes that would allow the pointer assignment FPTR => X." Is it this clause that effectively prohibits creating a C_FUNPTR to an internal procedure (and then passing it in a call to a C routine)?

This changed in F2018 - the argument to C_FUNLOC (and C_LOC) is no
longer required to be interoperable. Furthermore, an internal procedure
may be interoperable.

I tried the following with Intel Fortran 2021.1.2 (supports F2018) and
it worked:

program test
use, intrinsic :: iso_c_binding
implicit none

integer :: id
type(C_FUNPTR) :: fp
id = 314159

fp = C_FUNLOC (introut)

call callit (fp)

contains

subroutine introut () BIND(C)
print *, id
return
end subroutine introut

subroutine callit (fp)
type(C_FUNPTR) :: fp
abstract interface
subroutine asub () BIND(C)
end subroutine asub
end interface
procedure(asub), pointer :: psub
call C_F_PROCPOINTER (fp, psub)
call psub
end subroutine callit

end program test

D:\Projects>t.exe
314159

m_b_metcalf

unread,
Feb 22, 2021, 4:28:04 AM2/22/21
to
Further to Steve's reply, we have already noted the need to revise this, and I add below the text of Section 19.9 on p. 375 of MFE as it will appear in the latest reprinting. Note also Section 21.9.2.

Regards,

Mike

A Fortran procedure is interoperable if it has an explicit interface
and is declared with the {bind} attribute:

function func(i, j, k, l, m) bind(c)
subroutine subr () bind(c)

Note that even for a subroutine with no arguments the parentheses are
required.
Each dummy argument must be interoperable and neither optional
nor an array with the {value} attribute.
For a function, the result must be scalar and interoperable.

The procedure usually has a {binding label}, which has global scope
and is the name by which it is known to
the C processor.{footnote[...]}
By default, it is the lower-case version of the
Fortran name. For example, the function in the previous paragraph
has the binding label {func}. An alternative binding label may be specified
for an external or module procedure:

function func(i, j, k, l, m) bind(c, name='c_func')

but this is not permitted for an abstract interface, dummy procedure,
or internal procedure.
The value following the {name=} must be a scalar default character
constant expression. Unless this expression has zero length or is all blanks,
the binding label is the result of discarding all its leading and trailing
blanks. The case is significant.

Richard Townsend

unread,
Feb 22, 2021, 1:06:59 PM2/22/21
to
Thanks, Steve & Mike, for you answers!

cheers,

Rich


gah4

unread,
Feb 23, 2021, 3:40:01 AM2/23/21
to
On Saturday, February 20, 2021 at 10:29:16 AM UTC-8, Steve Lionel wrote:

(snip)
>
> One of the requirements for a Fortran procedure to be interoperable is:
>
> (1) the interface has the BIND attribute,
> (18.3.6p2)
>
> The BIND attribute is a proc-language-binding-spec.
>
> In F2003, there is:
>
> C1237 (R1225) A proc-language-binding-spec shall not be specified for an
> internal procedure.
>
> which blocks this combination. This constraint disappeared in F2008 (and
> does not reappear in F2018.)
>
> Whatever the answer ends up being, it can't be restricted to the
> description of C_FUNLOC. I will have to research this some more.

I thought I remembered that there were some questions related to recursion,
and which instance of an internal routine, specifically which set of local
variables you see.

I haven't thought about this for a while, though, but it seems that the
problem must have been solved.

Steve Lionel

unread,
Feb 23, 2021, 10:18:07 AM2/23/21
to
On 2/23/2021 3:40 AM, gah4 wrote:
> I thought I remembered that there were some questions related to recursion,
> and which instance of an internal routine, specifically which set of local
> variables you see.
>
> I haven't thought about this for a while, though, but it seems that the
> problem must have been solved.

The standard is clear about the context of the passed internal
procedure, and the implementation is done in the obvious way. You DO
have to make sure that the eventual call to the internal procedure is
done while the creator of the "thunk" is still active.

gah4

unread,
Feb 23, 2021, 3:42:52 PM2/23/21
to
On Tuesday, February 23, 2021 at 7:18:07 AM UTC-8, Steve Lionel wrote:
> On 2/23/2021 3:40 AM, gah4 wrote:
> > I thought I remembered that there were some questions related to recursion,
> > and which instance of an internal routine, specifically which set of local
> > variables you see.
> >
> > I haven't thought about this for a while, though, but it seems that the
> > problem must have been solved.

> The standard is clear about the context of the passed internal
> procedure, and the implementation is done in the obvious way. You DO
> have to make sure that the eventual call to the internal procedure is
> done while the creator of the "thunk" is still active.

But also if more than one is active, it remembers which one it is?

Thunks are well known from call-by-name in ALGOL 60, which as well
as I know is where they were named.

https://en.wikipedia.org/wiki/Thunk

doesn't mention the use in Fortran.

Steve Lionel

unread,
Feb 23, 2021, 4:31:46 PM2/23/21
to
On 2/23/2021 3:42 PM, gah4 wrote:
>> The standard is clear about the context of the passed internal
>> procedure, and the implementation is done in the obvious way. You DO
>> have to make sure that the eventual call to the internal procedure is
>> done while the creator of the "thunk" is still active.
> But also if more than one is active, it remembers which one it is?

Yes - the thunk is specific to the invocation that created it. I
describe this more in
https://stevelionel.com/drfortran/2009/09/02/doctor-fortran-in-think-thank-thunk/

James Van Buskirk

unread,
Feb 23, 2021, 6:45:59 PM2/23/21
to
"m_b_metcalf" wrote in message
news:73d8e794-eb60-4371...@googlegroups.com...

> An alternative binding label may be specified
> for an external or module procedure:

> function func(i, j, k, l, m) bind(c, name='c_func')

> but this is not permitted for an abstract interface, dummy procedure,
> or internal procedure.
> The value following the {name=} must be a scalar default character
> constant expression.

That has been sort of a sore point in the standard. You would want the
expression within an interface to somehow be able to inherit from
the module in which the interface block resides. But an IMPORT
or USE statement lies after the FUNCTION statement. So does the
expression get to use host constants without the IMPORT or does it
inherit via IMPORT or USE or can it use implicit typing rules within
the function or any constants defined within the specification part
of the function, or is it just completely isolated?

gah4

unread,
Feb 23, 2021, 8:06:33 PM2/23/21
to
On Tuesday, February 23, 2021 at 1:31:46 PM UTC-8, Steve Lionel wrote:

(snip, I wrote)

> > But also if more than one is active, it remembers which one it is?

> Yes - the thunk is specific to the invocation that created it. I
> describe this more in
> https://stevelionel.com/drfortran/2009/09/02/doctor-fortran-in-think-thank-thunk/

Pretty neat.

And so the compiler knows which ones reference host variables, and only uses
thunks for those?

And an (optional) warning, so that the user knows that this is happening?

Also, it seems that there is need for something stronger than
IMPLICIT NONE to also disallow (accidental) references to host variables.

I suppose that is more for those who aren't so original in their variable
naming, so that ones could accidentally match host variables.

gah4

unread,
Feb 23, 2021, 8:31:22 PM2/23/21
to
On Tuesday, February 23, 2021 at 1:31:46 PM UTC-8, Steve Lionel wrote:

(snip)

> Yes - the thunk is specific to the invocation that created it. I
> describe this more in
> https://stevelionel.com/drfortran/2009/09/02/doctor-fortran-in-think-thank-thunk/

I presume you are right, but note that in the sample program there
is only one instance of subroutine callit. The variable changes, but within
the same instance.

The more interesting ones are where you save a reference (such as loc()) to
an instance, and then recursively (directly or indirectly) call that routine, such
that there is a new instance. (Not that I am asking you to write and debug one.)

It would be nice to know that someone, somewhere, in the development of
such compilers had done it, though.

thanks!

Ian

unread,
Feb 24, 2021, 3:06:27 AM2/24/21
to
Like

Import, None

and

Import, Only :: ...

?

I wish gfortran implemented these .... At least to be fair in the latest version I have I get

ian@eris:~/work/stack$ gfortran-10 abc.f90
abc.f90:2:9:

2 | Import none
| 1
Error: IMPORT statement at (1) only permitted in an INTERFACE body



Steve Lionel

unread,
Feb 24, 2021, 10:29:39 AM2/24/21
to
On 2/23/2021 8:06 PM, gah4 wrote:
> And so the compiler knows which ones reference host variables, and only uses
> thunks for those?
Yes.

> And an (optional) warning, so that the user knows that this is happening?
No - warnings for uses that are of an inherent standard feature are
frowned upon. If you want that, use "IMPORT, NONE" (F2018).

Steve Lionel

unread,
Feb 24, 2021, 10:32:18 AM2/24/21
to
On 2/23/2021 8:31 PM, gah4 wrote:
> I presume you are right, but note that in the sample program there
> is only one instance of subroutine callit. The variable changes, but within
> the same instance.
>
> The more interesting ones are where you save a reference (such as loc()) to
> an instance, and then recursively (directly or indirectly) call that routine, such
> that there is a new instance. (Not that I am asking you to write and d

Each instance of the procedure has (usually) a stack frame, and any
thunks created reference that stack frame. Recursive calls are properly
handled. It is the programmer's responsibility to ensure that the
instance that created the thunk has not exited at the time the thunk is
called.

Note that LOC() is non-standard and is not required to create a thunk.

Steve Lionel

unread,
Feb 24, 2021, 10:33:07 AM2/24/21
to
On 2/24/2021 3:06 AM, Ian wrote:
> 2 | Import none
> | 1
> Error: IMPORT statement at (1) only permitted in an INTERFACE body

There needs to be a comma after "Import". This is a F2018 feature - I
don't know if gfortran supports it yet.

Ian

unread,
Feb 24, 2021, 1:20:25 PM2/24/21
to
D'oh! Yes with the comma it is fine. That said the error message is not the best

JCampbell

unread,
Mar 3, 2021, 12:26:38 AM3/3/21
to
Can someone provide some clarification, as I don't see the requirement for bind(c) for a contained function.
A contains function has scope limited to the containing procedure (and other contained routines) so what is the meaning of interoperability for this type of function ?

Ian Harvey

unread,
Mar 10, 2021, 2:02:31 AM3/10/21
to
On 3/03/2021 2:56 pm, JCampbell wrote:
...> Can someone provide some clarification, as I don't see the
> requirement for bind(c) for a contained function. A contains function
> has scope limited to the containing procedure (and other contained
> routines) so what is the meaning of interoperability for this type of
> function ?

Scope describes the visibility of the name of the procedure.

In the scope of the name of the internal procedure, you pass the
interoperable internal procedure as an actual argument to a C function.
The C function can then call the interoperable internal procedure.


James Van Buskirk

unread,
Mar 11, 2021, 1:20:21 AM3/11/21
to
"Ian Harvey" wrote in message news:iar984...@mid.individual.net...
I think of what happens more like you pass a pointer to a trampoline
that loads a pointer to the instance variables inherited from the host
procedure and then jumps to the internal procedure. The C function
will eventually invoke the trampoline.

0 new messages