[PATCH] libsupc++: Change _Unordered comparison value to minimum value of signed char.
Jonathan Wakely
jwakely@redhat.com
Wed Aug 27 09:05:41 GMT 2025
On Wed, 27 Aug 2025 at 07:33, Tomasz Kamiński <tkaminsk@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.
>
> The operator<=(partial_order, zero_type) now checks if the reversed value is
> positive. This works correctly because the _Unordered value remains unchanged
> and thus negative.
>
> libstdc++-v3/ChangeLog:
>
> * libsupc++/compare (__cmp_cat::__utype): Define.
> (_Ncmp::_Unordered): Change the value to minimum value of
> signed char.
> (partial_ordering::_M_reverse()): Define.
> (operator<=(partial_ordering, __cmp_cat::__unspec))
> (operator>=(__cmp_cat::__unspec, partial_ordering)): Implemented
> in terms of negated _M_value.
> (operator>=(partial_ordering, __cmp_cat::__unspec))
> (operator<=(__cmp_cat::__unspec, partial_ordering)): Directly
> compare _M_value, as _Unordered value is negative.
> ---
> Tested on x86_64-linux. Testing on powerpc64le.
> OK for trunk when test passes?
>
> libstdc++-v3/libsupc++/compare | 25 +++++++++++++++++++------
> 1 file changed, 19 insertions(+), 6 deletions(-)
>
> diff --git a/libstdc++-v3/libsupc++/compare b/libstdc++-v3/libsupc++/compare
> index 82b5c53139c..ae3a1c5e612 100644
> --- a/libstdc++-v3/libsupc++/compare
> +++ b/libstdc++-v3/libsupc++/compare
> @@ -53,10 +53,14 @@ namespace std _GLIBCXX_VISIBILITY(default)
> namespace __cmp_cat
> {
> using type = signed char;
> + using __utype = unsigned char;
>
> enum class _Ord : type { equivalent = 0, less = -1, greater = 1 };
>
> - enum class _Ncmp : type { _Unordered = 2 };
> + enum class _Ncmp : type {
> + // minimum value of signed char, wraparound negation is no-op
> + _Unordered = static_cast<type>(static_cast<__utype>(1u << (__CHAR_BIT__ - 1)))
Oops, I accidentally replied offlist, repeating my comment for "reply all":
This could be just (-__SCHAR_MAX__ - 1) which seems simpler and has no UB.
Otherwise I really like this change. It's a useful property for the
negative of the value to have the correct meaning for reversed args.
> + };
>
> struct __unspec
> {
> @@ -66,7 +70,7 @@ namespace std _GLIBCXX_VISIBILITY(default)
>
> class partial_ordering
> {
> - // less=0xff, equiv=0x00, greater=0x01, unordered=0x02
> + // less=0xff, equiv=0x00, greater=0x01, unordered=0x80
> __cmp_cat::type _M_value;
>
> constexpr explicit
> @@ -82,6 +86,15 @@ namespace std _GLIBCXX_VISIBILITY(default)
> friend class weak_ordering;
> friend class strong_ordering;
>
> + [[__gnu__::__always_inline__]]
> + constexpr __cmp_cat::type
> + _M_reverse() const
> + {
> + return static_cast<__cmp_cat::type>(
> + static_cast<__cmp_cat::__utype>(
> + static_cast<unsigned int>(-_M_value)));
> + }
> +
> public:
> // valid values
> static const partial_ordering less;
> @@ -112,12 +125,12 @@ namespace std _GLIBCXX_VISIBILITY(default)
> [[nodiscard]]
> friend constexpr bool
> operator<=(partial_ordering __v, __cmp_cat::__unspec) noexcept
> - { return __v._M_value <= 0; }
> + { return __v._M_reverse() >= 0; }
>
> [[nodiscard]]
> friend constexpr bool
> operator>=(partial_ordering __v, __cmp_cat::__unspec) noexcept
> - { return __cmp_cat::type(__v._M_value & 1) == __v._M_value; }
> + { return __v._M_value >= 0; }
>
> [[nodiscard]]
> friend constexpr bool
> @@ -132,12 +145,12 @@ namespace std _GLIBCXX_VISIBILITY(default)
> [[nodiscard]]
> friend constexpr bool
> operator<=(__cmp_cat::__unspec, partial_ordering __v) noexcept
> - { return __cmp_cat::type(__v._M_value & 1) == __v._M_value; }
> + { return 0 <= __v._M_value; }
>
> [[nodiscard]]
> friend constexpr bool
> operator>=(__cmp_cat::__unspec, partial_ordering __v) noexcept
> - { return 0 >= __v._M_value; }
> + { return 0 <= __v._M_reverse(); }
>
> [[nodiscard]]
> friend constexpr partial_ordering
> --
> 2.50.1
>
More information about the Libstdc++
mailing list