[libcxx-commits] [libcxx] c4566ca - [libc++][spaceship] Implement std::variant::operator<=>

Kent Ross via libcxx-commits libcxx-commits at lists.llvm.org
Sun Aug 14 16:17:37 PDT 2022


Author: Kent Ross
Date: 2022-08-14T16:16:52-07:00
New Revision: c4566cac490cf81c141e7deb84008b2cc1de48b7

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

LOG: [libc++][spaceship] Implement std::variant::operator<=>

Implements [variant.relops] and [variant.monostate.relops] for P1614R2

Reviewed By: Mordante, #libc, avogelsgesang

Differential Revision: https://reviews.llvm.org/D131372

Added: 
    libcxx/test/std/utilities/variant/variant.relops/three_way.pass.cpp

Modified: 
    libcxx/docs/Status/SpaceshipProjects.csv
    libcxx/include/__variant/monostate.h
    libcxx/include/variant
    libcxx/test/std/utilities/variant/variant.monostate.relops/relops.pass.cpp
    libcxx/test/support/test_comparisons.h

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/Status/SpaceshipProjects.csv b/libcxx/docs/Status/SpaceshipProjects.csv
index efb38b3e662f..ee077dccb5b1 100644
--- a/libcxx/docs/Status/SpaceshipProjects.csv
+++ b/libcxx/docs/Status/SpaceshipProjects.csv
@@ -25,7 +25,7 @@ Section,Description,Dependencies,Assignee,Complete
 | nullopt",None,Kent Ross,|In Progress|
 "| `[variant.relops] <https://wg21.link/variant.relops>`_
 | `[variant.monostate.relops] <https://wg21.link/variant.monostate.relops>`_","| `monostate <https://reviews.llvm.org/D131372>`_
-| `variant <https://reviews.llvm.org/D131372>`_",None,Kent Ross,|In Progress|
+| `variant <https://reviews.llvm.org/D131372>`_",None,Kent Ross,|Complete|
 | `[unique.ptr.special] <https://wg21.link/unique.ptr.special>`_,| `unique_ptr <https://reviews.llvm.org/D130838>`_,[comparisons.three.way],Adrian Vogelsgesang,|Complete|
 | `[util.smartptr.shared.cmp] <https://wg21.link/util.smartptr.shared.cmp>`_,| `shared_ptr <https://reviews.llvm.org/D130852>`_,[comparisons.three.way],Adrian Vogelsgesang,|Complete|
 | `[type.index.members] <https://wg21.link/type.index.members>`_,| `type_index <https://reviews.llvm.org/D131357>`_,None,Adrian Vogelsgesang,|Complete|

diff  --git a/libcxx/include/__variant/monostate.h b/libcxx/include/__variant/monostate.h
index b389c3b56b36..b3b4597dd985 100644
--- a/libcxx/include/__variant/monostate.h
+++ b/libcxx/include/__variant/monostate.h
@@ -10,6 +10,7 @@
 #ifndef _LIBCPP___VARIANT_MONOSTATE_H
 #define _LIBCPP___VARIANT_MONOSTATE_H
 
+#include <__compare/ordering.h>
 #include <__config>
 #include <__functional/hash.h>
 #include <cstddef>
@@ -24,31 +25,34 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 struct _LIBCPP_TEMPLATE_VIS monostate {};
 
-inline _LIBCPP_INLINE_VISIBILITY
-constexpr bool operator<(monostate, monostate) noexcept { return false; }
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(monostate, monostate) noexcept { return true; }
 
-inline _LIBCPP_INLINE_VISIBILITY
-constexpr bool operator>(monostate, monostate) noexcept { return false; }
+#  if _LIBCPP_STD_VER > 17
 
-inline _LIBCPP_INLINE_VISIBILITY
-constexpr bool operator<=(monostate, monostate) noexcept { return true; }
+_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering operator<=>(monostate, monostate) noexcept {
+  return strong_ordering::equal;
+}
 
-inline _LIBCPP_INLINE_VISIBILITY
-constexpr bool operator>=(monostate, monostate) noexcept { return true; }
+#  else // _LIBCPP_STD_VER > 17
 
-inline _LIBCPP_INLINE_VISIBILITY
-constexpr bool operator==(monostate, monostate) noexcept { return true; }
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(monostate, monostate) noexcept { return false; }
 
-inline _LIBCPP_INLINE_VISIBILITY
-constexpr bool operator!=(monostate, monostate) noexcept { return false; }
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(monostate, monostate) noexcept { return false; }
+
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(monostate, monostate) noexcept { return false; }
+
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(monostate, monostate) noexcept { return true; }
+
+_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(monostate, monostate) noexcept { return true; }
+
+#  endif // _LIBCPP_STD_VER > 17
 
 template <>
 struct _LIBCPP_TEMPLATE_VIS hash<monostate> {
   using argument_type = monostate;
   using result_type = size_t;
 
-  inline _LIBCPP_INLINE_VISIBILITY
-  result_type operator()(const argument_type&) const _NOEXCEPT {
+  inline _LIBCPP_HIDE_FROM_ABI result_type operator()(const argument_type&) const _NOEXCEPT {
     return 66740831; // return a fundamentally attractive random value.
   }
 };

diff  --git a/libcxx/include/variant b/libcxx/include/variant
index 8a86e4c1aed7..69ff0e5b6ed9 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -165,6 +165,10 @@ namespace std {
   template <class... Types>
   constexpr bool operator>=(const variant<Types...>&, const variant<Types...>&);
 
+  template <class... Types>
+  constexpr common_comparison_category_t<compare_three_way_result_t<Types>...>
+    operator<=>(const variant<Types...>&, const variant<Types...>&);           // since C++20
+
   // 20.7.6, visitation
   template <class Visitor, class... Variants>
   constexpr see below visit(Visitor&&, Variants&&...);
@@ -176,12 +180,13 @@ namespace std {
   struct monostate;
 
   // 20.7.8, monostate relational operators
-  constexpr bool operator<(monostate, monostate) noexcept;
-  constexpr bool operator>(monostate, monostate) noexcept;
-  constexpr bool operator<=(monostate, monostate) noexcept;
-  constexpr bool operator>=(monostate, monostate) noexcept;
   constexpr bool operator==(monostate, monostate) noexcept;
-  constexpr bool operator!=(monostate, monostate) noexcept;
+  constexpr bool operator!=(monostate, monostate) noexcept;             // until C++20
+  constexpr bool operator<(monostate, monostate) noexcept;              // until C++20
+  constexpr bool operator>(monostate, monostate) noexcept;              // until C++20
+  constexpr bool operator<=(monostate, monostate) noexcept;             // until C++20
+  constexpr bool operator>=(monostate, monostate) noexcept;             // until C++20
+  constexpr strong_ordering operator<=>(monostate, monostate) noexcept; // since C++20
 
   // 20.7.9, specialized algorithms
   template <class... Types>
@@ -201,6 +206,9 @@ namespace std {
 
 #include <__assert> // all public C++ headers provide the assertion handler
 #include <__availability>
+#include <__compare/common_comparison_category.h>
+#include <__compare/compare_three_way_result.h>
+#include <__compare/three_way_comparable.h>
 #include <__config>
 #include <__functional/hash.h>
 #include <__functional/operations.h>
@@ -262,7 +270,7 @@ struct __farray {
 };
 
 _LIBCPP_NORETURN
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_HIDE_FROM_ABI
 _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
 void __throw_bad_variant_access() {
 #ifndef _LIBCPP_NO_EXCEPTIONS
@@ -373,7 +381,7 @@ __as_variant(const variant<_Types...>&& __vs) noexcept {
 namespace __find_detail {
 
 template <class _Tp, class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
 constexpr size_t __find_index() {
   constexpr bool __matches[] = {is_same_v<_Tp, _Types>...};
   size_t __result = __not_found;
@@ -418,7 +426,7 @@ constexpr _Trait __trait =
         ? _Trait::_TriviallyAvailable
         : _IsAvailable<_Tp>::value ? _Trait::_Available : _Trait::_Unavailable;
 
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
 constexpr _Trait __common_trait(initializer_list<_Trait> __traits) {
   _Trait __result = _Trait::_TriviallyAvailable;
   for (_Trait __t : __traits) {
@@ -457,13 +465,13 @@ namespace __access {
 
 struct __union {
   template <class _Vp>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   static constexpr auto&& __get_alt(_Vp&& __v, in_place_index_t<0>) {
     return _VSTD::forward<_Vp>(__v).__head;
   }
 
   template <class _Vp, size_t _Ip>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   static constexpr auto&& __get_alt(_Vp&& __v, in_place_index_t<_Ip>) {
     return __get_alt(_VSTD::forward<_Vp>(__v).__tail, in_place_index<_Ip - 1>);
   }
@@ -471,7 +479,7 @@ struct __union {
 
 struct __base {
   template <size_t _Ip, class _Vp>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   static constexpr auto&& __get_alt(_Vp&& __v) {
     return __union::__get_alt(_VSTD::forward<_Vp>(__v).__data,
                               in_place_index<_Ip>);
@@ -480,7 +488,7 @@ struct __base {
 
 struct __variant {
   template <size_t _Ip, class _Vp>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   static constexpr auto&& __get_alt(_Vp&& __v) {
     return __base::__get_alt<_Ip>(_VSTD::forward<_Vp>(__v).__impl);
   }
@@ -492,7 +500,7 @@ namespace __visitation {
 
 struct __base {
   template <class _Visitor, class... _Vs>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   static constexpr decltype(auto)
   __visit_alt_at(size_t __index, _Visitor&& __visitor, _Vs&&... __vs) {
     constexpr auto __fdiagonal =
@@ -503,7 +511,7 @@ struct __base {
   }
 
   template <class _Visitor, class... _Vs>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   static constexpr decltype(auto) __visit_alt(_Visitor&& __visitor,
                                               _Vs&&... __vs) {
     constexpr auto __fmatrix =
@@ -516,11 +524,11 @@ struct __base {
 
 private:
   template <class _Tp>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   static constexpr const _Tp& __at(const _Tp& __elem) { return __elem; }
 
   template <class _Tp, size_t _Np, typename... _Indices>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   static constexpr auto&& __at(const __farray<_Tp, _Np>& __elems,
                                size_t __index, _Indices... __indices) {
     return __at(__elems[__index], __indices...);
@@ -534,7 +542,7 @@ private:
   }
 
   template <class... _Fs>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   static constexpr auto __make_farray(_Fs&&... __fs) {
     __std_visit_visitor_return_type_check<__uncvref_t<_Fs>...>();
     using __result = __farray<common_type_t<__uncvref_t<_Fs>...>, sizeof...(_Fs)>;
@@ -544,7 +552,7 @@ private:
   template <size_t... _Is>
   struct __dispatcher {
     template <class _Fp, class... _Vs>
-    inline _LIBCPP_INLINE_VISIBILITY
+    _LIBCPP_HIDE_FROM_ABI
     static constexpr decltype(auto) __dispatch(_Fp __f, _Vs... __vs) {
         return _VSTD::__invoke(
             static_cast<_Fp>(__f),
@@ -553,26 +561,26 @@ private:
   };
 
   template <class _Fp, class... _Vs, size_t... _Is>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   static constexpr auto __make_dispatch(index_sequence<_Is...>) {
     return __dispatcher<_Is...>::template __dispatch<_Fp, _Vs...>;
   }
 
   template <size_t _Ip, class _Fp, class... _Vs>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   static constexpr auto __make_fdiagonal_impl() {
     return __make_dispatch<_Fp, _Vs...>(
         index_sequence<((void)__type_identity<_Vs>{}, _Ip)...>{});
   }
 
   template <class _Fp, class... _Vs, size_t... _Is>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   static constexpr auto __make_fdiagonal_impl(index_sequence<_Is...>) {
     return __base::__make_farray(__make_fdiagonal_impl<_Is, _Fp, _Vs...>()...);
   }
 
   template <class _Fp, class _Vp, class... _Vs>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   static constexpr auto __make_fdiagonal() {
     constexpr size_t _Np = __uncvref_t<_Vp>::__size();
     static_assert(__all<(_Np == __uncvref_t<_Vs>::__size())...>::value);
@@ -580,13 +588,13 @@ private:
   }
 
   template <class _Fp, class... _Vs, size_t... _Is>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   static constexpr auto __make_fmatrix_impl(index_sequence<_Is...> __is) {
     return __make_dispatch<_Fp, _Vs...>(__is);
   }
 
   template <class _Fp, class... _Vs, size_t... _Is, size_t... _Js, class... _Ls>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   static constexpr auto __make_fmatrix_impl(index_sequence<_Is...>,
                                             index_sequence<_Js...>,
                                             _Ls... __ls) {
@@ -595,7 +603,7 @@ private:
   }
 
   template <class _Fp, class... _Vs>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   static constexpr auto __make_fmatrix() {
     return __make_fmatrix_impl<_Fp, _Vs...>(
         index_sequence<>{}, make_index_sequence<__uncvref_t<_Vs>::__size()>{}...);
@@ -604,7 +612,7 @@ private:
 
 struct __variant {
   template <class _Visitor, class... _Vs>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   static constexpr decltype(auto)
   __visit_alt_at(size_t __index, _Visitor&& __visitor, _Vs&&... __vs) {
     return __base::__visit_alt_at(__index,
@@ -613,7 +621,7 @@ struct __variant {
   }
 
   template <class _Visitor, class... _Vs>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   static constexpr decltype(auto) __visit_alt(_Visitor&& __visitor,
                                               _Vs&&... __vs) {
     return __base::__visit_alt(
@@ -622,7 +630,7 @@ struct __variant {
   }
 
   template <class _Visitor, class... _Vs>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   static constexpr decltype(auto)
   __visit_value_at(size_t __index, _Visitor&& __visitor, _Vs&&... __vs) {
     return __visit_alt_at(
@@ -632,7 +640,7 @@ struct __variant {
   }
 
   template <class _Visitor, class... _Vs>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   static constexpr decltype(auto) __visit_value(_Visitor&& __visitor,
                                                 _Vs&&... __vs) {
     return __visit_alt(
@@ -642,7 +650,7 @@ struct __variant {
 
 #if _LIBCPP_STD_VER > 17
   template <class _Rp, class _Visitor, class... _Vs>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   static constexpr _Rp __visit_value(_Visitor&& __visitor,
                                      _Vs&&... __vs) {
     return __visit_alt(
@@ -661,7 +669,7 @@ private:
   template <class _Visitor>
   struct __value_visitor {
     template <class... _Alts>
-    inline _LIBCPP_INLINE_VISIBILITY
+    _LIBCPP_HIDE_FROM_ABI
     constexpr decltype(auto) operator()(_Alts&&... __alts) const {
       __std_visit_exhaustive_visitor_check<
           _Visitor,
@@ -676,7 +684,7 @@ private:
   template <class _Rp, class _Visitor>
   struct __value_visitor_return_type {
     template <class... _Alts>
-    inline _LIBCPP_INLINE_VISIBILITY
+    _LIBCPP_HIDE_FROM_ABI
     constexpr _Rp operator()(_Alts&&... __alts) const {
       __std_visit_exhaustive_visitor_check<
           _Visitor,
@@ -696,14 +704,14 @@ private:
 #endif
 
   template <class _Visitor>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   static constexpr auto __make_value_visitor(_Visitor&& __visitor) {
     return __value_visitor<_Visitor>{_VSTD::forward<_Visitor>(__visitor)};
   }
 
 #if _LIBCPP_STD_VER > 17
   template <class _Rp, class _Visitor>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   static constexpr auto __make_value_visitor(_Visitor&& __visitor) {
     return __value_visitor_return_type<_Rp, _Visitor>{_VSTD::forward<_Visitor>(__visitor)};
   }
@@ -717,7 +725,7 @@ struct _LIBCPP_TEMPLATE_VIS __alt {
   using __value_type = _Tp;
 
   template <class... _Args>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   explicit constexpr __alt(in_place_t, _Args&&... __args)
       : __value(_VSTD::forward<_Args>(__args)...) {}
 
@@ -732,21 +740,21 @@ union _LIBCPP_TEMPLATE_VIS __union<_DestructibleTrait, _Index> {};
 
 #define _LIBCPP_VARIANT_UNION(destructible_trait, destructor)                  \
   template <size_t _Index, class _Tp, class... _Types>                         \
-  union _LIBCPP_TEMPLATE_VIS __union<destructible_trait,                      \
+  union _LIBCPP_TEMPLATE_VIS __union<destructible_trait,                       \
                                       _Index,                                  \
                                       _Tp,                                     \
                                       _Types...> {                             \
   public:                                                                      \
-    inline _LIBCPP_INLINE_VISIBILITY                                           \
+    _LIBCPP_HIDE_FROM_ABI                                                      \
     explicit constexpr __union(__valueless_t) noexcept : __dummy{} {}          \
                                                                                \
     template <class... _Args>                                                  \
-    inline _LIBCPP_INLINE_VISIBILITY                                           \
+    _LIBCPP_HIDE_FROM_ABI                                                      \
     explicit constexpr __union(in_place_index_t<0>, _Args&&... __args)         \
         : __head(in_place, _VSTD::forward<_Args>(__args)...) {}                \
                                                                                \
     template <size_t _Ip, class... _Args>                                      \
-    inline _LIBCPP_INLINE_VISIBILITY                                           \
+    _LIBCPP_HIDE_FROM_ABI                                                      \
     explicit constexpr __union(in_place_index_t<_Ip>, _Args&&... __args)       \
         : __tail(in_place_index<_Ip - 1>, _VSTD::forward<_Args>(__args)...) {} \
                                                                                \
@@ -777,41 +785,41 @@ class _LIBCPP_TEMPLATE_VIS __base {
 public:
   using __index_t = __variant_index_t<sizeof...(_Types)>;
 
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   explicit constexpr __base(__valueless_t __tag) noexcept
       : __data(__tag), __index(__variant_npos<__index_t>) {}
 
   template <size_t _Ip, class... _Args>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   explicit constexpr __base(in_place_index_t<_Ip>, _Args&&... __args)
       :
         __data(in_place_index<_Ip>, _VSTD::forward<_Args>(__args)...),
         __index(_Ip) {}
 
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   constexpr bool valueless_by_exception() const noexcept {
     return index() == variant_npos;
   }
 
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   constexpr size_t index() const noexcept {
     return __index == __variant_npos<__index_t> ? variant_npos : __index;
   }
 
 protected:
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   constexpr auto&& __as_base() & { return *this; }
 
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   constexpr auto&& __as_base() && { return _VSTD::move(*this); }
 
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   constexpr auto&& __as_base() const & { return *this; }
 
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   constexpr auto&& __as_base() const && { return _VSTD::move(*this); }
 
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   static constexpr size_t __size() { return sizeof...(_Types); }
 
   __union<_DestructibleTrait, 0, _Types...> __data;
@@ -843,7 +851,7 @@ class _LIBCPP_TEMPLATE_VIS __dtor;
     __dtor& operator=(__dtor&&) = default;                                     \
                                                                                \
   protected:                                                                   \
-    inline _LIBCPP_INLINE_VISIBILITY                                           \
+    inline _LIBCPP_HIDE_FROM_ABI                                               \
     destroy                                                                    \
   }
 
@@ -884,7 +892,7 @@ public:
 
 protected:
   template <size_t _Ip, class _Tp, class... _Args>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   static _Tp& __construct_alt(__alt<_Ip, _Tp>& __a, _Args&&... __args) {
     ::new ((void*)_VSTD::addressof(__a))
         __alt<_Ip, _Tp>(in_place, _VSTD::forward<_Args>(__args)...);
@@ -892,7 +900,7 @@ protected:
   }
 
   template <class _Rhs>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   static void __generic_construct(__ctor& __lhs, _Rhs&& __rhs) {
     __lhs.__destroy();
     if (!__rhs.valueless_by_exception()) {
@@ -955,7 +963,7 @@ class _LIBCPP_TEMPLATE_VIS __copy_constructor;
 #define _LIBCPP_VARIANT_COPY_CONSTRUCTOR(copy_constructible_trait,             \
                                          copy_constructor)                     \
   template <class... _Types>                                                   \
-  class _LIBCPP_TEMPLATE_VIS __copy_constructor<__traits<_Types...>,          \
+  class _LIBCPP_TEMPLATE_VIS __copy_constructor<__traits<_Types...>,           \
                                                  copy_constructible_trait>     \
       : public __move_constructor<__traits<_Types...>> {                       \
     using __base_type = __move_constructor<__traits<_Types...>>;               \
@@ -997,7 +1005,7 @@ public:
   using __base_type::operator=;
 
   template <size_t _Ip, class... _Args>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   auto& __emplace(_Args&&... __args) {
     this->__destroy();
     auto& __res = this->__construct_alt(__access::__base::__get_alt<_Ip>(*this),
@@ -1008,7 +1016,7 @@ public:
 
 protected:
   template <size_t _Ip, class _Tp, class _Arg>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   void __assign_alt(__alt<_Ip, _Tp>& __a, _Arg&& __arg) {
     if (this->index() == _Ip) {
       __a.__value = _VSTD::forward<_Arg>(__arg);
@@ -1029,7 +1037,7 @@ protected:
   }
 
   template <class _That>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   void __generic_assign(_That&& __that) {
     if (this->valueless_by_exception() && __that.valueless_by_exception()) {
       // do nothing.
@@ -1054,7 +1062,7 @@ class _LIBCPP_TEMPLATE_VIS __move_assignment;
 #define _LIBCPP_VARIANT_MOVE_ASSIGNMENT(move_assignable_trait,                 \
                                         move_assignment)                       \
   template <class... _Types>                                                   \
-  class _LIBCPP_TEMPLATE_VIS __move_assignment<__traits<_Types...>,           \
+  class _LIBCPP_TEMPLATE_VIS __move_assignment<__traits<_Types...>,            \
                                                 move_assignable_trait>         \
       : public __assignment<__traits<_Types...>> {                             \
     using __base_type = __assignment<__traits<_Types...>>;                     \
@@ -1095,7 +1103,7 @@ class _LIBCPP_TEMPLATE_VIS __copy_assignment;
 #define _LIBCPP_VARIANT_COPY_ASSIGNMENT(copy_assignable_trait,                 \
                                         copy_assignment)                       \
   template <class... _Types>                                                   \
-  class _LIBCPP_TEMPLATE_VIS __copy_assignment<__traits<_Types...>,           \
+  class _LIBCPP_TEMPLATE_VIS __copy_assignment<__traits<_Types...>,            \
                                                 copy_assignable_trait>         \
       : public __move_assignment<__traits<_Types...>> {                        \
     using __base_type = __move_assignment<__traits<_Types...>>;                \
@@ -1141,13 +1149,13 @@ public:
   __impl& operator=(__impl&&) = default;
 
   template <size_t _Ip, class _Arg>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   void __assign(_Arg&& __arg) {
     this->__assign_alt(__access::__base::__get_alt<_Ip>(*this),
                        _VSTD::forward<_Arg>(__arg));
   }
 
-  inline _LIBCPP_INLINE_VISIBILITY
+  inline _LIBCPP_HIDE_FROM_ABI
   void __swap(__impl& __that)  {
     if (this->valueless_by_exception() && __that.valueless_by_exception()) {
       // do nothing.
@@ -1193,7 +1201,7 @@ public:
   }
 
 private:
-  inline _LIBCPP_INLINE_VISIBILITY
+  inline _LIBCPP_HIDE_FROM_ABI
   bool __move_nothrow() const {
     constexpr bool __results[] = {is_nothrow_move_constructible_v<_Types>...};
     return this->valueless_by_exception() || __results[this->index()];
@@ -1299,7 +1307,7 @@ public:
             enable_if_t<__dependent_type<is_default_constructible<__first_type>,
                                          _Dummy>::value,
                         int> = 0>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   constexpr variant() noexcept(is_nothrow_default_constructible_v<__first_type>)
       : __impl(in_place_index<0>) {}
 
@@ -1315,7 +1323,7 @@ public:
       size_t _Ip =
           __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value,
       enable_if_t<is_constructible_v<_Tp, _Arg>, int> = 0>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   constexpr variant(_Arg&& __arg) noexcept(
       is_nothrow_constructible_v<_Tp, _Arg>)
       : __impl(in_place_index<_Ip>, _VSTD::forward<_Arg>(__arg)) {}
@@ -1324,7 +1332,7 @@ public:
             class = enable_if_t<(_Ip < sizeof...(_Types)), int>,
             class _Tp = variant_alternative_t<_Ip, variant<_Types...>>,
             enable_if_t<is_constructible_v<_Tp, _Args...>, int> = 0>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   explicit constexpr variant(
       in_place_index_t<_Ip>,
       _Args&&... __args) noexcept(is_nothrow_constructible_v<_Tp, _Args...>)
@@ -1338,7 +1346,7 @@ public:
       class _Tp = variant_alternative_t<_Ip, variant<_Types...>>,
       enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>,
                   int> = 0>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   explicit constexpr variant(
       in_place_index_t<_Ip>,
       initializer_list<_Up> __il,
@@ -1352,7 +1360,7 @@ public:
       size_t _Ip =
           __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value,
       enable_if_t<is_constructible_v<_Tp, _Args...>, int> = 0>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   explicit constexpr variant(in_place_type_t<_Tp>, _Args&&... __args) noexcept(
       is_nothrow_constructible_v<_Tp, _Args...>)
       : __impl(in_place_index<_Ip>, _VSTD::forward<_Args>(__args)...) {}
@@ -1365,7 +1373,7 @@ public:
           __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value,
       enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>,
                   int> = 0>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   explicit constexpr variant(
       in_place_type_t<_Tp>,
       initializer_list<_Up> __il,
@@ -1386,7 +1394,7 @@ public:
           __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value,
       enable_if_t<is_assignable_v<_Tp&, _Arg> && is_constructible_v<_Tp, _Arg>,
                   int> = 0>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   variant& operator=(_Arg&& __arg) noexcept(
       is_nothrow_assignable_v<_Tp&, _Arg> &&
       is_nothrow_constructible_v<_Tp, _Arg>) {
@@ -1400,7 +1408,7 @@ public:
       enable_if_t<(_Ip < sizeof...(_Types)), int> = 0,
       class _Tp = variant_alternative_t<_Ip, variant<_Types...>>,
       enable_if_t<is_constructible_v<_Tp, _Args...>, int> = 0>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   _Tp& emplace(_Args&&... __args) {
     return __impl.template __emplace<_Ip>(_VSTD::forward<_Args>(__args)...);
   }
@@ -1413,7 +1421,7 @@ public:
       class _Tp = variant_alternative_t<_Ip, variant<_Types...>>,
       enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>,
                   int> = 0>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) {
     return __impl.template __emplace<_Ip>(__il, _VSTD::forward<_Args>(__args)...);
   }
@@ -1424,7 +1432,7 @@ public:
       size_t _Ip =
           __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value,
       enable_if_t<is_constructible_v<_Tp, _Args...>, int> = 0>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   _Tp& emplace(_Args&&... __args) {
     return __impl.template __emplace<_Ip>(_VSTD::forward<_Args>(__args)...);
   }
@@ -1437,17 +1445,17 @@ public:
           __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value,
       enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>,
                   int> = 0>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) {
     return __impl.template __emplace<_Ip>(__il, _VSTD::forward<_Args>(__args)...);
   }
 
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   constexpr bool valueless_by_exception() const noexcept {
     return __impl.valueless_by_exception();
   }
 
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   constexpr size_t index() const noexcept { return __impl.index(); }
 
   template <
@@ -1457,7 +1465,7 @@ public:
               __dependent_type<is_move_constructible<_Types>, _Dummy>::value &&
               __dependent_type<is_swappable<_Types>, _Dummy>::value)...>::value,
           int> = 0>
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   void swap(variant& __that) noexcept(
       __all<(is_nothrow_move_constructible_v<_Types> &&
              is_nothrow_swappable_v<_Types>)...>::value) {
@@ -1472,19 +1480,19 @@ private:
 };
 
 template <size_t _Ip, class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
 constexpr bool __holds_alternative(const variant<_Types...>& __v) noexcept {
   return __v.index() == _Ip;
 }
 
 template <class _Tp, class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
 constexpr bool holds_alternative(const variant<_Types...>& __v) noexcept {
   return __holds_alternative<__find_exactly_one_t<_Tp, _Types...>::value>(__v);
 }
 
 template <size_t _Ip, class _Vp>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
 _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
 constexpr auto&& __generic_get(_Vp&& __v) {
   using __variant_detail::__access::__variant;
@@ -1495,7 +1503,7 @@ constexpr auto&& __generic_get(_Vp&& __v) {
 }
 
 template <size_t _Ip, class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
 _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
 constexpr variant_alternative_t<_Ip, variant<_Types...>>& get(
     variant<_Types...>& __v) {
@@ -1505,7 +1513,7 @@ constexpr variant_alternative_t<_Ip, variant<_Types...>>& get(
 }
 
 template <size_t _Ip, class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
 _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
 constexpr variant_alternative_t<_Ip, variant<_Types...>>&& get(
     variant<_Types...>&& __v) {
@@ -1515,7 +1523,7 @@ constexpr variant_alternative_t<_Ip, variant<_Types...>>&& get(
 }
 
 template <size_t _Ip, class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
 _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
 constexpr const variant_alternative_t<_Ip, variant<_Types...>>& get(
     const variant<_Types...>& __v) {
@@ -1525,7 +1533,7 @@ constexpr const variant_alternative_t<_Ip, variant<_Types...>>& get(
 }
 
 template <size_t _Ip, class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
 _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
 constexpr const variant_alternative_t<_Ip, variant<_Types...>>&& get(
     const variant<_Types...>&& __v) {
@@ -1535,7 +1543,7 @@ constexpr const variant_alternative_t<_Ip, variant<_Types...>>&& get(
 }
 
 template <class _Tp, class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
 _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
 constexpr _Tp& get(variant<_Types...>& __v) {
   static_assert(!is_void_v<_Tp>);
@@ -1543,7 +1551,7 @@ constexpr _Tp& get(variant<_Types...>& __v) {
 }
 
 template <class _Tp, class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
 _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
 constexpr _Tp&& get(variant<_Types...>&& __v) {
   static_assert(!is_void_v<_Tp>);
@@ -1552,7 +1560,7 @@ constexpr _Tp&& get(variant<_Types...>&& __v) {
 }
 
 template <class _Tp, class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
 _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
 constexpr const _Tp& get(const variant<_Types...>& __v) {
   static_assert(!is_void_v<_Tp>);
@@ -1560,7 +1568,7 @@ constexpr const _Tp& get(const variant<_Types...>& __v) {
 }
 
 template <class _Tp, class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
 _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
 constexpr const _Tp&& get(const variant<_Types...>&& __v) {
   static_assert(!is_void_v<_Tp>);
@@ -1569,7 +1577,7 @@ constexpr const _Tp&& get(const variant<_Types...>&& __v) {
 }
 
 template <size_t _Ip, class _Vp>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
 constexpr auto* __generic_get_if(_Vp* __v) noexcept {
   using __variant_detail::__access::__variant;
   return __v && __holds_alternative<_Ip>(*__v)
@@ -1578,7 +1586,7 @@ constexpr auto* __generic_get_if(_Vp* __v) noexcept {
 }
 
 template <size_t _Ip, class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
 constexpr add_pointer_t<variant_alternative_t<_Ip, variant<_Types...>>>
 get_if(variant<_Types...>* __v) noexcept {
   static_assert(_Ip < sizeof...(_Types));
@@ -1587,7 +1595,7 @@ get_if(variant<_Types...>* __v) noexcept {
 }
 
 template <size_t _Ip, class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
 constexpr add_pointer_t<const variant_alternative_t<_Ip, variant<_Types...>>>
 get_if(const variant<_Types...>* __v) noexcept {
   static_assert(_Ip < sizeof...(_Types));
@@ -1596,7 +1604,7 @@ get_if(const variant<_Types...>* __v) noexcept {
 }
 
 template <class _Tp, class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
 constexpr add_pointer_t<_Tp>
 get_if(variant<_Types...>* __v) noexcept {
   static_assert(!is_void_v<_Tp>);
@@ -1604,7 +1612,7 @@ get_if(variant<_Types...>* __v) noexcept {
 }
 
 template <class _Tp, class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
 constexpr add_pointer_t<const _Tp>
 get_if(const variant<_Types...>* __v) noexcept {
   static_assert(!is_void_v<_Tp>);
@@ -1614,7 +1622,8 @@ get_if(const variant<_Types...>* __v) noexcept {
 template <class _Operator>
 struct __convert_to_bool {
   template <class _T1, class _T2>
-  _LIBCPP_INLINE_VISIBILITY constexpr bool operator()(_T1 && __t1, _T2&& __t2) const {
+  _LIBCPP_HIDE_FROM_ABI
+  constexpr bool operator()(_T1 && __t1, _T2&& __t2) const {
     static_assert(is_convertible<decltype(_Operator{}(_VSTD::forward<_T1>(__t1), _VSTD::forward<_T2>(__t2))), bool>::value,
         "the relational operator does not return a type which is implicitly convertible to bool");
     return _Operator{}(_VSTD::forward<_T1>(__t1), _VSTD::forward<_T2>(__t2));
@@ -1622,7 +1631,7 @@ struct __convert_to_bool {
 };
 
 template <class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
 constexpr bool operator==(const variant<_Types...>& __lhs,
                           const variant<_Types...>& __rhs) {
   using __variant_detail::__visitation::__variant;
@@ -1631,8 +1640,29 @@ constexpr bool operator==(const variant<_Types...>& __lhs,
   return __variant::__visit_value_at(__lhs.index(), __convert_to_bool<equal_to<>>{}, __lhs, __rhs);
 }
 
+#  if _LIBCPP_STD_VER > 17
+
 template <class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI constexpr common_comparison_category_t<compare_three_way_result_t<_Types>...>
+operator<=>(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) {
+  using __variant_detail::__visitation::__variant;
+  using __result_t = common_comparison_category_t<compare_three_way_result_t<_Types>...>;
+  if (__lhs.valueless_by_exception() && __rhs.valueless_by_exception())
+    return strong_ordering::equal;
+  if (__lhs.valueless_by_exception())
+    return strong_ordering::less;
+  if (__rhs.valueless_by_exception())
+    return strong_ordering::greater;
+  if (auto __c = __lhs.index() <=> __rhs.index(); __c != 0)
+    return __c;
+  auto __three_way = []<class _Type>(const _Type& __v, const _Type& __w) -> __result_t { return __v <=> __w; };
+  return __variant::__visit_value_at(__lhs.index(), __three_way, __lhs, __rhs);
+}
+
+#  endif // _LIBCPP_STD_VER > 17
+
+template <class... _Types>
+_LIBCPP_HIDE_FROM_ABI
 constexpr bool operator!=(const variant<_Types...>& __lhs,
                           const variant<_Types...>& __rhs) {
   using __variant_detail::__visitation::__variant;
@@ -1643,7 +1673,7 @@ constexpr bool operator!=(const variant<_Types...>& __lhs,
 }
 
 template <class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
 constexpr bool operator<(const variant<_Types...>& __lhs,
                          const variant<_Types...>& __rhs) {
   using __variant_detail::__visitation::__variant;
@@ -1655,7 +1685,7 @@ constexpr bool operator<(const variant<_Types...>& __lhs,
 }
 
 template <class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
 constexpr bool operator>(const variant<_Types...>& __lhs,
                          const variant<_Types...>& __rhs) {
   using __variant_detail::__visitation::__variant;
@@ -1667,7 +1697,7 @@ constexpr bool operator>(const variant<_Types...>& __lhs,
 }
 
 template <class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
 constexpr bool operator<=(const variant<_Types...>& __lhs,
                           const variant<_Types...>& __rhs) {
   using __variant_detail::__visitation::__variant;
@@ -1680,7 +1710,7 @@ constexpr bool operator<=(const variant<_Types...>& __lhs,
 }
 
 template <class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
 constexpr bool operator>=(const variant<_Types...>& __lhs,
                           const variant<_Types...>& __rhs) {
   using __variant_detail::__visitation::__variant;
@@ -1693,9 +1723,9 @@ constexpr bool operator>=(const variant<_Types...>& __lhs,
 }
 
 template <class... _Vs>
-inline _LIBCPP_INLINE_VISIBILITY
-    _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr void
-    __throw_if_valueless(_Vs&&... __vs) {
+_LIBCPP_HIDE_FROM_ABI
+_LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
+constexpr void __throw_if_valueless(_Vs&&... __vs) {
   const bool __valueless =
       (... || _VSTD::__as_variant(__vs).valueless_by_exception());
   if (__valueless) {
@@ -1706,9 +1736,9 @@ inline _LIBCPP_INLINE_VISIBILITY
 template <
     class _Visitor, class... _Vs,
     typename = void_t<decltype(_VSTD::__as_variant(declval<_Vs>()))...> >
-inline _LIBCPP_INLINE_VISIBILITY
-    _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr
-    decltype(auto) visit(_Visitor&& __visitor, _Vs&&... __vs) {
+_LIBCPP_HIDE_FROM_ABI
+_LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
+constexpr decltype(auto) visit(_Visitor&& __visitor, _Vs&&... __vs) {
   using __variant_detail::__visitation::__variant;
   _VSTD::__throw_if_valueless(_VSTD::forward<_Vs>(__vs)...);
   return __variant::__visit_value(_VSTD::forward<_Visitor>(__visitor),
@@ -1719,9 +1749,9 @@ inline _LIBCPP_INLINE_VISIBILITY
 template <
     class _Rp, class _Visitor, class... _Vs,
     typename = void_t<decltype(_VSTD::__as_variant(declval<_Vs>()))...> >
-inline _LIBCPP_INLINE_VISIBILITY
-    _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr _Rp
-    visit(_Visitor&& __visitor, _Vs&&... __vs) {
+_LIBCPP_HIDE_FROM_ABI
+_LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
+constexpr _Rp visit(_Visitor&& __visitor, _Vs&&... __vs) {
   using __variant_detail::__visitation::__variant;
   _VSTD::__throw_if_valueless(_VSTD::forward<_Vs>(__vs)...);
   return __variant::__visit_value<_Rp>(_VSTD::forward<_Visitor>(__visitor),
@@ -1730,7 +1760,7 @@ inline _LIBCPP_INLINE_VISIBILITY
 #endif
 
 template <class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
 auto swap(variant<_Types...>& __lhs, variant<_Types...>& __rhs)
   noexcept(noexcept(__lhs.swap(__rhs)))
   -> decltype(      __lhs.swap(__rhs))
@@ -1742,7 +1772,7 @@ struct _LIBCPP_TEMPLATE_VIS hash<
   using argument_type = variant<_Types...>;
   using result_type = size_t;
 
-  inline _LIBCPP_INLINE_VISIBILITY
+  _LIBCPP_HIDE_FROM_ABI
   result_type operator()(const argument_type& __v) const {
     using __variant_detail::__visitation::__variant;
     size_t __res =
@@ -1764,20 +1794,20 @@ struct _LIBCPP_TEMPLATE_VIS hash<
 // type whereas std::get will throw or returning nullptr. This makes it faster than
 // std::get.
 template <size_t _Ip, class _Vp>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
 constexpr auto&& __unchecked_get(_Vp&& __v) noexcept {
   using __variant_detail::__access::__variant;
   return __variant::__get_alt<_Ip>(_VSTD::forward<_Vp>(__v)).__value;
 }
 
 template <class _Tp, class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
 constexpr auto&& __unchecked_get(const variant<_Types...>& __v) noexcept {
   return __unchecked_get<__find_exactly_one_t<_Tp, _Types...>::value>(__v);
 }
 
 template <class _Tp, class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
 constexpr auto&& __unchecked_get(variant<_Types...>& __v) noexcept {
   return __unchecked_get<__find_exactly_one_t<_Tp, _Types...>::value>(__v);
 }

diff  --git a/libcxx/test/std/utilities/variant/variant.monostate.relops/relops.pass.cpp b/libcxx/test/std/utilities/variant/variant.monostate.relops/relops.pass.cpp
index 6e4e3116fa0e..fab67be3e4b5 100644
--- a/libcxx/test/std/utilities/variant/variant.monostate.relops/relops.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.monostate.relops/relops.pass.cpp
@@ -16,40 +16,32 @@
 // constexpr bool operator>=(monostate, monostate) noexcept { return true; }
 // constexpr bool operator==(monostate, monostate) noexcept { return true; }
 // constexpr bool operator!=(monostate, monostate) noexcept { return false; }
+// constexpr strong_ordering operator<=>(monostate, monostate) noexcept { return strong_ordering::equal; } // since C++20
 
-#include "test_macros.h"
 #include <cassert>
-#include <type_traits>
 #include <variant>
 
-int main(int, char**) {
+#include "test_comparisons.h"
+#include "test_macros.h"
+
+constexpr bool test() {
   using M = std::monostate;
   constexpr M m1{};
   constexpr M m2{};
-  {
-    static_assert((m1 < m2) == false, "");
-    ASSERT_NOEXCEPT(m1 < m2);
-  }
-  {
-    static_assert((m1 > m2) == false, "");
-    ASSERT_NOEXCEPT(m1 > m2);
-  }
-  {
-    static_assert((m1 <= m2) == true, "");
-    ASSERT_NOEXCEPT(m1 <= m2);
-  }
-  {
-    static_assert((m1 >= m2) == true, "");
-    ASSERT_NOEXCEPT(m1 >= m2);
-  }
-  {
-    static_assert((m1 == m2) == true, "");
-    ASSERT_NOEXCEPT(m1 == m2);
-  }
-  {
-    static_assert((m1 != m2) == false, "");
-    ASSERT_NOEXCEPT(m1 != m2);
-  }
+  assert(testComparisons(m1, m2, /*isEqual*/ true, /*isLess*/ false));
+  AssertComparisonsAreNoexcept<M>();
+
+#if TEST_STD_VER > 17
+  assert(testOrder(m1, m2, std::strong_ordering::equal));
+  AssertOrderAreNoexcept<M>();
+#endif // TEST_STD_VER > 17
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
 
   return 0;
 }

diff  --git a/libcxx/test/std/utilities/variant/variant.relops/three_way.pass.cpp b/libcxx/test/std/utilities/variant/variant.relops/three_way.pass.cpp
new file mode 100644
index 000000000000..f851c535e40a
--- /dev/null
+++ b/libcxx/test/std/utilities/variant/variant.relops/three_way.pass.cpp
@@ -0,0 +1,198 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+// <variant>
+
+// template <class... Types> class variant;
+
+// template<class... Types>
+//   constexpr std::common_comparison_category_t<
+//     std::compare_three_way_result_t<Types>...>
+//   operator<=>(const variant<Types...>& t, const variant<Types...>& u);
+
+#include <cassert>
+#include <limits>
+#include <type_traits>
+#include <utility>
+#include <variant>
+
+#include "test_macros.h"
+#include "test_comparisons.h"
+
+#ifndef TEST_HAS_NO_EXCEPTIONS
+// MakeEmptyT throws in operator=(&&), so we can move to it to create valueless-by-exception variants.
+struct MakeEmptyT {
+  MakeEmptyT() = default;
+  MakeEmptyT(MakeEmptyT&&) { throw 42; }
+  MakeEmptyT& operator=(MakeEmptyT&&) { throw 42; }
+};
+inline bool operator==(const MakeEmptyT&, const MakeEmptyT&) {
+  assert(false);
+  return false;
+}
+inline std::weak_ordering operator<=>(const MakeEmptyT&, const MakeEmptyT&) {
+  assert(false);
+  return std::weak_ordering::equivalent;
+}
+
+template <class Variant>
+void makeEmpty(Variant& v) {
+  Variant v2(std::in_place_type<MakeEmptyT>);
+  try {
+    v = std::move(v2);
+    assert(false);
+  } catch (...) {
+    assert(v.valueless_by_exception());
+  }
+}
+
+void test_empty() {
+  {
+    using V = std::variant<int, MakeEmptyT>;
+    V v1;
+    V v2;
+    makeEmpty(v2);
+    assert(testOrder(v1, v2, std::weak_ordering::greater));
+  }
+  {
+    using V = std::variant<int, MakeEmptyT>;
+    V v1;
+    makeEmpty(v1);
+    V v2;
+    assert(testOrder(v1, v2, std::weak_ordering::less));
+  }
+  {
+    using V = std::variant<int, MakeEmptyT>;
+    V v1;
+    makeEmpty(v1);
+    V v2;
+    makeEmpty(v2);
+    assert(testOrder(v1, v2, std::weak_ordering::equivalent));
+  }
+}
+#endif // TEST_HAS_NO_EXCEPTIONS
+
+template <class T1, class T2, class Order>
+constexpr bool test_with_types() {
+  using V = std::variant<T1, T2>;
+  AssertOrderReturn<Order, V>();
+  { // same index, same value
+    constexpr V v1(std::in_place_index<0>, T1{1});
+    constexpr V v2(std::in_place_index<0>, T1{1});
+    assert(testOrder(v1, v2, Order::equivalent));
+  }
+  { // same index, value < other_value
+    constexpr V v1(std::in_place_index<0>, T1{0});
+    constexpr V v2(std::in_place_index<0>, T1{1});
+    assert(testOrder(v1, v2, Order::less));
+  }
+  { // same index, value > other_value
+    constexpr V v1(std::in_place_index<0>, T1{1});
+    constexpr V v2(std::in_place_index<0>, T1{0});
+    assert(testOrder(v1, v2, Order::greater));
+  }
+  { // LHS.index() < RHS.index()
+    constexpr V v1(std::in_place_index<0>, T1{0});
+    constexpr V v2(std::in_place_index<1>, T2{0});
+    assert(testOrder(v1, v2, Order::less));
+  }
+  { // LHS.index() > RHS.index()
+    constexpr V v1(std::in_place_index<1>, T2{0});
+    constexpr V v2(std::in_place_index<0>, T1{0});
+    assert(testOrder(v1, v2, Order::greater));
+  }
+
+  return true;
+}
+
+constexpr bool test_three_way() {
+  assert((test_with_types<int, double, std::partial_ordering>()));
+  assert((test_with_types<int, long, std::strong_ordering>()));
+
+  {
+    using V              = std::variant<int, double>;
+    constexpr double nan = std::numeric_limits<double>::quiet_NaN();
+    {
+      constexpr V v1(std::in_place_type<int>, 1);
+      constexpr V v2(std::in_place_type<double>, nan);
+      assert(testOrder(v1, v2, std::partial_ordering::less));
+    }
+    {
+      constexpr V v1(std::in_place_type<double>, nan);
+      constexpr V v2(std::in_place_type<int>, 2);
+      assert(testOrder(v1, v2, std::partial_ordering::greater));
+    }
+    {
+      constexpr V v1(std::in_place_type<double>, nan);
+      constexpr V v2(std::in_place_type<double>, nan);
+      assert(testOrder(v1, v2, std::partial_ordering::unordered));
+    }
+  }
+
+  return true;
+}
+
+// SFINAE tests
+template <class T, class U = T>
+concept has_three_way_op = requires (T& t, U& u) { t <=> u; };
+
+// std::three_way_comparable is a more stringent requirement that demands
+// operator== and a few other things.
+using std::three_way_comparable;
+
+struct HasSimpleOrdering {
+  constexpr bool operator==(const HasSimpleOrdering&) const;
+  constexpr bool operator<(const HasSimpleOrdering&) const;
+};
+
+struct HasOnlySpaceship {
+  constexpr bool operator==(const HasOnlySpaceship&) const = delete;
+  constexpr std::weak_ordering operator<=>(const HasOnlySpaceship&) const;
+};
+
+struct HasFullOrdering {
+  constexpr bool operator==(const HasFullOrdering&) const;
+  constexpr std::weak_ordering operator<=>(const HasFullOrdering&) const;
+};
+
+// operator<=> must resolve the return types of all its union types'
+// operator<=>s to determine its own return type, so it is detectable by SFINAE
+static_assert(!has_three_way_op<HasSimpleOrdering>);
+static_assert(!has_three_way_op<std::variant<int, HasSimpleOrdering>>);
+
+static_assert(!three_way_comparable<HasSimpleOrdering>);
+static_assert(!three_way_comparable<std::variant<int, HasSimpleOrdering>>);
+
+static_assert( has_three_way_op<HasOnlySpaceship>);
+static_assert( has_three_way_op<std::variant<int, HasOnlySpaceship>>);
+
+// variants containing types with unavailable operator== still exist but will
+// generate a compilation error if their operator== is invoked, so the variant
+// type here participates when asked for operator== and operator<=> even though
+// it would actually fail.
+static_assert(!three_way_comparable<HasOnlySpaceship>);
+static_assert( three_way_comparable<std::variant<int, HasOnlySpaceship>>);
+
+static_assert( has_three_way_op<HasFullOrdering>);
+static_assert( has_three_way_op<std::variant<int, HasFullOrdering>>);
+
+static_assert( three_way_comparable<HasFullOrdering>);
+static_assert( three_way_comparable<std::variant<int, HasFullOrdering>>);
+
+int main(int, char**) {
+  test_three_way();
+  static_assert(test_three_way());
+
+#ifndef TEST_HAS_NO_EXCEPTIONS
+  test_empty();
+#endif // TEST_HAS_NO_EXCEPTIONS
+
+  return 0;
+}

diff  --git a/libcxx/test/support/test_comparisons.h b/libcxx/test/support/test_comparisons.h
index e4bb4196543b..8187a7c1a215 100644
--- a/libcxx/test/support/test_comparisons.h
+++ b/libcxx/test/support/test_comparisons.h
@@ -23,18 +23,20 @@
 #ifndef TEST_COMPARISONS_H
 #define TEST_COMPARISONS_H
 
-#include <type_traits>
 #include <cassert>
 #include <concepts>
+#include <type_traits>
+#include <utility>
+
 #include "test_macros.h"
 
-//  Test all six comparison operations for sanity
+// Test the consistency of the six basic comparison operators for values that are ordered or unordered.
 template <class T, class U = T>
-TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool testComparisons(const T& t1, const U& t2, bool isEqual, bool isLess)
-{
-    assert(!(isEqual && isLess) && "isEqual and isLess cannot be both true");
-    if (isEqual)
-        {
+TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool
+testComparisonsComplete(const T& t1, const U& t2, bool isEqual, bool isLess, bool isGreater) {
+    assert(((isEqual ? 1 : 0) + (isLess ? 1 : 0) + (isGreater ? 1 : 0) <= 1) &&
+           "at most one of isEqual, isLess, and isGreater can be true");
+    if (isEqual) {
         if (!(t1 == t2)) return false;
         if (!(t2 == t1)) return false;
         if ( (t1 != t2)) return false;
@@ -47,9 +49,7 @@ TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool testComparisons(const T& t1, const U& t
         if ( (t2  > t1)) return false;
         if (!(t1 >= t2)) return false;
         if (!(t2 >= t1)) return false;
-        }
-    else if (isLess)
-        {
+    } else if (isLess) {
         if ( (t1 == t2)) return false;
         if ( (t2 == t1)) return false;
         if (!(t1 != t2)) return false;
@@ -62,9 +62,7 @@ TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool testComparisons(const T& t1, const U& t
         if (!(t2  > t1)) return false;
         if ( (t1 >= t2)) return false;
         if (!(t2 >= t1)) return false;
-        }
-    else /* greater */
-        {
+    } else if (isGreater) {
         if ( (t1 == t2)) return false;
         if ( (t2 == t1)) return false;
         if (!(t1 != t2)) return false;
@@ -77,19 +75,41 @@ TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool testComparisons(const T& t1, const U& t
         if ( (t2  > t1)) return false;
         if (!(t1 >= t2)) return false;
         if ( (t2 >= t1)) return false;
-        }
+    } else { // unordered
+        if ( (t1 == t2)) return false;
+        if ( (t2 == t1)) return false;
+        if (!(t1 != t2)) return false;
+        if (!(t2 != t1)) return false;
+        if ( (t1  < t2)) return false;
+        if ( (t2  < t1)) return false;
+        if ( (t1 <= t2)) return false;
+        if ( (t2 <= t1)) return false;
+        if ( (t1  > t2)) return false;
+        if ( (t2  > t1)) return false;
+        if ( (t1 >= t2)) return false;
+        if ( (t2 >= t1)) return false;
+    }
 
     return true;
 }
 
+// Test the six basic comparison operators for ordered values.
+template <class T, class U = T>
+TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool testComparisons(const T& t1, const U& t2, bool isEqual, bool isLess) {
+    assert(!(isEqual && isLess) && "isEqual and isLess cannot be both true");
+    bool isGreater = !isEqual && !isLess;
+    return testComparisonsComplete(t1, t2, isEqual, isLess, isGreater);
+}
+
 //  Easy call when you can init from something already comparable.
 template <class T, class Param>
 TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool testComparisonsValues(Param val1, Param val2)
 {
-    const bool isEqual = val1 == val2;
-    const bool isLess  = val1  < val2;
+    const bool isEqual   = val1 == val2;
+    const bool isLess    = val1 <  val2;
+    const bool isGreater = val1  > val2;
 
-    return testComparisons(T(val1), T(val2), isEqual, isLess);
+    return testComparisonsComplete(T(val1), T(val2), isEqual, isLess, isGreater);
 }
 
 template <class T, class U = T>
@@ -138,10 +158,11 @@ constexpr void AssertOrderReturn() {
 
 template <class Order, class T, class U = T>
 TEST_NODISCARD constexpr bool testOrder(const T& t1, const U& t2, Order order) {
-    bool equal = order == Order::equivalent;
-    bool less = order == Order::less;
+    bool equal   = order == Order::equivalent;
+    bool less    = order == Order::less;
+    bool greater = order == Order::greater;
 
-    return (t1 <=> t2 == order) && testComparisons(t1, t2, equal, less);
+    return (t1 <=> t2 == order) && testComparisonsComplete(t1, t2, equal, less, greater);
 }
 
 template <class T, class Param>


        


More information about the libcxx-commits mailing list