Skip to content

Commit 45e5d45

Browse files
1 parent fdb6ed2 commit 45e5d45

2 files changed

Lines changed: 49 additions & 17 deletions

File tree

stl/inc/compare

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ enum class _Compare_ord : _Compare_t { less = -1, greater = 1 };
4848
enum class _Compare_ncmp : _Compare_t { unordered = -128 };
4949

5050
_EXPORT_STD struct partial_ordering {
51+
template <int> // Prevent unwanted construction without interfering with overload resolution or the MSVC ABI.
52+
constexpr partial_ordering() = delete; // constexpr is necessary, see N5032 [basic.types.general]/10.5.3.4.
53+
5154
static const partial_ordering less;
5255
static const partial_ordering equivalent;
5356
static const partial_ordering greater;
@@ -102,24 +105,29 @@ _EXPORT_STD struct partial_ordering {
102105
// The stored value is either less (0xff), equivalent (0x00), greater (0x01), or unordered (0x80).
103106
// Subtracting from 0 produces either 0x01, 0x00, 0xff, or 0x80. Note that the effect is to
104107
// exchange less for greater (and vice versa), while leaving equivalent and unordered unchanged.
105-
return {static_cast<_Compare_t>(0 - static_cast<unsigned int>(_Val._Value))};
108+
return _STD _Bit_cast<partial_ordering>(static_cast<_Compare_t>(0 - static_cast<unsigned int>(_Val._Value)));
106109
}
107110

108111
_Compare_t _Value;
109112
};
110113

111-
inline constexpr partial_ordering partial_ordering::less{static_cast<_Compare_t>(_Compare_ord::less)};
112-
inline constexpr partial_ordering partial_ordering::equivalent{static_cast<_Compare_t>(_Compare_eq::equivalent)};
113-
inline constexpr partial_ordering partial_ordering::greater{static_cast<_Compare_t>(_Compare_ord::greater)};
114-
inline constexpr partial_ordering partial_ordering::unordered{static_cast<_Compare_t>(_Compare_ncmp::unordered)};
114+
inline constexpr partial_ordering partial_ordering::less{_STD _Bit_cast<partial_ordering>(_Compare_ord::less)};
115+
inline constexpr partial_ordering partial_ordering::equivalent{
116+
_STD _Bit_cast<partial_ordering>(_Compare_eq::equivalent)};
117+
inline constexpr partial_ordering partial_ordering::greater{_STD _Bit_cast<partial_ordering>(_Compare_ord::greater)};
118+
inline constexpr partial_ordering partial_ordering::unordered{
119+
_STD _Bit_cast<partial_ordering>(_Compare_ncmp::unordered)};
115120

116121
_EXPORT_STD struct weak_ordering {
122+
template <int> // Prevent unwanted construction without interfering with overload resolution or the MSVC ABI.
123+
constexpr weak_ordering() = delete; // constexpr is necessary, see N5032 [basic.types.general]/10.5.3.4.
124+
117125
static const weak_ordering less;
118126
static const weak_ordering equivalent;
119127
static const weak_ordering greater;
120128

121129
constexpr operator partial_ordering() const noexcept {
122-
return {static_cast<_Compare_t>(_Value)};
130+
return _STD _Bit_cast<partial_ordering>(_Value);
123131
}
124132

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

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

171179
_Compare_t _Value;
172180
};
173181

174-
inline constexpr weak_ordering weak_ordering::less{static_cast<_Compare_t>(_Compare_ord::less)};
175-
inline constexpr weak_ordering weak_ordering::equivalent{static_cast<_Compare_t>(_Compare_eq::equivalent)};
176-
inline constexpr weak_ordering weak_ordering::greater{static_cast<_Compare_t>(_Compare_ord::greater)};
182+
inline constexpr weak_ordering weak_ordering::less{_STD _Bit_cast<weak_ordering>(_Compare_ord::less)};
183+
inline constexpr weak_ordering weak_ordering::equivalent{_STD _Bit_cast<weak_ordering>(_Compare_eq::equivalent)};
184+
inline constexpr weak_ordering weak_ordering::greater{_STD _Bit_cast<weak_ordering>(_Compare_ord::greater)};
177185

178186
_EXPORT_STD struct strong_ordering {
187+
template <int> // Prevent unwanted construction without interfering with overload resolution or the MSVC ABI.
188+
constexpr strong_ordering() = delete; // constexpr is necessary, see N5032 [basic.types.general]/10.5.3.4.
189+
179190
static const strong_ordering less;
180191
static const strong_ordering equal;
181192
static const strong_ordering equivalent;
182193
static const strong_ordering greater;
183194

184195
constexpr operator partial_ordering() const noexcept {
185-
return {static_cast<_Compare_t>(_Value)};
196+
return _STD _Bit_cast<partial_ordering>(_Value);
186197
}
187198

188199
constexpr operator weak_ordering() const noexcept {
189-
return {static_cast<_Compare_t>(_Value)};
200+
return _STD _Bit_cast<weak_ordering>(_Value);
190201
}
191202

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

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

238249
_Compare_t _Value;
239250
};
240251

241-
inline constexpr strong_ordering strong_ordering::less{static_cast<_Compare_t>(_Compare_ord::less)};
242-
inline constexpr strong_ordering strong_ordering::equal{static_cast<_Compare_t>(_Compare_eq::equal)};
243-
inline constexpr strong_ordering strong_ordering::equivalent{static_cast<_Compare_t>(_Compare_eq::equivalent)};
244-
inline constexpr strong_ordering strong_ordering::greater{static_cast<_Compare_t>(_Compare_ord::greater)};
252+
inline constexpr strong_ordering strong_ordering::less{_STD _Bit_cast<strong_ordering>(_Compare_ord::less)};
253+
inline constexpr strong_ordering strong_ordering::equal{_STD _Bit_cast<strong_ordering>(_Compare_eq::equal)};
254+
inline constexpr strong_ordering strong_ordering::equivalent{_STD _Bit_cast<strong_ordering>(_Compare_eq::equivalent)};
255+
inline constexpr strong_ordering strong_ordering::greater{_STD _Bit_cast<strong_ordering>(_Compare_ord::greater)};
245256

246257
_EXPORT_STD _NODISCARD constexpr bool is_eq(const partial_ordering _Comp) noexcept {
247258
return _Comp == 0;

tests/std/tests/P0768R1_spaceship_operator/test.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,23 @@ void test_algorithm() {
217217
assert((test_algorithm2<Ty2, Ty1>()));
218218
}
219219

220+
// Test GH-5689 "<compare>: ordering types are default constructible and constructible from integer types"
221+
template <class T>
222+
void test_not_constructible() {
223+
static_assert(!std::is_default_constructible_v<T>);
224+
static_assert(!std::is_constructible_v<T, int>);
225+
}
226+
227+
// Additionally verify that the comparison category types avoid ambiguities in scenarios like LWG-3160.
228+
struct ImplicitlyDefaultConstructible {};
229+
230+
double test_gh_5689_overload_resolution(ImplicitlyDefaultConstructible);
231+
void test_gh_5689_overload_resolution(std::strong_ordering);
232+
void test_gh_5689_overload_resolution(std::weak_ordering);
233+
void test_gh_5689_overload_resolution(std::partial_ordering);
234+
235+
static_assert(std::is_same_v<decltype(test_gh_5689_overload_resolution({})), double>);
236+
220237
int main() {
221238
static_assert(test_orderings());
222239
test_orderings();
@@ -230,4 +247,8 @@ int main() {
230247
test_algorithm<int, char>();
231248
test_algorithm<int, unsigned char>();
232249
test_algorithm<char, unsigned char>();
250+
251+
test_not_constructible<std::strong_ordering>();
252+
test_not_constructible<std::weak_ordering>();
253+
test_not_constructible<std::partial_ordering>();
233254
}

0 commit comments

Comments
 (0)