How can this be a bug in our code? Wraparound of unsigned values is
well-defined.

True, it is well-defined, but it was not intended for sure, hence it's a 100% bug. Eli's term of "undefined behavior" was an exaggeration I think.

I don't think the compiler is justified in making this optimization.
Since when is an infinite loop undefined behavior? GCC has no right to
alter program semantics in this case, loop unrolling or no.

I would agree here, throwing out wrapped loop is just too much even though such loop was unintended. GCC should have either left it alone since it is infinite or make a warning. I think this case is still worth showing to GCC developers.