No virtual destructors in fortran 2003? - fortran

Do I understand correctly that there are no virtual destructors in F2k3 ?
stefanos-imac:oop borini$ cat a.f90
module AModule
type :: AType
contains
final :: A_dtor
end type
contains
subroutine A_dtor(self)
type(AType), intent(inout) :: self
print *, "A_dtor"
end subroutine
end
stefanos-imac:oop borini$ cat b.f90
module BModule
use AModule
type,extends(AType) :: BType
contains
final :: B_dtor
end type
contains
subroutine B_dtor(self)
type(BType), intent(inout) :: self
print *, "B_dtor"
end subroutine
end
stefanos-imac:oop borini$ cat x.f90
program x
use AModule
use BModule
class (AType), pointer :: baseptr
type(BType), pointer :: derivedptr
allocate(derivedptr)
baseptr => derivedptr
deallocate(baseptr)
end program
stefanos-imac:oop borini$ ./a.out
A_dtor
forrtl: severe (173): A pointer passed to DEALLOCATE points to an array that cannot be deallocated
Image PC Routine Line Source
a.out 0000000108A731F4 Unknown Unknown Unknown
a.out 0000000108A7198E Unknown Unknown Unknown
a.out 0000000108A4D791 Unknown Unknown Unknown
a.out 0000000108A2283E Unknown Unknown Unknown
a.out 0000000108A3B930 Unknown Unknown Unknown
a.out 0000000108A1EF10 Unknown Unknown Unknown
a.out 0000000108A0A104 Unknown Unknown Unknown
a.out 0000000108A09F0C Unknown Unknown Unknown
a.out 0000000108A09EC4 Unknown Unknown Unknown

I am not so sure about the C++ or Java terminology you use (virtual). I would prefer using Fortran terms when speaking about Fortran. In Fortran terms finalization procedures are not inherited and cannot be overriden. Finalization procedures of both the new type and the extended type should be executed.
As far as I understand the problem, even though I do not have a compiler with a good support for it, your program seems correct. I would expect output:
B_dtor
A_dtor
Do not make assumptions about Fortran 2003 and 2008 standards form some specific compilers, because there are no true Fortran 2003 compilers yet, eventhough couple of them pretend to be. Intel Fortran AFAIK does not claim to be fully Fortran 2003 compliant.

Related

Fortran use gdb to print function name from address

Let's assume I have the following code:
module eval_mod
implicit none(type, external)
private
public :: eval
abstract interface
real pure function real_function_t(x)
real, intent(in) :: x
end function
end interface
contains
pure function eval(f, x) result(res)
procedure(real_function_t) :: f
real, intent(in) :: x
real :: res
res = f(x)
end function
end module
program main
use iso_fortran_env, only: stdout => output_unit
use eval_mod, only: eval
implicit none(type, external)
write(stdout, *) eval(double, 2.)
write(stdout, *) eval(triple, 2.)
contains
pure real function double(x)
real, intent(in) :: x
double = 2. * x
end function
pure real function triple(x)
real, intent(in) :: x
triple = 3. * x
end function
end program
and compile it with gfortran -Wall -Wextra -Werror -g -fbounds-check.
If I set a breakpoint to eval_mod::eval, I would like to see with which function argument eval was called.
What I actually see is
Breakpoint 2, eval_mod::eval (f=0x7fffffffced8, x=2) at main.F90:17
If I take the address and follow this question, I should be able to see the function name in the symbol table by doing:
info symbol 0x7fffffffced8
Unfortunately I get an error
No symbol matches 0x7fffffffced8.
How can I see the function name of a function passed as argument?
PS: I use gfortran 7.5.0 and gdb 11.1.
double and triple are internal functions (inside the main program). Passing internal functions is tricky due to the host association of the variables from the parent scope. Therefore they are often implemented using trampolines. The address you see is the address of the trampoline, in other words, a so called thunk. The trampoline than calls the actual function.
The address most likely points somewhere on the stack where the trampoline code is placed. In that code you will likely find a jump instruction with the address of the actual function.
See also this great article by Steve Lionel Doctor Fortran in “Think, Thank, Thunk”

GNU Fortran compiler on Windows Subsystem for Linux - Segmentation fault with passing internal function to another procedure [duplicate]

This question already has an answer here:
Segmentation fault when passing internal function as argument
(1 answer)
Closed 2 years ago.
I believe the following is a valid Fortran 2008 program and it works fine on genuine macOS, Linux, and Windows operating systems with both Intel and GNU Fortran compilers.
module InternalFuncCaller_mod
implicit none
abstract interface
function getInternalFunc_proc(input) result(output)
implicit none
real, intent(in) :: input
real :: output
end function getInternalFunc_proc
end interface
contains
subroutine callInternalFunc(getInternalFunc, x)
implicit none
procedure(getInternalFunc_proc) :: getInternalFunc
real, intent(in) :: x
write(*,*) getInternalFunc(x)
end subroutine callInternalFunc
end module InternalFuncCaller_mod
module InternalFunc_mod
implicit none
contains
subroutine passInternalFunc()
use InternalFuncCaller_mod, only: callInternalFunc
implicit none
call callInternalFunc(getThisInternalFunc, x = 4.)
contains
function getThisInternalFunc(x) result(sqrtx)
implicit none
real, intent(in) :: x
real :: sqrtx
sqrtx = sqrt(x)
end function getThisInternalFunc
end subroutine passInternalFunc
end module InternalFunc_mod
program testInternalFuncCall
use InternalFunc_mod
implicit none
call passInternalFunc()
write(*,*) "Done."
end program testInternalFuncCall
However, when compiled with GFortran on a Windows Subsystem for Linux (WSL) (Ubuntu) and run, it gives the following SegFault error message:
Program received signal SIGSEGV: Segmentation fault - invalid memory reference.
Backtrace for this error:
#0 0x7ffb84580d3a
#1 0x7ffb8457fed5
#2 0x7ffb843a620f
#3 0x7fffde946cb0
Segmentation fault (core dumped)
I have traced the issue to the internal function call by the external procedure. But the same code works fine on all other Operating Systems with different Fortran compilers. So, this does not appear to be a bug with GNU GFortran, but more likely an issue with static compilation and execution of code that contains external calls to internal procedures of another procedure, in particular, on WSL OS.
To give more information, I have noticed that the library works fine (even with internal function calls) when it is built as a shared library. However, it fails with the same error message when compiled a static library.
So, it seems like a combination of some GFortran flags can somehow resolve the error (-fPIC -shared). Any help on how to resolve this problem is greatly appreciated.
As the person with the problem in Segmentation fault when passing internal function as argument I've found moving to WSL version 2 fixes the issue for me.

iso_fortran_env kind values not compile-time constant [duplicate]

In a Fortran 2003 module I'm defining a type called t_savepoint and, later, I want to define an interface for a subroutine called fs_initializesavepoint, which takes an object of type t_savepoint as only argument.
Here is the code for the whole module:
module m_serialization
implicit none
type :: t_savepoint
integer :: savepoint_index
real :: savepoint_value
end type t_savepoint
interface
subroutine fs_initializesavepoint(savepoint)
type(t_savepoint) :: savepoint
end subroutine fs_initializesavepoint
end interface
end module m_serialization
The reason why I want such an interface is that later on I will make this fortran module interoperate with C.
If I try to compile it (gfortran-4.7.0), I get the following error message:
type(t_savepoint) :: savepoint
1
Error: The type of 'savepoint' at (1) has not been declared within the interface
The error disappears if I move the definition of the type inside the subroutine; but if then I want to use the same type within many subroutines, should I repeat the definition in all of them?
Thank you in advance.
EDIT: a solution would be to move the definition of the type onto another module and then to use it in every subroutine. However I don't like this solution too much, because the type t_savepoint and the subroutines are part of the same conceptual topic.
Rightly or wrongly in an interface block you don't have access to the environment by host association. To fix this you need to import the datatype exlicitly:
[luser#cromer stackoverflow]$ cat type.f90
module m_serialization
implicit none
type :: t_savepoint
integer :: savepoint_index
real :: savepoint_value
end type t_savepoint
interface
subroutine fs_initializesavepoint(savepoint)
Import :: t_savepoint
type(t_savepoint) :: savepoint
end subroutine fs_initializesavepoint
end interface
end module m_serialization
[luser#cromer stackoverflow]$ gfortran -c type.f90
This is f2003.
However I suspect the way you have put this suggests you are not going about coding this up the best way. Better is simply to put the routine itself in the module. Then you don't need bother with the interface at all:
module m_serialization
implicit none
type :: t_savepoint
integer :: savepoint_index
real :: savepoint_value
end type t_savepoint
Contains
Subroutine fs_initializesavepoint(savepoint)
type(t_savepoint) :: savepoint
Write( *, * ) savepoint%savepoint_index, savepoint%savepoint_value
End Subroutine fs_initializesavepoint
end module m_serialization
[luser#cromer stackoverflow]$ gfortran -c type.f90
Given that modules are really designed to deal with connected entities this is really the way to do it in Fortran. It also has the advantage of only requiring a f95 compiler, so is universally available (though admittedly import is commonly implemented)

Signature matches another specific subroutine that shares the same assignment generic binding (but it doesn't)

I am migrating from ifort14 to ifort16, on 14 the code compiles and runs fine on 16 I get a compile time error which makes no sense to me. Long story short the compiler complains about a procedure whose definition is the last in the file and if I change the order it will complain about a different procedure, again the one that comes last. The error does not make any sense and this behaviour does not make sense either. Does this sound familiar to someone and do you have any idea where I could look for the problem?
I have the following structure
File1:
module model_generic
implicit none
type, abstract :: modelGen
logical, public :: init_flag = .false.
contains
procedure :: isInit => dispInitFlag_model
procedure, nopass :: taylorRule_func
procedure, nopass :: penalty_func
end type modelGen
contains
function dispInitFlag_model(this) result(init_flag)
class(modelGen), intent(in) :: this
logical :: init_flag
init_flag = this%init_flag
end function dispInitFlag_model
end module model_generic
File2:
module model_nk_generic
use model_generic
implicit none
type, abstract, extends(modelGen) :: model_nk
logical, public :: init_flag_nk = .false.
contains
procedure :: isInit => dispInitFlag_model_nk
procedure :: setIniGuess => setIniGuess_model_nk_default
! deferred procedures
procedure(obj_func), deferred :: lossFunction
procedure(IS_PC_curves), deferred :: IS_PC0
procedure(Taylor_IS_PC_curves), deferred :: taylor_IS_PC
procedure(IS_curve), deferred :: IS
procedure(PC_curve), deferred :: PC
procedure(R_trans), deferred :: R_lom
procedure(A_trans), deferred :: A_lom
procedure(eps_trans), deferred :: eps_lom
generic :: IS_PC => IS_PC0, taylor_IS_PC
end type model_nk
abstract interface
! omitted
end interface
contains
function dispInitFlag_model_nk(this) result(init_flag_nk)
class(model_nk), intent(in) :: this
logical :: init_flag_nk
init_flag_nk = this%init_flag_nk
end function dispInitFlag_model_nk
subroutine setIniGuess_model_nk_default(this,VFonGrid,grid)
class(model_nk), intent(in) :: this
real(KIND=DP), dimension(:), intent(out) :: VFonGrid
real(KIND=DP), dimension(:,:), intent(in), optional :: grid
VFonGrid = 0e0
!VFonGrid = 1._DP
end subroutine setIniGuess_model_nk_default
end module model_nk_generic
The error I receive during compilation (the above is compiled as a part of a bigger project) is
error #8437: The type/rank signature for the arguments of this specific
subroutine matches another specific subroutine that shares the same
ASSIGNMENT generic binding.
end subroutine setIniGuess_model_nk_default
^
The procedure (or its binding name) does not appear anywhere else in the programme except one module where it is called (I grepped for it to be sure). Thus it cannot share any generic binding. When I delete it the compiler gives me the same error with the dispInitFlag_model_nk procedure. When I add a do_nothing procedure then it will complain about that one. The compiler seems to always complain about the last procedure in the file.
A minimalistic test case like below compiles fine (using the same makefile). Another code without any OOP features compiles fine too.
program main
use model_generic
use model_nk_generic
class(model_nk), allocatable :: svars
end program main
Every time I do a clean compilation, all libraries that I use I compile from source except MKL but that should be linked correctly I have checked that.
Does any one have any idea what could be wrong with the source file or with my compiling environment?
Edit1: Forgot to mention the compiler flags. Normally I use ifort -openmp -O3 but I also tried my usual set of debugging flags ifort -openmp -g -p -traceback -check bounds -ftrapuv -fpe0 -O0 -warn -check uninit -gen-interfaces -warn interfaces -check all and I tried with and without the -openmp flag. At some point the compiler told me the flag was deprecated but using -qopenmp instead did not change things.
Edit2: Probably I should also have mentioned that I also use the preprocessor. And both files are preprocessed. But again on v14 it works fine and the error occurs in file2 after file1 (its dependency) is compiled.

accessing variables of fortran module from c++

Currently I am working on a project that requires integrating fortran code to c++. In fortran module lots of variables and arrays are declared. I am able to access the integer,float and double types from c by declaring a c variable as extern double common_area_mp_rmax_ when the corresponding fortran declaration is real*8 rmax and the name of the module is common_area. However, when I try to do the same for an array I am getting error.
suppose the code in fortran module is:
real*8,allocatable,dimension(:,:,:) :: x
I have cretaed a c double pointer as:
extern "C"
{
double* common_area_mp_x_;
}
Now when I compile the whole project, it says "multiple definition of `variable_area_mp_x_'". I am using CMake to compile the whole project.
Can someone shed some light what I am doing wrong? I am new to fortran and it is getting hard for me to fix this. I appreciate your time and help.
Thanks,
mindbender
Fortran 2003 introduced interoperability with C into the standard Fortran language. Unless you have good reasons to the contrary, you should be using the facilities provided by this language feature. See the fortran-iso-c-binding tag on this site for examples.
Under the current Fortran standard (and in the draft of the next standard revision), a Fortran allocatable module variable is not interoperable with a C variable.
In terms of implementation, the Fortran compiler will use a descriptor to store the allocation status of the allocatable variable. There is more to this descriptor than just a pointer to the data - see "Handling Fortran Array Descriptors" in the compiler's User and Reference guide for more information.
The best approach to sharing information in this case depends on what you are trying to do. One option is to give the allocatable array the TARGET attribute, and then have a separate variable of TYPE(C_PTR) with a binding label with the C address of the target. Aspects such as the size of the array would need to be communicated separately.
MODULE common_area
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTR, C_DOUBLE
IMPLICIT NONE
...
REAL(C_DOUBLE), ALLOCATABLE, TARGET :: x(:,:,:)
TYPE(C_PTR), BIND(C, NAME='x_ptr') :: x_ptr
CONTAINS
! Call before operating on x_ptr in C++
SUBROUTINE init
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_LOC
ALLOCATE(x(1,2,3))
x_ptr = C_LOC(x)
END SUBROUTINE init
~~~
// After init has been executed, this is a
// pointer to the value of the allocatable module variable
extern "C" double *x_ptr;
Given a C++ file test.cpp with contents
extern "C" { double * foo; }
extern double bar;
double asdf;
with gnu tools
g++ -Wall -c test.cpp; nm test.o
> 0000000000000000 B asdf
> 0000000000000008 B foo
i.e. using the first option actually introduces a new symbol with that name.
In this case the right choice would be
extern double * common_area_mp_x_;