[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