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.

Reply via email to