The compiler is allowed to assume that if x and y are signed ints:
if (x < 0 || y < 0) return -1;
return x * y;
Will not overflow. And if you try to check for overflow with:
if (x < 0 || y < 0) return -1;
if (x * y < 0) return -2;
return x*y;
Then yes, the compiler is within spec to remove your check because the only situation in which you could hit that check would be after signed integer overflow, which it is allowed to assume won't happen.
One way to implement this check in GCC where the compiler will respect it would be:
if (x < 0 || y < 0) return -1;
int z;
if (__builtin_smul_overflow(x, y, &z)) return -2;
return z;
One way to implement this check in GCC where the compiler will respect it would be: