[libcxx] r329460 - Implement P0768r1: Library support for the Spaceship Operator.

Eric Fiselier via cfe-commits cfe-commits at lists.llvm.org
Fri Apr 6 21:03:55 PDT 2018


On Fri, Apr 6, 2018 at 4:00 PM, Richard Smith <richard at metafoo.co.uk> wrote:

> On 6 April 2018 at 14:37, Eric Fiselier via cfe-commits <
> cfe-commits at lists.llvm.org> wrote:
>
>> Author: ericwf
>> Date: Fri Apr  6 14:37:23 2018
>> New Revision: 329460
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=329460&view=rev
>> Log:
>> Implement P0768r1: Library support for the Spaceship Operator.
>>
>> this patch adds the <compare> header and implements all of it
>> except for [comp.alg].
>>
>> As I understand it, the header is needed by the compiler in
>> when implementing the semantics of operator<=>. For that reason
>> I feel it's important to land this header early, despite
>> all compilers lacking support.
>>
>> Added:
>>     libcxx/trunk/include/compare
>>     libcxx/trunk/test/libcxx/language.support/cmp/
>>     libcxx/trunk/test/libcxx/language.support/cmp/version.pass.cpp
>>     libcxx/trunk/test/std/language.support/cmp/
>>     libcxx/trunk/test/std/language.support/cmp/cmp.common/
>>     libcxx/trunk/test/std/language.support/cmp/cmp.common/
>> common_comparison_category.pass.cpp
>>     libcxx/trunk/test/std/language.support/cmp/cmp.partialord/
>>     libcxx/trunk/test/std/language.support/cmp/cmp.partialord/
>> partialord.pass.cpp
>>     libcxx/trunk/test/std/language.support/cmp/cmp.strongeq/
>>     libcxx/trunk/test/std/language.support/cmp/cmp.strongeq/cmp.
>> strongeq.pass.cpp
>>     libcxx/trunk/test/std/language.support/cmp/cmp.strongord/
>>     libcxx/trunk/test/std/language.support/cmp/cmp.strongord/
>> strongord.pass.cpp
>>     libcxx/trunk/test/std/language.support/cmp/cmp.weakeq/
>>     libcxx/trunk/test/std/language.support/cmp/cmp.weakeq/cmp.
>> weakeq.pass.cpp
>>     libcxx/trunk/test/std/language.support/cmp/cmp.weakord/
>>     libcxx/trunk/test/std/language.support/cmp/cmp.weakord/
>> weakord.pass.cpp
>> Modified:
>>     libcxx/trunk/include/CMakeLists.txt
>>     libcxx/trunk/include/__config
>>     libcxx/trunk/include/module.modulemap
>>     libcxx/trunk/test/libcxx/double_include.sh.cpp
>>     libcxx/trunk/test/support/test_macros.h
>>
>> Modified: libcxx/trunk/include/CMakeLists.txt
>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/CMa
>> keLists.txt?rev=329460&r1=329459&r2=329460&view=diff
>> ============================================================
>> ==================
>> --- libcxx/trunk/include/CMakeLists.txt (original)
>> +++ libcxx/trunk/include/CMakeLists.txt Fri Apr  6 14:37:23 2018
>> @@ -77,5 +77,4 @@ if (LIBCXX_INSTALL_HEADERS)
>>      add_custom_target(install-libcxx-headers DEPENDS
>> install-cxx-headers)
>>      add_custom_target(install-libcxx-headers-stripped DEPENDS
>> install-cxx-headers-stripped)
>>    endif()
>> -
>>  endif()
>>
>> Modified: libcxx/trunk/include/__config
>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/__
>> config?rev=329460&r1=329459&r2=329460&view=diff
>> ============================================================
>> ==================
>> --- libcxx/trunk/include/__config (original)
>> +++ libcxx/trunk/include/__config Fri Apr  6 14:37:23 2018
>> @@ -1196,6 +1196,11 @@ _LIBCPP_FUNC_VIS extern "C" void __sanit
>>  #define _LIBCPP_HAS_NO_COROUTINES
>>  #endif
>>
>> +// FIXME: Correct this macro when either (A) a feature test macro for the
>> +// spaceship operator is provided, or (B) a compiler provides a complete
>> +// implementation.
>> +#define _LIBCPP_HAS_NO_SPACESHIP_OPERATOR
>> +
>>  // Decide whether to use availability macros.
>>  #if !defined(_LIBCPP_BUILDING_LIBRARY) &&
>>         \
>>      !defined(_LIBCPP_DISABLE_AVAILABILITY) &&
>>         \
>>
>> Added: libcxx/trunk/include/compare
>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/com
>> pare?rev=329460&view=auto
>> ============================================================
>> ==================
>> --- libcxx/trunk/include/compare (added)
>> +++ libcxx/trunk/include/compare Fri Apr  6 14:37:23 2018
>> @@ -0,0 +1,679 @@
>> +// -*- C++ -*-
>> +//===-------------------------- compare ------------------------------
>> -----===//
>> +//
>> +//                     The LLVM Compiler Infrastructure
>> +//
>> +// This file is dual licensed under the MIT and the University of
>> Illinois Open
>> +// Source Licenses. See LICENSE.TXT for details.
>> +//
>> +//===------------------------------------------------------
>> ----------------===//
>> +
>> +#ifndef _LIBCPP_COMPARE
>> +#define _LIBCPP_COMPARE
>> +
>> +/*
>> +    compare synopsis
>> +
>> +namespace std {
>> +  // [cmp.categories], comparison category types
>> +  class weak_equality;
>> +  class strong_equality;
>> +  class partial_ordering;
>> +  class weak_ordering;
>> +  class strong_ordering;
>> +
>> +  // named comparison functions
>> +  constexpr bool is_eq  (weak_equality cmp) noexcept    { return cmp ==
>> 0; }
>> +  constexpr bool is_neq (weak_equality cmp) noexcept    { return cmp !=
>> 0; }
>> +  constexpr bool is_lt  (partial_ordering cmp) noexcept { return cmp <
>> 0; }
>> +  constexpr bool is_lteq(partial_ordering cmp) noexcept { return cmp <=
>> 0; }
>> +  constexpr bool is_gt  (partial_ordering cmp) noexcept { return cmp >
>> 0; }
>> +  constexpr bool is_gteq(partial_ordering cmp) noexcept { return cmp >=
>> 0; }
>> +
>> +  // [cmp.common], common comparison category type
>> +  template<class... Ts>
>> +  struct common_comparison_category {
>> +    using type = see below;
>> +  };
>> +  template<class... Ts>
>> +    using common_comparison_category_t = typename
>> common_comparison_category<Ts...>::type;
>> +
>> +  // [cmp.alg], comparison algorithms
>> +  template<class T> constexpr strong_ordering strong_order(const T& a,
>> const T& b);
>> +  template<class T> constexpr weak_ordering weak_order(const T& a, const
>> T& b);
>> +  template<class T> constexpr partial_ordering partial_order(const T& a,
>> const T& b);
>> +  template<class T> constexpr strong_equality strong_equal(const T& a,
>> const T& b);
>> +  template<class T> constexpr weak_equality weak_equal(const T& a, const
>> T& b);
>> +}
>> +*/
>> +
>> +#include <__config>
>> +#include <type_traits>
>> +#include <array>
>> +
>> +#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
>> +#pragma GCC system_header
>> +#endif
>> +
>> +_LIBCPP_BEGIN_NAMESPACE_STD
>> +
>> +#if _LIBCPP_STD_VER > 17
>> +
>> +// exposition only
>> +enum class _LIBCPP_ENUM_VIS _EqResult : unsigned char {
>> +  __zero = 0,
>> +  __equal = __zero,
>> +  __equiv = __equal,
>> +  __nonequal = 1,
>> +  __nonequiv = __nonequal
>> +};
>> +
>> +enum class _LIBCPP_ENUM_VIS _OrdResult : signed char {
>> +  __less = -1,
>> +  __greater = 1
>> +};
>> +
>> +enum class _LIBCPP_ENUM_VIS _NCmpResult : signed char {
>> +  __unordered = -127
>> +};
>> +
>> +struct _CmpUnspecifiedType;
>> +using _CmpUnspecifiedParam = void (_CmpUnspecifiedType::*)();
>>
>
> 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.
>

Awesome :-)


>
> +
>> +class  weak_equality {
>> +  _LIBCPP_INLINE_VISIBILITY
>> +  constexpr explicit weak_equality(_EqResult __val) noexcept :
>> __value_(__val) {}
>> +
>> +public:
>> +  static const weak_equality equivalent;
>> +  static const weak_equality nonequivalent;
>> +
>> +  friend constexpr bool operator==(weak_equality __v,
>> _CmpUnspecifiedParam) noexcept;
>> +  friend constexpr bool operator==(_CmpUnspecifiedParam, weak_equality
>> __v) noexcept;
>> +  friend constexpr bool operator!=(weak_equality __v,
>> _CmpUnspecifiedParam) noexcept;
>> +  friend constexpr bool operator!=(_CmpUnspecifiedParam, weak_equality
>> __v) noexcept;
>> +
>> +#ifndef _LIBCPP_HAS_NO_SPACESHIP_OPERATOR
>> +  friend constexpr weak_equality operator<=>(weak_equality __v,
>> _CmpUnspecifiedParam) noexcept;
>> +  friend constexpr weak_equality operator<=>(_CmpUnspecifiedParam,
>> weak_equality __v) noexcept;
>> +#endif
>> +
>> +private:
>> +  _EqResult __value_;
>> +};
>> +
>> +_LIBCPP_INLINE_VAR constexpr weak_equality weak_equality::equivalent(_EqR
>> esult::__equiv);
>> +_LIBCPP_INLINE_VAR constexpr weak_equality weak_equality::nonequivalent(_
>> EqResult::__nonequiv);
>> +
>> +_LIBCPP_INLINE_VISIBILITY
>> +inline constexpr bool operator==(weak_equality __v,
>> _CmpUnspecifiedParam) noexcept {
>> +  return __v.__value_ == _EqResult::__zero;
>> +}
>> +
>> +_LIBCPP_INLINE_VISIBILITY
>> +inline constexpr bool operator==(_CmpUnspecifiedParam, weak_equality
>> __v) noexcept {
>> +  return __v.__value_ == _EqResult::__zero;
>> +}
>> +
>> +_LIBCPP_INLINE_VISIBILITY
>> +inline constexpr bool operator!=(weak_equality __v,
>> _CmpUnspecifiedParam) noexcept {
>> +  return __v.__value_ != _EqResult::__zero;
>> +}
>> +
>> +_LIBCPP_INLINE_VISIBILITY
>> +inline constexpr bool operator!=(_CmpUnspecifiedParam, weak_equality
>> __v) noexcept {
>> +  return __v.__value_ != _EqResult::__zero;
>> +}
>> +
>> +#ifndef _LIBCPP_HAS_NO_SPACESHIP_OPERATOR
>> +_LIBCPP_INLINE_VISIBILITY
>> +inline constexpr weak_equality operator<=>(weak_equality __v,
>> _CmpUnspecifiedParam) noexcept {
>> +  return __v;
>> +}
>> +
>> +_LIBCPP_INLINE_VISIBILITY
>> +inline constexpr weak_equality operator<=>(_CmpUnspecifiedParam,
>> weak_equality __v) noexcept {
>> +  return __v;
>> +}
>> +#endif
>> +
>> +class strong_equality {
>> +  _LIBCPP_INLINE_VISIBILITY
>> +  explicit constexpr strong_equality(_EqResult __val) noexcept :
>> __value_(__val) {}
>> +
>> +public:
>> +  static const strong_equality equal;
>> +  static const strong_equality nonequal;
>> +  static const strong_equality equivalent;
>> +  static const strong_equality nonequivalent;
>> +
>> +  // conversion
>> +  constexpr operator weak_equality() const noexcept {
>> +    return __value_ == _EqResult::__zero ? weak_equality::equivalent
>> +          : weak_equality::nonequivalent;
>> +  }
>> +
>> +  // comparisons
>> +  friend constexpr bool operator==(strong_equality __v,
>> _CmpUnspecifiedParam) noexcept;
>> +  friend constexpr bool operator!=(strong_equality __v,
>> _CmpUnspecifiedParam) noexcept;
>> +  friend constexpr bool operator==(_CmpUnspecifiedParam,
>> strong_equality __v) noexcept;
>> +  friend constexpr bool operator!=(_CmpUnspecifiedParam,
>> strong_equality __v) noexcept;
>> +
>> +#ifndef _LIBCPP_HAS_NO_SPACESHIP_OPERATOR
>> +  friend constexpr strong_equality operator<=>(strong_equality __v,
>> _CmpUnspecifiedParam) noexcept;
>> +  friend constexpr strong_equality operator<=>(_CmpUnspecifiedParam,
>> strong_equality __v) noexcept;
>> +#endif
>> +private:
>> +  _EqResult __value_;
>> +};
>> +
>> +_LIBCPP_INLINE_VAR constexpr strong_equality
>> strong_equality::equal(_EqResult::__equal);
>> +_LIBCPP_INLINE_VAR constexpr strong_equality
>> strong_equality::nonequal(_EqResult::__nonequal);
>> +_LIBCPP_INLINE_VAR constexpr strong_equality
>> strong_equality::equivalent(_EqResult::__equiv);
>> +_LIBCPP_INLINE_VAR constexpr strong_equality
>> strong_equality::nonequivalent(_EqResult::__nonequiv);
>> +
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator==(strong_equality __v, _CmpUnspecifiedParam)
>> noexcept {
>> +  return __v.__value_ == _EqResult::__zero;
>> +}
>> +
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator==(_CmpUnspecifiedParam, strong_equality __v)
>> noexcept {
>> +  return __v.__value_ == _EqResult::__zero;
>> +}
>> +
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator!=(strong_equality __v, _CmpUnspecifiedParam)
>> noexcept {
>> +  return __v.__value_ != _EqResult::__zero;
>> +}
>> +
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator!=(_CmpUnspecifiedParam, strong_equality __v)
>> noexcept {
>> +  return __v.__value_ != _EqResult::__zero;
>> +}
>> +
>> +#ifndef _LIBCPP_HAS_NO_SPACESHIP_OPERATOR
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr strong_equality operator<=>(strong_equality __v,
>> _CmpUnspecifiedParam) noexcept {
>> +  return __v;
>> +}
>> +
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr strong_equality operator<=>(_CmpUnspecifiedParam,
>> strong_equality __v) noexcept {
>> +  return __v;
>> +}
>> +#endif // _LIBCPP_HAS_NO_SPACESHIP_OPERATOR
>> +
>> +class partial_ordering {
>> +  using _ValueT = signed char;
>> +
>> +  _LIBCPP_INLINE_VISIBILITY
>> +  explicit constexpr partial_ordering(_EqResult __v) noexcept
>> +      : __value_(_ValueT(__v)) {}
>> +
>> +  _LIBCPP_INLINE_VISIBILITY
>> +  explicit constexpr partial_ordering(_OrdResult __v) noexcept
>> +      : __value_(_ValueT(__v)) {}
>> +
>> +  _LIBCPP_INLINE_VISIBILITY
>> +  explicit constexpr partial_ordering(_NCmpResult __v) noexcept
>> +      : __value_(_ValueT(__v)) {}
>> +
>> +  constexpr bool __is_ordered() const noexcept {
>> +    return __value_ != _ValueT(_NCmpResult::__unordered);
>> +  }
>> +public:
>> +  // valid values
>> +  static const partial_ordering less;
>> +  static const partial_ordering equivalent;
>> +  static const partial_ordering greater;
>> +  static const partial_ordering unordered;
>> +
>> +  // conversion
>> +  constexpr operator weak_equality() const noexcept {
>> +    return __value_ == 0 ? weak_equality::equivalent :
>> weak_equality::nonequivalent;
>> +  }
>> +
>> +  // comparisons
>> +  friend constexpr bool operator==(partial_ordering __v,
>> _CmpUnspecifiedParam) noexcept;
>> +  friend constexpr bool operator!=(partial_ordering __v,
>> _CmpUnspecifiedParam) noexcept;
>> +  friend constexpr bool operator< (partial_ordering __v,
>> _CmpUnspecifiedParam) noexcept;
>> +  friend constexpr bool operator<=(partial_ordering __v,
>> _CmpUnspecifiedParam) noexcept;
>> +  friend constexpr bool operator> (partial_ordering __v,
>> _CmpUnspecifiedParam) noexcept;
>> +  friend constexpr bool operator>=(partial_ordering __v,
>> _CmpUnspecifiedParam) noexcept;
>> +  friend constexpr bool operator==(_CmpUnspecifiedParam,
>> partial_ordering __v) noexcept;
>> +  friend constexpr bool operator!=(_CmpUnspecifiedParam,
>> partial_ordering __v) noexcept;
>> +  friend constexpr bool operator< (_CmpUnspecifiedParam,
>> partial_ordering __v) noexcept;
>> +  friend constexpr bool operator<=(_CmpUnspecifiedParam,
>> partial_ordering __v) noexcept;
>> +  friend constexpr bool operator> (_CmpUnspecifiedParam,
>> partial_ordering __v) noexcept;
>> +  friend constexpr bool operator>=(_CmpUnspecifiedParam,
>> partial_ordering __v) noexcept;
>> +
>> +#ifndef _LIBCPP_HAS_NO_SPACESHIP_OPERATOR
>> +  friend constexpr partial_ordering operator<=>(partial_ordering __v,
>> _CmpUnspecifiedParam) noexcept;
>> +  friend constexpr partial_ordering operator<=>(_CmpUnspecifiedParam,
>> partial_ordering __v) noexcept;
>> +#endif
>> +
>> +private:
>> +  _ValueT __value_;
>> +};
>> +
>> +_LIBCPP_INLINE_VAR constexpr partial_ordering
>> partial_ordering::less(_OrdResult::__less);
>> +_LIBCPP_INLINE_VAR constexpr partial_ordering
>> partial_ordering::equivalent(_EqResult::__equiv);
>> +_LIBCPP_INLINE_VAR constexpr partial_ordering
>> partial_ordering::greater(_OrdResult::__greater);
>> +_LIBCPP_INLINE_VAR constexpr partial_ordering
>> partial_ordering::unordered(_NCmpResult ::__unordered);
>> +
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator==(partial_ordering __v, _CmpUnspecifiedParam)
>> noexcept {
>> +  return __v.__is_ordered() && __v.__value_ == 0;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator< (partial_ordering __v, _CmpUnspecifiedParam)
>> noexcept {
>> +  return __v.__is_ordered() && __v.__value_ < 0;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator<=(partial_ordering __v, _CmpUnspecifiedParam)
>> noexcept {
>> +  return __v.__is_ordered() && __v.__value_ <= 0;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator> (partial_ordering __v, _CmpUnspecifiedParam)
>> noexcept {
>> +  return __v.__is_ordered() && __v.__value_ > 0;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator>=(partial_ordering __v, _CmpUnspecifiedParam)
>> noexcept {
>> +  return __v.__is_ordered() && __v.__value_ >= 0;
>> +}
>> +
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator==(_CmpUnspecifiedParam, partial_ordering __v)
>> noexcept {
>> +  return __v.__is_ordered() && 0 == __v.__value_;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator< (_CmpUnspecifiedParam, partial_ordering __v)
>> noexcept {
>> +  return __v.__is_ordered() && 0 < __v.__value_;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator<=(_CmpUnspecifiedParam, partial_ordering __v)
>> noexcept {
>> +  return __v.__is_ordered() && 0 <= __v.__value_;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator> (_CmpUnspecifiedParam, partial_ordering __v)
>> noexcept {
>> +  return __v.__is_ordered() && 0 > __v.__value_;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator>=(_CmpUnspecifiedParam, partial_ordering __v)
>> noexcept {
>> +  return __v.__is_ordered() && 0 >= __v.__value_;
>> +}
>> +
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator!=(partial_ordering __v, _CmpUnspecifiedParam)
>> noexcept {
>> +  return !__v.__is_ordered() || __v.__value_ != 0;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator!=(_CmpUnspecifiedParam, partial_ordering __v)
>> noexcept {
>> +  return !__v.__is_ordered() || __v.__value_ != 0;
>> +}
>> +
>> +#ifndef _LIBCPP_HAS_NO_SPACESHIP_OPERATOR
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr partial_ordering operator<=>(partial_ordering __v,
>> _CmpUnspecifiedParam) noexcept {
>> +  return __v;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr partial_ordering operator<=>(_CmpUnspecifiedParam,
>> partial_ordering __v) noexcept {
>> +  return __v < 0 ? partial_ordering::greater : (__v > 0 ?
>> partial_ordering::less : __v);
>> +}
>> +#endif // _LIBCPP_HAS_NO_SPACESHIP_OPERATOR
>> +
>> +class weak_ordering {
>> +  using _ValueT = signed char;
>> +
>> +  _LIBCPP_INLINE_VISIBILITY
>> +  explicit constexpr weak_ordering(_EqResult __v) noexcept :
>> __value_(_ValueT(__v)) {}
>> +  _LIBCPP_INLINE_VISIBILITY
>> +  explicit constexpr weak_ordering(_OrdResult __v) noexcept :
>> __value_(_ValueT(__v)) {}
>> +
>> +public:
>> +  static const weak_ordering less;
>> +  static const weak_ordering equivalent;
>> +  static const weak_ordering greater;
>> +
>> +  // conversions
>> +  _LIBCPP_INLINE_VISIBILITY
>> +  constexpr operator weak_equality() const noexcept {
>> +    return __value_ == 0 ? weak_equality::equivalent
>> +                         : weak_equality::nonequivalent;
>> +  }
>> +
>> +  _LIBCPP_INLINE_VISIBILITY
>> +  constexpr operator partial_ordering() const noexcept {
>> +    return __value_ == 0 ? partial_ordering::equivalent
>> +        : (__value_ < 0 ? partial_ordering::less :
>> partial_ordering::greater);
>> +  }
>> +
>> +  // comparisons
>> +  friend constexpr bool operator==(weak_ordering __v,
>> _CmpUnspecifiedParam) noexcept;
>> +  friend constexpr bool operator!=(weak_ordering __v,
>> _CmpUnspecifiedParam) noexcept;
>> +  friend constexpr bool operator< (weak_ordering __v,
>> _CmpUnspecifiedParam) noexcept;
>> +  friend constexpr bool operator<=(weak_ordering __v,
>> _CmpUnspecifiedParam) noexcept;
>> +  friend constexpr bool operator> (weak_ordering __v,
>> _CmpUnspecifiedParam) noexcept;
>> +  friend constexpr bool operator>=(weak_ordering __v,
>> _CmpUnspecifiedParam) noexcept;
>> +  friend constexpr bool operator==(_CmpUnspecifiedParam, weak_ordering
>> __v) noexcept;
>> +  friend constexpr bool operator!=(_CmpUnspecifiedParam, weak_ordering
>> __v) noexcept;
>> +  friend constexpr bool operator< (_CmpUnspecifiedParam, weak_ordering
>> __v) noexcept;
>> +  friend constexpr bool operator<=(_CmpUnspecifiedParam, weak_ordering
>> __v) noexcept;
>> +  friend constexpr bool operator> (_CmpUnspecifiedParam, weak_ordering
>> __v) noexcept;
>> +  friend constexpr bool operator>=(_CmpUnspecifiedParam, weak_ordering
>> __v) noexcept;
>> +
>> +#ifndef _LIBCPP_HAS_NO_SPACESHIP_OPERATOR
>> +  friend constexpr weak_ordering operator<=>(weak_ordering __v,
>> _CmpUnspecifiedParam) noexcept;
>> +  friend constexpr weak_ordering operator<=>(_CmpUnspecifiedParam,
>> weak_ordering __v) noexcept;
>> +#endif
>> +
>> +private:
>> +  _ValueT __value_;
>> +};
>> +
>> +_LIBCPP_INLINE_VAR constexpr weak_ordering weak_ordering::less(_OrdResult
>> ::__less);
>> +_LIBCPP_INLINE_VAR constexpr weak_ordering weak_ordering::equivalent(_EqR
>> esult::__equiv);
>> +_LIBCPP_INLINE_VAR constexpr weak_ordering weak_ordering::greater(_OrdRes
>> ult::__greater);
>> +
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator==(weak_ordering __v, _CmpUnspecifiedParam)
>> noexcept {
>> +  return __v.__value_ == 0;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator!=(weak_ordering __v, _CmpUnspecifiedParam)
>> noexcept {
>> +  return __v.__value_ != 0;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator< (weak_ordering __v, _CmpUnspecifiedParam)
>> noexcept {
>> +  return __v.__value_ < 0;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator<=(weak_ordering __v, _CmpUnspecifiedParam)
>> noexcept {
>> +  return __v.__value_ <= 0;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator> (weak_ordering __v, _CmpUnspecifiedParam)
>> noexcept {
>> +  return __v.__value_ > 0;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator>=(weak_ordering __v, _CmpUnspecifiedParam)
>> noexcept {
>> +  return __v.__value_ >= 0;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator==(_CmpUnspecifiedParam, weak_ordering __v)
>> noexcept {
>> +  return 0 == __v.__value_;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator!=(_CmpUnspecifiedParam, weak_ordering __v)
>> noexcept {
>> +  return 0 != __v.__value_;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator< (_CmpUnspecifiedParam, weak_ordering __v)
>> noexcept {
>> +  return 0 < __v.__value_;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator<=(_CmpUnspecifiedParam, weak_ordering __v)
>> noexcept {
>> +  return 0 <= __v.__value_;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator> (_CmpUnspecifiedParam, weak_ordering __v)
>> noexcept {
>> +  return 0 > __v.__value_;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator>=(_CmpUnspecifiedParam, weak_ordering __v)
>> noexcept {
>> +  return 0 >= __v.__value_;
>> +}
>> +
>> +#ifndef _LIBCPP_HAS_NO_SPACESHIP_OPERATOR
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr weak_ordering operator<=>(weak_ordering __v,
>> _CmpUnspecifiedParam) noexcept {
>> +  return __v;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr weak_ordering operator<=>(_CmpUnspecifiedParam, weak_ordering
>> __v) noexcept {
>> +  return __v < 0 ? weak_ordering::greater : (__v > 0 ?
>> weak_ordering::less : __v);
>> +}
>> +#endif // _LIBCPP_HAS_NO_SPACESHIP_OPERATOR
>> +
>> +class strong_ordering {
>> +  using _ValueT = signed char;
>> +
>> +  _LIBCPP_INLINE_VISIBILITY
>> +  explicit constexpr strong_ordering(_EqResult __v) noexcept :
>> __value_(_ValueT(__v)) {}
>> +  _LIBCPP_INLINE_VISIBILITY
>> +  explicit constexpr strong_ordering(_OrdResult __v) noexcept :
>> __value_(_ValueT(__v)) {}
>> +
>> +public:
>> +  static const strong_ordering less;
>> +  static const strong_ordering equal;
>> +  static const strong_ordering equivalent;
>> +  static const strong_ordering greater;
>> +
>> +  // conversions
>> +  _LIBCPP_INLINE_VISIBILITY
>> +  constexpr operator weak_equality() const noexcept {
>> +    return __value_ == 0 ? weak_equality::equivalent
>> +                         : weak_equality::nonequivalent;
>> +  }
>> +
>> +  _LIBCPP_INLINE_VISIBILITY
>> +  constexpr operator strong_equality() const noexcept {
>> +    return __value_ == 0 ? strong_equality::equal
>> +                         : strong_equality::nonequal;
>> +  }
>> +
>> +  _LIBCPP_INLINE_VISIBILITY
>> +  constexpr operator partial_ordering() const noexcept {
>> +    return __value_ == 0 ? partial_ordering::equivalent
>> +        : (__value_ < 0 ? partial_ordering::less :
>> partial_ordering::greater);
>> +  }
>> +
>> +  _LIBCPP_INLINE_VISIBILITY
>> +  constexpr operator weak_ordering() const noexcept {
>> +    return __value_ == 0 ? weak_ordering::equivalent
>> +        : (__value_ < 0 ? weak_ordering::less : weak_ordering::greater);
>> +  }
>> +
>> +  // comparisons
>> +  friend constexpr bool operator==(strong_ordering __v,
>> _CmpUnspecifiedParam) noexcept;
>> +  friend constexpr bool operator!=(strong_ordering __v,
>> _CmpUnspecifiedParam) noexcept;
>> +  friend constexpr bool operator< (strong_ordering __v,
>> _CmpUnspecifiedParam) noexcept;
>> +  friend constexpr bool operator<=(strong_ordering __v,
>> _CmpUnspecifiedParam) noexcept;
>> +  friend constexpr bool operator> (strong_ordering __v,
>> _CmpUnspecifiedParam) noexcept;
>> +  friend constexpr bool operator>=(strong_ordering __v,
>> _CmpUnspecifiedParam) noexcept;
>> +  friend constexpr bool operator==(_CmpUnspecifiedParam,
>> strong_ordering __v) noexcept;
>> +  friend constexpr bool operator!=(_CmpUnspecifiedParam,
>> strong_ordering __v) noexcept;
>> +  friend constexpr bool operator< (_CmpUnspecifiedParam, strong_ordering
>> __v) noexcept;
>> +  friend constexpr bool operator<=(_CmpUnspecifiedParam,
>> strong_ordering __v) noexcept;
>> +  friend constexpr bool operator> (_CmpUnspecifiedParam, strong_ordering
>> __v) noexcept;
>> +  friend constexpr bool operator>=(_CmpUnspecifiedParam,
>> strong_ordering __v) noexcept;
>> +
>> +#ifndef _LIBCPP_HAS_NO_SPACESHIP_OPERATOR
>> +  friend constexpr strong_ordering operator<=>(strong_ordering __v,
>> _CmpUnspecifiedParam) noexcept;
>> +  friend constexpr strong_ordering operator<=>(_CmpUnspecifiedParam,
>> strong_ordering __v) noexcept;
>> +#endif
>> +
>> +private:
>> +  _ValueT __value_;
>> +};
>> +
>> +_LIBCPP_INLINE_VAR constexpr strong_ordering
>> strong_ordering::less(_OrdResult::__less);
>> +_LIBCPP_INLINE_VAR constexpr strong_ordering
>> strong_ordering::equal(_EqResult::__equal);
>> +_LIBCPP_INLINE_VAR constexpr strong_ordering
>> strong_ordering::equivalent(_EqResult::__equiv);
>> +_LIBCPP_INLINE_VAR constexpr strong_ordering
>> strong_ordering::greater(_OrdResult::__greater);
>> +
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator==(strong_ordering __v, _CmpUnspecifiedParam)
>> noexcept {
>> +  return __v.__value_ == 0;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator!=(strong_ordering __v, _CmpUnspecifiedParam)
>> noexcept {
>> +  return __v.__value_ != 0;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator< (strong_ordering __v, _CmpUnspecifiedParam)
>> noexcept {
>> +  return __v.__value_ < 0;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator<=(strong_ordering __v, _CmpUnspecifiedParam)
>> noexcept {
>> +  return __v.__value_ <= 0;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator> (strong_ordering __v, _CmpUnspecifiedParam)
>> noexcept {
>> +  return __v.__value_ > 0;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator>=(strong_ordering __v, _CmpUnspecifiedParam)
>> noexcept {
>> +  return __v.__value_ >= 0;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator==(_CmpUnspecifiedParam, strong_ordering __v)
>> noexcept {
>> +  return 0 == __v.__value_;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator!=(_CmpUnspecifiedParam, strong_ordering __v)
>> noexcept {
>> +  return 0 != __v.__value_;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator< (_CmpUnspecifiedParam, strong_ordering __v)
>> noexcept {
>> +  return 0 < __v.__value_;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator<=(_CmpUnspecifiedParam, strong_ordering __v)
>> noexcept {
>> +  return 0 <= __v.__value_;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator> (_CmpUnspecifiedParam, strong_ordering __v)
>> noexcept {
>> +  return 0 > __v.__value_;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool operator>=(_CmpUnspecifiedParam, strong_ordering __v)
>> noexcept {
>> +  return 0 >= __v.__value_;
>> +}
>> +
>> +#ifndef _LIBCPP_HAS_NO_SPACESHIP_OPERATOR
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr strong_ordering operator<=>(strong_ordering __v,
>> _CmpUnspecifiedParam) noexcept {
>> +  return __v;
>> +}
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr strong_ordering operator<=>(_CmpUnspecifiedParam,
>> strong_ordering __v) noexcept {
>> +  return __v < 0 ? strong_ordering::greater : (__v > 0 ?
>> strong_ordering::less : __v);
>> +}
>> +#endif // _LIBCPP_HAS_NO_SPACESHIP_OPERATOR
>> +
>> +// named comparison functions
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool is_eq(weak_equality __cmp) noexcept    { return __cmp ==
>> 0; }
>> +
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool is_neq(weak_equality __cmp) noexcept    { return __cmp !=
>> 0; }
>> +
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool is_lt(partial_ordering __cmp) noexcept { return __cmp <
>> 0; }
>> +
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool is_lteq(partial_ordering __cmp) noexcept { return __cmp
>> <= 0; }
>> +
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool is_gt(partial_ordering __cmp) noexcept { return __cmp >
>> 0; }
>> +
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr bool is_gteq(partial_ordering __cmp) noexcept { return __cmp
>> >= 0; }
>> +
>> +namespace __comp_detail {
>> +
>> +enum _ClassifyCompCategory : unsigned{
>> +  _None,
>> +  _WeakEq,
>> +  _StrongEq,
>> +  _PartialOrd,
>> +  _WeakOrd,
>> +  _StrongOrd,
>> +  _CCC_Size
>> +};
>> +
>> +template <class _Tp>
>> +_LIBCPP_INLINE_VISIBILITY
>> +constexpr _ClassifyCompCategory __type_to_enum() noexcept {
>> +  if (is_same_v<_Tp, weak_equality>)
>> +    return _WeakEq;
>> +  if (is_same_v<_Tp, strong_equality>)
>> +    return _StrongEq;
>> +  if (is_same_v<_Tp, partial_ordering>)
>> +    return _PartialOrd;
>> +  if (is_same_v<_Tp, weak_ordering>)
>> +    return _WeakOrd;
>> +  if (is_same_v<_Tp, strong_ordering>)
>> +    return _StrongOrd;
>> +  return _None;
>> +}
>> +
>> +template <size_t _Size>
>> +constexpr _ClassifyCompCategory
>> +__compute_comp_type(std::array<_ClassifyCompCategory, _Size> __types) {
>> +  std::array<int, _CCC_Size> __seen = {};
>> +  for (auto __type : __types)
>> +    ++__seen[__type];
>> +  if (__seen[_None])
>> +    return _None;
>> +  if (__seen[_WeakEq])
>> +    return _WeakEq;
>> +  if (__seen[_StrongEq] && (__seen[_PartialOrd] || __seen[_WeakOrd]))
>> +    return _WeakEq;
>> +  if (__seen[_StrongEq])
>> +    return _StrongEq;
>> +  if (__seen[_PartialOrd])
>> +    return _PartialOrd;
>> +  if (__seen[_WeakOrd])
>> +    return _WeakOrd;
>> +  return _StrongOrd;
>> +}
>>
>
> Hmm, it'd be nice to ask the compiler to work this out rather than
> repeating the algorithm here. For example, something like:
>
> template<size_t, typename T> struct CCT { friend T operator<=>(const CCT&,
> const CCT&); };
> template<typename N, typename ...T> struct CCC;
> template<size_t ...N, typename ...T> struct CCC : CCT<N, T>... {
>   friend auto operator<=>(const CCC&, const CCC&) = default;
> };
> template<typename ...T> struct common_comparison_category {
>   template<typename C> static auto test(int) -> decltype(declval<const
> C&>() <=> declval<const C&>());
>   template<typename C> static void test(...);
>   using type = decltype(test<CCC<std::make_index_sequence<sizeof...(T)>,
> T...>>(0));
> }
>
> ... should allow you to ask the compiler for the common comparison type.
>

Looks good to me. Once we actually have a compiler I can do that with I'll
make the change.
For now I think it's preferable to have a working implementation.

FYI, I have an almost complete implementation of [expr.spaceship].

I was about to start making ExprConstant work, but I think that requires a
new AST node to
represent three-way comparisons. Since <=> builtins return a DeclRefExpr
for the appropriate
comparison category type member (ex. strong_equality::equal), and we can't
build these
in ExprConstant so it seems appropriate to build them earlier and store
them in the
operator expression node (I suspect this problem also arises during
CodeGen).

Does that seem reasonable?


>
>> +
>> +template <class ..._Ts>
>> +constexpr auto __get_comp_type() {
>> +  using _CCC = _ClassifyCompCategory;
>> +  constexpr array<_CCC, sizeof...(_Ts)> __type_kinds{__comp_detail::__
>> type_to_enum<_Ts>()...};
>> +  constexpr _CCC _Cat = sizeof...(_Ts) == 0 ? _StrongOrd
>> +      : __compute_comp_type(__type_kinds);
>> +  if constexpr (_Cat == _None)
>> +    return ((void)0);
>>
>
> 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<...>::type
> should not exist in the case where there is no common comparison type, for
> consistency with the other traits.)
>

I forgot about `void()`. Thanks.

I'll look into the library spec tomorrow, and probably file an issue.


>
>
>> +  else if constexpr (_Cat == _WeakEq)
>> +    return weak_equality::equivalent;
>> +  else if constexpr (_Cat == _StrongEq)
>> +    return strong_equality::equivalent;
>> +  else if constexpr (_Cat == _PartialOrd)
>> +    return partial_ordering::equivalent;
>> +  else if constexpr (_Cat == _WeakOrd)
>> +    return weak_ordering::equivalent;
>> +  else if constexpr (_Cat == _StrongOrd)
>> +    return strong_ordering::equivalent;
>> +  else
>> +    static_assert(_Cat != _Cat, "unhandled case");
>> +}
>> +} // namespace __comp_detail
>> +
>> +// [cmp.common], common comparison category type
>> +template<class... _Ts>
>> +struct _LIBCPP_TEMPLATE_VIS common_comparison_category {
>> +  using type = decltype(__comp_detail::__get_comp_type<_Ts...>());
>> +};
>> +
>> +template<class... _Ts>
>> +using common_comparison_category_t = typename
>> common_comparison_category<_Ts...>::type;
>> +
>> +// [cmp.alg], comparison algorithms
>> +// TODO: unimplemented
>> +template<class _Tp> constexpr strong_ordering strong_order(const _Tp&
>> __lhs, const _Tp& __rhs);
>> +template<class _Tp> constexpr weak_ordering weak_order(const _Tp& __lhs,
>> const _Tp& __rhs);
>> +template<class _Tp> constexpr partial_ordering partial_order(const _Tp&
>> __lhs, const _Tp& __rhs);
>> +template<class _Tp> constexpr strong_equality strong_equal(const _Tp&
>> __lhs, const _Tp& __rhs);
>> +template<class _Tp> constexpr weak_equality weak_equal(const _Tp& __lhs,
>> const _Tp& __rhs);
>> +
>> +#endif // _LIBCPP_STD_VER > 17
>> +
>> +_LIBCPP_END_NAMESPACE_STD
>> +
>> +#endif // _LIBCPP_COMPARE
>>
>> Modified: libcxx/trunk/include/module.modulemap
>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/mod
>> ule.modulemap?rev=329460&r1=329459&r2=329460&view=diff
>> ============================================================
>> ==================
>> --- libcxx/trunk/include/module.modulemap (original)
>> +++ libcxx/trunk/include/module.modulemap Fri Apr  6 14:37:23 2018
>> @@ -243,6 +243,10 @@ module std [system] {
>>      header "codecvt"
>>      export *
>>    }
>> +  module compare {
>> +    header "compare"
>> +    export *
>> +  }
>>    module complex {
>>      header "complex"
>>      export *
>>
>> Modified: libcxx/trunk/test/libcxx/double_include.sh.cpp
>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx
>> /double_include.sh.cpp?rev=329460&r1=329459&r2=329460&view=diff
>> ============================================================
>> ==================
>> --- libcxx/trunk/test/libcxx/double_include.sh.cpp (original)
>> +++ libcxx/trunk/test/libcxx/double_include.sh.cpp Fri Apr  6 14:37:23
>> 2018
>> @@ -41,6 +41,7 @@
>>  #include <clocale>
>>  #include <cmath>
>>  #include <codecvt>
>> +#include <compare>
>>  #include <complex>
>>  #include <complex.h>
>>  #include <condition_variable>
>>
>> Added: libcxx/trunk/test/libcxx/language.support/cmp/version.pass.cpp
>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx
>> /language.support/cmp/version.pass.cpp?rev=329460&view=auto
>> ============================================================
>> ==================
>> --- libcxx/trunk/test/libcxx/language.support/cmp/version.pass.cpp
>> (added)
>> +++ libcxx/trunk/test/libcxx/language.support/cmp/version.pass.cpp Fri
>> Apr  6 14:37:23 2018
>> @@ -0,0 +1,20 @@
>> +//===------------------------------------------------------
>> ----------------===//
>> +//
>> +//                     The LLVM Compiler Infrastructure
>> +//
>> +// This file is dual licensed under the MIT and the University of
>> Illinois Open
>> +// Source Licenses. See LICENSE.TXT for details.
>> +//
>> +//===------------------------------------------------------
>> ----------------===//
>> +
>> +// <compare>
>> +
>> +#include <compare>
>> +
>> +#ifndef _LIBCPP_VERSION
>> +#error _LIBCPP_VERSION not defined
>> +#endif
>> +
>> +int main()
>> +{
>> +}
>>
>> Added: libcxx/trunk/test/std/language.support/cmp/cmp.common/
>> common_comparison_category.pass.cpp
>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/la
>> nguage.support/cmp/cmp.common/common_comparison_category.
>> pass.cpp?rev=329460&view=auto
>> ============================================================
>> ==================
>> --- libcxx/trunk/test/std/language.support/cmp/cmp.common/
>> common_comparison_category.pass.cpp (added)
>> +++ libcxx/trunk/test/std/language.support/cmp/cmp.common/
>> common_comparison_category.pass.cpp Fri Apr  6 14:37:23 2018
>> @@ -0,0 +1,93 @@
>> +//===------------------------------------------------------
>> ----------------===//
>> +//
>> +//                     The LLVM Compiler Infrastructure
>> +//
>> +// This file is dual licensed under the MIT and the University of
>> Illinois Open
>> +// Source Licenses. See LICENSE.TXT for details.
>> +//
>> +//===------------------------------------------------------
>> ----------------===//
>> +
>> +// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17
>> +
>> +// <compare>
>> +
>> +// template <class ...Ts> struct common_comparison_category
>> +// template <class ...Ts> using common_comparison_category_t
>> +
>> +
>> +#include <compare>
>> +#include <type_traits>
>> +#include <cassert>
>> +
>> +#include "test_macros.h"
>> +
>> +const volatile void* volatile sink;
>> +
>> +template <class Expect, class ...Args>
>> +void test_cat() {
>> +  using Cat = std::common_comparison_category<Args...>;
>> +  using CatT = typename Cat::type;
>> +  static_assert(std::is_same<CatT, std::common_comparison_category_t<Args...>>::value,
>> "");
>> +  static_assert(std::is_same<CatT, Expect>::value, "expected different
>> category");
>> +};
>> +
>> +
>> +// [class.spaceship]p4: The 'common comparison type' U of a
>> possibly-empty list
>> +//   of 'n' types T0, T1, ..., TN, is defined as follows:
>> +int main() {
>> +  using WE = std::weak_equality;
>> +  using SE = std::strong_equality;
>> +  using PO = std::partial_ordering;
>> +  using WO = std::weak_ordering;
>> +  using SO = std::strong_ordering;
>> +
>> +  // [class.spaceship]p4.1: If any Ti is not a comparison category tpe,
>> U is void.
>> +  {
>> +    test_cat<void, void>();
>> +    test_cat<void, int*>();
>> +    test_cat<void, SO&>();
>> +    test_cat<void, SO const>();
>> +    test_cat<void, SO*>();
>> +    test_cat<void, SO, void, SO>();
>> +  }
>> +
>> +  // [class.spaceship]p4.2: Otherwise, if at least on Ti is
>> +  // std::weak_equality, or at least one Ti is std::strong_equality and
>> at least
>> +  // one Tj is std::partial_ordering or std::weak_ordering, U is
>> std::weak_equality
>> +  {
>> +    test_cat<WE, WE>();
>> +    test_cat<WE, SO, WE, SO>();
>> +    test_cat<WE, SE, SO, PO>();
>> +    test_cat<WE, WO, SO, SE>();
>> +  }
>> +
>> +  // [class.spaceship]p4.3: Otherwise, if at least one Ti is
>> std::strong_equality,
>> +  // U is std::strong_equality
>> +  {
>> +    test_cat<SE, SE>();
>> +    test_cat<SE, SO, SE, SO>();
>> +  }
>> +
>> +  // [class.spaceship]p4.4: Otherwise, if at least one Ti is
>> std::partial_ordering,
>> +  // U is std::partial_ordering
>> +  {
>> +    test_cat<PO, PO>();
>> +    test_cat<PO, SO, PO, SO>();
>> +    test_cat<PO, WO, PO, SO>();
>> +  }
>> +
>> +  // [class.spaceship]p4.5: Otherwise, if at least one Ti is
>> std::weak_ordering,
>> +  // U is std::weak_ordering
>> +  {
>> +    test_cat<WO, WO>();
>> +    test_cat<WO, SO, WO, SO>();
>> +  }
>> +
>> +  // [class.spaceship]p4.6: Otherwise, U is std::strong_ordering. [Note:
>> in
>> +  // particular this is the result when n is 0. -- end note]
>> +  {
>> +    test_cat<SO>(); // empty type list
>> +    test_cat<SO, SO>();
>> +    test_cat<SO, SO, SO>();
>> +  }
>> +}
>>
>> Added: libcxx/trunk/test/std/language.support/cmp/cmp.partialord/
>> partialord.pass.cpp
>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/la
>> nguage.support/cmp/cmp.partialord/partialord.pass.cpp?rev=
>> 329460&view=auto
>> ============================================================
>> ==================
>> --- libcxx/trunk/test/std/language.support/cmp/cmp.partialord/partialord.pass.cpp
>> (added)
>> +++ libcxx/trunk/test/std/language.support/cmp/cmp.partialord/partialord.pass.cpp
>> Fri Apr  6 14:37:23 2018
>> @@ -0,0 +1,164 @@
>> +//===------------------------------------------------------
>> ----------------===//
>> +//
>> +//                     The LLVM Compiler Infrastructure
>> +//
>> +// This file is dual licensed under the MIT and the University of
>> Illinois Open
>> +// Source Licenses. See LICENSE.TXT for details.
>> +//
>> +//===------------------------------------------------------
>> ----------------===//
>> +
>> +// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17
>> +
>> +// <compare>
>> +
>> +// class partial_ordering
>> +
>> +
>> +#include <compare>
>> +#include <type_traits>
>> +#include <cassert>
>> +
>> +#include "test_macros.h"
>> +
>> +const volatile void* volatile sink;
>> +
>> +void test_static_members() {
>> +  DoNotOptimize(&std::partial_ordering::less);
>> +  DoNotOptimize(&std::partial_ordering::equivalent);
>> +  DoNotOptimize(&std::partial_ordering::greater);
>> +  DoNotOptimize(&std::partial_ordering::unordered);
>> +}
>> +
>> +void test_signatures() {
>> +  auto& Eq = std::partial_ordering::equivalent;
>> +
>> +  ASSERT_NOEXCEPT(Eq == 0);
>> +  ASSERT_NOEXCEPT(0 == Eq);
>> +  ASSERT_NOEXCEPT(Eq != 0);
>> +  ASSERT_NOEXCEPT(0 != Eq);
>> +  ASSERT_NOEXCEPT(0 < Eq);
>> +  ASSERT_NOEXCEPT(Eq < 0);
>> +  ASSERT_NOEXCEPT(0 <= Eq);
>> +  ASSERT_NOEXCEPT(Eq <= 0);
>> +  ASSERT_NOEXCEPT(0 > Eq);
>> +  ASSERT_NOEXCEPT(Eq > 0);
>> +  ASSERT_NOEXCEPT(0 >= Eq);
>> +  ASSERT_NOEXCEPT(Eq >= 0);
>> +#ifndef TEST_HAS_NO_SPACESHIP_OPERATOR
>> +  ASSERT_NOEXCEPT(0 <=> Eq);
>> +  ASSERT_NOEXCEPT(Eq <=> 0);
>> +  ASSERT_SAME_TYPE(decltype(Eq <=> 0), std::partial_ordering);
>> +  ASSERT_SAME_TYPE(decltype(0 <=> Eq), std::partial_ordering);
>> +#endif
>> +}
>> +
>> +constexpr bool test_conversion() {
>> +  static_assert(std::is_convertible<const std::partial_ordering,
>> std::weak_equality>::value, "");
>> +  { // value == 0
>> +    auto V = std::partial_ordering::equivalent;
>> +    std::weak_equality WV = V;
>> +    assert(WV == 0);
>> +  }
>> +  std::partial_ordering TestCases[] = {
>> +      std::partial_ordering::less,
>> +      std::partial_ordering::greater,
>> +      std::partial_ordering::unordered
>> +  };
>> +  for (auto V : TestCases)
>> +  { // value != 0
>> +    std::weak_equality WV = V;
>> +    assert(WV != 0);
>> +  }
>> +  return true;
>> +}
>> +
>> +constexpr bool test_constexpr() {
>> +  auto& Eq = std::partial_ordering::equivalent;
>> +  auto& Less = std::partial_ordering::less;
>> +  auto& Greater = std::partial_ordering::greater;
>> +  auto& Unord = std::partial_ordering::unordered;
>> +  struct {
>> +    std::partial_ordering Value;
>> +    bool ExpectEq;
>> +    bool ExpectNeq;
>> +    bool ExpectLess;
>> +    bool ExpectGreater;
>> +  } TestCases[] = {
>> +      {Eq, true, false, false, false},
>> +      {Less, false, true, true, false},
>> +      {Greater, false, true, false, true},
>> +      {Unord, false, true, false, false}
>> +  };
>> +  for (auto TC : TestCases) {
>> +    auto V = TC.Value;
>> +    assert((V == 0) == TC.ExpectEq);
>> +    assert((0 == V) == TC.ExpectEq);
>> +    assert((V != 0) == TC.ExpectNeq);
>> +    assert((0 != V) == TC.ExpectNeq);
>> +
>> +    assert((V < 0) == TC.ExpectLess);
>> +    assert((V > 0) == TC.ExpectGreater);
>> +    assert((V <= 0) == (TC.ExpectLess || TC.ExpectEq));
>> +    assert((V >= 0) == (TC.ExpectGreater || TC.ExpectEq));
>> +
>> +    assert((0 < V) == TC.ExpectGreater);
>> +    assert((0 > V) == TC.ExpectLess);
>> +    assert((0 <= V) == (TC.ExpectGreater || TC.ExpectEq));
>> +    assert((0 >= V) == (TC.ExpectLess || TC.ExpectEq));
>> +  }
>> +#ifndef TEST_HAS_NO_SPACESHIP_OPERATOR
>> +  {
>> +    std::partial_ordering res = (Eq <=> 0);
>> +    ((void)res);
>> +    res = (0 <=> Eq);
>> +    ((void)res);
>> +  }
>> +  enum ExpectRes {
>> +    ER_Greater,
>> +    ER_Less,
>> +    ER_Equiv,
>> +    ER_Unord
>> +  };
>> +  struct {
>> +    std::partial_ordering Value;
>> +    ExpectRes Expect;
>> +  } SpaceshipTestCases[] = {
>> +      {std::partial_ordering::equivalent, ER_Equiv},
>> +      {std::partial_ordering::less, ER_Less},
>> +      {std::partial_ordering::greater, ER_Greater},
>> +      {std::partial_ordering::unordered, ER_Unord}
>> +  };
>> +  for (auto TC : SpaceshipTestCases)
>> +  {
>> +    std::partial_ordering Res = (0 <=> TC.Value);
>> +    switch (TC.Expect) {
>> +    case ER_Equiv:
>> +      assert(Res == 0);
>> +      assert(0 == Res);
>> +      break;
>> +    case ER_Less:
>> +      assert(Res < 0);
>> +      break;
>> +    case ER_Greater:
>> +      assert(Res > 0);
>> +      break;
>> +    case ER_Unord:
>> +      assert(Res != 0);
>> +      assert(0 != Res);
>> +      assert((Res < 0) == false);
>> +      assert((Res > 0) == false);
>> +      assert((Res == 0) == false);
>> +      break;
>> +    }
>> +  }
>> +#endif
>> +
>> +  return true;
>> +}
>> +
>> +int main() {
>> +  test_static_members();
>> +  test_signatures();
>> +  static_assert(test_conversion(), "conversion test failed");
>> +  static_assert(test_constexpr(), "constexpr test failed");
>> +}
>>
>> Added: libcxx/trunk/test/std/language.support/cmp/cmp.strongeq/cmp.
>> strongeq.pass.cpp
>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/la
>> nguage.support/cmp/cmp.strongeq/cmp.strongeq.pass.cpp?rev=
>> 329460&view=auto
>> ============================================================
>> ==================
>> --- libcxx/trunk/test/std/language.support/cmp/cmp.strongeq/cmp.strongeq.pass.cpp
>> (added)
>> +++ libcxx/trunk/test/std/language.support/cmp/cmp.strongeq/cmp.strongeq.pass.cpp
>> Fri Apr  6 14:37:23 2018
>> @@ -0,0 +1,96 @@
>> +//===------------------------------------------------------
>> ----------------===//
>> +//
>> +//                     The LLVM Compiler Infrastructure
>> +//
>> +// This file is dual licensed under the MIT and the University of
>> Illinois Open
>> +// Source Licenses. See LICENSE.TXT for details.
>> +//
>> +//===------------------------------------------------------
>> ----------------===//
>> +
>> +// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17
>> +
>> +// <compare>
>> +
>> +// class strong_equality
>> +
>> +
>> +#include <compare>
>> +#include <type_traits>
>> +#include <cassert>
>> +
>> +#include "test_macros.h"
>> +
>> +const volatile void* volatile sink;
>> +
>> +void test_static_members() {
>> +  DoNotOptimize(&std::strong_equality::equal);
>> +  DoNotOptimize(&std::strong_equality::nonequal);
>> +  DoNotOptimize(&std::strong_equality::equivalent);
>> +  DoNotOptimize(&std::strong_equality::nonequivalent);
>> +}
>> +
>> +void test_signatures() {
>> +  auto& Eq = std::strong_equality::equivalent;
>> +
>> +  ASSERT_NOEXCEPT(Eq == 0);
>> +  ASSERT_NOEXCEPT(0 == Eq);
>> +  ASSERT_NOEXCEPT(Eq != 0);
>> +  ASSERT_NOEXCEPT(0 != Eq);
>> +#ifndef TEST_HAS_NO_SPACESHIP_OPERATOR
>> +  ASSERT_NOEXCEPT(0 <=> Eq);
>> +  ASSERT_NOEXCEPT(Eq <=> 0);
>> +  ASSERT_SAME_TYPE(decltype(Eq <=> 0), std::strong_equality);
>> +  ASSERT_SAME_TYPE(decltype(0 <=> Eq), std::strong_equality);
>> +#endif
>> +}
>> +
>> +void test_conversion() {
>> +  constexpr std::weak_equality res = std::strong_equality::equivalent;
>> +  static_assert(res == 0, "");
>> +  static_assert(std::is_convertible<const std::strong_equality&,
>> +      std::weak_equality>::value, "");
>> +  static_assert(res == 0, "expected equal");
>> +
>> +  constexpr std::weak_equality neq_res = std::strong_equality::nonequiv
>> alent;
>> +  static_assert(neq_res != 0, "expected not equal");
>> +}
>> +
>> +constexpr bool test_constexpr() {
>> +  auto& Eq = std::strong_equality::equal;
>> +  auto& NEq = std::strong_equality::nonequal;
>> +  auto& Equiv = std::strong_equality::equivalent;
>> +  auto& NEquiv = std::strong_equality::nonequivalent;
>> +  assert((Eq == 0) == true);
>> +  assert((0 == Eq) == true);
>> +  assert((Equiv == 0) == true);
>> +  assert((0 == Equiv) == true);
>> +  assert((NEq == 0) == false);
>> +  assert((0 == NEq) == false);
>> +  assert((NEquiv == 0) == false);
>> +  assert((0 == NEquiv) == false);
>> +
>> +  assert((Eq != 0) == false);
>> +  assert((0 != Eq) == false);
>> +  assert((Equiv != 0) == false);
>> +  assert((0 != Equiv) == false);
>> +  assert((NEq != 0) == true);
>> +  assert((0 != NEq) == true);
>> +  assert((NEquiv != 0) == true);
>> +  assert((0 != NEquiv) == true);
>> +
>> +#ifndef TEST_HAS_NO_SPACESHIP_OPERATOR
>> +  std::strong_equality res = (Eq <=> 0);
>> +  ((void)res);
>> +  res = (0 <=> Eq);
>> +  ((void)res);
>> +#endif
>> +
>> +  return true;
>> +}
>> +
>> +int main() {
>> +  test_static_members();
>> +  test_signatures();
>> +  test_conversion();
>> +  static_assert(test_constexpr(), "constexpr test failed");
>> +}
>>
>> Added: libcxx/trunk/test/std/language.support/cmp/cmp.strongord/
>> strongord.pass.cpp
>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/la
>> nguage.support/cmp/cmp.strongord/strongord.pass.cpp?rev=329460&view=auto
>> ============================================================
>> ==================
>> --- libcxx/trunk/test/std/language.support/cmp/cmp.strongord/strongord.pass.cpp
>> (added)
>> +++ libcxx/trunk/test/std/language.support/cmp/cmp.strongord/strongord.pass.cpp
>> Fri Apr  6 14:37:23 2018
>> @@ -0,0 +1,212 @@
>> +//===------------------------------------------------------
>> ----------------===//
>> +//
>> +//                     The LLVM Compiler Infrastructure
>> +//
>> +// This file is dual licensed under the MIT and the University of
>> Illinois Open
>> +// Source Licenses. See LICENSE.TXT for details.
>> +//
>> +//===------------------------------------------------------
>> ----------------===//
>> +
>> +// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17
>> +
>> +// <compare>
>> +
>> +// class strong_ordering
>> +
>> +
>> +#include <compare>
>> +#include <type_traits>
>> +#include <cassert>
>> +
>> +#include "test_macros.h"
>> +
>> +const volatile void* volatile sink;
>> +
>> +void test_static_members() {
>> +  DoNotOptimize(&std::strong_ordering::less);
>> +  DoNotOptimize(&std::strong_ordering::equal);
>> +  DoNotOptimize(&std::strong_ordering::equivalent);
>> +  DoNotOptimize(&std::strong_ordering::greater);
>> +}
>> +
>> +void test_signatures() {
>> +  auto& Eq = std::strong_ordering::equivalent;
>> +
>> +  ASSERT_NOEXCEPT(Eq == 0);
>> +  ASSERT_NOEXCEPT(0 == Eq);
>> +  ASSERT_NOEXCEPT(Eq != 0);
>> +  ASSERT_NOEXCEPT(0 != Eq);
>> +  ASSERT_NOEXCEPT(0 < Eq);
>> +  ASSERT_NOEXCEPT(Eq < 0);
>> +  ASSERT_NOEXCEPT(0 <= Eq);
>> +  ASSERT_NOEXCEPT(Eq <= 0);
>> +  ASSERT_NOEXCEPT(0 > Eq);
>> +  ASSERT_NOEXCEPT(Eq > 0);
>> +  ASSERT_NOEXCEPT(0 >= Eq);
>> +  ASSERT_NOEXCEPT(Eq >= 0);
>> +#ifndef TEST_HAS_NO_SPACESHIP_OPERATOR
>> +  ASSERT_NOEXCEPT(0 <=> Eq);
>> +  ASSERT_NOEXCEPT(Eq <=> 0);
>> +  ASSERT_SAME_TYPE(decltype(Eq <=> 0), std::strong_ordering);
>> +  ASSERT_SAME_TYPE(decltype(0 <=> Eq), std::strong_ordering);
>> +#endif
>> +}
>> +
>> +constexpr bool test_conversion() {
>> +  static_assert(std::is_convertible<const std::strong_ordering&,
>> +      std::weak_equality>::value, "");
>> +  { // value == 0
>> +    auto V = std::strong_ordering::equivalent;
>> +    std::weak_equality WV = V;
>> +    assert(WV == 0);
>> +  }
>> +  std::strong_ordering WeakTestCases[] = {
>> +      std::strong_ordering::less,
>> +      std::strong_ordering::greater,
>> +  };
>> +  for (auto V : WeakTestCases)
>> +  { // value != 0
>> +    std::weak_equality WV = V;
>> +    assert(WV != 0);
>> +  }
>> +  static_assert(std::is_convertible<const std::strong_ordering&,
>> +      std::strong_equality>::value, "");
>> +  { // value == 0
>> +    auto V = std::strong_ordering::equivalent;
>> +    std::strong_equality WV = V;
>> +    assert(WV == 0);
>> +  }
>> +  { // value == 0
>> +    auto V = std::strong_ordering::equal;
>> +    std::strong_equality WV = V;
>> +    assert(WV == 0);
>> +  }
>> +  std::strong_ordering StrongTestCases[] = {
>> +      std::strong_ordering::less,
>> +      std::strong_ordering::greater,
>> +  };
>> +  for (auto V : StrongTestCases)
>> +  { // value != 0
>> +    std::strong_equality WV = V;
>> +    assert(WV != 0);
>> +  }
>> +
>> +  static_assert(std::is_convertible<const std::strong_ordering&,
>> +      std::partial_ordering>::value, "");
>> +  { // value == 0
>> +    auto V = std::strong_ordering::equivalent;
>> +    std::partial_ordering WV = V;
>> +    assert(WV == 0);
>> +  }
>> +  { // value < 0
>> +    auto V = std::strong_ordering::less;
>> +    std::partial_ordering WV = V;
>> +    assert(WV < 0);
>> +  }
>> +  { // value > 0
>> +    auto V = std::strong_ordering::greater;
>> +    std::partial_ordering WV = V;
>> +    assert(WV > 0);
>> +  }
>> +
>> +  static_assert(std::is_convertible<const std::strong_ordering&,
>> +      std::weak_ordering>::value, "");
>> +  { // value == 0
>> +    auto V = std::strong_ordering::equivalent;
>> +    std::weak_ordering WV = V;
>> +    assert(WV == 0);
>> +  }
>> +  { // value < 0
>> +    auto V = std::strong_ordering::less;
>> +    std::weak_ordering WV = V;
>> +    assert(WV < 0);
>> +  }
>> +  { // value > 0
>> +    auto V = std::strong_ordering::greater;
>> +    std::weak_ordering WV = V;
>> +    assert(WV > 0);
>> +  }
>> +  return true;
>> +}
>> +
>> +constexpr bool test_constexpr() {
>> +  auto& Eq = std::strong_ordering::equal;
>> +  auto& Equiv = std::strong_ordering::equivalent;
>> +  auto& Less = std::strong_ordering::less;
>> +  auto& Greater = std::strong_ordering::greater;
>> +  struct {
>> +    std::strong_ordering Value;
>> +    bool ExpectEq;
>> +    bool ExpectNeq;
>> +    bool ExpectLess;
>> +    bool ExpectGreater;
>> +  } TestCases[] = {
>> +      {Eq, true, false, false, false},
>> +      {Equiv, true, false, false, false},
>> +      {Less, false, true, true, false},
>> +      {Greater, false, true, false, true},
>> +  };
>> +  for (auto TC : TestCases) {
>> +    auto V = TC.Value;
>> +    assert((V == 0) == TC.ExpectEq);
>> +    assert((0 == V) == TC.ExpectEq);
>> +    assert((V != 0) == TC.ExpectNeq);
>> +    assert((0 != V) == TC.ExpectNeq);
>> +
>> +    assert((V < 0) == TC.ExpectLess);
>> +    assert((V > 0) == TC.ExpectGreater);
>> +    assert((V <= 0) == (TC.ExpectLess || TC.ExpectEq));
>> +    assert((V >= 0) == (TC.ExpectGreater || TC.ExpectEq));
>> +
>> +    assert((0 < V) == TC.ExpectGreater);
>> +    assert((0 > V) == TC.ExpectLess);
>> +    assert((0 <= V) == (TC.ExpectGreater || TC.ExpectEq));
>> +    assert((0 >= V) == (TC.ExpectLess || TC.ExpectEq));
>> +  }
>> +#ifndef TEST_HAS_NO_SPACESHIP_OPERATOR
>> +  {
>> +    std::strong_ordering res = (Eq <=> 0);
>> +    ((void)res);
>> +    res = (0 <=> Eq);
>> +    ((void)res);
>> +  }
>> +  enum ExpectRes {
>> +    ER_Greater,
>> +    ER_Less,
>> +    ER_Equiv
>> +  };
>> +  struct {
>> +    std::strong_ordering Value;
>> +    ExpectRes Expect;
>> +  } SpaceshipTestCases[] = {
>> +      {std::strong_ordering::equivalent, ER_Equiv},
>> +      {std::strong_ordering::less, ER_Less},
>> +      {std::strong_ordering::greater, ER_Greater},
>> +  };
>> +  for (auto TC : SpaceshipTestCases)
>> +  {
>> +    std::strong_ordering Res = (0 <=> TC.Value);
>> +    switch (TC.Expect) {
>> +    case ER_Equiv:
>> +      assert(Res == 0);
>> +      assert(0 == Res);
>> +      break;
>> +    case ER_Less:
>> +      assert(Res < 0);
>> +      break;
>> +    case ER_Greater:
>> +      assert(Res > 0);
>> +      break;
>> +    }
>> +  }
>> +#endif
>> +
>> +  return true;
>> +}
>> +
>> +int main() {
>> +  test_static_members();
>> +  test_signatures();
>> +  static_assert(test_conversion(), "conversion test failed");
>> +  static_assert(test_constexpr(), "constexpr test failed");
>> +}
>>
>> Added: libcxx/trunk/test/std/language.support/cmp/cmp.weakeq/cmp.
>> weakeq.pass.cpp
>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/la
>> nguage.support/cmp/cmp.weakeq/cmp.weakeq.pass.cpp?rev=329460&view=auto
>> ============================================================
>> ==================
>> --- libcxx/trunk/test/std/language.support/cmp/cmp.weakeq/cmp.weakeq.pass.cpp
>> (added)
>> +++ libcxx/trunk/test/std/language.support/cmp/cmp.weakeq/cmp.weakeq.pass.cpp
>> Fri Apr  6 14:37:23 2018
>> @@ -0,0 +1,70 @@
>> +//===------------------------------------------------------
>> ----------------===//
>> +//
>> +//                     The LLVM Compiler Infrastructure
>> +//
>> +// This file is dual licensed under the MIT and the University of
>> Illinois Open
>> +// Source Licenses. See LICENSE.TXT for details.
>> +//
>> +//===------------------------------------------------------
>> ----------------===//
>> +
>> +// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17
>> +
>> +// <compare>
>> +
>> +// class weak_equality
>> +
>> +
>> +#include <compare>
>> +#include <cassert>
>> +#include "test_macros.h"
>> +
>> +const volatile void* volatile sink;
>> +
>> +void test_static_members() {
>> +  DoNotOptimize(&std::weak_equality::equivalent);
>> +  DoNotOptimize(&std::weak_equality::nonequivalent);
>> +}
>> +
>> +void test_signatures() {
>> +  auto& Eq = std::weak_equality::equivalent;
>> +
>> +  ASSERT_NOEXCEPT(Eq == 0);
>> +  ASSERT_NOEXCEPT(0 == Eq);
>> +  ASSERT_NOEXCEPT(Eq != 0);
>> +  ASSERT_NOEXCEPT(0 != Eq);
>> +#ifndef TEST_HAS_NO_SPACESHIP_OPERATOR
>> +  ASSERT_NOEXCEPT(0 <=> Eq);
>> +  ASSERT_NOEXCEPT(Eq <=> 0);
>> +  ASSERT_SAME_TYPE(decltype(Eq <=> 0), std::weak_equality);
>> +  ASSERT_SAME_TYPE(decltype(0 <=> Eq), std::weak_equality);
>> +#endif
>> +}
>> +
>> +constexpr bool test_constexpr() {
>> +  auto& Eq = std::weak_equality::equivalent;
>> +  auto& NEq = std::weak_equality::nonequivalent;
>> +  assert((Eq == 0) == true);
>> +  assert((0 == Eq) == true);
>> +  assert((NEq == 0) == false);
>> +  assert((0 == NEq) == false);
>> +
>> +  assert((Eq != 0) == false);
>> +  assert((0 != Eq) == false);
>> +  assert((NEq != 0) == true);
>> +  assert((0 != NEq) == true);
>> +
>> +#ifndef TEST_HAS_NO_SPACESHIP_OPERATOR
>> +  std::weak_equality res = (Eq <=> 0);
>> +  ((void)res);
>> +  res = (0 <=> Eq);
>> +  ((void)res);
>> +#endif
>> +
>> +  return true;
>> +}
>> +
>> +int main() {
>> +  test_static_members();
>> +  test_signatures();
>> +  static_assert(test_constexpr(), "constexpr test failed");
>> +}
>>
>> Added: libcxx/trunk/test/std/language.support/cmp/cmp.weakord/
>> weakord.pass.cpp
>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/la
>> nguage.support/cmp/cmp.weakord/weakord.pass.cpp?rev=329460&view=auto
>> ============================================================
>> ==================
>> --- libcxx/trunk/test/std/language.support/cmp/cmp.weakord/weakord.pass.cpp
>> (added)
>> +++ libcxx/trunk/test/std/language.support/cmp/cmp.weakord/weakord.pass.cpp
>> Fri Apr  6 14:37:23 2018
>> @@ -0,0 +1,169 @@
>> +//===------------------------------------------------------
>> ----------------===//
>> +//
>> +//                     The LLVM Compiler Infrastructure
>> +//
>> +// This file is dual licensed under the MIT and the University of
>> Illinois Open
>> +// Source Licenses. See LICENSE.TXT for details.
>> +//
>> +//===------------------------------------------------------
>> ----------------===//
>> +
>> +// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17
>> +
>> +// <compare>
>> +
>> +// class weak_ordering
>> +
>> +
>> +#include <compare>
>> +#include <type_traits>
>> +#include <cassert>
>> +
>> +#include "test_macros.h"
>> +
>> +const volatile void* volatile sink;
>> +
>> +void test_static_members() {
>> +  DoNotOptimize(&std::weak_ordering::less);
>> +  DoNotOptimize(&std::weak_ordering::equivalent);
>> +  DoNotOptimize(&std::weak_ordering::greater);
>> +}
>> +
>> +void test_signatures() {
>> +  auto& Eq = std::weak_ordering::equivalent;
>> +
>> +  ASSERT_NOEXCEPT(Eq == 0);
>> +  ASSERT_NOEXCEPT(0 == Eq);
>> +  ASSERT_NOEXCEPT(Eq != 0);
>> +  ASSERT_NOEXCEPT(0 != Eq);
>> +  ASSERT_NOEXCEPT(0 < Eq);
>> +  ASSERT_NOEXCEPT(Eq < 0);
>> +  ASSERT_NOEXCEPT(0 <= Eq);
>> +  ASSERT_NOEXCEPT(Eq <= 0);
>> +  ASSERT_NOEXCEPT(0 > Eq);
>> +  ASSERT_NOEXCEPT(Eq > 0);
>> +  ASSERT_NOEXCEPT(0 >= Eq);
>> +  ASSERT_NOEXCEPT(Eq >= 0);
>> +#ifndef TEST_HAS_NO_SPACESHIP_OPERATOR
>> +  ASSERT_NOEXCEPT(0 <=> Eq);
>> +  ASSERT_NOEXCEPT(Eq <=> 0);
>> +  ASSERT_SAME_TYPE(decltype(Eq <=> 0), std::weak_ordering);
>> +  ASSERT_SAME_TYPE(decltype(0 <=> Eq), std::weak_ordering);
>> +#endif
>> +}
>> +
>> +constexpr bool test_conversion() {
>> +  static_assert(std::is_convertible<const std::weak_ordering&,
>> +      std::weak_equality>::value, "");
>> +  { // value == 0
>> +    auto V = std::weak_ordering::equivalent;
>> +    std::weak_equality WV = V;
>> +    assert(WV == 0);
>> +  }
>> +  std::weak_ordering WeakTestCases[] = {
>> +      std::weak_ordering::less,
>> +      std::weak_ordering::greater,
>> +  };
>> +  for (auto V : WeakTestCases)
>> +  { // value != 0
>> +    std::weak_equality WV = V;
>> +    assert(WV != 0);
>> +  }
>> +  static_assert(std::is_convertible<const std::weak_ordering&,
>> +      std::partial_ordering>::value, "");
>> +  { // value == 0
>> +    auto V = std::weak_ordering::equivalent;
>> +    std::partial_ordering WV = V;
>> +    assert(WV == 0);
>> +  }
>> +  { // value < 0
>> +    auto V = std::weak_ordering::less;
>> +    std::partial_ordering WV = V;
>> +    assert(WV < 0);
>> +  }
>> +  { // value > 0
>> +    auto V = std::weak_ordering::greater;
>> +    std::partial_ordering WV = V;
>> +    assert(WV > 0);
>> +  }
>> +  return true;
>> +}
>> +
>> +constexpr bool test_constexpr() {
>> +  auto& Eq = std::weak_ordering::equivalent;
>> +  auto& Less = std::weak_ordering::less;
>> +  auto& Greater = std::weak_ordering::greater;
>> +  struct {
>> +    std::weak_ordering Value;
>> +    bool ExpectEq;
>> +    bool ExpectNeq;
>> +    bool ExpectLess;
>> +    bool ExpectGreater;
>> +  } TestCases[] = {
>> +      {Eq, true, false, false, false},
>> +      {Less, false, true, true, false},
>> +      {Greater, false, true, false, true},
>> +  };
>> +  for (auto TC : TestCases) {
>> +    auto V = TC.Value;
>> +    assert((V == 0) == TC.ExpectEq);
>> +    assert((0 == V) == TC.ExpectEq);
>> +    assert((V != 0) == TC.ExpectNeq);
>> +    assert((0 != V) == TC.ExpectNeq);
>> +
>> +    assert((V < 0) == TC.ExpectLess);
>> +    assert((V > 0) == TC.ExpectGreater);
>> +    assert((V <= 0) == (TC.ExpectLess || TC.ExpectEq));
>> +    assert((V >= 0) == (TC.ExpectGreater || TC.ExpectEq));
>> +
>> +    assert((0 < V) == TC.ExpectGreater);
>> +    assert((0 > V) == TC.ExpectLess);
>> +    assert((0 <= V) == (TC.ExpectGreater || TC.ExpectEq));
>> +    assert((0 >= V) == (TC.ExpectLess || TC.ExpectEq));
>> +  }
>> +#ifndef TEST_HAS_NO_SPACESHIP_OPERATOR
>> +  {
>> +    std::weak_ordering res = (Eq <=> 0);
>> +    ((void)res);
>> +    res = (0 <=> Eq);
>> +    ((void)res);
>> +  }
>> +  enum ExpectRes {
>> +    ER_Greater,
>> +    ER_Less,
>> +    ER_Equiv
>> +  };
>> +  struct {
>> +    std::weak_ordering Value;
>> +    ExpectRes Expect;
>> +  } SpaceshipTestCases[] = {
>> +      {std::weak_ordering::equivalent, ER_Equiv},
>> +      {std::weak_ordering::less, ER_Less},
>> +      {std::weak_ordering::greater, ER_Greater},
>> +  };
>> +  for (auto TC : SpaceshipTestCases)
>> +  {
>> +    std::weak_ordering Res = (0 <=> TC.Value);
>> +    switch (TC.Expect) {
>> +    case ER_Equiv:
>> +      assert(Res == 0);
>> +      assert(0 == Res);
>> +      break;
>> +    case ER_Less:
>> +      assert(Res < 0);
>> +      break;
>> +    case ER_Greater:
>> +      assert(Res > 0);
>> +      break;
>> +    }
>> +  }
>> +#endif
>> +
>> +  return true;
>> +}
>> +
>> +int main() {
>> +  test_static_members();
>> +  test_signatures();
>> +  static_assert(test_conversion(), "conversion test failed");
>> +  static_assert(test_constexpr(), "constexpr test failed");
>> +}
>>
>> Modified: libcxx/trunk/test/support/test_macros.h
>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/suppor
>> t/test_macros.h?rev=329460&r1=329459&r2=329460&view=diff
>> ============================================================
>> ==================
>> --- libcxx/trunk/test/support/test_macros.h (original)
>> +++ libcxx/trunk/test/support/test_macros.h Fri Apr  6 14:37:23 2018
>> @@ -169,6 +169,11 @@
>>  #define TEST_SAFE_STATIC
>>  #endif
>>
>> +// FIXME: Fix this feature check when either (A) a compiler provides a
>> complete
>> +// implementation, or (b) a feature check macro is specified
>> +#define TEST_HAS_NO_SPACESHIP_OPERATOR
>> +
>> +
>>  #if TEST_STD_VER < 11
>>  #define ASSERT_NOEXCEPT(...)
>>  #define ASSERT_NOT_NOEXCEPT(...)
>>
>>
>> _______________________________________________
>> cfe-commits mailing list
>> cfe-commits at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20180406/cef10da6/attachment-0001.html>


More information about the cfe-commits mailing list