<compare>: fix constructibility of ordering types, prevent structured bindings#5911
<compare>: fix constructibility of ordering types, prevent structured bindings#5911vmichal wants to merge 8 commits intomicrosoft:mainfrom
<compare>: fix constructibility of ordering types, prevent structured bindings#5911Conversation
…onstructible from int. Prevent structured bindings.
stl/inc/compare
Outdated
| friend struct weak_ordering; | ||
| friend struct strong_ordering; | ||
|
|
||
| constexpr explicit partial_ordering(_Compare_t _Value) : _Value{_Value} {} |
There was a problem hiding this comment.
I think we need to ensure that partial_ordering can still be returned in register. This constructor seemingly prevents returning in register for MSVC ABI.
A deleted constructor seems OK but we possibly need to work around it by _Bit_cast, etc..
There was a problem hiding this comment.
I have some ideas.
Expand to show the long content.
diff --git a/stl/inc/compare b/stl/inc/compare
index 09554ea15..dee7bd905 100644
--- a/stl/inc/compare
+++ b/stl/inc/compare
@@ -47,7 +47,17 @@ 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 {
+ _Secret_ordering_construction_tag() = default;
+};
+
_EXPORT_STD struct partial_ordering {
+ // This needs to be implicit to allow passing and returning in registers.
+ 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 +112,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 {
+ // This needs to be implicit to allow passing and returning in registers.
+ 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<partial_ordering>(_Value);
}
_NODISCARD friend constexpr bool operator==(const weak_ordering _Val, _Literal_zero) noexcept {
@@ -165,28 +180,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 {
+ // This needs to be implicit to allow passing and returning in registers.
+ 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<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 {
@@ -232,16 +250,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;There was a problem hiding this comment.
Would just partial_ordering() = delete; work instead?
There was a problem hiding this comment.
Would just
partial_ordering() = delete;work instead?
I guess this works. But this will still interfere with overload resolution. As shown by LWG-3160, the difference between "deleted default constructor" and "no default constructor at all" is observable.
| template <> | ||
| struct tuple_size<partial_ordering> { | ||
| void value(); | ||
| }; |
There was a problem hiding this comment.
This doesn't seem conforming. I think tuple_size<partial_ordering> etc. are supposed to be incomplete types.
Also, accidentally allowing structured binding doesn't seem to be a bug even if a strict resolution of LWG-4306 is accepted.
<compare>: fix constructibility of ordering types, prevent structured bindings
|
The PR description does not match the current PR strategy |
Touches
std::strong_ordering,std::weak_ordering,std::partial_ordering.Add private constructor from
_Compare_t- deletes default ctor and prevents construction from int outside of class scope.Add specializations of
std::tuple_sizeto prevent structured bindings.Fixes #5689