Semantically, the language establishes that the right side of the assignment is fully evaluated before the left side is modified. This in effect means two (at least) loops - one to create a temporary array with the expression result, then one to store the result. Early F90 compilers in fact did it this way.
Over the years, compiler writers have enhanced dependence analysis techniques that can often let a compiler detect that there is no overlap or loop-carried dependence and the operation can be simplified using direct stores as the computation progresses. Then the two loops can be combined into one in an optimization called loop fusion.
In the particular cases you mention, additional optimizations such as "strength reduction" can make the array operation as efficient as a DO loop, but sometimes a temp may still be created if the compiler isn't able to determine that it can be avoided.