The default is no INTENT specified, which is not the same as INTENT(INOUT). INTENT(INOUT) specifies the argument is definable, so technically you could not pass an expression, for example.
INTENT(OUT) means I am going to specify the value on return but do not need the current value, INTENT(INOUT) means I need the current value and am going to set the value on return and no INTENT means no such assumptions. So both
INTENT(OUT) and INTENT(INOUT) imply the argument passed is definable and should not be a constant or expression, for example.
You might get the same answer if you remove all the INTENT attributes and they were done correctly but perhaps not the same optimizations. Passing an argument that the compiler decides to do a gather/scatter on would not need to do the scatter if INTENT(IN) is specified, for example. The standard leaves nearly everthing up to the compiler but nothing prevents the compiler from enforcing INTENT, it is just very difficult to enforce.
NOTE 4 in section 8.5.10 gives perhaps the best condensed description; although the behavior with pointer arguments is a bit harder to digest.
Obviously at least one compiler actually uses the INTENT(OUT) description as it caused the bug you described; so it is not like INTENT always has no effect; but the machine code produced is often the same whether the option is there or not; partly because the compiler can be smart enough to draw the same conclusion; perhaps because the compiler treats it merely as a comment mostly useful to someone maintaining the code in the future.
Because of the very bug you describe that can be introduced I have seen several discussions where people say they remove all the INTENT attributes, but I find it useful myself.
8.5.10 INTENT attribute
NOTE4
Argument intent speciļ¬cations serve several purposes in addition to documenting the intended use of dummy
arguments. A processor can check whether an INTENT (IN) dummy argument is used in a way that could
redeļ¬ne it. A slightly more sophisticated processor could check to see whether an INTENT (OUT) dummy
argument could possibly be referenced before it is defined. If the procedureās interface is explicit, the processor
can also verify that actual arguments corresponding to INTENT (OUT) or INTENT (INOUT) dummy argu-
ments are definable. A more sophisticated processor could use this information to optimize the translation of
the referencing scoping unit by taking advantage of the fact that actual arguments corresponding to INTENT
(IN) dummy arguments will not be changed and that any prior value of an actual argument corresponding to
an INTENT (OUT) dummy argument will not be referenced and could thus be discarded.
INTENT (OUT) means that the value of the argument after invoking the procedure is entirely the result of
executing that procedure. If an argument might not be redeļ¬ned and it is desired to have the argument retain its
value in that case, INTENT (OUT) cannot be used because it would cause the argument to become undeļ¬ned;
however, INTENT (INOUT) can be used, even if there is no explicit reference to the value of the dummy
argument.
INTENT (INOUT) is not equivalent to omitting the INTENT attribute. The actual argument corresponding
to an INTENT (INOUT) dummy argument is always required to be deļ¬nable, while an actual argument
corresponding to a dummy argument without an INTENT attribute need be deļ¬nable only if the dummy
argument is actually redeļ¬ned.
I wish it was enforced more often, and I wish it was implemented on the procedure header itself and optionally on the call as well, so it looked like
subroutine(a>,b>,<c>,<c) or (a>,b>,c<>,d<). If that notation meant a call had to use matching notation it would be easier for a compiler to enforce, but that would mean if you changed the routine you would have to change all the calls and is perhaps too burdensum a syntax.
I think the default being anything but the current lack of intent would be problematic for a subroutine, but I do wish functions defaulted to everything being INTENT(IN) as well, but that is somewhat a personal taste I suppose ( I really like to avoid changing input values with a function, but admit to doing it occasionally with an optional error code parameter).