Well, if a compiler does short circuit it is a bug or at least an extension starting with 2023 Fortran according to my read of some of the following sections, although I was using said extensions early on, particularly with passing an optional argument to MERGE
At least in the 2023 Standard all the arguments are required to be evaluated
per 15.5.3 (Function reference) and 15.5.4 (Subroutine reference).
There were some compilers that treated a MERGE() just like IF/ELSE/ENDIF
and so only evaluated one of the first two arguments of MERGE() but so far
everyone I tested now evaluates both expressions, at least with a simple
test using contained procedures with side effects.
program main
use shortcircuit, only: say_hello
implicit none
integer,save :: countone=0, counttwo=0
integer :: result=0
call say_hello()
result=result+merge(one(),two(),.true.)
result=result+merge(one(),two(),.false.)
write(*,*)result
write(*,*)countone,counttwo
contains
function one()
integer :: one
one=1
countone=countone+1
end function one
function two()
integer :: two
two=2
counttwo=counttwo+1
end function two
end program main
Output
That is, the standard requires the counts to be 2:
3
2 2
The pertinent part of the standard is
15.5.3 Function reference
A function is invoked during expression evaluation by a
function-reference or by a defined operation (10.1.6). When it
is invoked, all actual argument expressions are evaluated then the
arguments are associated, and then the function is executed. When
execution of the function is complete, the value of the function
result is available for use in the expression that caused the
function to be invoked. The characteristics of the function result
(15.3.3) are determined by the interface of the function. If a
reference to an elemental function (15.9) is an elemental reference,
all array arguments shall have the same shape.
Notice the “all actual argument expressions are evaluted”**.
Note C.6.1 says the order is up to the compiler, but whether arguments are
evaluated is not (now?) per 15.5.3.
So there is all kinds of related information relating to why you should not pass
optional parameters to MERGE, what happens with unallocated arguments, arrays,
masked arrays, pointers …
Much of it relates to the history of choosing the syntax for test?expr1:expr2,
borrowed from C which is my least favorite C syntax after the overuse of “{}”;
and why MERGE() was not just made a special case that did shortcircuit.
I did not go back to see how far that clear a statement was there, as I remember
thinking it was not defined by the standard and up to the processor; and there
are definitely places where the processor is allowed (but not required) to
short-circuit, as in
10.1.7 Evaluation of operands
It is not necessary for a processor to evaluate all of the operands
of an expression, or to evaluate entirely each operand, if the value
of the expression can be determined otherwise.
NOTE1
This principle is most often applicable to logical expressions,
zero-sized arrays, and zero-length strings, but it
applies to all
expressions.
For example, in evaluating the expression
X > Y .OR. L (Z)
where X, Y, and Z are real and L is a function of type logical, the
function reference L (Z) need not be evaluated
if X is greater than
Y. Similarly, in the array expression
W (Z) + A
where A is of size zero and W is a function, the function reference W
(Z) need not be evaluated.
but a good rule to go by is to assume everything is evaluated
unless you use test?expr1:expr2 or flow control (eg. if-else-elseif-endif, do, …).