There is no x==x in example 4.3. This is like structured binding where x binds to the first element of the tuple.
If you overload the == operator such that x==x is false then I call UB. Reading and understanding such a codebase would be a nightmare.
Is it actually UB or just stupid? I've never tried to dig in and understand C++ at the standards level, so I don't know, but you don't get to just "call" UB; it has to be UB by the standard.
By itself it is just stupid. Standard defines "EqualityComparable" property and which parts of STL require it to be satisfied. There even some places where it notes that EqualityComparable property isn't required. It is much easier to get UB by having bad < operator.
NaN == NaN is always false (at least in other languages I know).
This will be the case in any language that confirms to IEEE 754 (so, hopefully, all of them (because the only thing more confusing than properly implementing IEEE 754 is improperly implementing your own bespoke subset)). This property of NaN is required by the spec (and is, for example, why Rust's default HashMap refuses to accept floating point numbers as keys).
I can confirm that this is true in C++ (or at least the common implementations), as required by IEEE. In particular, this means that sorting a container including NaNs is undefined behavior (since typical sorting algorithms rely on the property that for any x and y, exactly one of x < y, y < x, or x = y is true).