Reputation:
Consider the following programm :
Subroutine foo(p,v)
implicit none
integer, intent(in) :: p
double precision, dimension(p), intent(in) :: v
!local variables
integer,parameter :: n=floor(par(p))
double precision :: z(2*n)
[...]
End Subroutine
I get the following error:
Error: Array ‘v’ at (1) is a variable, which does not reduce to a constant expression
which is quite explicit but I would like to know if there is a way to manage that kind of situation: assign an intent(in)
argument of the subroutine to a parameter variable?
Upvotes: 2
Views: 986
Reputation: 974
You can use zero-length variables to hold intermediate results that can be extracted from them via specification inquiries. Time for an example:
module mod_par
implicit none
contains
pure function par(x)
double precision par
integer, intent(in) :: x
par = 1+sqrt(real(1,kind(par))+x)
end function par
end module mod_par
module mod_foo
! use mod_par
implicit none
double precision par
contains
subroutine foo(p,v)
implicit none
integer p
double precision v
character(0) sv_i(floor(par(p)))
character(floor(par(p))) sv_j(0)
logical sv_k(floor(par(p)),0)
type t
! Intentionally empty
end type t
type(t) sv_L(floor(par(p)))
type u(len)
integer, len :: len
! intentionally empty
end type u
type(u(floor(par(p)))) sv_m
double precision z(size(sv_i),len(sv_j),size(sv_k,1),size(sv_L),sv_m%len,0)
! double precision z(size(sv_i),len(sv_j),size(sv_k,1),size(sv_L),0)
write(*,*) shape(z)
end subroutine foo
end module mod_foo
program bar
use mod_par
use mod_foo
implicit none
call foo(10,1.0d0)
end program bar
This fails on both ifort and gfortran because a specification function, here par
, must be PURE
and its interface must be explicit. Here par
, though PURE
has an implicit interface, so it's rejected. In fact both compilers seem to get confused:
specvar.f90:21:25:
character(floor(par(p))) sv_j(0)
1
Error: Function 'par' at (1) has no IMPLICIT type
For gfortran, and ifort says
specvar.f90(31): error #6404: This name does not have a type, and must have an e
xplicit type. [PAR]
type(u(floor(par(p)))) sv_m
----------------------^
So we fix this programming error...
module mod_par
implicit none
contains
pure function par(x)
double precision par
integer, intent(in) :: x
par = 1+sqrt(real(1,kind(par))+x)
end function par
end module mod_par
module mod_foo
use mod_par
implicit none
! double precision par
contains
subroutine foo(p,v)
implicit none
integer p
double precision v
character(0) sv_i(floor(par(p)))
character(floor(par(p))) sv_j(0)
logical sv_k(floor(par(p)),0)
type t
! Intentionally empty
end type t
type(t) sv_L(floor(par(p)))
type u(len)
integer, len :: len
! intentionally empty
end type u
type(u(floor(par(p)))) sv_m
double precision z(size(sv_i),len(sv_j),size(sv_k,1),size(sv_L),sv_m%len,0)
! double precision z(size(sv_i),len(sv_j),size(sv_k,1),size(sv_L),0)
write(*,*) shape(z)
end subroutine foo
end module mod_foo
program bar
use mod_par
use mod_foo
implicit none
call foo(10,1.0d0)
end program bar
But now gfortran says
specvar.f90:32:73:
double precision z(size(sv_i),len(sv_j),size(sv_k,1),size(sv_L),sv_m%l
en,0)
1
Error: Variable 'sv_m' cannot appear in the expression at (1)
And ifort:
specvar.f90(31): error #6279: A specification expression object must be a dummy
argument, a COMMON block object, or an object accessible through host or use ass
ociation. [SV_M]
type(u(floor(par(p)))) sv_m
--------------------------------^
So I don't have a sufficiently recent version of either compiler to support type parameter inquiries. Bummer. So we get rid of that last bit...
module mod_par
implicit none
contains
pure function par(x)
double precision par
integer, intent(in) :: x
par = 1+sqrt(real(1,kind(par))+x)
end function par
end module mod_par
module mod_foo
use mod_par
implicit none
! double precision par
contains
subroutine foo(p,v)
implicit none
integer p
double precision v
character(0) sv_i(floor(par(p)))
character(floor(par(p))) sv_j(0)
logical sv_k(floor(par(p)),0)
type t
! Intentionally empty
end type t
type(t) sv_L(floor(par(p)))
type u(len)
integer, len :: len
! intentionally empty
end type u
type(u(floor(par(p)))) sv_m
! double precision z(size(sv_i),len(sv_j),size(sv_k,1),size(sv_L),sv_m%len,0)
double precision z(size(sv_i),len(sv_j),size(sv_k,1),size(sv_L),0)
write(*,*) shape(z)
end subroutine foo
end module mod_foo
program bar
use mod_par
use mod_foo
implicit none
call foo(10,1.0d0)
end program bar
And now both compilers produce good code. So you can see that there are many ways to save a temporary integer variable in specifications of zero-length automatic variables that can be used in further specification expressions. Note that if you get too fancy with this kind of syntax you will crash the compiler a lot.
Upvotes: 0
Reputation: 59998
No, that is impossible. A parameter is a compile-time constant. Its value cannot come from any argument or variable.
It is also not clear at all why would you want to do that (see https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem ). You do not need a parameter to declare an array
double precision :: z(2*floor(par(p)))
because in automatic arrays the bounds can be procedure arguments.
Upvotes: 5