Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 28 additions & 17 deletions stl/inc/compare
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ enum class _Compare_ord : _Compare_t { less = -1, greater = 1 };
enum class _Compare_ncmp : _Compare_t { unordered = -128 };

_EXPORT_STD struct partial_ordering {
template <int> // Prevent unwanted construction without interfering with overload resolution or the MSVC ABI.
constexpr partial_ordering() = delete; // constexpr is necessary, see N5032 [basic.types.general]/10.5.3.4.

static const partial_ordering less;
static const partial_ordering equivalent;
static const partial_ordering greater;
Expand Down Expand Up @@ -102,24 +105,29 @@ _EXPORT_STD struct partial_ordering {
// The stored value is either less (0xff), equivalent (0x00), greater (0x01), or unordered (0x80).
// Subtracting from 0 produces either 0x01, 0x00, 0xff, or 0x80. Note that the effect is to
// exchange less for greater (and vice versa), while leaving equivalent and unordered unchanged.
return {static_cast<_Compare_t>(0 - static_cast<unsigned int>(_Val._Value))};
return _STD _Bit_cast<partial_ordering>(static_cast<_Compare_t>(0 - static_cast<unsigned int>(_Val._Value)));
}

_Compare_t _Value;
};

inline constexpr partial_ordering partial_ordering::less{static_cast<_Compare_t>(_Compare_ord::less)};
inline constexpr partial_ordering partial_ordering::equivalent{static_cast<_Compare_t>(_Compare_eq::equivalent)};
inline constexpr partial_ordering partial_ordering::greater{static_cast<_Compare_t>(_Compare_ord::greater)};
inline constexpr partial_ordering partial_ordering::unordered{static_cast<_Compare_t>(_Compare_ncmp::unordered)};
inline constexpr partial_ordering partial_ordering::less{_STD _Bit_cast<partial_ordering>(_Compare_ord::less)};
inline constexpr partial_ordering partial_ordering::equivalent{
_STD _Bit_cast<partial_ordering>(_Compare_eq::equivalent)};
inline constexpr partial_ordering partial_ordering::greater{_STD _Bit_cast<partial_ordering>(_Compare_ord::greater)};
inline constexpr partial_ordering partial_ordering::unordered{
_STD _Bit_cast<partial_ordering>(_Compare_ncmp::unordered)};

_EXPORT_STD struct weak_ordering {
template <int> // Prevent unwanted construction without interfering with overload resolution or the MSVC ABI.
constexpr weak_ordering() = delete; // constexpr is necessary, see N5032 [basic.types.general]/10.5.3.4.

static const weak_ordering less;
static const weak_ordering equivalent;
static const weak_ordering greater;

constexpr operator partial_ordering() const noexcept {
return {static_cast<_Compare_t>(_Value)};
return _STD _Bit_cast<partial_ordering>(_Value);
}

_NODISCARD friend constexpr bool operator==(const weak_ordering _Val, _Literal_zero) noexcept {
Expand Down Expand Up @@ -165,28 +173,31 @@ _EXPORT_STD struct weak_ordering {
}

_NODISCARD friend constexpr weak_ordering operator<=>(_Literal_zero, const weak_ordering _Val) noexcept {
return {static_cast<_Compare_t>(-_Val._Value)};
return _STD _Bit_cast<weak_ordering>(static_cast<_Compare_t>(-_Val._Value));
}

_Compare_t _Value;
};

inline constexpr weak_ordering weak_ordering::less{static_cast<_Compare_t>(_Compare_ord::less)};
inline constexpr weak_ordering weak_ordering::equivalent{static_cast<_Compare_t>(_Compare_eq::equivalent)};
inline constexpr weak_ordering weak_ordering::greater{static_cast<_Compare_t>(_Compare_ord::greater)};
inline constexpr weak_ordering weak_ordering::less{_STD _Bit_cast<weak_ordering>(_Compare_ord::less)};
inline constexpr weak_ordering weak_ordering::equivalent{_STD _Bit_cast<weak_ordering>(_Compare_eq::equivalent)};
inline constexpr weak_ordering weak_ordering::greater{_STD _Bit_cast<weak_ordering>(_Compare_ord::greater)};

_EXPORT_STD struct strong_ordering {
template <int> // Prevent unwanted construction without interfering with overload resolution or the MSVC ABI.
constexpr strong_ordering() = delete; // constexpr is necessary, see N5032 [basic.types.general]/10.5.3.4.

static const strong_ordering less;
static const strong_ordering equal;
static const strong_ordering equivalent;
static const strong_ordering greater;

constexpr operator partial_ordering() const noexcept {
return {static_cast<_Compare_t>(_Value)};
return _STD _Bit_cast<partial_ordering>(_Value);
}

constexpr operator weak_ordering() const noexcept {
return {static_cast<_Compare_t>(_Value)};
return _STD _Bit_cast<weak_ordering>(_Value);
}

_NODISCARD friend constexpr bool operator==(const strong_ordering _Val, _Literal_zero) noexcept {
Expand Down Expand Up @@ -232,16 +243,16 @@ _EXPORT_STD struct strong_ordering {
}

_NODISCARD friend constexpr strong_ordering operator<=>(_Literal_zero, const strong_ordering _Val) noexcept {
return {static_cast<_Compare_t>(-_Val._Value)};
return _STD _Bit_cast<strong_ordering>(static_cast<_Compare_t>(-_Val._Value));
}

_Compare_t _Value;
};

inline constexpr strong_ordering strong_ordering::less{static_cast<_Compare_t>(_Compare_ord::less)};
inline constexpr strong_ordering strong_ordering::equal{static_cast<_Compare_t>(_Compare_eq::equal)};
inline constexpr strong_ordering strong_ordering::equivalent{static_cast<_Compare_t>(_Compare_eq::equivalent)};
inline constexpr strong_ordering strong_ordering::greater{static_cast<_Compare_t>(_Compare_ord::greater)};
inline constexpr strong_ordering strong_ordering::less{_STD _Bit_cast<strong_ordering>(_Compare_ord::less)};
inline constexpr strong_ordering strong_ordering::equal{_STD _Bit_cast<strong_ordering>(_Compare_eq::equal)};
inline constexpr strong_ordering strong_ordering::equivalent{_STD _Bit_cast<strong_ordering>(_Compare_eq::equivalent)};
inline constexpr strong_ordering strong_ordering::greater{_STD _Bit_cast<strong_ordering>(_Compare_ord::greater)};

_EXPORT_STD _NODISCARD constexpr bool is_eq(const partial_ordering _Comp) noexcept {
return _Comp == 0;
Expand Down
21 changes: 21 additions & 0 deletions tests/std/tests/P0768R1_spaceship_operator/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,23 @@ void test_algorithm() {
assert((test_algorithm2<Ty2, Ty1>()));
}

// Test GH-5689 "<compare>: ordering types are default constructible and constructible from integer types"
template <class T>
void test_not_constructible() {
static_assert(!std::is_default_constructible_v<T>);
static_assert(!std::is_constructible_v<T, int>);
}

// Additionally verify that the comparison category types avoid ambiguities in scenarios like LWG-3160.
struct ImplicitlyDefaultConstructible {};

double test_gh_5689_overload_resolution(ImplicitlyDefaultConstructible);
void test_gh_5689_overload_resolution(std::strong_ordering);
void test_gh_5689_overload_resolution(std::weak_ordering);
void test_gh_5689_overload_resolution(std::partial_ordering);

static_assert(std::is_same_v<decltype(test_gh_5689_overload_resolution({})), double>);

int main() {
static_assert(test_orderings());
test_orderings();
Expand All @@ -230,4 +247,8 @@ int main() {
test_algorithm<int, char>();
test_algorithm<int, unsigned char>();
test_algorithm<char, unsigned char>();

test_not_constructible<std::strong_ordering>();
test_not_constructible<std::weak_ordering>();
test_not_constructible<std::partial_ordering>();
}