- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi.
The following code
module mod1
implicit none
abstract interface
subroutine i_proc()
end subroutine
end interface
contains
function gen_proc(str) result(p)
procedure(i_proc), pointer :: p
character(*), intent(in) :: str
p => cp
contains
subroutine cp()
print*,'str=',trim(str)
end subroutine
end function
subroutine match(p)
procedure(i_proc) :: p
call p()
end subroutine
end module mod1
use mod1
implicit none
call match(gen_proc('Hello'))
end
Fails to compile with
$ ifx -V return-proc.f90
Intel(R) Fortran Compiler for applications running on Intel(R) 64, Version 2024.1.0 Build 20240308
Copyright (C) 1985-2024 Intel Corporation. All rights reserved.
Intel(R) Fortran 24.0-1472.3
return-proc.f90(31): error #6636: When a dummy argument is a subroutine, the corresponding actual argument must also be a subroutine.
call match(gen_proc('Hello'))
-----------^
compilation aborted for return-proc.f90 (code 1)
I'm not sure if my interpretation is correct, but it seems like the expression's result is not being considered, and the compiler is assuming that I'm trying to pass a function as actual argument.
When compiling the code with gfortran 13, I get the expected outcome:
$ gfortran -std=f2018 return-proc.f90 && ./a.out
/usr/bin/ld: warning: /tmp/cc2N2xku.o: requires executable stack (because the .note.GNU-stack section is executable)
str=Hello
(The warning issued by the linker is just a side-effect of the way GCC implements nested functions)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The copy of nagfor I have (7.2-7203) doesn't display an ICE, but it doesn't generate an object much less an exe. However, I agree with Andrew that this is not legal code. The "thunk" created by the pointer assignment p=>cp becomes undefined on return from gen_proc. Whether it "works" or not is unpredictable.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
nagfor gets an internal compiler error
nagfor -v return-proc.f90
NAG Fortran Compiler Release 7.1(Hanzomon) Build 7125
return-proc.f90:
Segmentation violation
Internal error - please report this bug
I'll try our ifx mainline branch.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
the latest ifx nightly build also gives the error you describe. I will have to check the syntax to see if this code is conformant. It is suspicious when something crashes the NAG compiler.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The code is simply implementing a closure.
From what I understood in this old post from Steve Lionel, the context from gen_proc execution should be kept around (which is probably what GCC refers to when performing the stack jump).
In Steve Lionel's example, the contained procedure is passed as an argument to another procedure directly, but imho same (context preservation) rules should apply here... unless procedure pointers to contained procedures are not allowed at all as function results in Fortran.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Even if it did compile and run. I don't think it should work and is probably not legal code. I used a temporary pointer to hold the result of gen_proc, than passed that to match. This compiles and runs but crashes.
After the execution returns from gen_proc, its argument str is removed from the stack and is gone. Then when you call the pointer to it's internal procedure cp, it attempts to access str and protection violates.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
This page from IBM Fortran says its not legal to call an internal procedure from outside. Procedure pointers (Fortran 2003) - IBM Documentation
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@Andrew_Smith wrote:This page from IBM Fortran says its not legal to call an internal procedure from outside. Procedure pointers (Fortran 2003) - IBM Documentation
Starting Fortran 2008 revision (current standard is 2023) around 14 years ago, this restriction around internal procedures has been lifted in a way.
Meaning, starting with 2008 standard publication, "An internal procedure can be used as an actual argument
or procedure pointer target." This effectively provides a mechanism for the internal procedure to be invoked in a scope that is external to the host.
The standard can be referred to for further details; the book "Modern Fortran Explained" provides some commentary about this.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The copy of nagfor I have (7.2-7203) doesn't display an ICE, but it doesn't generate an object much less an exe. However, I agree with Andrew that this is not legal code. The "thunk" created by the pointer assignment p=>cp becomes undefined on return from gen_proc. Whether it "works" or not is unpredictable.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@Steve_Lionel wrote:The copy of nagfor I have (7.2-7203) doesn't display an ICE, but it doesn't generate an object much less an exe. However, I agree with Andrew that this is not legal code. The "thunk" created by the pointer assignment p=>cp becomes undefined on return from gen_proc. Whether it "works" or not is unpredictable.
In (a draft of) the Fortran 2023 standard, around the function-stmt definition, I see the following
If the function result is a pointer, on return the pointer association status of the function result shall not be undefined.
And there's also the following note:
The function result is similar to any other entity (variable or procedure pointer) local to a function subprogram. Its existence begins when execution of the function is initiated and ends when execution of the function is terminated. However, because the final value of this entity is used subsequently in the evaluation of the expression that invoked the function, an implementation might defer releasing the storage occupied by that entity until after its value has been used in expression evaluation.
Which seems to be exactly what gfortran is doing (i.e., using the result in the immediate expression).
But if you say the code is not legal, then I believe you.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
For whatever it's worth, my understanding is your code in the original post does not conform per the standard (c.f. proxy document 23-007r1.pdf). But it is not so per the stated reasons in this thread, whether with a thunk (no such thing is recognized by the standard) or an internal subprogram or any such argument. Rather the non-conformance is simply due to a reference to any undefined object ('str`) on line 17 on the code in your original post.
Consider a slight variant of your code in the original post where the object reference is replaced with something valid, two options - a) a module entity thus with default SAVE attribute or a "static" (per common CS parlance) object `SAVE` in the host. I reckon such code conforms starting with Fortran 2008 standard revision. And any processor (compiler) unable to complete the instructions with such a program shall be non-conforming with Fortran 2008 and subsequent revisions (2018 and 2023(:
module m
abstract interface
subroutine Iproc()
end subroutine
end interface
character(len=:), allocatable, save :: s !<-- option a ; comment out for option b
contains
function gen_proc(str) result(p)
procedure(Iproc), pointer :: p
character(*), intent(in) :: str
!character(len=:), allocatable, save :: s !<-- uncomment this line for option b
s = str
p => cp
contains
subroutine cp()
print*,'str=',trim(s)
end subroutine
end function
subroutine match( p )
procedure(Iproc) :: p
call p()
end subroutine
end module
use m
call match( gen_proc('Hello') )
end
Intel Support team may want to submit above case with Intel Fortran team as a bug incident for resolution.
In the meantime, a further variant of above works with Intel Fortran processor and that's good news.
module m
abstract interface
subroutine Iproc()
end subroutine
end interface
character(len=:), allocatable, save :: s !<-- option a ; comment out for option b
contains
function gen_proc(str) result(p)
procedure(Iproc), pointer :: p
character(*), intent(in) :: str
!character(len=:), allocatable, save :: s !<-- uncomment this line for option b
s = str
p => cp
contains
subroutine cp()
print*,'str=',trim(s)
end subroutine
end function
subroutine match( p )
procedure(Iproc) :: p
call p()
end subroutine
end module
use m
procedure(Iproc), pointer :: proc
proc => gen_proc('Hello')
call match( proc )
end
C:\temp>ifx /standard-semantics /free p.f
Intel(R) Fortran Compiler for applications running on Intel(R) 64, Version 2024.1.0 Build 20240308
Copyright (C) 1985-2024 Intel Corporation. All rights reserved.
Microsoft (R) Incremental Linker Version 14.36.32537.0
Copyright (C) Microsoft Corporation. All rights reserved.
-out:p.exe
-subsystem:console
p.obj
C:\temp>p.exe
str=Hello
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
"An internal procedure cannot be invoked using a procedure pointer from either Fortran or C after the host
instance completes execution, because the pointer is then undefined. While the host instance is active, however,
if an internal procedure was passed as an actual argument or is the target of a procedure pointer, it could be
invoked from outside of the host subprogram." (F2023 15.5.1)
Malcolm Cohen (NAG) agrees the code is invalid and is fixing nagfor to give a run-time error in this case.
The text you cite refers to the function return value (procedure pointer in this case) itself, not the pointer's target. For example, a function returning an allocatable array keeps the result around until consumed.

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page