<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Apr 6, 2018 at 4:00 PM, Richard Smith <span dir="ltr"><<a href="mailto:richard@metafoo.co.uk" target="_blank">richard@metafoo.co.uk</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><div class="h5">On 6 April 2018 at 14:37, Eric Fiselier via cfe-commits <span dir="ltr"><<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: ericwf<br>
Date: Fri Apr  6 14:37:23 2018<br>
New Revision: 329460<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=329460&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject?rev=329460&view=rev</a><br>
Log:<br>
Implement P0768r1: Library support for the Spaceship Operator.<br>
<br>
this patch adds the <compare> header and implements all of it<br>
except for [comp.alg].<br>
<br>
As I understand it, the header is needed by the compiler in<br>
when implementing the semantics of operator<=>. For that reason<br>
I feel it's important to land this header early, despite<br>
all compilers lacking support.<br>
<br>
Added:<br>
    libcxx/trunk/include/compare<br>
    libcxx/trunk/test/libcxx/langu<wbr>age.support/cmp/<br>
    libcxx/trunk/test/libcxx/langu<wbr>age.support/cmp/version.pass.<wbr>cpp<br>
    libcxx/trunk/test/std/language<wbr>.support/cmp/<br>
    libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.common/<br>
    libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.common/<wbr>common_comparison_category.<wbr>pass.cpp<br>
    libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.partialord/<br>
    libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.partialord/<wbr>partialord.pass.cpp<br>
    libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.strongeq/<br>
    libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.strongeq/cmp.<wbr>strongeq.pass.cpp<br>
    libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.strongord/<br>
    libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.strongord/<wbr>strongord.pass.cpp<br>
    libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.weakeq/<br>
    libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.weakeq/cmp.<wbr>weakeq.pass.cpp<br>
    libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.weakord/<br>
    libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.weakord/<wbr>weakord.pass.cpp<br>
Modified:<br>
    libcxx/trunk/include/CMakeList<wbr>s.txt<br>
    libcxx/trunk/include/__config<br>
    libcxx/trunk/include/module.mo<wbr>dulemap<br>
    libcxx/trunk/test/libcxx/doubl<wbr>e_include.sh.cpp<br>
    libcxx/trunk/test/support/test<wbr>_macros.h<br>
<br>
Modified: libcxx/trunk/include/CMakeList<wbr>s.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/CMakeLists.txt?rev=329460&r1=329459&r2=329460&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/libcxx/trunk/include/CMa<wbr>keLists.txt?rev=329460&r1=3294<wbr>59&r2=329460&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/include/CMakeList<wbr>s.txt (original)<br>
+++ libcxx/trunk/include/CMakeList<wbr>s.txt Fri Apr  6 14:37:23 2018<br>
@@ -77,5 +77,4 @@ if (LIBCXX_INSTALL_HEADERS)<br>
     add_custom_target(install-lib<wbr>cxx-headers DEPENDS install-cxx-headers)<br>
     add_custom_target(install-lib<wbr>cxx-headers-stripped DEPENDS install-cxx-headers-stripped)<br>
   endif()<br>
-<br>
 endif()<br>
<br>
Modified: libcxx/trunk/include/__config<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/__config?rev=329460&r1=329459&r2=329460&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/libcxx/trunk/include/__<wbr>config?rev=329460&r1=329459&r2<wbr>=329460&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/include/__config (original)<br>
+++ libcxx/trunk/include/__config Fri Apr  6 14:37:23 2018<br>
@@ -1196,6 +1196,11 @@ _LIBCPP_FUNC_VIS extern "C" void __sanit<br>
 #define _LIBCPP_HAS_NO_COROUTINES<br>
 #endif<br>
<br>
+// FIXME: Correct this macro when either (A) a feature test macro for the<br>
+// spaceship operator is provided, or (B) a compiler provides a complete<br>
+// implementation.<br>
+#define _LIBCPP_HAS_NO_SPACESHIP_OPERA<wbr>TOR<br>
+<br>
 // Decide whether to use availability macros.<br>
 #if !defined(_LIBCPP_BUILDING_LIBR<wbr>ARY) &&                                      \<br>
     !defined(_LIBCPP_DISABLE_AVAI<wbr>LABILITY) &&                                  \<br>
<br>
Added: libcxx/trunk/include/compare<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/compare?rev=329460&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/libcxx/trunk/include/com<wbr>pare?rev=329460&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/include/compare (added)<br>
+++ libcxx/trunk/include/compare Fri Apr  6 14:37:23 2018<br>
@@ -0,0 +1,679 @@<br>
+// -*- C++ -*-<br>
+//===------------------------<wbr>-- compare ------------------------------<wbr>-----===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is dual licensed under the MIT and the University of Illinois Open<br>
+// Source Licenses. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+#ifndef _LIBCPP_COMPARE<br>
+#define _LIBCPP_COMPARE<br>
+<br>
+/*<br>
+    compare synopsis<br>
+<br>
+namespace std {<br>
+  // [cmp.categories], comparison category types<br>
+  class weak_equality;<br>
+  class strong_equality;<br>
+  class partial_ordering;<br>
+  class weak_ordering;<br>
+  class strong_ordering;<br>
+<br>
+  // named comparison functions<br>
+  constexpr bool is_eq  (weak_equality cmp) noexcept    { return cmp == 0; }<br>
+  constexpr bool is_neq (weak_equality cmp) noexcept    { return cmp != 0; }<br>
+  constexpr bool is_lt  (partial_ordering cmp) noexcept { return cmp < 0; }<br>
+  constexpr bool is_lteq(partial_ordering cmp) noexcept { return cmp <= 0; }<br>
+  constexpr bool is_gt  (partial_ordering cmp) noexcept { return cmp > 0; }<br>
+  constexpr bool is_gteq(partial_ordering cmp) noexcept { return cmp >= 0; }<br>
+<br>
+  // [cmp.common], common comparison category type<br>
+  template<class... Ts><br>
+  struct common_comparison_category {<br>
+    using type = see below;<br>
+  };<br>
+  template<class... Ts><br>
+    using common_comparison_category_t = typename common_comparison_category<Ts.<wbr>..>::type;<br>
+<br>
+  // [cmp.alg], comparison algorithms<br>
+  template<class T> constexpr strong_ordering strong_order(const T& a, const T& b);<br>
+  template<class T> constexpr weak_ordering weak_order(const T& a, const T& b);<br>
+  template<class T> constexpr partial_ordering partial_order(const T& a, const T& b);<br>
+  template<class T> constexpr strong_equality strong_equal(const T& a, const T& b);<br>
+  template<class T> constexpr weak_equality weak_equal(const T& a, const T& b);<br>
+}<br>
+*/<br>
+<br>
+#include <__config><br>
+#include <type_traits><br>
+#include <array><br>
+<br>
+#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_H<wbr>EADER<br>
+#pragma GCC system_header<br>
+#endif<br>
+<br>
+_LIBCPP_BEGIN_NAMESPACE_STD<br>
+<br>
+#if _LIBCPP_STD_VER > 17<br>
+<br>
+// exposition only<br>
+enum class _LIBCPP_ENUM_VIS _EqResult : unsigned char {<br>
+  __zero = 0,<br>
+  __equal = __zero,<br>
+  __equiv = __equal,<br>
+  __nonequal = 1,<br>
+  __nonequiv = __nonequal<br>
+};<br>
+<br>
+enum class _LIBCPP_ENUM_VIS _OrdResult : signed char {<br>
+  __less = -1,<br>
+  __greater = 1<br>
+};<br>
+<br>
+enum class _LIBCPP_ENUM_VIS _NCmpResult : signed char {<br>
+  __unordered = -127<br>
+};<br>
+<br>
+struct _CmpUnspecifiedType;<br>
+using _CmpUnspecifiedParam = void (_CmpUnspecifiedType::*)();<br></blockquote><div><br></div></div></div><div>FYI, I've been planning to add a __zero_type to the compiler for this (a type that can only be initialized by a literal zero, not e.g. by nullptr). Looks like that would be easy to retrofit here once it's available.</div></div></div></div></blockquote><div><br></div><div>Awesome :-)</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><div class="h5"><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+class  weak_equality {<br>
+  _LIBCPP_INLINE_VISIBILITY<br>
+  constexpr explicit weak_equality(_EqResult __val) noexcept : __value_(__val) {}<br>
+<br>
+public:<br>
+  static const weak_equality equivalent;<br>
+  static const weak_equality nonequivalent;<br>
+<br>
+  friend constexpr bool operator==(weak_equality __v, _CmpUnspecifiedParam) noexcept;<br>
+  friend constexpr bool operator==(_CmpUnspecifiedPara<wbr>m, weak_equality __v) noexcept;<br>
+  friend constexpr bool operator!=(weak_equality __v, _CmpUnspecifiedParam) noexcept;<br>
+  friend constexpr bool operator!=(_CmpUnspecifiedPara<wbr>m, weak_equality __v) noexcept;<br>
+<br>
+#ifndef _LIBCPP_HAS_NO_SPACESHIP_OPERA<wbr>TOR<br>
+  friend constexpr weak_equality operator<=>(weak_equality __v, _CmpUnspecifiedParam) noexcept;<br>
+  friend constexpr weak_equality operator<=>(_CmpUnspecifiedPar<wbr>am, weak_equality __v) noexcept;<br>
+#endif<br>
+<br>
+private:<br>
+  _EqResult __value_;<br>
+};<br>
+<br>
+_LIBCPP_INLINE_VAR constexpr weak_equality weak_equality::equivalent(_EqR<wbr>esult::__equiv);<br>
+_LIBCPP_INLINE_VAR constexpr weak_equality weak_equality::nonequivalent(_<wbr>EqResult::__nonequiv);<br>
+<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+inline constexpr bool operator==(weak_equality __v, _CmpUnspecifiedParam) noexcept {<br>
+  return __v.__value_ == _EqResult::__zero;<br>
+}<br>
+<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+inline constexpr bool operator==(_CmpUnspecifiedPara<wbr>m, weak_equality __v) noexcept {<br>
+  return __v.__value_ == _EqResult::__zero;<br>
+}<br>
+<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+inline constexpr bool operator!=(weak_equality __v, _CmpUnspecifiedParam) noexcept {<br>
+  return __v.__value_ != _EqResult::__zero;<br>
+}<br>
+<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+inline constexpr bool operator!=(_CmpUnspecifiedPara<wbr>m, weak_equality __v) noexcept {<br>
+  return __v.__value_ != _EqResult::__zero;<br>
+}<br>
+<br>
+#ifndef _LIBCPP_HAS_NO_SPACESHIP_OPERA<wbr>TOR<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+inline constexpr weak_equality operator<=>(weak_equality __v, _CmpUnspecifiedParam) noexcept {<br>
+  return __v;<br>
+}<br>
+<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+inline constexpr weak_equality operator<=>(_CmpUnspecifiedPar<wbr>am, weak_equality __v) noexcept {<br>
+  return __v;<br>
+}<br>
+#endif<br>
+<br>
+class strong_equality {<br>
+  _LIBCPP_INLINE_VISIBILITY<br>
+  explicit constexpr strong_equality(_EqResult __val) noexcept : __value_(__val) {}<br>
+<br>
+public:<br>
+  static const strong_equality equal;<br>
+  static const strong_equality nonequal;<br>
+  static const strong_equality equivalent;<br>
+  static const strong_equality nonequivalent;<br>
+<br>
+  // conversion<br>
+  constexpr operator weak_equality() const noexcept {<br>
+    return __value_ == _EqResult::__zero ? weak_equality::equivalent<br>
+          : weak_equality::nonequivalent;<br>
+  }<br>
+<br>
+  // comparisons<br>
+  friend constexpr bool operator==(strong_equality __v, _CmpUnspecifiedParam) noexcept;<br>
+  friend constexpr bool operator!=(strong_equality __v, _CmpUnspecifiedParam) noexcept;<br>
+  friend constexpr bool operator==(_CmpUnspecifiedPara<wbr>m, strong_equality __v) noexcept;<br>
+  friend constexpr bool operator!=(_CmpUnspecifiedPara<wbr>m, strong_equality __v) noexcept;<br>
+<br>
+#ifndef _LIBCPP_HAS_NO_SPACESHIP_OPERA<wbr>TOR<br>
+  friend constexpr strong_equality operator<=>(strong_equality __v, _CmpUnspecifiedParam) noexcept;<br>
+  friend constexpr strong_equality operator<=>(_CmpUnspecifiedPar<wbr>am, strong_equality __v) noexcept;<br>
+#endif<br>
+private:<br>
+  _EqResult __value_;<br>
+};<br>
+<br>
+_LIBCPP_INLINE_VAR constexpr strong_equality strong_equality::equal(_EqResu<wbr>lt::__equal);<br>
+_LIBCPP_INLINE_VAR constexpr strong_equality strong_equality::nonequal(_EqR<wbr>esult::__nonequal);<br>
+_LIBCPP_INLINE_VAR constexpr strong_equality strong_equality::equivalent(_E<wbr>qResult::__equiv);<br>
+_LIBCPP_INLINE_VAR constexpr strong_equality strong_equality::nonequivalent<wbr>(_EqResult::__nonequiv);<br>
+<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator==(strong_equality __v, _CmpUnspecifiedParam) noexcept {<br>
+  return __v.__value_ == _EqResult::__zero;<br>
+}<br>
+<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator==(_CmpUnspecifiedPara<wbr>m, strong_equality __v) noexcept {<br>
+  return __v.__value_ == _EqResult::__zero;<br>
+}<br>
+<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator!=(strong_equality __v, _CmpUnspecifiedParam) noexcept {<br>
+  return __v.__value_ != _EqResult::__zero;<br>
+}<br>
+<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator!=(_CmpUnspecifiedPara<wbr>m, strong_equality __v) noexcept {<br>
+  return __v.__value_ != _EqResult::__zero;<br>
+}<br>
+<br>
+#ifndef _LIBCPP_HAS_NO_SPACESHIP_OPERA<wbr>TOR<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr strong_equality operator<=>(strong_equality __v, _CmpUnspecifiedParam) noexcept {<br>
+  return __v;<br>
+}<br>
+<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr strong_equality operator<=>(_CmpUnspecifiedPar<wbr>am, strong_equality __v) noexcept {<br>
+  return __v;<br>
+}<br>
+#endif // _LIBCPP_HAS_NO_SPACESHIP_OPERA<wbr>TOR<br>
+<br>
+class partial_ordering {<br>
+  using _ValueT = signed char;<br>
+<br>
+  _LIBCPP_INLINE_VISIBILITY<br>
+  explicit constexpr partial_ordering(_EqResult __v) noexcept<br>
+      : __value_(_ValueT(__v)) {}<br>
+<br>
+  _LIBCPP_INLINE_VISIBILITY<br>
+  explicit constexpr partial_ordering(_OrdResult __v) noexcept<br>
+      : __value_(_ValueT(__v)) {}<br>
+<br>
+  _LIBCPP_INLINE_VISIBILITY<br>
+  explicit constexpr partial_ordering(_NCmpResult __v) noexcept<br>
+      : __value_(_ValueT(__v)) {}<br>
+<br>
+  constexpr bool __is_ordered() const noexcept {<br>
+    return __value_ != _ValueT(_NCmpResult::__unorder<wbr>ed);<br>
+  }<br>
+public:<br>
+  // valid values<br>
+  static const partial_ordering less;<br>
+  static const partial_ordering equivalent;<br>
+  static const partial_ordering greater;<br>
+  static const partial_ordering unordered;<br>
+<br>
+  // conversion<br>
+  constexpr operator weak_equality() const noexcept {<br>
+    return __value_ == 0 ? weak_equality::equivalent : weak_equality::nonequivalent;<br>
+  }<br>
+<br>
+  // comparisons<br>
+  friend constexpr bool operator==(partial_ordering __v, _CmpUnspecifiedParam) noexcept;<br>
+  friend constexpr bool operator!=(partial_ordering __v, _CmpUnspecifiedParam) noexcept;<br>
+  friend constexpr bool operator< (partial_ordering __v, _CmpUnspecifiedParam) noexcept;<br>
+  friend constexpr bool operator<=(partial_ordering __v, _CmpUnspecifiedParam) noexcept;<br>
+  friend constexpr bool operator> (partial_ordering __v, _CmpUnspecifiedParam) noexcept;<br>
+  friend constexpr bool operator>=(partial_ordering __v, _CmpUnspecifiedParam) noexcept;<br>
+  friend constexpr bool operator==(_CmpUnspecifiedPara<wbr>m, partial_ordering __v) noexcept;<br>
+  friend constexpr bool operator!=(_CmpUnspecifiedPara<wbr>m, partial_ordering __v) noexcept;<br>
+  friend constexpr bool operator< (_CmpUnspecifiedParam, partial_ordering __v) noexcept;<br>
+  friend constexpr bool operator<=(_CmpUnspecifiedPara<wbr>m, partial_ordering __v) noexcept;<br>
+  friend constexpr bool operator> (_CmpUnspecifiedParam, partial_ordering __v) noexcept;<br>
+  friend constexpr bool operator>=(_CmpUnspecifiedPara<wbr>m, partial_ordering __v) noexcept;<br>
+<br>
+#ifndef _LIBCPP_HAS_NO_SPACESHIP_OPERA<wbr>TOR<br>
+  friend constexpr partial_ordering operator<=>(partial_ordering __v, _CmpUnspecifiedParam) noexcept;<br>
+  friend constexpr partial_ordering operator<=>(_CmpUnspecifiedPar<wbr>am, partial_ordering __v) noexcept;<br>
+#endif<br>
+<br>
+private:<br>
+  _ValueT __value_;<br>
+};<br>
+<br>
+_LIBCPP_INLINE_VAR constexpr partial_ordering partial_ordering::less(_OrdRes<wbr>ult::__less);<br>
+_LIBCPP_INLINE_VAR constexpr partial_ordering partial_ordering::equivalent(_<wbr>EqResult::__equiv);<br>
+_LIBCPP_INLINE_VAR constexpr partial_ordering partial_ordering::greater(_Ord<wbr>Result::__greater);<br>
+_LIBCPP_INLINE_VAR constexpr partial_ordering partial_ordering::unordered(_N<wbr>CmpResult ::__unordered);<br>
+<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator==(partial_ordering __v, _CmpUnspecifiedParam) noexcept {<br>
+  return __v.__is_ordered() && __v.__value_ == 0;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator< (partial_ordering __v, _CmpUnspecifiedParam) noexcept {<br>
+  return __v.__is_ordered() && __v.__value_ < 0;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator<=(partial_ordering __v, _CmpUnspecifiedParam) noexcept {<br>
+  return __v.__is_ordered() && __v.__value_ <= 0;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator> (partial_ordering __v, _CmpUnspecifiedParam) noexcept {<br>
+  return __v.__is_ordered() && __v.__value_ > 0;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator>=(partial_ordering __v, _CmpUnspecifiedParam) noexcept {<br>
+  return __v.__is_ordered() && __v.__value_ >= 0;<br>
+}<br>
+<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator==(_CmpUnspecifiedPara<wbr>m, partial_ordering __v) noexcept {<br>
+  return __v.__is_ordered() && 0 == __v.__value_;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator< (_CmpUnspecifiedParam, partial_ordering __v) noexcept {<br>
+  return __v.__is_ordered() && 0 < __v.__value_;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator<=(_CmpUnspecifiedPara<wbr>m, partial_ordering __v) noexcept {<br>
+  return __v.__is_ordered() && 0 <= __v.__value_;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator> (_CmpUnspecifiedParam, partial_ordering __v) noexcept {<br>
+  return __v.__is_ordered() && 0 > __v.__value_;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator>=(_CmpUnspecifiedPara<wbr>m, partial_ordering __v) noexcept {<br>
+  return __v.__is_ordered() && 0 >= __v.__value_;<br>
+}<br>
+<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator!=(partial_ordering __v, _CmpUnspecifiedParam) noexcept {<br>
+  return !__v.__is_ordered() || __v.__value_ != 0;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator!=(_CmpUnspecifiedPara<wbr>m, partial_ordering __v) noexcept {<br>
+  return !__v.__is_ordered() || __v.__value_ != 0;<br>
+}<br>
+<br>
+#ifndef _LIBCPP_HAS_NO_SPACESHIP_OPERA<wbr>TOR<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr partial_ordering operator<=>(partial_ordering __v, _CmpUnspecifiedParam) noexcept {<br>
+  return __v;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr partial_ordering operator<=>(_CmpUnspecifiedPar<wbr>am, partial_ordering __v) noexcept {<br>
+  return __v < 0 ? partial_ordering::greater : (__v > 0 ? partial_ordering::less : __v);<br>
+}<br>
+#endif // _LIBCPP_HAS_NO_SPACESHIP_OPERA<wbr>TOR<br>
+<br>
+class weak_ordering {<br>
+  using _ValueT = signed char;<br>
+<br>
+  _LIBCPP_INLINE_VISIBILITY<br>
+  explicit constexpr weak_ordering(_EqResult __v) noexcept : __value_(_ValueT(__v)) {}<br>
+  _LIBCPP_INLINE_VISIBILITY<br>
+  explicit constexpr weak_ordering(_OrdResult __v) noexcept : __value_(_ValueT(__v)) {}<br>
+<br>
+public:<br>
+  static const weak_ordering less;<br>
+  static const weak_ordering equivalent;<br>
+  static const weak_ordering greater;<br>
+<br>
+  // conversions<br>
+  _LIBCPP_INLINE_VISIBILITY<br>
+  constexpr operator weak_equality() const noexcept {<br>
+    return __value_ == 0 ? weak_equality::equivalent<br>
+                         : weak_equality::nonequivalent;<br>
+  }<br>
+<br>
+  _LIBCPP_INLINE_VISIBILITY<br>
+  constexpr operator partial_ordering() const noexcept {<br>
+    return __value_ == 0 ? partial_ordering::equivalent<br>
+        : (__value_ < 0 ? partial_ordering::less : partial_ordering::greater);<br>
+  }<br>
+<br>
+  // comparisons<br>
+  friend constexpr bool operator==(weak_ordering __v, _CmpUnspecifiedParam) noexcept;<br>
+  friend constexpr bool operator!=(weak_ordering __v, _CmpUnspecifiedParam) noexcept;<br>
+  friend constexpr bool operator< (weak_ordering __v, _CmpUnspecifiedParam) noexcept;<br>
+  friend constexpr bool operator<=(weak_ordering __v, _CmpUnspecifiedParam) noexcept;<br>
+  friend constexpr bool operator> (weak_ordering __v, _CmpUnspecifiedParam) noexcept;<br>
+  friend constexpr bool operator>=(weak_ordering __v, _CmpUnspecifiedParam) noexcept;<br>
+  friend constexpr bool operator==(_CmpUnspecifiedPara<wbr>m, weak_ordering __v) noexcept;<br>
+  friend constexpr bool operator!=(_CmpUnspecifiedPara<wbr>m, weak_ordering __v) noexcept;<br>
+  friend constexpr bool operator< (_CmpUnspecifiedParam, weak_ordering __v) noexcept;<br>
+  friend constexpr bool operator<=(_CmpUnspecifiedPara<wbr>m, weak_ordering __v) noexcept;<br>
+  friend constexpr bool operator> (_CmpUnspecifiedParam, weak_ordering __v) noexcept;<br>
+  friend constexpr bool operator>=(_CmpUnspecifiedPara<wbr>m, weak_ordering __v) noexcept;<br>
+<br>
+#ifndef _LIBCPP_HAS_NO_SPACESHIP_OPERA<wbr>TOR<br>
+  friend constexpr weak_ordering operator<=>(weak_ordering __v, _CmpUnspecifiedParam) noexcept;<br>
+  friend constexpr weak_ordering operator<=>(_CmpUnspecifiedPar<wbr>am, weak_ordering __v) noexcept;<br>
+#endif<br>
+<br>
+private:<br>
+  _ValueT __value_;<br>
+};<br>
+<br>
+_LIBCPP_INLINE_VAR constexpr weak_ordering weak_ordering::less(_OrdResult<wbr>::__less);<br>
+_LIBCPP_INLINE_VAR constexpr weak_ordering weak_ordering::equivalent(_EqR<wbr>esult::__equiv);<br>
+_LIBCPP_INLINE_VAR constexpr weak_ordering weak_ordering::greater(_OrdRes<wbr>ult::__greater);<br>
+<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator==(weak_ordering __v, _CmpUnspecifiedParam) noexcept {<br>
+  return __v.__value_ == 0;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator!=(weak_ordering __v, _CmpUnspecifiedParam) noexcept {<br>
+  return __v.__value_ != 0;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator< (weak_ordering __v, _CmpUnspecifiedParam) noexcept {<br>
+  return __v.__value_ < 0;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator<=(weak_ordering __v, _CmpUnspecifiedParam) noexcept {<br>
+  return __v.__value_ <= 0;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator> (weak_ordering __v, _CmpUnspecifiedParam) noexcept {<br>
+  return __v.__value_ > 0;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator>=(weak_ordering __v, _CmpUnspecifiedParam) noexcept {<br>
+  return __v.__value_ >= 0;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator==(_CmpUnspecifiedPara<wbr>m, weak_ordering __v) noexcept {<br>
+  return 0 == __v.__value_;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator!=(_CmpUnspecifiedPara<wbr>m, weak_ordering __v) noexcept {<br>
+  return 0 != __v.__value_;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator< (_CmpUnspecifiedParam, weak_ordering __v) noexcept {<br>
+  return 0 < __v.__value_;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator<=(_CmpUnspecifiedPara<wbr>m, weak_ordering __v) noexcept {<br>
+  return 0 <= __v.__value_;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator> (_CmpUnspecifiedParam, weak_ordering __v) noexcept {<br>
+  return 0 > __v.__value_;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator>=(_CmpUnspecifiedPara<wbr>m, weak_ordering __v) noexcept {<br>
+  return 0 >= __v.__value_;<br>
+}<br>
+<br>
+#ifndef _LIBCPP_HAS_NO_SPACESHIP_OPERA<wbr>TOR<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr weak_ordering operator<=>(weak_ordering __v, _CmpUnspecifiedParam) noexcept {<br>
+  return __v;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr weak_ordering operator<=>(_CmpUnspecifiedPar<wbr>am, weak_ordering __v) noexcept {<br>
+  return __v < 0 ? weak_ordering::greater : (__v > 0 ? weak_ordering::less : __v);<br>
+}<br>
+#endif // _LIBCPP_HAS_NO_SPACESHIP_OPERA<wbr>TOR<br>
+<br>
+class strong_ordering {<br>
+  using _ValueT = signed char;<br>
+<br>
+  _LIBCPP_INLINE_VISIBILITY<br>
+  explicit constexpr strong_ordering(_EqResult __v) noexcept : __value_(_ValueT(__v)) {}<br>
+  _LIBCPP_INLINE_VISIBILITY<br>
+  explicit constexpr strong_ordering(_OrdResult __v) noexcept : __value_(_ValueT(__v)) {}<br>
+<br>
+public:<br>
+  static const strong_ordering less;<br>
+  static const strong_ordering equal;<br>
+  static const strong_ordering equivalent;<br>
+  static const strong_ordering greater;<br>
+<br>
+  // conversions<br>
+  _LIBCPP_INLINE_VISIBILITY<br>
+  constexpr operator weak_equality() const noexcept {<br>
+    return __value_ == 0 ? weak_equality::equivalent<br>
+                         : weak_equality::nonequivalent;<br>
+  }<br>
+<br>
+  _LIBCPP_INLINE_VISIBILITY<br>
+  constexpr operator strong_equality() const noexcept {<br>
+    return __value_ == 0 ? strong_equality::equal<br>
+                         : strong_equality::nonequal;<br>
+  }<br>
+<br>
+  _LIBCPP_INLINE_VISIBILITY<br>
+  constexpr operator partial_ordering() const noexcept {<br>
+    return __value_ == 0 ? partial_ordering::equivalent<br>
+        : (__value_ < 0 ? partial_ordering::less : partial_ordering::greater);<br>
+  }<br>
+<br>
+  _LIBCPP_INLINE_VISIBILITY<br>
+  constexpr operator weak_ordering() const noexcept {<br>
+    return __value_ == 0 ? weak_ordering::equivalent<br>
+        : (__value_ < 0 ? weak_ordering::less : weak_ordering::greater);<br>
+  }<br>
+<br>
+  // comparisons<br>
+  friend constexpr bool operator==(strong_ordering __v, _CmpUnspecifiedParam) noexcept;<br>
+  friend constexpr bool operator!=(strong_ordering __v, _CmpUnspecifiedParam) noexcept;<br>
+  friend constexpr bool operator< (strong_ordering __v, _CmpUnspecifiedParam) noexcept;<br>
+  friend constexpr bool operator<=(strong_ordering __v, _CmpUnspecifiedParam) noexcept;<br>
+  friend constexpr bool operator> (strong_ordering __v, _CmpUnspecifiedParam) noexcept;<br>
+  friend constexpr bool operator>=(strong_ordering __v, _CmpUnspecifiedParam) noexcept;<br>
+  friend constexpr bool operator==(_CmpUnspecifiedPara<wbr>m, strong_ordering __v) noexcept;<br>
+  friend constexpr bool operator!=(_CmpUnspecifiedPara<wbr>m, strong_ordering __v) noexcept;<br>
+  friend constexpr bool operator< (_CmpUnspecifiedParam, strong_ordering __v) noexcept;<br>
+  friend constexpr bool operator<=(_CmpUnspecifiedPara<wbr>m, strong_ordering __v) noexcept;<br>
+  friend constexpr bool operator> (_CmpUnspecifiedParam, strong_ordering __v) noexcept;<br>
+  friend constexpr bool operator>=(_CmpUnspecifiedPara<wbr>m, strong_ordering __v) noexcept;<br>
+<br>
+#ifndef _LIBCPP_HAS_NO_SPACESHIP_OPERA<wbr>TOR<br>
+  friend constexpr strong_ordering operator<=>(strong_ordering __v, _CmpUnspecifiedParam) noexcept;<br>
+  friend constexpr strong_ordering operator<=>(_CmpUnspecifiedPar<wbr>am, strong_ordering __v) noexcept;<br>
+#endif<br>
+<br>
+private:<br>
+  _ValueT __value_;<br>
+};<br>
+<br>
+_LIBCPP_INLINE_VAR constexpr strong_ordering strong_ordering::less(_OrdResu<wbr>lt::__less);<br>
+_LIBCPP_INLINE_VAR constexpr strong_ordering strong_ordering::equal(_EqResu<wbr>lt::__equal);<br>
+_LIBCPP_INLINE_VAR constexpr strong_ordering strong_ordering::equivalent(_E<wbr>qResult::__equiv);<br>
+_LIBCPP_INLINE_VAR constexpr strong_ordering strong_ordering::greater(_OrdR<wbr>esult::__greater);<br>
+<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator==(strong_ordering __v, _CmpUnspecifiedParam) noexcept {<br>
+  return __v.__value_ == 0;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator!=(strong_ordering __v, _CmpUnspecifiedParam) noexcept {<br>
+  return __v.__value_ != 0;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator< (strong_ordering __v, _CmpUnspecifiedParam) noexcept {<br>
+  return __v.__value_ < 0;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator<=(strong_ordering __v, _CmpUnspecifiedParam) noexcept {<br>
+  return __v.__value_ <= 0;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator> (strong_ordering __v, _CmpUnspecifiedParam) noexcept {<br>
+  return __v.__value_ > 0;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator>=(strong_ordering __v, _CmpUnspecifiedParam) noexcept {<br>
+  return __v.__value_ >= 0;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator==(_CmpUnspecifiedPara<wbr>m, strong_ordering __v) noexcept {<br>
+  return 0 == __v.__value_;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator!=(_CmpUnspecifiedPara<wbr>m, strong_ordering __v) noexcept {<br>
+  return 0 != __v.__value_;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator< (_CmpUnspecifiedParam, strong_ordering __v) noexcept {<br>
+  return 0 < __v.__value_;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator<=(_CmpUnspecifiedPara<wbr>m, strong_ordering __v) noexcept {<br>
+  return 0 <= __v.__value_;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator> (_CmpUnspecifiedParam, strong_ordering __v) noexcept {<br>
+  return 0 > __v.__value_;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool operator>=(_CmpUnspecifiedPara<wbr>m, strong_ordering __v) noexcept {<br>
+  return 0 >= __v.__value_;<br>
+}<br>
+<br>
+#ifndef _LIBCPP_HAS_NO_SPACESHIP_OPERA<wbr>TOR<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr strong_ordering operator<=>(strong_ordering __v, _CmpUnspecifiedParam) noexcept {<br>
+  return __v;<br>
+}<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr strong_ordering operator<=>(_CmpUnspecifiedPar<wbr>am, strong_ordering __v) noexcept {<br>
+  return __v < 0 ? strong_ordering::greater : (__v > 0 ? strong_ordering::less : __v);<br>
+}<br>
+#endif // _LIBCPP_HAS_NO_SPACESHIP_OPERA<wbr>TOR<br>
+<br>
+// named comparison functions<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool is_eq(weak_equality __cmp) noexcept    { return __cmp == 0; }<br>
+<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool is_neq(weak_equality __cmp) noexcept    { return __cmp != 0; }<br>
+<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool is_lt(partial_ordering __cmp) noexcept { return __cmp < 0; }<br>
+<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool is_lteq(partial_ordering __cmp) noexcept { return __cmp <= 0; }<br>
+<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool is_gt(partial_ordering __cmp) noexcept { return __cmp > 0; }<br>
+<br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr bool is_gteq(partial_ordering __cmp) noexcept { return __cmp >= 0; }<br>
+<br>
+namespace __comp_detail {<br>
+<br>
+enum _ClassifyCompCategory : unsigned{<br>
+  _None,<br>
+  _WeakEq,<br>
+  _StrongEq,<br>
+  _PartialOrd,<br>
+  _WeakOrd,<br>
+  _StrongOrd,<br>
+  _CCC_Size<br>
+};<br>
+<br>
+template <class _Tp><br>
+_LIBCPP_INLINE_VISIBILITY<br>
+constexpr _ClassifyCompCategory __type_to_enum() noexcept {<br>
+  if (is_same_v<_Tp, weak_equality>)<br>
+    return _WeakEq;<br>
+  if (is_same_v<_Tp, strong_equality>)<br>
+    return _StrongEq;<br>
+  if (is_same_v<_Tp, partial_ordering>)<br>
+    return _PartialOrd;<br>
+  if (is_same_v<_Tp, weak_ordering>)<br>
+    return _WeakOrd;<br>
+  if (is_same_v<_Tp, strong_ordering>)<br>
+    return _StrongOrd;<br>
+  return _None;<br>
+}<br>
+<br>
+template <size_t _Size><br>
+constexpr _ClassifyCompCategory<br>
+__compute_comp_type(std::arra<wbr>y<_ClassifyCompCategory, _Size> __types) {<br>
+  std::array<int, _CCC_Size> __seen = {};<br>
+  for (auto __type : __types)<br>
+    ++__seen[__type];<br>
+  if (__seen[_None])<br>
+    return _None;<br>
+  if (__seen[_WeakEq])<br>
+    return _WeakEq;<br>
+  if (__seen[_StrongEq] && (__seen[_PartialOrd] || __seen[_WeakOrd]))<br>
+    return _WeakEq;<br>
+  if (__seen[_StrongEq])<br>
+    return _StrongEq;<br>
+  if (__seen[_PartialOrd])<br>
+    return _PartialOrd;<br>
+  if (__seen[_WeakOrd])<br>
+    return _WeakOrd;<br>
+  return _StrongOrd;<br>
+}<br></blockquote><div><br></div></div></div><div>Hmm, it'd be nice to ask the compiler to work this out rather than repeating the algorithm here. For example, something like:</div><div><br></div><div>template<size_t, typename T> struct CCT { friend T operator<=>(const CCT&, const CCT&); };</div><div>template<typename N, typename ...T> struct CCC;</div><div><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial">template<size_t ...N, typename ...T> struct CCC : CCT<N, T>... {</div></div><div>  friend auto operator<=>(const CCC&, const CCC&) = default;</div><div>};</div><div>template<typename ...T> struct common_comparison_category {</div><div>  template<typename C> static auto test(int) -> decltype(declval<const C&>() <=> declval<const C&>());<br></div><div><span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">  template<typename C> static void test(...);</span></div><div>  using type = decltype(test<<span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">CCC<std::make_<wbr>index_sequence<sizeof...(T)>, T...></span>>(0));<br></div><div>}</div><div><br></div><div>... should allow you to ask the compiler for the common comparison type.</div></div></div></div></blockquote><div><br></div><div>Looks good to me. Once we actually have a compiler I can do that with I'll make the change.</div><div>For now I think it's preferable to have a working implementation.</div><div><br></div><div>FYI, I have an almost complete implementation of [expr.spaceship].</div><div><br></div><div>I was about to start making ExprConstant work, but I think that requires a new AST node to</div><div>represent three-way comparisons. Since <=> builtins return a DeclRefExpr for the appropriate</div><div>comparison category type member (ex. strong_equality::equal), and we can't build these</div><div>in ExprConstant so it seems appropriate to build them earlier and store them in the</div><div>operator expression node (I suspect this problem also arises during CodeGen).</div><div><br></div><div>Does that seem reasonable?</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span class=""><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+template <class ..._Ts><br>
+constexpr auto __get_comp_type() {<br>
+  using _CCC = _ClassifyCompCategory;<br>
+  constexpr array<_CCC, sizeof...(_Ts)> __type_kinds{__comp_detail::__<wbr>type_to_enum<_Ts>()...};<br>
+  constexpr _CCC _Cat = sizeof...(_Ts) == 0 ? _StrongOrd<br>
+      : __compute_comp_type(__type_kin<wbr>ds);<br>
+  if constexpr (_Cat == _None)<br>
+    return ((void)0);<br></blockquote><div><br></div></span><div>void() is a more idiomatic way to write this. (Incidentally, this case seems like a bug in the library spec to me -- common_comparison_category<...<wbr>>::type should not exist in the case where there is no common comparison type, for consistency with the other traits.)</div></div></div></div></blockquote><div><br></div><div>I forgot about `void()`. Thanks.</div><div><br></div><div>I'll look into the library spec tomorrow, and probably file an issue.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><div class="h5"><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+  else if constexpr (_Cat == _WeakEq)<br>
+    return weak_equality::equivalent;<br>
+  else if constexpr (_Cat == _StrongEq)<br>
+    return strong_equality::equivalent;<br>
+  else if constexpr (_Cat == _PartialOrd)<br>
+    return partial_ordering::equivalent;<br>
+  else if constexpr (_Cat == _WeakOrd)<br>
+    return weak_ordering::equivalent;<br>
+  else if constexpr (_Cat == _StrongOrd)<br>
+    return strong_ordering::equivalent;<br>
+  else<br>
+    static_assert(_Cat != _Cat, "unhandled case");<br>
+}<br>
+} // namespace __comp_detail<br>
+<br>
+// [cmp.common], common comparison category type<br>
+template<class... _Ts><br>
+struct _LIBCPP_TEMPLATE_VIS common_comparison_category {<br>
+  using type = decltype(__comp_detail::__get_<wbr>comp_type<_Ts...>());<br>
+};<br>
+<br>
+template<class... _Ts><br>
+using common_comparison_category_t = typename common_comparison_category<_Ts<wbr>...>::type;<br>
+<br>
+// [cmp.alg], comparison algorithms<br>
+// TODO: unimplemented<br>
+template<class _Tp> constexpr strong_ordering strong_order(const _Tp& __lhs, const _Tp& __rhs);<br>
+template<class _Tp> constexpr weak_ordering weak_order(const _Tp& __lhs, const _Tp& __rhs);<br>
+template<class _Tp> constexpr partial_ordering partial_order(const _Tp& __lhs, const _Tp& __rhs);<br>
+template<class _Tp> constexpr strong_equality strong_equal(const _Tp& __lhs, const _Tp& __rhs);<br>
+template<class _Tp> constexpr weak_equality weak_equal(const _Tp& __lhs, const _Tp& __rhs);<br>
+<br>
+#endif // _LIBCPP_STD_VER > 17<br>
+<br>
+_LIBCPP_END_NAMESPACE_STD<br>
+<br>
+#endif // _LIBCPP_COMPARE<br>
<br>
Modified: libcxx/trunk/include/module.mo<wbr>dulemap<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/module.modulemap?rev=329460&r1=329459&r2=329460&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/libcxx/trunk/include/mod<wbr>ule.modulemap?rev=329460&r1=<wbr>329459&r2=329460&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/include/module.mo<wbr>dulemap (original)<br>
+++ libcxx/trunk/include/module.mo<wbr>dulemap Fri Apr  6 14:37:23 2018<br>
@@ -243,6 +243,10 @@ module std [system] {<br>
     header "codecvt"<br>
     export *<br>
   }<br>
+  module compare {<br>
+    header "compare"<br>
+    export *<br>
+  }<br>
   module complex {<br>
     header "complex"<br>
     export *<br>
<br>
Modified: libcxx/trunk/test/libcxx/doubl<wbr>e_include.sh.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/double_include.sh.cpp?rev=329460&r1=329459&r2=329460&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/libcxx/trunk/test/libcxx<wbr>/double_include.sh.cpp?rev=<wbr>329460&r1=329459&r2=329460&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/libcxx/doubl<wbr>e_include.sh.cpp (original)<br>
+++ libcxx/trunk/test/libcxx/doubl<wbr>e_include.sh.cpp Fri Apr  6 14:37:23 2018<br>
@@ -41,6 +41,7 @@<br>
 #include <clocale><br>
 #include <cmath><br>
 #include <codecvt><br>
+#include <compare><br>
 #include <complex><br>
 #include <complex.h><br>
 #include <condition_variable><br>
<br>
Added: libcxx/trunk/test/libcxx/langu<wbr>age.support/cmp/version.pass.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/language.support/cmp/version.pass.cpp?rev=329460&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/libcxx/trunk/test/libcxx<wbr>/language.support/cmp/version.<wbr>pass.cpp?rev=329460&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/libcxx/langu<wbr>age.support/cmp/version.pass.<wbr>cpp (added)<br>
+++ libcxx/trunk/test/libcxx/langu<wbr>age.support/cmp/version.pass.<wbr>cpp Fri Apr  6 14:37:23 2018<br>
@@ -0,0 +1,20 @@<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is dual licensed under the MIT and the University of Illinois Open<br>
+// Source Licenses. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+// <compare><br>
+<br>
+#include <compare><br>
+<br>
+#ifndef _LIBCPP_VERSION<br>
+#error _LIBCPP_VERSION not defined<br>
+#endif<br>
+<br>
+int main()<br>
+{<br>
+}<br>
<br>
Added: libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.common/<wbr>common_comparison_category.<wbr>pass.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/language.support/cmp/cmp.common/common_comparison_category.pass.cpp?rev=329460&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/libcxx/trunk/test/std/la<wbr>nguage.support/cmp/cmp.common/<wbr>common_comparison_category.<wbr>pass.cpp?rev=329460&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.common/<wbr>common_comparison_category.<wbr>pass.cpp (added)<br>
+++ libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.common/<wbr>common_comparison_category.<wbr>pass.cpp Fri Apr  6 14:37:23 2018<br>
@@ -0,0 +1,93 @@<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is dual licensed under the MIT and the University of Illinois Open<br>
+// Source Licenses. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17<br>
+<br>
+// <compare><br>
+<br>
+// template <class ...Ts> struct common_comparison_category<br>
+// template <class ...Ts> using common_comparison_category_t<br>
+<br>
+<br>
+#include <compare><br>
+#include <type_traits><br>
+#include <cassert><br>
+<br>
+#include "test_macros.h"<br>
+<br>
+const volatile void* volatile sink;<br>
+<br>
+template <class Expect, class ...Args><br>
+void test_cat() {<br>
+  using Cat = std::common_comparison_categor<wbr>y<Args...>;<br>
+  using CatT = typename Cat::type;<br>
+  static_assert(std::is_same<Cat<wbr>T, std::common_comparison_categor<wbr>y_t<Args...>>::value, "");<br>
+  static_assert(std::is_same<Cat<wbr>T, Expect>::value, "expected different category");<br>
+};<br>
+<br>
+<br>
+// [class.spaceship]p4: The 'common comparison type' U of a possibly-empty list<br>
+//   of 'n' types T0, T1, ..., TN, is defined as follows:<br>
+int main() {<br>
+  using WE = std::weak_equality;<br>
+  using SE = std::strong_equality;<br>
+  using PO = std::partial_ordering;<br>
+  using WO = std::weak_ordering;<br>
+  using SO = std::strong_ordering;<br>
+<br>
+  // [class.spaceship]p4.1: If any Ti is not a comparison category tpe, U is void.<br>
+  {<br>
+    test_cat<void, void>();<br>
+    test_cat<void, int*>();<br>
+    test_cat<void, SO&>();<br>
+    test_cat<void, SO const>();<br>
+    test_cat<void, SO*>();<br>
+    test_cat<void, SO, void, SO>();<br>
+  }<br>
+<br>
+  // [class.spaceship]p4.2: Otherwise, if at least on Ti is<br>
+  // std::weak_equality, or at least one Ti is std::strong_equality and at least<br>
+  // one Tj is std::partial_ordering or std::weak_ordering, U is std::weak_equality<br>
+  {<br>
+    test_cat<WE, WE>();<br>
+    test_cat<WE, SO, WE, SO>();<br>
+    test_cat<WE, SE, SO, PO>();<br>
+    test_cat<WE, WO, SO, SE>();<br>
+  }<br>
+<br>
+  // [class.spaceship]p4.3: Otherwise, if at least one Ti is std::strong_equality,<br>
+  // U is std::strong_equality<br>
+  {<br>
+    test_cat<SE, SE>();<br>
+    test_cat<SE, SO, SE, SO>();<br>
+  }<br>
+<br>
+  // [class.spaceship]p4.4: Otherwise, if at least one Ti is std::partial_ordering,<br>
+  // U is std::partial_ordering<br>
+  {<br>
+    test_cat<PO, PO>();<br>
+    test_cat<PO, SO, PO, SO>();<br>
+    test_cat<PO, WO, PO, SO>();<br>
+  }<br>
+<br>
+  // [class.spaceship]p4.5: Otherwise, if at least one Ti is std::weak_ordering,<br>
+  // U is std::weak_ordering<br>
+  {<br>
+    test_cat<WO, WO>();<br>
+    test_cat<WO, SO, WO, SO>();<br>
+  }<br>
+<br>
+  // [class.spaceship]p4.6: Otherwise, U is std::strong_ordering. [Note: in<br>
+  // particular this is the result when n is 0. -- end note]<br>
+  {<br>
+    test_cat<SO>(); // empty type list<br>
+    test_cat<SO, SO>();<br>
+    test_cat<SO, SO, SO>();<br>
+  }<br>
+}<br>
<br>
Added: libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.partialord/<wbr>partialord.pass.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/language.support/cmp/cmp.partialord/partialord.pass.cpp?rev=329460&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/libcxx/trunk/test/std/la<wbr>nguage.support/cmp/cmp.partial<wbr>ord/partialord.pass.cpp?rev=<wbr>329460&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.partialord/<wbr>partialord.pass.cpp (added)<br>
+++ libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.partialord/<wbr>partialord.pass.cpp Fri Apr  6 14:37:23 2018<br>
@@ -0,0 +1,164 @@<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is dual licensed under the MIT and the University of Illinois Open<br>
+// Source Licenses. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17<br>
+<br>
+// <compare><br>
+<br>
+// class partial_ordering<br>
+<br>
+<br>
+#include <compare><br>
+#include <type_traits><br>
+#include <cassert><br>
+<br>
+#include "test_macros.h"<br>
+<br>
+const volatile void* volatile sink;<br>
+<br>
+void test_static_members() {<br>
+  DoNotOptimize(&std::partial_or<wbr>dering::less);<br>
+  DoNotOptimize(&std::partial_or<wbr>dering::equivalent);<br>
+  DoNotOptimize(&std::partial_or<wbr>dering::greater);<br>
+  DoNotOptimize(&std::partial_or<wbr>dering::unordered);<br>
+}<br>
+<br>
+void test_signatures() {<br>
+  auto& Eq = std::partial_ordering::equival<wbr>ent;<br>
+<br>
+  ASSERT_NOEXCEPT(Eq == 0);<br>
+  ASSERT_NOEXCEPT(0 == Eq);<br>
+  ASSERT_NOEXCEPT(Eq != 0);<br>
+  ASSERT_NOEXCEPT(0 != Eq);<br>
+  ASSERT_NOEXCEPT(0 < Eq);<br>
+  ASSERT_NOEXCEPT(Eq < 0);<br>
+  ASSERT_NOEXCEPT(0 <= Eq);<br>
+  ASSERT_NOEXCEPT(Eq <= 0);<br>
+  ASSERT_NOEXCEPT(0 > Eq);<br>
+  ASSERT_NOEXCEPT(Eq > 0);<br>
+  ASSERT_NOEXCEPT(0 >= Eq);<br>
+  ASSERT_NOEXCEPT(Eq >= 0);<br>
+#ifndef TEST_HAS_NO_SPACESHIP_OPERATOR<br>
+  ASSERT_NOEXCEPT(0 <=> Eq);<br>
+  ASSERT_NOEXCEPT(Eq <=> 0);<br>
+  ASSERT_SAME_TYPE(decltype(Eq <=> 0), std::partial_ordering);<br>
+  ASSERT_SAME_TYPE(decltype(0 <=> Eq), std::partial_ordering);<br>
+#endif<br>
+}<br>
+<br>
+constexpr bool test_conversion() {<br>
+  static_assert(std::is_converti<wbr>ble<const std::partial_ordering, std::weak_equality>::value, "");<br>
+  { // value == 0<br>
+    auto V = std::partial_ordering::equival<wbr>ent;<br>
+    std::weak_equality WV = V;<br>
+    assert(WV == 0);<br>
+  }<br>
+  std::partial_ordering TestCases[] = {<br>
+      std::partial_ordering::less,<br>
+      std::partial_ordering::greater<wbr>,<br>
+      std::partial_ordering::unorder<wbr>ed<br>
+  };<br>
+  for (auto V : TestCases)<br>
+  { // value != 0<br>
+    std::weak_equality WV = V;<br>
+    assert(WV != 0);<br>
+  }<br>
+  return true;<br>
+}<br>
+<br>
+constexpr bool test_constexpr() {<br>
+  auto& Eq = std::partial_ordering::equival<wbr>ent;<br>
+  auto& Less = std::partial_ordering::less;<br>
+  auto& Greater = std::partial_ordering::greater<wbr>;<br>
+  auto& Unord = std::partial_ordering::unorder<wbr>ed;<br>
+  struct {<br>
+    std::partial_ordering Value;<br>
+    bool ExpectEq;<br>
+    bool ExpectNeq;<br>
+    bool ExpectLess;<br>
+    bool ExpectGreater;<br>
+  } TestCases[] = {<br>
+      {Eq, true, false, false, false},<br>
+      {Less, false, true, true, false},<br>
+      {Greater, false, true, false, true},<br>
+      {Unord, false, true, false, false}<br>
+  };<br>
+  for (auto TC : TestCases) {<br>
+    auto V = TC.Value;<br>
+    assert((V == 0) == TC.ExpectEq);<br>
+    assert((0 == V) == TC.ExpectEq);<br>
+    assert((V != 0) == TC.ExpectNeq);<br>
+    assert((0 != V) == TC.ExpectNeq);<br>
+<br>
+    assert((V < 0) == TC.ExpectLess);<br>
+    assert((V > 0) == TC.ExpectGreater);<br>
+    assert((V <= 0) == (TC.ExpectLess || TC.ExpectEq));<br>
+    assert((V >= 0) == (TC.ExpectGreater || TC.ExpectEq));<br>
+<br>
+    assert((0 < V) == TC.ExpectGreater);<br>
+    assert((0 > V) == TC.ExpectLess);<br>
+    assert((0 <= V) == (TC.ExpectGreater || TC.ExpectEq));<br>
+    assert((0 >= V) == (TC.ExpectLess || TC.ExpectEq));<br>
+  }<br>
+#ifndef TEST_HAS_NO_SPACESHIP_OPERATOR<br>
+  {<br>
+    std::partial_ordering res = (Eq <=> 0);<br>
+    ((void)res);<br>
+    res = (0 <=> Eq);<br>
+    ((void)res);<br>
+  }<br>
+  enum ExpectRes {<br>
+    ER_Greater,<br>
+    ER_Less,<br>
+    ER_Equiv,<br>
+    ER_Unord<br>
+  };<br>
+  struct {<br>
+    std::partial_ordering Value;<br>
+    ExpectRes Expect;<br>
+  } SpaceshipTestCases[] = {<br>
+      {std::partial_ordering::equiva<wbr>lent, ER_Equiv},<br>
+      {std::partial_ordering::less, ER_Less},<br>
+      {std::partial_ordering::greate<wbr>r, ER_Greater},<br>
+      {std::partial_ordering::unorde<wbr>red, ER_Unord}<br>
+  };<br>
+  for (auto TC : SpaceshipTestCases)<br>
+  {<br>
+    std::partial_ordering Res = (0 <=> TC.Value);<br>
+    switch (TC.Expect) {<br>
+    case ER_Equiv:<br>
+      assert(Res == 0);<br>
+      assert(0 == Res);<br>
+      break;<br>
+    case ER_Less:<br>
+      assert(Res < 0);<br>
+      break;<br>
+    case ER_Greater:<br>
+      assert(Res > 0);<br>
+      break;<br>
+    case ER_Unord:<br>
+      assert(Res != 0);<br>
+      assert(0 != Res);<br>
+      assert((Res < 0) == false);<br>
+      assert((Res > 0) == false);<br>
+      assert((Res == 0) == false);<br>
+      break;<br>
+    }<br>
+  }<br>
+#endif<br>
+<br>
+  return true;<br>
+}<br>
+<br>
+int main() {<br>
+  test_static_members();<br>
+  test_signatures();<br>
+  static_assert(test_conversion(<wbr>), "conversion test failed");<br>
+  static_assert(test_constexpr()<wbr>, "constexpr test failed");<br>
+}<br>
<br>
Added: libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.strongeq/cmp.<wbr>strongeq.pass.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/language.support/cmp/cmp.strongeq/cmp.strongeq.pass.cpp?rev=329460&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/libcxx/trunk/test/std/la<wbr>nguage.support/cmp/cmp.stronge<wbr>q/cmp.strongeq.pass.cpp?rev=<wbr>329460&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.strongeq/cmp.<wbr>strongeq.pass.cpp (added)<br>
+++ libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.strongeq/cmp.<wbr>strongeq.pass.cpp Fri Apr  6 14:37:23 2018<br>
@@ -0,0 +1,96 @@<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is dual licensed under the MIT and the University of Illinois Open<br>
+// Source Licenses. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17<br>
+<br>
+// <compare><br>
+<br>
+// class strong_equality<br>
+<br>
+<br>
+#include <compare><br>
+#include <type_traits><br>
+#include <cassert><br>
+<br>
+#include "test_macros.h"<br>
+<br>
+const volatile void* volatile sink;<br>
+<br>
+void test_static_members() {<br>
+  DoNotOptimize(&std::strong_equ<wbr>ality::equal);<br>
+  DoNotOptimize(&std::strong_equ<wbr>ality::nonequal);<br>
+  DoNotOptimize(&std::strong_equ<wbr>ality::equivalent);<br>
+  DoNotOptimize(&std::strong_equ<wbr>ality::nonequivalent);<br>
+}<br>
+<br>
+void test_signatures() {<br>
+  auto& Eq = std::strong_equality::equivale<wbr>nt;<br>
+<br>
+  ASSERT_NOEXCEPT(Eq == 0);<br>
+  ASSERT_NOEXCEPT(0 == Eq);<br>
+  ASSERT_NOEXCEPT(Eq != 0);<br>
+  ASSERT_NOEXCEPT(0 != Eq);<br>
+#ifndef TEST_HAS_NO_SPACESHIP_OPERATOR<br>
+  ASSERT_NOEXCEPT(0 <=> Eq);<br>
+  ASSERT_NOEXCEPT(Eq <=> 0);<br>
+  ASSERT_SAME_TYPE(decltype(Eq <=> 0), std::strong_equality);<br>
+  ASSERT_SAME_TYPE(decltype(0 <=> Eq), std::strong_equality);<br>
+#endif<br>
+}<br>
+<br>
+void test_conversion() {<br>
+  constexpr std::weak_equality res = std::strong_equality::equivale<wbr>nt;<br>
+  static_assert(res == 0, "");<br>
+  static_assert(std::is_converti<wbr>ble<const std::strong_equality&,<br>
+      std::weak_equality>::value, "");<br>
+  static_assert(res == 0, "expected equal");<br>
+<br>
+  constexpr std::weak_equality neq_res = std::strong_equality::nonequiv<wbr>alent;<br>
+  static_assert(neq_res != 0, "expected not equal");<br>
+}<br>
+<br>
+constexpr bool test_constexpr() {<br>
+  auto& Eq = std::strong_equality::equal;<br>
+  auto& NEq = std::strong_equality::nonequal<wbr>;<br>
+  auto& Equiv = std::strong_equality::equivale<wbr>nt;<br>
+  auto& NEquiv = std::strong_equality::nonequiv<wbr>alent;<br>
+  assert((Eq == 0) == true);<br>
+  assert((0 == Eq) == true);<br>
+  assert((Equiv == 0) == true);<br>
+  assert((0 == Equiv) == true);<br>
+  assert((NEq == 0) == false);<br>
+  assert((0 == NEq) == false);<br>
+  assert((NEquiv == 0) == false);<br>
+  assert((0 == NEquiv) == false);<br>
+<br>
+  assert((Eq != 0) == false);<br>
+  assert((0 != Eq) == false);<br>
+  assert((Equiv != 0) == false);<br>
+  assert((0 != Equiv) == false);<br>
+  assert((NEq != 0) == true);<br>
+  assert((0 != NEq) == true);<br>
+  assert((NEquiv != 0) == true);<br>
+  assert((0 != NEquiv) == true);<br>
+<br>
+#ifndef TEST_HAS_NO_SPACESHIP_OPERATOR<br>
+  std::strong_equality res = (Eq <=> 0);<br>
+  ((void)res);<br>
+  res = (0 <=> Eq);<br>
+  ((void)res);<br>
+#endif<br>
+<br>
+  return true;<br>
+}<br>
+<br>
+int main() {<br>
+  test_static_members();<br>
+  test_signatures();<br>
+  test_conversion();<br>
+  static_assert(test_constexpr()<wbr>, "constexpr test failed");<br>
+}<br>
<br>
Added: libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.strongord/<wbr>strongord.pass.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/language.support/cmp/cmp.strongord/strongord.pass.cpp?rev=329460&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/libcxx/trunk/test/std/la<wbr>nguage.support/cmp/cmp.strongo<wbr>rd/strongord.pass.cpp?rev=<wbr>329460&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.strongord/<wbr>strongord.pass.cpp (added)<br>
+++ libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.strongord/<wbr>strongord.pass.cpp Fri Apr  6 14:37:23 2018<br>
@@ -0,0 +1,212 @@<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is dual licensed under the MIT and the University of Illinois Open<br>
+// Source Licenses. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17<br>
+<br>
+// <compare><br>
+<br>
+// class strong_ordering<br>
+<br>
+<br>
+#include <compare><br>
+#include <type_traits><br>
+#include <cassert><br>
+<br>
+#include "test_macros.h"<br>
+<br>
+const volatile void* volatile sink;<br>
+<br>
+void test_static_members() {<br>
+  DoNotOptimize(&std::strong_ord<wbr>ering::less);<br>
+  DoNotOptimize(&std::strong_ord<wbr>ering::equal);<br>
+  DoNotOptimize(&std::strong_ord<wbr>ering::equivalent);<br>
+  DoNotOptimize(&std::strong_ord<wbr>ering::greater);<br>
+}<br>
+<br>
+void test_signatures() {<br>
+  auto& Eq = std::strong_ordering::equivale<wbr>nt;<br>
+<br>
+  ASSERT_NOEXCEPT(Eq == 0);<br>
+  ASSERT_NOEXCEPT(0 == Eq);<br>
+  ASSERT_NOEXCEPT(Eq != 0);<br>
+  ASSERT_NOEXCEPT(0 != Eq);<br>
+  ASSERT_NOEXCEPT(0 < Eq);<br>
+  ASSERT_NOEXCEPT(Eq < 0);<br>
+  ASSERT_NOEXCEPT(0 <= Eq);<br>
+  ASSERT_NOEXCEPT(Eq <= 0);<br>
+  ASSERT_NOEXCEPT(0 > Eq);<br>
+  ASSERT_NOEXCEPT(Eq > 0);<br>
+  ASSERT_NOEXCEPT(0 >= Eq);<br>
+  ASSERT_NOEXCEPT(Eq >= 0);<br>
+#ifndef TEST_HAS_NO_SPACESHIP_OPERATOR<br>
+  ASSERT_NOEXCEPT(0 <=> Eq);<br>
+  ASSERT_NOEXCEPT(Eq <=> 0);<br>
+  ASSERT_SAME_TYPE(decltype(Eq <=> 0), std::strong_ordering);<br>
+  ASSERT_SAME_TYPE(decltype(0 <=> Eq), std::strong_ordering);<br>
+#endif<br>
+}<br>
+<br>
+constexpr bool test_conversion() {<br>
+  static_assert(std::is_converti<wbr>ble<const std::strong_ordering&,<br>
+      std::weak_equality>::value, "");<br>
+  { // value == 0<br>
+    auto V = std::strong_ordering::equivale<wbr>nt;<br>
+    std::weak_equality WV = V;<br>
+    assert(WV == 0);<br>
+  }<br>
+  std::strong_ordering WeakTestCases[] = {<br>
+      std::strong_ordering::less,<br>
+      std::strong_ordering::greater,<br>
+  };<br>
+  for (auto V : WeakTestCases)<br>
+  { // value != 0<br>
+    std::weak_equality WV = V;<br>
+    assert(WV != 0);<br>
+  }<br>
+  static_assert(std::is_converti<wbr>ble<const std::strong_ordering&,<br>
+      std::strong_equality>::value, "");<br>
+  { // value == 0<br>
+    auto V = std::strong_ordering::equivale<wbr>nt;<br>
+    std::strong_equality WV = V;<br>
+    assert(WV == 0);<br>
+  }<br>
+  { // value == 0<br>
+    auto V = std::strong_ordering::equal;<br>
+    std::strong_equality WV = V;<br>
+    assert(WV == 0);<br>
+  }<br>
+  std::strong_ordering StrongTestCases[] = {<br>
+      std::strong_ordering::less,<br>
+      std::strong_ordering::greater,<br>
+  };<br>
+  for (auto V : StrongTestCases)<br>
+  { // value != 0<br>
+    std::strong_equality WV = V;<br>
+    assert(WV != 0);<br>
+  }<br>
+<br>
+  static_assert(std::is_converti<wbr>ble<const std::strong_ordering&,<br>
+      std::partial_ordering>::value, "");<br>
+  { // value == 0<br>
+    auto V = std::strong_ordering::equivale<wbr>nt;<br>
+    std::partial_ordering WV = V;<br>
+    assert(WV == 0);<br>
+  }<br>
+  { // value < 0<br>
+    auto V = std::strong_ordering::less;<br>
+    std::partial_ordering WV = V;<br>
+    assert(WV < 0);<br>
+  }<br>
+  { // value > 0<br>
+    auto V = std::strong_ordering::greater;<br>
+    std::partial_ordering WV = V;<br>
+    assert(WV > 0);<br>
+  }<br>
+<br>
+  static_assert(std::is_converti<wbr>ble<const std::strong_ordering&,<br>
+      std::weak_ordering>::value, "");<br>
+  { // value == 0<br>
+    auto V = std::strong_ordering::equivale<wbr>nt;<br>
+    std::weak_ordering WV = V;<br>
+    assert(WV == 0);<br>
+  }<br>
+  { // value < 0<br>
+    auto V = std::strong_ordering::less;<br>
+    std::weak_ordering WV = V;<br>
+    assert(WV < 0);<br>
+  }<br>
+  { // value > 0<br>
+    auto V = std::strong_ordering::greater;<br>
+    std::weak_ordering WV = V;<br>
+    assert(WV > 0);<br>
+  }<br>
+  return true;<br>
+}<br>
+<br>
+constexpr bool test_constexpr() {<br>
+  auto& Eq = std::strong_ordering::equal;<br>
+  auto& Equiv = std::strong_ordering::equivale<wbr>nt;<br>
+  auto& Less = std::strong_ordering::less;<br>
+  auto& Greater = std::strong_ordering::greater;<br>
+  struct {<br>
+    std::strong_ordering Value;<br>
+    bool ExpectEq;<br>
+    bool ExpectNeq;<br>
+    bool ExpectLess;<br>
+    bool ExpectGreater;<br>
+  } TestCases[] = {<br>
+      {Eq, true, false, false, false},<br>
+      {Equiv, true, false, false, false},<br>
+      {Less, false, true, true, false},<br>
+      {Greater, false, true, false, true},<br>
+  };<br>
+  for (auto TC : TestCases) {<br>
+    auto V = TC.Value;<br>
+    assert((V == 0) == TC.ExpectEq);<br>
+    assert((0 == V) == TC.ExpectEq);<br>
+    assert((V != 0) == TC.ExpectNeq);<br>
+    assert((0 != V) == TC.ExpectNeq);<br>
+<br>
+    assert((V < 0) == TC.ExpectLess);<br>
+    assert((V > 0) == TC.ExpectGreater);<br>
+    assert((V <= 0) == (TC.ExpectLess || TC.ExpectEq));<br>
+    assert((V >= 0) == (TC.ExpectGreater || TC.ExpectEq));<br>
+<br>
+    assert((0 < V) == TC.ExpectGreater);<br>
+    assert((0 > V) == TC.ExpectLess);<br>
+    assert((0 <= V) == (TC.ExpectGreater || TC.ExpectEq));<br>
+    assert((0 >= V) == (TC.ExpectLess || TC.ExpectEq));<br>
+  }<br>
+#ifndef TEST_HAS_NO_SPACESHIP_OPERATOR<br>
+  {<br>
+    std::strong_ordering res = (Eq <=> 0);<br>
+    ((void)res);<br>
+    res = (0 <=> Eq);<br>
+    ((void)res);<br>
+  }<br>
+  enum ExpectRes {<br>
+    ER_Greater,<br>
+    ER_Less,<br>
+    ER_Equiv<br>
+  };<br>
+  struct {<br>
+    std::strong_ordering Value;<br>
+    ExpectRes Expect;<br>
+  } SpaceshipTestCases[] = {<br>
+      {std::strong_ordering::equival<wbr>ent, ER_Equiv},<br>
+      {std::strong_ordering::less, ER_Less},<br>
+      {std::strong_ordering::greater<wbr>, ER_Greater},<br>
+  };<br>
+  for (auto TC : SpaceshipTestCases)<br>
+  {<br>
+    std::strong_ordering Res = (0 <=> TC.Value);<br>
+    switch (TC.Expect) {<br>
+    case ER_Equiv:<br>
+      assert(Res == 0);<br>
+      assert(0 == Res);<br>
+      break;<br>
+    case ER_Less:<br>
+      assert(Res < 0);<br>
+      break;<br>
+    case ER_Greater:<br>
+      assert(Res > 0);<br>
+      break;<br>
+    }<br>
+  }<br>
+#endif<br>
+<br>
+  return true;<br>
+}<br>
+<br>
+int main() {<br>
+  test_static_members();<br>
+  test_signatures();<br>
+  static_assert(test_conversion(<wbr>), "conversion test failed");<br>
+  static_assert(test_constexpr()<wbr>, "constexpr test failed");<br>
+}<br>
<br>
Added: libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.weakeq/cmp.<wbr>weakeq.pass.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/language.support/cmp/cmp.weakeq/cmp.weakeq.pass.cpp?rev=329460&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/libcxx/trunk/test/std/la<wbr>nguage.support/cmp/cmp.weakeq/<wbr>cmp.weakeq.pass.cpp?rev=<wbr>329460&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.weakeq/cmp.<wbr>weakeq.pass.cpp (added)<br>
+++ libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.weakeq/cmp.<wbr>weakeq.pass.cpp Fri Apr  6 14:37:23 2018<br>
@@ -0,0 +1,70 @@<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is dual licensed under the MIT and the University of Illinois Open<br>
+// Source Licenses. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17<br>
+<br>
+// <compare><br>
+<br>
+// class weak_equality<br>
+<br>
+<br>
+#include <compare><br>
+#include <cassert><br>
+#include "test_macros.h"<br>
+<br>
+const volatile void* volatile sink;<br>
+<br>
+void test_static_members() {<br>
+  DoNotOptimize(&std::weak_equal<wbr>ity::equivalent);<br>
+  DoNotOptimize(&std::weak_equal<wbr>ity::nonequivalent);<br>
+}<br>
+<br>
+void test_signatures() {<br>
+  auto& Eq = std::weak_equality::equivalent<wbr>;<br>
+<br>
+  ASSERT_NOEXCEPT(Eq == 0);<br>
+  ASSERT_NOEXCEPT(0 == Eq);<br>
+  ASSERT_NOEXCEPT(Eq != 0);<br>
+  ASSERT_NOEXCEPT(0 != Eq);<br>
+#ifndef TEST_HAS_NO_SPACESHIP_OPERATOR<br>
+  ASSERT_NOEXCEPT(0 <=> Eq);<br>
+  ASSERT_NOEXCEPT(Eq <=> 0);<br>
+  ASSERT_SAME_TYPE(decltype(Eq <=> 0), std::weak_equality);<br>
+  ASSERT_SAME_TYPE(decltype(0 <=> Eq), std::weak_equality);<br>
+#endif<br>
+}<br>
+<br>
+constexpr bool test_constexpr() {<br>
+  auto& Eq = std::weak_equality::equivalent<wbr>;<br>
+  auto& NEq = std::weak_equality::nonequival<wbr>ent;<br>
+  assert((Eq == 0) == true);<br>
+  assert((0 == Eq) == true);<br>
+  assert((NEq == 0) == false);<br>
+  assert((0 == NEq) == false);<br>
+<br>
+  assert((Eq != 0) == false);<br>
+  assert((0 != Eq) == false);<br>
+  assert((NEq != 0) == true);<br>
+  assert((0 != NEq) == true);<br>
+<br>
+#ifndef TEST_HAS_NO_SPACESHIP_OPERATOR<br>
+  std::weak_equality res = (Eq <=> 0);<br>
+  ((void)res);<br>
+  res = (0 <=> Eq);<br>
+  ((void)res);<br>
+#endif<br>
+<br>
+  return true;<br>
+}<br>
+<br>
+int main() {<br>
+  test_static_members();<br>
+  test_signatures();<br>
+  static_assert(test_constexpr()<wbr>, "constexpr test failed");<br>
+}<br>
<br>
Added: libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.weakord/<wbr>weakord.pass.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/language.support/cmp/cmp.weakord/weakord.pass.cpp?rev=329460&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/libcxx/trunk/test/std/la<wbr>nguage.support/cmp/cmp.weakord<wbr>/weakord.pass.cpp?rev=329460&<wbr>view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.weakord/<wbr>weakord.pass.cpp (added)<br>
+++ libcxx/trunk/test/std/language<wbr>.support/cmp/cmp.weakord/<wbr>weakord.pass.cpp Fri Apr  6 14:37:23 2018<br>
@@ -0,0 +1,169 @@<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is dual licensed under the MIT and the University of Illinois Open<br>
+// Source Licenses. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17<br>
+<br>
+// <compare><br>
+<br>
+// class weak_ordering<br>
+<br>
+<br>
+#include <compare><br>
+#include <type_traits><br>
+#include <cassert><br>
+<br>
+#include "test_macros.h"<br>
+<br>
+const volatile void* volatile sink;<br>
+<br>
+void test_static_members() {<br>
+  DoNotOptimize(&std::weak_order<wbr>ing::less);<br>
+  DoNotOptimize(&std::weak_order<wbr>ing::equivalent);<br>
+  DoNotOptimize(&std::weak_order<wbr>ing::greater);<br>
+}<br>
+<br>
+void test_signatures() {<br>
+  auto& Eq = std::weak_ordering::equivalent<wbr>;<br>
+<br>
+  ASSERT_NOEXCEPT(Eq == 0);<br>
+  ASSERT_NOEXCEPT(0 == Eq);<br>
+  ASSERT_NOEXCEPT(Eq != 0);<br>
+  ASSERT_NOEXCEPT(0 != Eq);<br>
+  ASSERT_NOEXCEPT(0 < Eq);<br>
+  ASSERT_NOEXCEPT(Eq < 0);<br>
+  ASSERT_NOEXCEPT(0 <= Eq);<br>
+  ASSERT_NOEXCEPT(Eq <= 0);<br>
+  ASSERT_NOEXCEPT(0 > Eq);<br>
+  ASSERT_NOEXCEPT(Eq > 0);<br>
+  ASSERT_NOEXCEPT(0 >= Eq);<br>
+  ASSERT_NOEXCEPT(Eq >= 0);<br>
+#ifndef TEST_HAS_NO_SPACESHIP_OPERATOR<br>
+  ASSERT_NOEXCEPT(0 <=> Eq);<br>
+  ASSERT_NOEXCEPT(Eq <=> 0);<br>
+  ASSERT_SAME_TYPE(decltype(Eq <=> 0), std::weak_ordering);<br>
+  ASSERT_SAME_TYPE(decltype(0 <=> Eq), std::weak_ordering);<br>
+#endif<br>
+}<br>
+<br>
+constexpr bool test_conversion() {<br>
+  static_assert(std::is_converti<wbr>ble<const std::weak_ordering&,<br>
+      std::weak_equality>::value, "");<br>
+  { // value == 0<br>
+    auto V = std::weak_ordering::equivalent<wbr>;<br>
+    std::weak_equality WV = V;<br>
+    assert(WV == 0);<br>
+  }<br>
+  std::weak_ordering WeakTestCases[] = {<br>
+      std::weak_ordering::less,<br>
+      std::weak_ordering::greater,<br>
+  };<br>
+  for (auto V : WeakTestCases)<br>
+  { // value != 0<br>
+    std::weak_equality WV = V;<br>
+    assert(WV != 0);<br>
+  }<br>
+  static_assert(std::is_converti<wbr>ble<const std::weak_ordering&,<br>
+      std::partial_ordering>::value, "");<br>
+  { // value == 0<br>
+    auto V = std::weak_ordering::equivalent<wbr>;<br>
+    std::partial_ordering WV = V;<br>
+    assert(WV == 0);<br>
+  }<br>
+  { // value < 0<br>
+    auto V = std::weak_ordering::less;<br>
+    std::partial_ordering WV = V;<br>
+    assert(WV < 0);<br>
+  }<br>
+  { // value > 0<br>
+    auto V = std::weak_ordering::greater;<br>
+    std::partial_ordering WV = V;<br>
+    assert(WV > 0);<br>
+  }<br>
+  return true;<br>
+}<br>
+<br>
+constexpr bool test_constexpr() {<br>
+  auto& Eq = std::weak_ordering::equivalent<wbr>;<br>
+  auto& Less = std::weak_ordering::less;<br>
+  auto& Greater = std::weak_ordering::greater;<br>
+  struct {<br>
+    std::weak_ordering Value;<br>
+    bool ExpectEq;<br>
+    bool ExpectNeq;<br>
+    bool ExpectLess;<br>
+    bool ExpectGreater;<br>
+  } TestCases[] = {<br>
+      {Eq, true, false, false, false},<br>
+      {Less, false, true, true, false},<br>
+      {Greater, false, true, false, true},<br>
+  };<br>
+  for (auto TC : TestCases) {<br>
+    auto V = TC.Value;<br>
+    assert((V == 0) == TC.ExpectEq);<br>
+    assert((0 == V) == TC.ExpectEq);<br>
+    assert((V != 0) == TC.ExpectNeq);<br>
+    assert((0 != V) == TC.ExpectNeq);<br>
+<br>
+    assert((V < 0) == TC.ExpectLess);<br>
+    assert((V > 0) == TC.ExpectGreater);<br>
+    assert((V <= 0) == (TC.ExpectLess || TC.ExpectEq));<br>
+    assert((V >= 0) == (TC.ExpectGreater || TC.ExpectEq));<br>
+<br>
+    assert((0 < V) == TC.ExpectGreater);<br>
+    assert((0 > V) == TC.ExpectLess);<br>
+    assert((0 <= V) == (TC.ExpectGreater || TC.ExpectEq));<br>
+    assert((0 >= V) == (TC.ExpectLess || TC.ExpectEq));<br>
+  }<br>
+#ifndef TEST_HAS_NO_SPACESHIP_OPERATOR<br>
+  {<br>
+    std::weak_ordering res = (Eq <=> 0);<br>
+    ((void)res);<br>
+    res = (0 <=> Eq);<br>
+    ((void)res);<br>
+  }<br>
+  enum ExpectRes {<br>
+    ER_Greater,<br>
+    ER_Less,<br>
+    ER_Equiv<br>
+  };<br>
+  struct {<br>
+    std::weak_ordering Value;<br>
+    ExpectRes Expect;<br>
+  } SpaceshipTestCases[] = {<br>
+      {std::weak_ordering::equivalen<wbr>t, ER_Equiv},<br>
+      {std::weak_ordering::less, ER_Less},<br>
+      {std::weak_ordering::greater, ER_Greater},<br>
+  };<br>
+  for (auto TC : SpaceshipTestCases)<br>
+  {<br>
+    std::weak_ordering Res = (0 <=> TC.Value);<br>
+    switch (TC.Expect) {<br>
+    case ER_Equiv:<br>
+      assert(Res == 0);<br>
+      assert(0 == Res);<br>
+      break;<br>
+    case ER_Less:<br>
+      assert(Res < 0);<br>
+      break;<br>
+    case ER_Greater:<br>
+      assert(Res > 0);<br>
+      break;<br>
+    }<br>
+  }<br>
+#endif<br>
+<br>
+  return true;<br>
+}<br>
+<br>
+int main() {<br>
+  test_static_members();<br>
+  test_signatures();<br>
+  static_assert(test_conversion(<wbr>), "conversion test failed");<br>
+  static_assert(test_constexpr()<wbr>, "constexpr test failed");<br>
+}<br>
<br>
Modified: libcxx/trunk/test/support/test<wbr>_macros.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/support/test_macros.h?rev=329460&r1=329459&r2=329460&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/libcxx/trunk/test/suppor<wbr>t/test_macros.h?rev=329460&r1=<wbr>329459&r2=329460&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxx/trunk/test/support/test<wbr>_macros.h (original)<br>
+++ libcxx/trunk/test/support/test<wbr>_macros.h Fri Apr  6 14:37:23 2018<br>
@@ -169,6 +169,11 @@<br>
 #define TEST_SAFE_STATIC<br>
 #endif<br>
<br>
+// FIXME: Fix this feature check when either (A) a compiler provides a complete<br>
+// implementation, or (b) a feature check macro is specified<br>
+#define TEST_HAS_NO_SPACESHIP_OPERATOR<br>
+<br>
+<br>
 #if TEST_STD_VER < 11<br>
 #define ASSERT_NOEXCEPT(...)<br>
 #define ASSERT_NOT_NOEXCEPT(...)<br>
<br>
<br>
______________________________<wbr>_________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/cfe-commits</a><br>
</blockquote></div></div></div><br></div></div>
</blockquote></div><br></div></div>