I know that (at least at one point), the following is invalid Fortran due to aliasing
program main
integer :: x, y
! compilers assume a and b to be distinct
y = f(x, x)
contains
integer function f(a, b) result(c)
integer, intent(in out) :: a, b
a = 1
b = 2
c = a ! compiler can optimize to c = 1
end function
end program main
But is the following valid?
program main
integer :: x(3)
x = [1, 2, 3]
x = square_me(x)
contains
function square_me(a) result(squared)
integer, intent(in out) :: a(3)
integer :: squared(3)
squared = a ** 2
a(1) = 0 ! nasty side-effect
end function
end program main
It works in gfortran, but I'm not sure if it's standard-conforming.
I'm aware side-effects in functions are not a good idea. I'm dealing with >100k lines of legacy code that likes to use C-style integer-code-returning functions and modifying arguments, so this question is specifically about the standard.
Neither main program is valid.
The so-called aliasing rules in Fortran are generally taken to mean those restrictions which apply to entities during the execution of a procedure. In an assignment statement, however, evaluation of the right-hand side is fully performed before the left-hand side is affected.
Instead, what breaks the second main program is a restriction on side effects of functions.
A side effect is restricted (F2018, 10.1.4) in that, except in some cases not applicable here:
if a function reference causes definition or undefinition of an actual argument of the function, that argument or any associated entities shall not appear elsewhere in the same statement
The assignment to a(1)
causes definition of the actual argument x
, so x
may not appear elsewhere in the assignment statement (including the left-hand side).
There are several other (perhaps surprising) restrictions on side effects in functions. Let's just say: avoid side effects in functions if you can unless you really know the rules, and can be sure that everyone using your function also really really knows the rules.