[libcxx-commits] [libcxx] c31c334 - [libc++][optional] LWG4497: `std::nullopt_t` should be comparable (#214975)

via libcxx-commits libcxx-commits at lists.llvm.org
Sun Aug 16 18:05:44 PDT 2026


Author: Hristo Hristov
Date: 2026-08-17T04:05:38+03:00
New Revision: c31c334e11186d2c0b6a68a9f5619a4050cb87b7

URL: https://github.com/llvm/llvm-project/commit/c31c334e11186d2c0b6a68a9f5619a4050cb87b7
DIFF: https://github.com/llvm/llvm-project/commit/c31c334e11186d2c0b6a68a9f5619a4050cb87b7.diff

LOG: [libc++][optional] LWG4497: `std::nullopt_t` should be comparable (#214975)

Implements https://wg21.link/LWG4497

Closes #189854

Also implements LWG4612: https://cplusplus.github.io/LWG/issue4612

---------

Co-authored-by: Mohamed Atef <mohamedatef1698 at gmail.com>
Co-authored-by: Hristo Hristov <zingam at outlook.com>

Added: 
    libcxx/test/std/utilities/optional/optional.nullopt/compare.three_way.pass.cpp

Modified: 
    libcxx/docs/Status/Cxx26Issues.csv
    libcxx/docs/Status/Cxx29Issues.csv
    libcxx/include/__optional/nullopt_t.h

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/Status/Cxx26Issues.csv b/libcxx/docs/Status/Cxx26Issues.csv
index 46242eace0c97..2f22fdb63a815 100644
--- a/libcxx/docs/Status/Cxx26Issues.csv
+++ b/libcxx/docs/Status/Cxx26Issues.csv
@@ -309,7 +309,7 @@
 "`LWG4492 <https://wg21.link/LWG4492>`__","``std::generate`` and ``std::ranges::generate`` wording is unclear for parallel algorithms","2026-03 (Croydon)","","","`#189851 <https://github.com/llvm/llvm-project/issues/189851>`__",""
 "`LWG4493 <https://wg21.link/LWG4493>`__","Specification for some functions of bit reference types seems missing","2026-03 (Croydon)","","","`#189852 <https://github.com/llvm/llvm-project/issues/189852>`__",""
 "`LWG4496 <https://wg21.link/LWG4496>`__","Precedes vs Reachable in [meta.reflection]","2026-03 (Croydon)","","","`#189853 <https://github.com/llvm/llvm-project/issues/189853>`__",""
-"`LWG4497 <https://wg21.link/LWG4497>`__","``std::nullopt_t`` should be comparable","2026-03 (Croydon)","","","`#189854 <https://github.com/llvm/llvm-project/issues/189854>`__",""
+"`LWG4497 <https://wg21.link/LWG4497>`__","``std::nullopt_t`` should be comparable","2026-03 (Croydon)","|Complete|","24","`#189854 <https://github.com/llvm/llvm-project/issues/189854>`__",""
 "`LWG4499 <https://wg21.link/LWG4499>`__","``flat_set::insert_range`` specification may be problematic","2026-03 (Croydon)","","","`#189855 <https://github.com/llvm/llvm-project/issues/189855>`__",""
 "`LWG4500 <https://wg21.link/LWG4500>`__","``constant_wrapper`` wording problems","2026-03 (Croydon)","|Complete|","23","`#189856 <https://github.com/llvm/llvm-project/issues/189856>`__",""
 "`LWG4504 <https://wg21.link/LWG4504>`__","Wording problem in ``{simple_}counting_scope``","2026-03 (Croydon)","","","`#189857 <https://github.com/llvm/llvm-project/issues/189857>`__",""

diff  --git a/libcxx/docs/Status/Cxx29Issues.csv b/libcxx/docs/Status/Cxx29Issues.csv
index 13056a97782df..d84eeb44a23ff 100644
--- a/libcxx/docs/Status/Cxx29Issues.csv
+++ b/libcxx/docs/Status/Cxx29Issues.csv
@@ -17,3 +17,6 @@
 "`LWG4567 <https://wg21.link/LWG4567>`__","Feature test macro value for ``apply_result``, ``is_applicable``","2026-06 (Brno)","","","`#204455 <https://github.com/llvm/llvm-project/issues/204455>`__",""
 "`LWG4568 <https://wg21.link/LWG4568>`__","``std::execution::spawn_future`` is mishandling dependent senders","2026-06 (Brno)","","","`#204456 <https://github.com/llvm/llvm-project/issues/204456>`__",""
 "`LWG4579 <https://wg21.link/LWG4579>`__","``make-state<Rcvr>::state-type::complete`` uses ``Env`` which is not in scope","2026-06 (Brno)","","","`#204457 <https://github.com/llvm/llvm-project/issues/204457>`__",""
+"","","","","","",""
+"`LWG4612 <https://wg21.link/LWG4612>`__","Specify the details of ``std::nullopt_t``","Not Adopted Yet","|Complete|","24","",""
+"","","","","","",""

diff  --git a/libcxx/include/__optional/nullopt_t.h b/libcxx/include/__optional/nullopt_t.h
index afca31927254a..74c47d4160638 100644
--- a/libcxx/include/__optional/nullopt_t.h
+++ b/libcxx/include/__optional/nullopt_t.h
@@ -10,6 +10,7 @@
 #ifndef _LIBCPP___OPTIONAL_NULLOPT_T_H
 #define _LIBCPP___OPTIONAL_NULLOPT_T_H
 
+#include <__compare/ordering.h>
 #include <__config>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -28,6 +29,21 @@ struct nullopt_t {
     explicit __secret_tag() = default;
   };
   _LIBCPP_HIDE_FROM_ABI constexpr explicit nullopt_t(__secret_tag, __secret_tag) noexcept {}
+
+#  if _LIBCPP_STD_VER >= 20
+
+  _LIBCPP_HIDE_FROM_ABI constexpr friend strong_ordering operator<=>(nullopt_t, nullopt_t) = default;
+
+#  else
+
+  _LIBCPP_HIDE_FROM_ABI constexpr friend bool operator==(nullopt_t, nullopt_t) noexcept { return true; }
+  _LIBCPP_HIDE_FROM_ABI constexpr friend bool operator!=(nullopt_t, nullopt_t) noexcept { return false; }
+  _LIBCPP_HIDE_FROM_ABI constexpr friend bool operator>(nullopt_t, nullopt_t) noexcept { return false; }
+  _LIBCPP_HIDE_FROM_ABI constexpr friend bool operator<(nullopt_t, nullopt_t) noexcept { return false; }
+  _LIBCPP_HIDE_FROM_ABI constexpr friend bool operator>=(nullopt_t, nullopt_t) noexcept { return true; }
+  _LIBCPP_HIDE_FROM_ABI constexpr friend bool operator<=(nullopt_t, nullopt_t) noexcept { return true; }
+
+#  endif // _LIBCPP_STD_VER >= 20
 };
 
 inline constexpr nullopt_t nullopt{nullopt_t::__secret_tag{}, nullopt_t::__secret_tag{}};

diff  --git a/libcxx/test/std/utilities/optional/optional.nullopt/compare.three_way.pass.cpp b/libcxx/test/std/utilities/optional/optional.nullopt/compare.three_way.pass.cpp
new file mode 100644
index 0000000000000..80c72ddd50224
--- /dev/null
+++ b/libcxx/test/std/utilities/optional/optional.nullopt/compare.three_way.pass.cpp
@@ -0,0 +1,102 @@
+//===----------------------------------------------------------------------===//
+//
+// 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>
+
+// struct nullopt_t{see below};
+// inline constexpr nullopt_t nullopt(unspecified);
+
+// [optional.nullopt]/2:
+//  nullopt_t models copyable and three_way_comparable<strong_ordering>.
+
+#include <algorithm>
+#include <cassert>
+#include <concepts>
+#include <optional>
+#include <vector>
+
+#include "test_macros.h"
+
+#if TEST_STD_VER >= 20
+static_assert(std::copyable<std::nullopt_t>);
+static_assert(std::three_way_comparable<std::nullopt_t, std::strong_ordering>);
+#endif
+
+constexpr bool test() {
+  { // ==
+    decltype(auto) result = std::nullopt == std::nullopt;
+    static_assert(std::is_same_v<decltype(result), bool>);
+    static_assert(noexcept(std::nullopt == std::nullopt));
+
+    assert(result);
+  }
+  { // !=
+    decltype(auto) result = std::nullopt != std::nullopt;
+    static_assert(std::is_same_v<decltype(result), bool>);
+    static_assert(noexcept(std::nullopt != std::nullopt));
+
+    assert(!result);
+  }
+  { // <=
+    decltype(auto) result = std::nullopt <= std::nullopt;
+    static_assert(std::is_same_v<decltype(result), bool>);
+    static_assert(noexcept(std::nullopt <= std::nullopt));
+
+    assert(result);
+  }
+  { // >=
+    decltype(auto) result = std::nullopt >= std::nullopt;
+    static_assert(std::is_same_v<decltype(result), bool>);
+    static_assert(noexcept(std::nullopt >= std::nullopt));
+
+    assert(result);
+  }
+  { // >
+    decltype(auto) result = std::nullopt > std::nullopt;
+    static_assert(std::is_same_v<decltype(result), bool>);
+    static_assert(noexcept(std::nullopt > std::nullopt));
+
+    assert(!(std::nullopt > std::nullopt));
+  }
+  { // <
+    decltype(auto) result = std::nullopt < std::nullopt;
+    static_assert(std::is_same_v<decltype(result), bool>);
+    static_assert(noexcept(std::nullopt < std::nullopt));
+
+    assert(!result);
+  }
+
+#if TEST_STD_VER >= 20
+  { // <=>
+    std::same_as<std::strong_ordering> decltype(auto) result = std::nullopt <=> std::nullopt;
+    static_assert(noexcept(std::nullopt <=> std::nullopt));
+
+    assert(result == std::strong_ordering::equal);
+  }
+
+  { // Test ranges::find with nullopt
+    std::vector<std::optional<int>> v = {1, 2, std::nullopt, 4, 5};
+
+    auto it = std::ranges::find(v, std::nullopt);
+
+    assert(it != v.end());
+    assert(*it == std::nullopt);
+  }
+#endif
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}


        


More information about the libcxx-commits mailing list