This is embarrassing.
The reason the compiler (GCC in this case) was optimising away the comparison and isnan returned false was because someone in my team had turned on -ffast-math.
From the docs:
-ffast-math
Sets -fno-math-errno, -funsafe-math-optimizations, -fno-trapping-math,
-ffinite-math-only, -fno-rounding-math, -fno-signaling-nans and
fcx-limited-range.
This option causes the preprocessor macro __FAST_MATH__ to be defined.
This option should never be turned on by any -O option since it can result in
incorrect output for programs which depend on an exact implementation of IEEE
or ISO rules/specifications for math functions.
Notice the ending sentence – -ffast-math is unsafe.