From: bill on
The code below invokes the subroutine wrapcall with an actual
procedure argument, bar, whose interface differs from the associated
dummy argument, sub, because bar has an explicit-shape argument
declared as x(2) whereas sub has an assumed-shape argument x(:).

module foo
contains
subroutine bar(x)
real, intent(in) :: x(2)

print *, "In bar: x = ", x
end subroutine bar
end module foo

program runfoo
use foo
real :: x(2) = [1, 2]

call wrapcall(x, bar)
contains
subroutine wrapcall(x, sub)
real, intent(in) :: x(:)
interface
subroutine sub(x)
real, intent(in) :: x(:)
end subroutine sub
end interface

print *, "In wrapcall: x = ", x
call sub(x)
end subroutine wrapcall
end program runfoo

Compiling with gfortran we get the output

In wrapcall: x = 1.000000 2.000000
In bar: x = 8.8215270E-39 0.000000

presumably because wrapcall passes a descriptor of x but bar
expects to get the address of x(1). The same happens with g95,
but ifort flags a compilation error:


The characteristics of dummy argument 1 of the associated actual
procedure differ from the characteristics of dummy argument 1 of the
dummy procedure. (12.2) [BAR]
call wrapcall(x, bar)
--------------^
compilation aborted for runfoo.f90 (code 1)


The curious thing is that if we replace the interface block in
wrapcall by

procedure(sarg) :: sub

where sarg has the same (abstract) interface

subroutine sarg(x)
real, intent(in) :: x(:)
end subroutine sarg

then, compiling with g95, everything works fine:

In wrapcall: x = 1. 2.
In bar: x = 1. 2.

It seems perverse that we get a different outcome replacing
the interface block by the procedure statement in this way.
Is this really what the standard says should happen?
From: Richard Maine on
bill <w.mclean(a)unsw.edu.au> wrote:

> The code below invokes the subroutine wrapcall with an actual
> procedure argument, bar, whose interface differs from the associated
> dummy argument, sub, because bar has an explicit-shape argument
> declared as x(2) whereas sub has an assumed-shape argument x(:).

Presumably you know this is invalid, as ifort reports.

> The curious thing is that if we replace the interface block in
> wrapcall by
>
> procedure(sarg) :: sub
>
> where sarg has the same (abstract) interface
>
> subroutine sarg(x)
> real, intent(in) :: x(:)
> end subroutine sarg
>
> then, compiling with g95, everything works fine:
>
> In wrapcall: x = 1. 2.
> In bar: x = 1. 2.
>
> It seems perverse that we get a different outcome replacing
> the interface block by the procedure statement in this way.
> Is this really what the standard says should happen?

The standard says the code is invalid. That's pretty much the end of the
story. This is not a case of invalid code that a compiler is required to
be able to diagnose. The compiler is allowed to do anything with it.

I agree that it is a bit curious that the case with a procedure
statement gives a different result from the case with an interface body.
Sounds like there might be a compiler bug buried in there somewhere. But
even if so, this doesn't demonstrate a compiler bug in conformance to
the standard. It just might make me suspicious that, if the two cases
are treated differently, one might be able to come up with valid code
that doesn't work. But you don't have that. You have invalid code that
does "work"; that's not directly a compiler bug in this case.

--
Richard Maine | Good judgement comes from experience;
email: last name at domain . net | experience comes from bad judgement.
domain: summertriangle | -- Mark Twain
From: James Van Buskirk on
"bill" <w.mclean(a)unsw.edu.au> wrote in message
news:e450c51d-fbaf-4c18-afc6-16665227e0f8(a)s13g2000prd.googlegroups.com...

> The characteristics of dummy argument 1 of the associated actual
> procedure differ from the characteristics of dummy argument 1 of the
> dummy procedure. (12.2) [BAR]
> call wrapcall(x, bar)
> --------------^
> compilation aborted for runfoo.f90 (code 1)

Yeah, ifort has done this since the cvf or even dvf days. It behaves
as though it were building data structures corresponding to dummy
procedures and passing them around via the *.mod files. You get
spoiled by this extra degree of interface checking if dvf/cvf/ifort
is all you ever used, and when you try other compilers generally
you find that they can't distinguish between a function and a
subroutine dummy argument, much less check the whole signature of
the procedure. The reason for this lies in the possibility for a
dummy argument to simply be declared EXTERNAL and impicitly typed
so there is no way for the caller to check its interface. And you
can't require explicit interfaces for everything: what if a
RECURSIVE procedure could be passes itself as an actual argument?
Well, maybe there is no possible useful code where that happens,
but there is no linguistic prohibition either, so you have to take
into account dummies being declared EXTERNAL and implicitly typed,
hence being total wild cards.

There is a good reason for Intel and predecessors to check
procedure arguments possibly to the extent of building data
structures containing their interfaces: mismatched procedure
interfaces are ugly to debug because everything is OK in both the
caller and the callee, it's just the interaction between the two
that's a bug. There is good reason for other vendors not to do
so, however: it's always possible to subvert any procedure
interface checking mechanism, whether intentionally or through
code that is just complicated. Also any feature like this can
be tripped up to the extent of causing errors or ICE. Did
anyone suspect an example was coming?

C:\gfortran\clf\ambinterf>type ambinterf.f90
! File: ambinterf.f90
! Public domain 2008 James Van Buskirk
module interfs
implicit none
contains
subroutine callthru(qsub, option)
implicit logical(q)
integer, intent(in) :: option
external qsub

if(option == 1) then
write(*,'(a)') 'Calling subroutine A'
call A(qsub, 2)
else if(option == 2) then
write(*,'(a)') 'Calling subroutine B'
call B(qsub, 2)
else if(option == 3) then
write(*,'(a)') 'Calling subroutine C'
call C(qsub, 2)
end if
end subroutine callthru

subroutine A(sub, n)
integer, intent(in) :: n
interface
subroutine sub(x)
implicit none
real, intent(in) :: x(:)
end subroutine sub
end interface
real x(n)
integer i

x = [(i,i=1,n)]
call sub(x)
end subroutine A

subroutine subA(x)
real, intent(in) :: x(:)

write(*,*) 'In subA, x = ', x
end subroutine subA

subroutine B(sub, n)
integer, intent(in) :: n
interface
function sub(x)
implicit none
integer, intent(in) :: x
logical sub(x)
end function sub
end interface

write(*,*) 'Result of subB = ', sub(n)
end subroutine B

function subB(x)
integer, intent(in) :: x
logical subB(x)
integer i

subB = [(modulo(i,2) == 0,i=1,x)]
end function subB

subroutine C(sub, n)
integer, intent(in) :: n
interface
function sub(n)
implicit none
integer, intent(in) :: n
integer sub
end function sub
end interface

if(n /= 2) then
write(*,*) 'In subroutine C, result of subC = ', sub(n)
else
write(*,*) 'Nothing to do in subroutine C'
end if
end subroutine C

subroutine subC(n)
integer, intent(in) :: n

write(*,*) 'Shouldn''t have reached this statement'
end subroutine subC
end module interfs

program ambiguous
use interfs
implicit none
integer n

n = 1
call callthru(subA, n)
n = 2
call callthru(subB, n)
n = 3
call callthru(subC, n)
end program ambiguous
! End of file: ambinterf.f90

C:\gfortran\clf\ambinterf>c:\gcc_equation\bin\x86_64-pc-mingw32-gfortran
ambinte
rf.f90 -oambinterf
ambinterf.f90:16.19:

call B(qsub, 2)
1
Error: Type/rank mismatch in argument 'sub' at (1)
ambinterf.f90:19.19:

call C(qsub, 2)
1
Error: Type/rank mismatch in argument 'sub' at (1)
ambinterf.f90:90.14:

use interfs
1
Fatal Error: Can't open module file 'interfs.mod' for reading at (1): No
such fi
le or directory
x86_64-pc-mingw32-gfortran: Internal error: Aborted (program f951)
Please submit a full bug report.
See <http://gcc.gnu.org/bugs.html> for instructions.

C:\gfortran\clf\ambinterf>ifort ambinterf.f90
Intel(R) Fortran Compiler for Intel(R) EM64T-based applications, Version 9.1
Build 20061104
Copyright (C) 1985-2006 Intel Corporation. All rights reserved.

ambinterf.f90(97) : Error: The shape matching rules of actual arguments and
dumm
y arguments have been violated. [SUBB]
call callthru(subB, n)
-----------------^
compilation aborted for ambinterf.f90 (code 1)

Jeez, I thought gfortran would pass this and ifort reject it but
they are both abusing me here! Is there something really wrong
with the above code?

--
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end


From: Tobias Burnus on
On Apr 6, 3:56 am, "James Van Buskirk" <not_va...(a)comcast.net> wrote:
>       subroutine callthru(qsub, option)
>          implicit logical(q)
>          integer, intent(in) :: option
>          external qsub
>
>          if(option == 1) then
>             write(*,'(a)') 'Calling subroutine A'
>             call A(qsub, 2)

"A" takes a subroutine as argument.

>          else if(option == 2) then
>             write(*,'(a)') 'Calling subroutine B'
>             call B(qsub, 2)

While "B" takes a function as argument.

I believe the program is invalid. Quoting the Fortran 2003 standard:

"12.4.1.3 Actual arguments associated with dummy procedure entities"
[...]
"If the interface of the dummy argument is implicit and either the
name of the
dummy argument is explicitly typed or it is referenced as a function,
the dummy
argument shall not be referenced as a subroutine"

As you once reference "qsub" as function and once as subroutine (by
using them as actual argument), the program is invalid and the
compiler is free to reject it. Interestingly, most compiler accept a
reduced version which contains such calls. For the most reduced
version which uses implicit typing, of my compilers, only gfortran
rejects it. For the full program, most of my compilers reject it.

In conclusion, I think gfortran is right and your program is invalid.


>       subroutine  A(sub, n)
>          integer, intent(in) :: n
>          interface
>             subroutine sub(x)
>                implicit none
>                real, intent(in) :: x(:)
>             end subroutine sub
>          end interface

>       subroutine B(sub, n)
>          integer, intent(in) :: n
>          interface
>             function sub(x)
>                implicit none
>                integer, intent(in) :: x
>                logical sub(x)
>             end function sub
>          end interface

Tobias
From: glen herrmannsfeldt on
Tobias Burnus wrote:
(snip)

> I believe the program is invalid. Quoting the Fortran 2003 standard:
>
> "12.4.1.3 Actual arguments associated with dummy procedure entities"
> [...]
> "If the interface of the dummy argument is implicit and either the
> name of the dummy argument is explicitly typed or it is referenced
> as a function, the dummy argument shall not be referenced
> as a subroutine"

I once did something like:

external sub,fun
call test(sub,.true.,x)
call test(fun,.false.,y)
write(*,*) x,y
end

subroutine test(f,select,xy)
logical select
if(select) call f(xy)
if(.not.select) xy=f(1.23)
return
end

subroutine sub(x)
x=3.4
return
end

function fun(x)
fun=4.5
return
end


Note that sub is always called as a subroutine and fun always
as a function, yet some (most) compiler would refuse it.
It seems that the part of the standard quoted supports the
refusal to compile it.

Error: Unclassifiable statement following IF-clause at (1)

That is, in: if(.not.select) xy=f(1.23)

Commenting out the previous statement allows it to compile.
I do believe a better message could be expected in this case.

-- glen