On Wed, Aug 27, 2025 at 11:15 AM Jonathan Wakely <jwak...@redhat.com> wrote:
> On Wed, 27 Aug 2025 at 07:33, Tomasz Kamiński <tkami...@redhat.com> wrote: > > > > For any minimum value of a signed type, its negation (with wraparound) > results > > in the same value, behaving like zero. Representing the unordered result > with > > this minimum value, along with 0 for equal, 1 for greater, and -1 for > less > > in partial_ordering, allows its value to be reversed using unary > negation: > > static_cast<unsigned char>(static_cast<unsigned int>(-_M_value))). > > The static casts are required to avoid undefined behavior from signed > overflow. > > Do we need so many casts? C++20 guarantees two's complement and the > conversion should be well-defined in all cases. We can only have > signed overflow if signed char is the same width as int (which is > never true for any target supported by GCC). > Indeed there seem to not be any UB: https://eel.is/c++draft/basic.fundamental#4 > > So isn't this equivalent? > > return static_cast<__cmp_cat::type>(-_M_value); > I have gone extra safe to silence any overflow warnings, and tools being tripped by converting 128 to signed char. > -_M_value promotes to int and then there's no UB, because -128 just > becomes 128 which fits in int. The cast back to signed char wraps to > SCHAR_MIN which is the _Unordered value. > > We don't even need that static_cast because the conversion to the > return type does the same thing, but it's more explicit and so a bit > clearer. > Yes, getting back to signed char, is the thing that makes the whole thing work.