[libcxx-commits] [libcxx] [libc++] Resolve LWG4370 (PR #174062)
via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Dec 30 22:30:53 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: William Tran-Viet (smallp-o-p)
<details>
<summary>Changes</summary>
Resolves #<!-- -->171364
- Implement [proposed resolution of LWG4370](https://wg21.link/LWG4370)
- Add corresponding compile test
---
Full diff: https://github.com/llvm/llvm-project/pull/174062.diff
3 Files Affected:
- (modified) libcxx/docs/Status/Cxx2cIssues.csv (+1-1)
- (modified) libcxx/include/optional (+48-12)
- (added) libcxx/test/std/utilities/optional/optional.relops/relops.compile.pass.cpp (+42)
``````````diff
diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv
index 32f5117a0198a..8d312cd688daa 100644
--- a/libcxx/docs/Status/Cxx2cIssues.csv
+++ b/libcxx/docs/Status/Cxx2cIssues.csv
@@ -203,7 +203,7 @@
"`LWG4360 <https://wg21.link/LWG4360>`__","``awaitable-sender`` concept should qualify use of ``awaitable-receiver`` type","2025-11 (Kona)","","","`#171361 <https://github.com/llvm/llvm-project/issues/171361>`__",""
"`LWG4366 <https://wg21.link/LWG4366>`__","Heterogeneous comparison of ``expected`` may be ill-formed","2025-11 (Kona)","","","`#171362 <https://github.com/llvm/llvm-project/issues/171362>`__",""
"`LWG4369 <https://wg21.link/LWG4369>`__","``check-types`` function for ``upon_error`` and ``upon_stopped`` is wrong","2025-11 (Kona)","","","`#171363 <https://github.com/llvm/llvm-project/issues/171363>`__",""
-"`LWG4370 <https://wg21.link/LWG4370>`__","Comparison of ``optional<T>`` to ``T`` may be ill-formed","2025-11 (Kona)","","","`#171364 <https://github.com/llvm/llvm-project/issues/171364>`__",""
+"`LWG4370 <https://wg21.link/LWG4370>`__","Comparison of ``optional<T>`` to ``T`` may be ill-formed","2025-11 (Kona)","|Complete|","22","`#171364 <https://github.com/llvm/llvm-project/issues/171364>`__",""
"`LWG4372 <https://wg21.link/LWG4372>`__","Weaken *Mandates:* for dynamic padding values in padded layouts","2025-11 (Kona)","","","`#171365 <https://github.com/llvm/llvm-project/issues/171365>`__",""
"`LWG4375 <https://wg21.link/LWG4375>`__","``std::simd::bit_ceil`` should not be ``noexcept``","2025-11 (Kona)","","","`#171366 <https://github.com/llvm/llvm-project/issues/171366>`__",""
"`LWG4376 <https://wg21.link/LWG4376>`__","ABI tag in return type of [simd.mask.unary] is overconstrained","2025-11 (Kona)","","","`#171367 <https://github.com/llvm/llvm-project/issues/171367>`__",""
diff --git a/libcxx/include/optional b/libcxx/include/optional
index bea7474d49298..6d21225f1ac45 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -1405,7 +1405,10 @@ template <
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() == std::declval<const _Up&>()), bool>,
int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, const _Up& __v) {
- return static_cast<bool>(__x) ? *__x == __v : false;
+ if(__x.has_value()) {
+ return *__x == __v;
+ }
+ return false;
}
template <
@@ -1414,7 +1417,10 @@ template <
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() == std::declval<const _Up&>()), bool>,
int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const _Tp& __v, const optional<_Up>& __x) {
- return static_cast<bool>(__x) ? __v == *__x : false;
+ if(__x.has_value()) {
+ return __v == *__x;
+ }
+ return false;
}
template <
@@ -1423,7 +1429,10 @@ template <
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() != std::declval<const _Up&>()), bool>,
int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, const _Up& __v) {
- return static_cast<bool>(__x) ? *__x != __v : true;
+ if(__x.has_value()) {
+ return *__x != __v;
+ }
+ return true;
}
template <
@@ -1432,7 +1441,10 @@ template <
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() != std::declval<const _Up&>()), bool>,
int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const _Tp& __v, const optional<_Up>& __x) {
- return static_cast<bool>(__x) ? __v != *__x : true;
+ if(__x.has_value()) {
+ return __v != *__x;
+ }
+ return true;
}
template < class _Tp,
@@ -1440,7 +1452,10 @@ template < class _Tp,
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() < std::declval<const _Up&>()), bool>,
int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const optional<_Tp>& __x, const _Up& __v) {
- return static_cast<bool>(__x) ? *__x < __v : true;
+ if(__x.has_value()) {
+ return *__x < __v;
+ }
+ return true;
}
template < class _Tp,
@@ -1448,7 +1463,10 @@ template < class _Tp,
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() < std::declval<const _Up&>()), bool>,
int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const _Tp& __v, const optional<_Up>& __x) {
- return static_cast<bool>(__x) ? __v < *__x : false;
+ if(__x.has_value()) {
+ return __v < *__x;
+ }
+ return false;
}
template <
@@ -1457,7 +1475,10 @@ template <
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>()), bool>,
int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, const _Up& __v) {
- return static_cast<bool>(__x) ? *__x <= __v : true;
+ if(__x.has_value()) {
+ return *__x <= __v;
+ }
+ return true;
}
template <
@@ -1466,7 +1487,10 @@ template <
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>()), bool>,
int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const _Tp& __v, const optional<_Up>& __x) {
- return static_cast<bool>(__x) ? __v <= *__x : false;
+ if(__x.has_value()) {
+ return __v <= *__x;
+ }
+ return false;
}
template < class _Tp,
@@ -1474,7 +1498,10 @@ template < class _Tp,
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() > std::declval<const _Up&>()), bool>,
int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const optional<_Tp>& __x, const _Up& __v) {
- return static_cast<bool>(__x) ? *__x > __v : false;
+ if(__x.has_value()) {
+ return *__x > __v;
+ }
+ return false;
}
template < class _Tp,
@@ -1482,7 +1509,10 @@ template < class _Tp,
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() > std::declval<const _Up&>()), bool>,
int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const _Tp& __v, const optional<_Up>& __x) {
- return static_cast<bool>(__x) ? __v > *__x : true;
+ if(__x.has_value()){
+ return __v > *__x;
+ }
+ return true;
}
template <
@@ -1491,7 +1521,10 @@ template <
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>()), bool>,
int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const optional<_Tp>& __x, const _Up& __v) {
- return static_cast<bool>(__x) ? *__x >= __v : false;
+ if(__x.has_value()) {
+ return *__x >= __v;
+ }
+ return false;
}
template <
@@ -1500,7 +1533,10 @@ template <
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>()), bool>,
int> = 0>
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const _Tp& __v, const optional<_Up>& __x) {
- return static_cast<bool>(__x) ? __v >= *__x : true;
+ if(__x.has_value()) {
+ return __v >= *__x;
+ }
+ return true;
}
# if _LIBCPP_STD_VER >= 20
diff --git a/libcxx/test/std/utilities/optional/optional.relops/relops.compile.pass.cpp b/libcxx/test/std/utilities/optional/optional.relops/relops.compile.pass.cpp
new file mode 100644
index 0000000000000..5babd389cec1e
--- /dev/null
+++ b/libcxx/test/std/utilities/optional/optional.relops/relops.compile.pass.cpp
@@ -0,0 +1,42 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++17
+// <optional>
+
+// Verify that example provided for LWG4370 compiles.
+
+#include <cassert>
+#include <optional>
+
+struct Bool {
+ Bool(bool) {};
+ operator bool() const { return true; };
+};
+
+struct S {
+ Bool operator==(S) const { return true; }
+ Bool operator!=(S) const { return true; }
+ Bool operator<=(S) const { return true; }
+ Bool operator<(S) const { return true; }
+ Bool operator>(S) const { return true; }
+ Bool operator>=(S) const { return true; }
+};
+
+int main() {
+ std::optional<S> s{S{}};
+
+ (void)(s == S{});
+ (void)(s != S{});
+ (void)(s < S{});
+ (void)(s > S{});
+ (void)(s <= S{});
+ (void)(s >= S{});
+
+ return 0;
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/174062
More information about the libcxx-commits
mailing list