Silverfrost Forums

Welcome to our forums

Argument in brackets is an expression

5 Dec 2012 7:49 #11240

I found an inconsistency with /CHECKMATE and expressions as actual arguments. 😃

In the following two codes the argument (i) is an expression since i is in brackets.

In the first code (where i is undefined before the call to zzz), FTN95 correctly deduces that (i) cannot be evaluated since i is undefined and gives a run-time error with /CHECKMATE turned on.

module foo
contains
   subroutine zzz(j)
      integer :: j
      j = 5
   end subroutine
end module foo

program main
   use foo
   integer i        ! Declare i but leave it undefined
   call zzz((i))    ! Run time error generated here, since (i) is expression
   print *, i
end program main

In the second code (where i is defined before the call to zzz) the assignment to j should generate a run time error with /CHECKMATE but doesn't. However, if I replace (i) with a different expression, e.g. i+0 an error is generated.

module foo
contains
   subroutine zzz(j)
      integer :: j
      j = 5            ! Should generate a run time error here, but doesn't
   end subroutine
end module foo

program main
   use foo
   integer i     ! Declare i
   i = 0          ! Define i before call to zzz
   call zzz((i))
   print *, i
end program main

Is it possible for a dummy argument that is associated with a bracketed actual argument be treated as a variable which cannot be changed please.

5 Dec 2012 8:14 #11242

I have noted your request.

18 Jan 2015 10:21 #15333

I am resurrecting an old thread here.

In this code, where subroutine zzz has an explicit interface and uses intent(out), what is the correct treatment from the following list

  • A result of 0 (this is the answer it gives)
  • A result of 1
  • Compile error

It is clearly (to me anyway 😉 ) illegal code so I would have thought the third option.

I could understand if this was an extension and returned 1 (i.e. brackets are treated as superfluous and removed), but the subroutine returns 0.

module mmm
contains
   subroutine zzz(a)
      real, intent(out) :: a
      a = 1.0
   end subroutine zzz
end module mmm

program main
   use mmm
   real :: a
   a = 0.0
   call zzz((a))
   print *, a, ' <- Prints 0 but should this be 1 (or is this illegal code)?'
end program main
19 Jan 2015 1:11 #15334

I agree with you that the code is illegal. An INTENT(OUT) argument must be definable. An expression is not definable, so an expression cannot be the actual argument corresponding to an INTENT(OUT) dummy argument.

20 Jan 2015 11:06 #15352

This issue has now been fixed for the next release. The compiler now reports an error condition for expressions whilst before it only complained when the argument was a constant value.

20 Jan 2015 4:20 #15356

Paul, the issue reported at the beginning of this thread is still present in the 7.10 compiler.

20 Jan 2015 4:51 #15359

I had assumed that the two issues had the same cause and hence that both would be seen to be fixed in the next release. However it turns out that the first issue is still outstanding.

20 Jan 2015 9:55 #15361

Well I must admit to being a bit confused (again!).

As I understand it there are two issues:

(1) When an actual argument is a variable in brackets, the argument should be treated as an expression (I don't think the compiler vendor can do otherwise as an extension -- this is part of the Standard). In most cases compiling with /CHECKMATE will detect [u:f826cd001a]at run time[/u:f826cd001a] any attempt to alter the value of an actual argument expression by assigning a value to the dummy argument. However in the special case of a bracket-variable-expression it doesn't work.

(2) When an explicit interface (e.g. through USE of a module) [u:f826cd001a]and[/u:f826cd001a] intent(out) is used for the dummy argument, the compiler should be able to detect [u:f826cd001a]at compile time[/u:f826cd001a] that it cannot pass a constant or expression as the actual argument. It should be able to do this regardless of whether /CHECKMATE is used or not. In the special case of a bracket-variable-expression it doesn't work.

These issues are similar but not the same. One is a limitation of the run time checking system, the other is a bug in the syntactical analysis of the compiler.

Run-time checking with /CHECKMATE happens even with an explicit interface since version 6.30 (see release notes). The run time checking may seem redundant in such cases but it allows the 'constantness' of the variable to be checked if it is subsequently passed to an external subroutine/function without an explicit interface. Therefore for protection in all cases it is necessary that both (1) and (2) work.

It looks like Paul has fixed issue (2) but not issue (1). Perhaps you can confirm Paul ?

21 Jan 2015 12:07 #15363

It looks like Paul has fixed issue (2) but not issue (1).

It is quite clear to me from what Paul wrote that, indeed, that is true.

We should perhaps not be too fussy about whether a certain error is detected at compile time or at run time, although the former is most often preferable. Here is an example, taken from a rather large program, in which an active DO index is passed to a subroutine where it gets changed. FTN95 does not detect the bug at compile time, even if an explicit interface is available.

program tst
	implicit none
	integer :: i,j,k
	do i=10,20
	   j=2*i*i-3
	   call sub(i,j,k)
	   write(*,*)i,j,k
	end do
contains
	subroutine sub(i,j,k)
	implicit none
	integer,intent(in out) :: i
	integer, intent(in) :: j
	integer, intent(out) :: k
	k=i+j
	i=i+1 !<<<=== illegal
	return
	end subroutine sub
end program tst
21 Jan 2015 8:15 #15367

This is an interesting case.

FTN95 can catch such errors at run time if /CHECKMATE is used.

However, this is another case where widening the definition of what constitutes an actual argument expression would be helpful.

For now, changing the argument from i to i*1 allows the compiler to see it as an expression and issue an error.

I know that not all wrinkles in the compiler can always be patched but it is at least helpful to be aware of these shortcomings when programming.

21 Jan 2015 8:30 #15368

Going back to the original sample program on this thread where the INTENT is not specified and hence is unknown to the compiler, let me begin with a word of explanation for those reading this post who are less familiar with the details.

In the call to zzz, the argument is in brackets so the compiler treats this as an expression to be evaluated and stored as a temporary. The address of the temporary is passed to zzz where its value is changed. On return this value is 'lost' and the value of i remains the same as before the call to zzz. If i is initially undefined (and /UNDEF is used) then there will be a run-time failure when i is printed. In other words, you get the value of i before the call.

Given that the later issue (where the INTENT is specified) has been fixed for the next release, as far as I understand it, that's the best the compiler can do. In order to flag an error it is necessary to specify the INTENT as OUT or INOUT. If the INTENT is unknown to the compiler then (at the point of call) it cannot assume that it is not INTENT(IN).

24 Jan 2015 4:36 #15432

Quoted from PaulLaidler

In the call to zzz, the argument is in brackets so the compiler treats this as an expression to be evaluated and stored as a temporary. The address of the temporary is passed to zzz where its value is changed. On return this value is 'lost' and the value of i remains the same as before the call to zzz.

Yes indeed Paul; this is a good summary. But can you explain why the treatment of the temporary is different for the two codes below?

The first code gives '*** Error 14, Attempt to alter actual argument that is a constant, an expression, or ...', whilst the second code does not.

The only difference is that the expression in one case is (a) and in the other is a+0.

subroutine xxx(a)
   real :: a
   a = 1.0
end subroutine xxx

program main
   real :: a
   a = 0.0
   ! Argument is expression so address of temporary is passed
   call xxx(a+0)
   print *,'a = ', a, ' <-- should be zero'
end program main




subroutine xxx(a)
   real :: a
   a = 1.0
end subroutine xxx

program main
   real :: a
   a = 0.0
   ! Argument is expression so address of temporary is passed
   call xxx((a))
   print *,'a = ', a, ' <-- should be zero'
end program main
24 Jan 2015 5:06 #15433

For both the test programs in the previous post, NAG Fortran says:

Runtime Error: x1.f90, line 3: Dummy argument A is associated with an expression - cannot assign Program terminated by fatal error Note the line number where the error is detected.

26 Jan 2015 7:40 #15446

For me (i.e. using the pre-release version) there is no difference in the behaviour. So I think that you will find that there will be consistency here.

I am not sure why but this appears to be included in the current fix.

26 Jan 2015 8:07 #15461

Quoted from PaulLaidler For me (i.e. using the pre-release version) there is no difference in the behaviour.

When you fixed the issue with intent(out) you must have fixed this as well without knowing.

Ideally the consistent behaviour you talk about should be a run-time error for both codes 😄

Thanks Paul.

26 Jan 2015 9:10 #15463

My mistake! I forgot to use /undef in the latest test.

I will note this as still open.

26 Jan 2015 10:02 #15468

😛 Nothing is free after all.

I had a look at the assembly code for both codes with /check on and it was clear there is a difference with 7.1.

27 Jan 2015 1:02 #15480

This has now been fixed for the next release.

When using /CHECK,

call xxx(a+0)

and

call xxx((a))

both fail at run time when the INTENT is unknown and the dummy argument is assigned a value.

27 Jan 2015 1:17 (Edited: 15 Jun 2015 11:05) #15481

We appreciate the prompt and efficient response from Silverfrost to the bug report and look forward to the next release of the compiler.

[P.S., 15 June 2015: The bug is not present in FTN95-7.20]

27 Jan 2015 6:33 #15499

This is good news. Thanks very much Paul 😃

Please login to reply.