The compiler does a bunch of inlining, constant propagation, other optimizing transformations... and it ends up with some code paths that statically represent UB. If the original code couldn't display UB (up to the user to get this right), and the transformations preserve the original code's defined behavior (as of course they should), then it's safe to exploit the fact that these paths are impossible for further optimization or dead code elimination.
Reversing layers of optimization to decide "Is this UB something introduced by me or by the user?" is not something compilers are traditionally architected to do, nor can they typically perform the analysis necessary to determine if a UB code path from either source is guarded by some high level invariants.
In such cases, warnings would be actively harmful, as they'd suggest unneeded corrections.
int f(int x) { return x + 1; }
So can this one: int get(struct Something *s) { return s->field; }
Figuring out when undefined behavior needs a warning and when it's unnecessary because it's known by the programmer to be impossible is a Hard Problem. Especially since the compiler has no idea whether the programmer wrote f() knowing that they'll never pass in INT_MAX, or whether the programmer actually does expect to pass in INT_MAX and expects to receive INT_MIN as the result.Hell during my intro to C course I took at university they told me I should actually detect overflow by seeing if the signs change.
For example, since overflow is undefined, the compiler can assume that an expression like x > x + 1 is always true. Testing with the version of clang that comes with Xcode 7.2, it does this when compiling with -O3.
(Note that this is only true of signed overflow. Unsigned overflow is defined behavior, and all unsigned arithmetic is done modulo 2^n where n is the number of bits in the type.)
The underlying machine is, of course, two's complement. But nothing says the compiler must compile code to match how the underlying machine behaves.
Unfortunately, whoever taught your intro to C course apparently didn't understand C. This is a frighteningly common occurrence, of course. Most people seem to learn C is a very inconsistent way, and imagine a lot of things about it rather than learning how the language actually works.