diff --git a/stl/inc/compare b/stl/inc/compare index 09554ea1511..b95562018f4 100644 --- a/stl/inc/compare +++ b/stl/inc/compare @@ -47,7 +47,14 @@ enum class _Compare_eq : _Compare_t { equal = 0, equivalent = equal }; enum class _Compare_ord : _Compare_t { less = -1, greater = 1 }; enum class _Compare_ncmp : _Compare_t { unordered = -128 }; +// TRANSITION, ABI, this is used for allowing comparison category types to be passing and returning in registers +// in MSVC ABI while making them non-default-constructible. +// It is intentional to use a specific tag type to avoid impact on overload resolution. +struct _Secret_ordering_construction_tag {}; + _EXPORT_STD struct partial_ordering { + constexpr partial_ordering(same_as<_Secret_ordering_construction_tag> auto) = delete; + static const partial_ordering less; static const partial_ordering equivalent; static const partial_ordering greater; @@ -102,24 +109,28 @@ _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(_Val._Value))}; + return _STD _Bit_cast(static_cast<_Compare_t>(0 - static_cast(_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(_Compare_ord::less)}; +inline constexpr partial_ordering partial_ordering::equivalent{ + _STD _Bit_cast(_Compare_eq::equivalent)}; +inline constexpr partial_ordering partial_ordering::greater{_STD _Bit_cast(_Compare_ord::greater)}; +inline constexpr partial_ordering partial_ordering::unordered{ + _STD _Bit_cast(_Compare_ncmp::unordered)}; _EXPORT_STD struct weak_ordering { + constexpr weak_ordering(same_as<_Secret_ordering_construction_tag> auto) = delete; + 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(_Value); } _NODISCARD friend constexpr bool operator==(const weak_ordering _Val, _Literal_zero) noexcept { @@ -165,28 +176,30 @@ _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(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(_Compare_ord::less)}; +inline constexpr weak_ordering weak_ordering::equivalent{_STD _Bit_cast(_Compare_eq::equivalent)}; +inline constexpr weak_ordering weak_ordering::greater{_STD _Bit_cast(_Compare_ord::greater)}; _EXPORT_STD struct strong_ordering { + constexpr strong_ordering(same_as<_Secret_ordering_construction_tag> auto) = delete; + 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(_Value); } constexpr operator weak_ordering() const noexcept { - return {static_cast<_Compare_t>(_Value)}; + return _STD _Bit_cast(_Value); } _NODISCARD friend constexpr bool operator==(const strong_ordering _Val, _Literal_zero) noexcept { @@ -232,16 +245,35 @@ _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(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(_Compare_ord::less)}; +inline constexpr strong_ordering strong_ordering::equal{_STD _Bit_cast(_Compare_eq::equal)}; +inline constexpr strong_ordering strong_ordering::equivalent{_STD _Bit_cast(_Compare_eq::equivalent)}; +inline constexpr strong_ordering strong_ordering::greater{_STD _Bit_cast(_Compare_ord::greater)}; + +template +struct tuple_size; + +// Prevent structured binding to objects of xxx_ordering, see GH-5689 +template <> +struct tuple_size { + void value(); +}; + +template <> +struct tuple_size { + void value(); +}; + +template <> +struct tuple_size { + void value(); +}; _EXPORT_STD _NODISCARD constexpr bool is_eq(const partial_ordering _Comp) noexcept { return _Comp == 0; diff --git a/tests/std/tests/P0768R1_spaceship_operator/test.cpp b/tests/std/tests/P0768R1_spaceship_operator/test.cpp index 5db13bb77d4..b4780ae47ac 100644 --- a/tests/std/tests/P0768R1_spaceship_operator/test.cpp +++ b/tests/std/tests/P0768R1_spaceship_operator/test.cpp @@ -217,6 +217,19 @@ void test_algorithm() { assert((test_algorithm2())); } +// Test added to handle GH-5689 +template +void test_not_constructible() { + static_assert(!std::is_default_constructible_v); + static_assert(!std::is_constructible_v); + + // How to test this does not compile? + //{ + // auto [n] = 0 <=> 0; + // (void) n; + //} +} + int main() { static_assert(test_orderings()); test_orderings(); @@ -230,4 +243,8 @@ int main() { test_algorithm(); test_algorithm(); test_algorithm(); + + test_not_constructible(); + test_not_constructible(); + test_not_constructible(); }