nonportable-shortcircuit-inquiry (C161)
This rule is turned on by default.
What it does
Checks for use of a variable in the same logical expression as "definedness" inquiry.
Why is this bad?
Unlike many other languages, the Fortran standard doesn't mandate (or prohibit)
short-circuiting in logical expressions, so different compilers have different
behaviour when it comes to evaluating such expressions. This is commonly encountered
when using present() with an optional dummy argument and checking its value in the
same expression. Without short-circuiting, this can lead to segmentation faults when
the expression is evaluated if the argument isn't present.
Instead, you should nest the conditional statements, or use the Fortran 2023
"condtional expression" (also called ternary expressions in other
languages). Unfortunately, any else branches may need to be duplicated or
refactored to accommodate this change.
This lack of short-circuiting also affects other inquiry functions such as
associated and allocated which are used to guard invalid accesses.
Example
Don't do this:
integer function example(arg1)
integer, optional, intent(in) :: arg1
if (present(arg1) .and. arg1 > 2) then
example = arg1 * arg1
else
example = 1
end if
arg1 > 2 even if present(arg1) is
false. This is a runtime error, and may crash your program.
Use instead, noting that we either need to duplicate the else branch, or refactor
differently:
integer function example(arg1)
integer, optional, intent(in) :: arg1
if (present(arg1)) then
if (arg1 > 2) then
example = arg1 * arg1
else
example = 1
end if
else
example = 1
end if
Or with Fortran 2023 (not currently supported by most compilers!):
integer function example(arg1)
integer, optional, intent(in) :: arg1
example = present(arg1) ? (arg1 > 2 ? arg1 * arg1 : 1) : 1