The answer by Vladimir F tells the important part: for (i,j) to be a complex literal constant i and j must be constants.1 As stated there, the intrinsic complex function cmplx can be used in more general cases.
For the sake of some variety and providing options, I'll look at other aspects of complex arrays. In the examples which follow I'll ignore the output statement and assume the declarations given.
We have, then, Vladimir F's correction:
do i=1,3
do j=1,3
indx(i,j) = CMPLX(i,j) ! Note that this isn't in array element order
end do
end do
We could note, though, that cmplx is an elemental function:
do i=1,3
indx(i,:) = CMPLX(i,[(j,j=1,3)])
end do
On top of that, we can consider
indx = RESHAPE(CMPLX([((i,i=1,3),j=1,3)],[((j,i=1,3),j=1,3)]),[3,3])
where this time the right-hand side is in array element order for indx.
Well, I certainly won't say that this last (or perhaps even the second) is better than the original loop, but it's an option. In some cases it could be more elegant.
But we've yet other options. If one has compiler support for complex part designators we have an alternative for the first form:
do i=1,3
do j=1,3
indx(i,j)%re = i
indx(i,j)%im = j
end do
end do
This doesn't really give us anything, but note that we can have the complex part of an array:
do i=1,3
indx(i,:)%re = [(i,j=1,3)]
indx(i,:)%im = [(j,j=1,3)]
end do
or
do i=1,3
indx(i,:)%re = i ! Using scalar to array assignment
indx(i,:)%im = [(j,j=1,3)]
end do
And we could go all the way to
indx%re = RESHAPE([((i,i=1,3),j=1,3))],[3,3])
indx%im = RESHAPE([((j,i=1,3),j=1,3))],[3,3])
Again, that's all in the name of variety or for other applications. There's even spread to consider in some of these. But don't hate the person reviewing your code.
1 That's constants not constant expresssions.