(x*y).real() cannot be optimized into the "naive" formula x.real()*y.real() - x.imag()*y.imag() because they do not give equivalent results in all cases.
Although the ISO C++ standard doesn't seem to specify how std::complex behaves for non-numeric values (infinity, NaN, etc), Annex G of the ISO C standard does, and I would expect most C++ implementations to comply with it. Among its rules are:
A complex number is an infinity if either part is an infinity (+Inf or -Inf), even if the other is NaN.
An infinity multiplied by a finite number (both parts finite) is an infinity.
So for example, if x = (+Inf, NaN) and y = (+1.0, +1.0), then x*y must be an infinity; at least one of its parts must be infinity. But if we used the naive formulas for both the real and imaginary parts of x*y, they would both be NaN. (I suppose this doesn't rule out using the naive formula for the real part only, but it's hard to imagine a practical implementation of complex multiplication that could do this and meet all the constraints.)
Another example would be (+Inf, +Inf) * (+0.0, +1.0). The naive formula would give (NaN, Nan) but the result must be an infinity.
GCC and Clang support the flag -ffinite-math-only, telling them to assume that all floating-point numbers are finite (neither infinity nor NaN). Under this assumption, the naive formula is valid, and if we apply this flag to Pepjin Kramer's example code, you can see that both versions generate identical assembly: https://godbolt.org/z/q3jddhcWv