diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -190,7 +190,7 @@ ------------------------------------------------- ----------------- ``__cpp_lib_bind_front`` ``201907L`` ------------------------------------------------- ----------------- - ``__cpp_lib_bit_cast`` *unimplemented* + ``__cpp_lib_bit_cast`` ``201806L`` ------------------------------------------------- ----------------- ``__cpp_lib_bitops`` *unimplemented* ------------------------------------------------- ----------------- diff --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv --- a/libcxx/docs/Status/Cxx20Papers.csv +++ b/libcxx/docs/Status/Cxx20Papers.csv @@ -29,7 +29,7 @@ "`P0019R8 `__","LWG","Atomic Ref","Rapperswil","","" "`P0458R2 `__","LWG","Checking for Existence of an Element in Associative Containers","Rapperswil","|Complete|","13.0" "`P0475R1 `__","LWG","LWG 2511: guaranteed copy elision for piecewise construction","Rapperswil","|Complete|","" -"`P0476R2 `__","LWG","Bit-casting object representations","Rapperswil","","" +"`P0476R2 `__","LWG","Bit-casting object representations","Rapperswil","|Complete|","14.0" "`P0528R3 `__","CWG","The Curious Case of Padding Bits, Featuring Atomic Compare-and-Exchange","Rapperswil","","" "`P0542R5 `__","CWG","Support for contract based programming in C++","Rapperswil","*Removed in Cologne*","n/a" "`P0556R3 `__","LWG","Integral power-of-2 operations","Rapperswil","|Complete|","9.0" @@ -199,4 +199,4 @@ "`P2216R3 `__","LWG",std::format improvements,"June 2021","","" "`P2281R1 `__","LWG",Clarifying range adaptor objects,"June 2021","","" "`P2328R1 `__","LWG",join_view should join all views of ranges,"June 2021","","" -"`P2367R0 `__","LWG",Remove misuses of list-initialization from Clause 24,"June 2021","","" \ No newline at end of file +"`P2367R0 `__","LWG",Remove misuses of list-initialization from Clause 24,"June 2021","","" diff --git a/libcxx/docs/UsingLibcxx.rst b/libcxx/docs/UsingLibcxx.rst --- a/libcxx/docs/UsingLibcxx.rst +++ b/libcxx/docs/UsingLibcxx.rst @@ -338,6 +338,7 @@ * ``upper_bound`` * ``lock_guard``'s constructors * ``as_const`` +* ``bit_cast`` * ``forward`` * ``move`` * ``move_if_noexcept`` diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -94,6 +94,7 @@ __algorithm/upper_bound.h __availability __bit_reference + __bit/bit_cast.h __bits __bsd_locale_defaults.h __bsd_locale_fallbacks.h @@ -101,9 +102,13 @@ __charconv/from_chars_result.h __charconv/to_chars_result.h __compare/common_comparison_category.h + __compare/compare_three_way.h __compare/compare_three_way_result.h __compare/ordering.h + __compare/partial_order.h + __compare/strong_order.h __compare/three_way_comparable.h + __compare/weak_order.h __concepts/arithmetic.h __concepts/assignable.h __concepts/boolean_testable.h @@ -284,6 +289,7 @@ __utility/move.h __utility/pair.h __utility/piecewise_construct.h + __utility/priority_tag.h __utility/rel_ops.h __utility/swap.h __utility/to_underlying.h diff --git a/libcxx/include/__bit/bit_cast.h b/libcxx/include/__bit/bit_cast.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__bit/bit_cast.h @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___BIT_BIT_CAST_H +#define _LIBCPP___BIT_BIT_CAST_H + +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER > 17 + +template && + is_trivially_copyable_v<_FromType> +>> +_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI +constexpr _ToType bit_cast(_FromType const& __from) noexcept { + return __builtin_bit_cast(_ToType, __from); +} + +#endif // _LIBCPP_STD_VER > 17 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___BIT_BIT_CAST_H diff --git a/libcxx/include/__compare/compare_three_way.h b/libcxx/include/__compare/compare_three_way.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__compare/compare_three_way.h @@ -0,0 +1,41 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___COMPARE_COMPARE_THREE_WAY_H +#define _LIBCPP___COMPARE_COMPARE_THREE_WAY_H + +#include <__config> +#include <__compare/three_way_comparable.h> +#include <__utility/forward.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) + +struct _LIBCPP_TEMPLATE_VIS compare_three_way +{ + template + requires three_way_comparable_with<_T1, _T2> + constexpr _LIBCPP_INLINE_VISIBILITY + auto operator()(_T1&& __t, _T2&& __u) const + noexcept(noexcept(_VSTD::forward<_T1>(__t) <=> _VSTD::forward<_T2>(__u))) + { return _VSTD::forward<_T1>(__t) <=> _VSTD::forward<_T2>(__u); } + + using is_transparent = void; +}; + +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___COMPARE_COMPARE_THREE_WAY_H diff --git a/libcxx/include/__compare/partial_order.h b/libcxx/include/__compare/partial_order.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__compare/partial_order.h @@ -0,0 +1,79 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___COMPARE_PARTIAL_ORDER +#define _LIBCPP___COMPARE_PARTIAL_ORDER + +#include <__compare/compare_three_way.h> +#include <__compare/ordering.h> +#include <__compare/weak_order.h> +#include <__config> +#include <__utility/forward.h> +#include <__utility/priority_tag.h> +#include + +#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER +#pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) + +// [cmp.alg] +namespace __partial_order { + struct __fn { + template + requires is_same_v, decay_t<_Fp>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto + __go(_Ep&& __e, _Fp&& __f, _PriorityTag<2>) + noexcept(noexcept( partial_ordering(partial_order(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))) )) + -> decltype( partial_ordering(partial_order(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))) ) + { + return partial_ordering(partial_order(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))); + } + + template + requires is_same_v, decay_t<_Fp>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto + __go(_Ep&& __e, _Fp&& __f, _PriorityTag<1>) + noexcept(noexcept( partial_ordering(compare_three_way()(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))) )) + -> decltype( partial_ordering(compare_three_way()(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))) ) + { + return partial_ordering(compare_three_way()(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))); + } + + template + requires is_same_v, decay_t<_Fp>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto + __go(_Ep&& __e, _Fp&& __f, _PriorityTag<0>) + noexcept(noexcept( partial_ordering(_VSTD::weak_order(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))) )) + -> decltype( partial_ordering(_VSTD::weak_order(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))) ) + { + return partial_ordering(_VSTD::weak_order(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Ep&& __e, _Fp&& __f) const + noexcept(noexcept( __go(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f), _PriorityTag<2>()) )) + -> decltype( __go(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f), _PriorityTag<2>()) ) + { + return __go(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f), _PriorityTag<2>()); + } + }; +} // namespace __partial_order + +inline namespace __cpo { + inline constexpr auto partial_order = __partial_order::__fn{}; +} // namespace __cpo + +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___COMPARE_PARTIAL_ORDER diff --git a/libcxx/include/__compare/strong_order.h b/libcxx/include/__compare/strong_order.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__compare/strong_order.h @@ -0,0 +1,142 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___COMPARE_STRONG_ORDER +#define _LIBCPP___COMPARE_STRONG_ORDER + +#include <__bit/bit_cast.h> +#include <__compare/compare_three_way.h> +#include <__compare/ordering.h> +#include <__config> +#include <__utility/forward.h> +#include <__utility/priority_tag.h> +#include +#include +#include +#include + +#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER +#pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) + +// [cmp.alg] +namespace __strong_order { + struct __fn { + template + requires is_same_v, decay_t<_Fp>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto + __go(_Ep&& __e, _Fp&& __f, _PriorityTag<2>) + noexcept(noexcept( strong_ordering(strong_order(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))) )) + -> decltype( strong_ordering(strong_order(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))) ) + { + return strong_ordering(strong_order(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))); + } + + template> + requires is_same_v<_Dp, decay_t<_Fp>> && is_floating_point_v<_Dp> + _LIBCPP_HIDE_FROM_ABI static constexpr strong_ordering + __go(_Ep&& __e, _Fp&& __f, _PriorityTag<1>) noexcept + { + if constexpr (numeric_limits<_Dp>::is_iec559 && sizeof(_Dp) == sizeof(int32_t)) { + int32_t __rx = _VSTD::bit_cast(__e); + int32_t __ry = _VSTD::bit_cast(__f); + __rx = (__rx < 0) ? (numeric_limits::min() - __rx - 1) : __rx; + __ry = (__ry < 0) ? (numeric_limits::min() - __ry - 1) : __ry; + return (__rx <=> __ry); + } else if constexpr (numeric_limits<_Dp>::is_iec559 && sizeof(_Dp) == sizeof(int64_t)) { + int64_t __rx = _VSTD::bit_cast(__e); + int64_t __ry = _VSTD::bit_cast(__f); + __rx = (__rx < 0) ? (numeric_limits::min() - __rx - 1) : __rx; + __ry = (__ry < 0) ? (numeric_limits::min() - __ry - 1) : __ry; + return (__rx <=> __ry); + } else if (__e < __f) { + return strong_ordering::less; + } else if (__e > __f) { + return strong_ordering::greater; + } else if (__e == __f) { + if constexpr (numeric_limits<_Dp>::radix == 2) { + return _VSTD::signbit(__f) <=> _VSTD::signbit(__e); + } else { + // This is bullet 3 of the IEEE754 algorithm, relevant + // only for decimal floating-point; + // see https://stackoverflow.com/questions/69068075/ + if (__e == 0 || _VSTD::isinf(__e)) { + return _VSTD::signbit(__f) <=> _VSTD::signbit(__e); + } else { + int __eexp, __fexp; + (void)_VSTD::frexp(__e, &__eexp); + (void)_VSTD::frexp(__f, &__fexp); + return (__e < 0) ? (__eexp <=> __fexp) : (__fexp <=> __eexp); + } + } + } else { + // They're unordered, so one of them must be a NAN. + // The order is -QNAN, -SNAN, numbers, +SNAN, +QNAN. + bool __e_is_nan = _VSTD::isnan(__e); + bool __f_is_nan = _VSTD::isnan(__f); + bool __e_is_negative = _VSTD::signbit(__e); + bool __f_is_negative = _VSTD::signbit(__f); + using _IntType = std::conditional_t< + sizeof(__e) == sizeof(int), int, std::conditional_t< + sizeof(__e) == sizeof(long), long, std::conditional_t< + sizeof(__e) == sizeof(long long), long long, void>> + >; + static_assert(!std::is_same_v<_IntType, void>, "std::strong_order is unimplemented for this floating-point type"); + if (__e_is_nan && __f_is_nan) { + // Order by sign bit, then by "payload bits" (we'll just use bit_cast). + if (__e_is_negative != __f_is_negative) { + return (__f_is_negative <=> __e_is_negative); + } else { + return _VSTD::bit_cast<_IntType>(__e) <=> _VSTD::bit_cast<_IntType>(__f); + } + } else if (__e_is_nan) { + return __e_is_negative ? strong_ordering::less : strong_ordering::greater; + } else { + return __f_is_negative ? strong_ordering::greater : strong_ordering::less; + } + } + } + + template + requires is_same_v, decay_t<_Fp>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto + __go(_Ep&& __e, _Fp&& __f, _PriorityTag<0>) + noexcept(noexcept( strong_ordering(compare_three_way()(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))) )) + -> decltype( strong_ordering(compare_three_way()(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))) ) + { + return strong_ordering(compare_three_way()(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Ep&& __e, _Fp&& __f) const + noexcept(noexcept( __go(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f), _PriorityTag<2>()) )) + -> decltype( __go(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f), _PriorityTag<2>()) ) + { + return __go(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f), _PriorityTag<2>()); + } + }; +} // namespace __strong_order + +inline namespace __cpo { + inline constexpr auto strong_order = __strong_order::__fn{}; +} // namespace __cpo + +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___COMPARE_STRONG_ORDER diff --git a/libcxx/include/__compare/weak_order.h b/libcxx/include/__compare/weak_order.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__compare/weak_order.h @@ -0,0 +1,108 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___COMPARE_WEAK_ORDER +#define _LIBCPP___COMPARE_WEAK_ORDER + +#include <__compare/compare_three_way.h> +#include <__compare/ordering.h> +#include <__compare/strong_order.h> +#include <__config> +#include <__utility/forward.h> +#include <__utility/priority_tag.h> +#include +#include + +#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER +#pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) + +// [cmp.alg] +namespace __weak_order { + struct __fn { + template + requires is_same_v, decay_t<_Fp>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto + __go(_Ep&& __e, _Fp&& __f, _PriorityTag<3>) + noexcept(noexcept( weak_ordering(weak_order(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))) )) + -> decltype( weak_ordering(weak_order(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))) ) + { + return weak_ordering(weak_order(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))); + } + + template> + requires is_same_v<_Dp, decay_t<_Fp>> && is_floating_point_v<_Dp> + _LIBCPP_HIDE_FROM_ABI static constexpr weak_ordering + __go(_Ep&& __e, _Fp&& __f, _PriorityTag<2>) noexcept + { + std::partial_ordering __po = (__e <=> __f); + if (__po == std::partial_ordering::less) { + return std::weak_ordering::less; + } else if (__po == std::partial_ordering::equivalent) { + return std::weak_ordering::equivalent; + } else if (__po == std::partial_ordering::greater) { + return std::weak_ordering::greater; + } else { + // Otherwise, at least one of them is a NaN. + bool __e_is_nan = _VSTD::isnan(__e); + bool __f_is_nan = _VSTD::isnan(__f); + bool __e_is_negative = _VSTD::signbit(__e); + bool __f_is_negative = _VSTD::signbit(__f); + if (__e_is_nan && __f_is_nan) { + return (__f_is_negative <=> __e_is_negative); + } else if (__e_is_nan) { + return __e_is_negative ? weak_ordering::less : weak_ordering::greater; + } else { + return __f_is_negative ? weak_ordering::greater : weak_ordering::less; + } + } + } + + template + requires is_same_v, decay_t<_Fp>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto + __go(_Ep&& __e, _Fp&& __f, _PriorityTag<1>) + noexcept(noexcept( weak_ordering(compare_three_way()(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))) )) + -> decltype( weak_ordering(compare_three_way()(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))) ) + { + return weak_ordering(compare_three_way()(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))); + } + + template + requires is_same_v, decay_t<_Fp>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto + __go(_Ep&& __e, _Fp&& __f, _PriorityTag<0>) + noexcept(noexcept( weak_ordering(_VSTD::strong_order(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))) )) + -> decltype( weak_ordering(_VSTD::strong_order(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))) ) + { + return weak_ordering(_VSTD::strong_order(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Ep&& __e, _Fp&& __f) const + noexcept(noexcept( __go(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f), _PriorityTag<3>()) )) + -> decltype( __go(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f), _PriorityTag<3>()) ) + { + return __go(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f), _PriorityTag<3>()); + } + }; +} // namespace __weak_order + +inline namespace __cpo { + inline constexpr auto weak_order = __weak_order::__fn{}; +} // namespace __cpo + +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___COMPARE_WEAK_ORDER diff --git a/libcxx/include/__memory/pointer_traits.h b/libcxx/include/__memory/pointer_traits.h --- a/libcxx/include/__memory/pointer_traits.h +++ b/libcxx/include/__memory/pointer_traits.h @@ -173,7 +173,9 @@ } // enable_if is needed here to avoid instantiating checks for fancy pointers on raw pointers -template ::value> > +template ::value && !is_array<_Pointer>::value && !is_function<_Pointer>::value +> > _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR typename decay::__call(declval()))>::type __to_address(const _Pointer& __p) _NOEXCEPT { @@ -199,6 +201,12 @@ }; #if _LIBCPP_STD_VER > 17 +template +inline _LIBCPP_INLINE_VISIBILITY constexpr +auto to_address(_Tp *__p) noexcept { + return _VSTD::__to_address(__p); +} + template inline _LIBCPP_INLINE_VISIBILITY constexpr auto to_address(const _Pointer& __p) noexcept { diff --git a/libcxx/include/__ranges/data.h b/libcxx/include/__ranges/data.h --- a/libcxx/include/__ranges/data.h +++ b/libcxx/include/__ranges/data.h @@ -68,7 +68,7 @@ } // end namespace __data inline namespace __cpo { - inline constexpr const auto data = __data::__fn{}; + inline constexpr auto data = __data::__fn{}; } // namespace __cpo } // namespace ranges diff --git a/libcxx/include/__ranges/size.h b/libcxx/include/__ranges/size.h --- a/libcxx/include/__ranges/size.h +++ b/libcxx/include/__ranges/size.h @@ -114,7 +114,7 @@ } inline namespace __cpo { - inline constexpr const auto ssize = __ssize::__fn{}; + inline constexpr auto ssize = __ssize::__fn{}; } // namespace __cpo } // namespace ranges diff --git a/libcxx/include/__utility/priority_tag.h b/libcxx/include/__utility/priority_tag.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__utility/priority_tag.h @@ -0,0 +1,26 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___UTILITY_PRIORITY_TAG_H +#define _LIBCPP___UTILITY_PRIORITY_TAG_H + +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template struct _PriorityTag : _PriorityTag<_Ip - 1> {}; +template<> struct _PriorityTag<0> {}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___UTILITY_PRIORITY_TAG_H diff --git a/libcxx/include/bit b/libcxx/include/bit --- a/libcxx/include/bit +++ b/libcxx/include/bit @@ -14,6 +14,9 @@ bit synopsis namespace std { + // [bit.cast], bit_cast + template + constexpr To bit_cast(const From& from) noexcept; // C++20 // [bit.pow.two], integral powers of 2 template @@ -54,8 +57,9 @@ */ -#include <__config> +#include <__bit/bit_cast.h> #include <__bits> // __libcpp_clz +#include <__config> #include <__debug> #include #include diff --git a/libcxx/include/compare b/libcxx/include/compare --- a/libcxx/include/compare +++ b/libcxx/include/compare @@ -47,6 +47,9 @@ template using compare_three_way_result_t = typename compare_three_way_result::type; + // [comparisons.three.way], class compare_three_way + struct compare_three_way; + // [cmp.alg], comparison algorithms template constexpr strong_ordering strong_order(const T& a, const T& b); template constexpr weak_ordering weak_order(const T& a, const T& b); @@ -133,27 +136,13 @@ */ #include <__compare/common_comparison_category.h> +#include <__compare/compare_three_way.h> #include <__compare/compare_three_way_result.h> #include <__compare/ordering.h> +#include <__compare/partial_order.h> +#include <__compare/strong_order.h> #include <__compare/three_way_comparable.h> +#include <__compare/weak_order.h> #include <__config> -#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER -#pragma GCC system_header -#endif - -_LIBCPP_BEGIN_NAMESPACE_STD - -#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) - -// [cmp.alg], comparison algorithms -// TODO: unimplemented -template constexpr strong_ordering strong_order(const _Tp& __lhs, const _Tp& __rhs); -template constexpr weak_ordering weak_order(const _Tp& __lhs, const _Tp& __rhs); -template constexpr partial_ordering partial_order(const _Tp& __lhs, const _Tp& __rhs); - -#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) - -_LIBCPP_END_NAMESPACE_STD - #endif // _LIBCPP_COMPARE diff --git a/libcxx/include/functional b/libcxx/include/functional --- a/libcxx/include/functional +++ b/libcxx/include/functional @@ -135,6 +135,9 @@ bool operator()(const T& x, const T& y) const; }; +// [comparisons.three.way], class compare_three_way +struct compare_three_way; + template // in C++14 struct logical_and { bool operator()(const T& x, const T& y) const; @@ -488,6 +491,7 @@ */ #include <__algorithm/search.h> +#include <__compare/compare_three_way.h> #include <__config> #include <__debug> #include <__functional/binary_function.h> // TODO: deprecate diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -335,6 +335,10 @@ module bit { header "bit" export * + + module __bit { + module bit_cast { private header "__bit/bit_cast.h" } + } } module bitset { header "bitset" @@ -368,9 +372,13 @@ module __compare { module common_comparison_category { private header "__compare/common_comparison_category.h" } + module compare_three_way { private header "__compare/compare_three_way.h" } module compare_three_way_result { private header "__compare/compare_three_way_result.h" } module ordering { private header "__compare/ordering.h" } + module partial_order { private header "__compare/partial_order.h" } + module strong_order { private header "__compare/strong_order.h" } module three_way_comparable { private header "__compare/three_way_comparable.h" } + module weak_order { private header "__compare/weak_order.h" } } } module complex { @@ -818,6 +826,7 @@ module move { private header "__utility/move.h" } module pair { private header "__utility/pair.h" } module piecewise_construct { private header "__utility/piecewise_construct.h" } + module priority_tag { private header "__utility/priority_tag.h" } module rel_ops { private header "__utility/rel_ops.h" } module swap { private header "__utility/swap.h" } module to_underlying { private header "__utility/to_underlying.h" } diff --git a/libcxx/include/utility b/libcxx/include/utility --- a/libcxx/include/utility +++ b/libcxx/include/utility @@ -220,6 +220,7 @@ #include <__utility/move.h> #include <__utility/pair.h> #include <__utility/piecewise_construct.h> +#include <__utility/priority_tag.h> #include <__utility/rel_ops.h> #include <__utility/swap.h> #include <__utility/to_underlying.h> diff --git a/libcxx/include/version b/libcxx/include/version --- a/libcxx/include/version +++ b/libcxx/include/version @@ -286,7 +286,7 @@ # define __cpp_lib_barrier 201907L # endif # define __cpp_lib_bind_front 201907L -// # define __cpp_lib_bit_cast 201806L +# define __cpp_lib_bit_cast 201806L // # define __cpp_lib_bitops 201907L # define __cpp_lib_bounded_array_traits 201902L # if !defined(_LIBCPP_HAS_NO_CHAR8_T) diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/bit/bit_cast.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/bit/bit_cast.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/bit/bit_cast.module.verify.cpp @@ -0,0 +1,16 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: modules-build + +// WARNING: This test was generated by 'generate_private_header_tests.py' +// and should not be edited manually. + +// expected-error@*:* {{use of private header from outside its module: '__bit/bit_cast.h'}} +#include <__bit/bit_cast.h> diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/compare/compare_three_way.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/compare/compare_three_way.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/compare/compare_three_way.module.verify.cpp @@ -0,0 +1,16 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: modules-build + +// WARNING: This test was generated by 'generate_private_header_tests.py' +// and should not be edited manually. + +// expected-error@*:* {{use of private header from outside its module: '__compare/compare_three_way.h'}} +#include <__compare/compare_three_way.h> diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/compare/partial_order.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/compare/partial_order.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/compare/partial_order.module.verify.cpp @@ -0,0 +1,16 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: modules-build + +// WARNING: This test was generated by 'generate_private_header_tests.py' +// and should not be edited manually. + +// expected-error@*:* {{use of private header from outside its module: '__compare/partial_order.h'}} +#include <__compare/partial_order.h> diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/compare/strong_order.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/compare/strong_order.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/compare/strong_order.module.verify.cpp @@ -0,0 +1,16 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: modules-build + +// WARNING: This test was generated by 'generate_private_header_tests.py' +// and should not be edited manually. + +// expected-error@*:* {{use of private header from outside its module: '__compare/strong_order.h'}} +#include <__compare/strong_order.h> diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/compare/weak_order.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/compare/weak_order.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/compare/weak_order.module.verify.cpp @@ -0,0 +1,16 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: modules-build + +// WARNING: This test was generated by 'generate_private_header_tests.py' +// and should not be edited manually. + +// expected-error@*:* {{use of private header from outside its module: '__compare/weak_order.h'}} +#include <__compare/weak_order.h> diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/utility/priority_tag.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/utility/priority_tag.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/utility/priority_tag.module.verify.cpp @@ -0,0 +1,16 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: modules-build + +// WARNING: This test was generated by 'generate_private_header_tests.py' +// and should not be edited manually. + +// expected-error@*:* {{use of private header from outside its module: '__utility/priority_tag.h'}} +#include <__utility/priority_tag.h> diff --git a/libcxx/test/libcxx/diagnostics/nodiscard_extensions.pass.cpp b/libcxx/test/libcxx/diagnostics/nodiscard_extensions.pass.cpp --- a/libcxx/test/libcxx/diagnostics/nodiscard_extensions.pass.cpp +++ b/libcxx/test/libcxx/diagnostics/nodiscard_extensions.pass.cpp @@ -18,6 +18,7 @@ // be listed in `UsingLibcxx.rst` in the documentation for the extension. #include +#include // bit_cast #include // to_integer #include // identity #include @@ -170,8 +171,8 @@ std::to_integer(b); #endif -#if TEST_STD_VER >= 20 - // std::bit_cast(42); +#if TEST_STD_VER > 17 + std::bit_cast(42); #endif #if TEST_STD_VER > 20 diff --git a/libcxx/test/libcxx/diagnostics/nodiscard_extensions.verify.cpp b/libcxx/test/libcxx/diagnostics/nodiscard_extensions.verify.cpp --- a/libcxx/test/libcxx/diagnostics/nodiscard_extensions.verify.cpp +++ b/libcxx/test/libcxx/diagnostics/nodiscard_extensions.verify.cpp @@ -19,6 +19,7 @@ // ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_NODISCARD #include +#include // bit_cast #include // to_integer #include // identity #include @@ -329,8 +330,9 @@ std::to_integer(b); #endif -#if TEST_STD_VER >= 20 - // std::bit_cast(42); +#if TEST_STD_VER > 17 + // expected-warning-re@+1 {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}} + std::bit_cast(42); #endif #if TEST_STD_VER > 20 diff --git a/libcxx/test/libcxx/utilities/memory/pointer.conversion/to_address.pass.cpp b/libcxx/test/libcxx/utilities/memory/pointer.conversion/to_address.pass.cpp --- a/libcxx/test/libcxx/utilities/memory/pointer.conversion/to_address.pass.cpp +++ b/libcxx/test/libcxx/utilities/memory/pointer.conversion/to_address.pass.cpp @@ -137,6 +137,14 @@ assert(std::__to_address(p8b) == p8_nil); ASSERT_SAME_TYPE(decltype(std::__to_address(p8b)), decltype(p8_nil)); + int p9[2] = {}; + assert(std::__to_address(p9) == p9); + ASSERT_SAME_TYPE(decltype(std::__to_address(p9)), int*); + + const int p10[2] = {}; + assert(std::__to_address(p10) == p10); + ASSERT_SAME_TYPE(decltype(std::__to_address(p10)), const int*); + return true; } diff --git a/libcxx/test/libcxx/utilities/memory/pointer.conversion/to_address_on_funcptr.verify.cpp b/libcxx/test/libcxx/utilities/memory/pointer.conversion/to_address_on_funcptr.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/memory/pointer.conversion/to_address_on_funcptr.verify.cpp @@ -0,0 +1,20 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// template constexpr T* __to_address(T* p) noexcept; +// Mandates: T is not a function type. + +#include + +int (*pf)(); + +void test() { + (void)std::__to_address(pf); // expected-error@*:* {{is a function type}} +} diff --git a/libcxx/test/libcxx/utilities/memory/pointer.conversion/to_address_on_function.verify.cpp b/libcxx/test/libcxx/utilities/memory/pointer.conversion/to_address_on_function.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/memory/pointer.conversion/to_address_on_function.verify.cpp @@ -0,0 +1,20 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// template constexpr T* __to_address(T* p) noexcept; +// Mandates: T is not a function type. + +#include + +int f(); + +void test() { + (void)std::__to_address(f); // expected-error@*:* {{is a function type}} +} diff --git a/libcxx/test/std/language.support/cmp/cmp.alg/strong_order.pass.cpp b/libcxx/test/std/language.support/cmp/cmp.alg/strong_order.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/language.support/cmp/cmp.alg/strong_order.pass.cpp @@ -0,0 +1,448 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// + +// class strong_ordering + +#include + +#include +#include +#include // std::size +#include +#include +#include + +#include "test_macros.h" + +template +constexpr auto has_strong_order(T&& t, U&& u) + -> decltype(std::strong_order(static_cast(t), static_cast(u)), true) +{ + return true; +} + +constexpr bool has_strong_order(...) { + return false; +} + +namespace N11 { + struct A {}; + struct B {}; + std::strong_ordering strong_order(const A&, const A&) { return std::strong_ordering::less; } + std::strong_ordering strong_order(const A&, const B&); +} + +void test_1_1() +{ + // If the decayed types of E and F differ, strong_order(E, F) is ill-formed. + + static_assert( has_strong_order(1, 2)); + static_assert(!has_strong_order(1, (short)2)); + static_assert(!has_strong_order(1, 2.0)); + static_assert(!has_strong_order(1.0f, 2.0)); + + static_assert( has_strong_order((int*)nullptr, (int*)nullptr)); + static_assert(!has_strong_order((int*)nullptr, (const int*)nullptr)); + static_assert(!has_strong_order((const int*)nullptr, (int*)nullptr)); + static_assert( has_strong_order((const int*)nullptr, (const int*)nullptr)); + + N11::A a; + N11::B b; + static_assert( has_strong_order(a, a)); + static_assert(!has_strong_order(a, b)); +} + +namespace N12 { + struct A {}; + std::strong_ordering strong_order(A&, A&&) { return std::strong_ordering::less; } + std::strong_ordering strong_order(A&&, A&&) { return std::strong_ordering::equal; } + std::strong_ordering strong_order(const A&, const A&); + + struct B { + friend std::weak_ordering strong_order(B&, B&); + }; + + struct Order { + explicit operator std::strong_ordering() const { return std::strong_ordering::less; } + }; + struct C { + bool touched = false; + friend Order strong_order(C& lhs, C&) { lhs.touched = true; return Order(); } + }; +} + +void test_1_2() +{ + // Otherwise, strong_ordering(strong_order(E, F)) + // if it is a well-formed expression with overload resolution performed + // in a context that does not include a declaration of std::strong_order. + + // Test that strong_order does not const-qualify the forwarded arguments. + N12::A a; + assert(std::strong_order(a, std::move(a)) == std::strong_ordering::less); + assert(std::strong_order(std::move(a), std::move(a)) == std::strong_ordering::equal); + + // The type of strong_order(e,f) must be explicitly convertible to strong_order. + N12::B b; + static_assert(!has_strong_order(b, b)); + + N12::C c1, c2; + ASSERT_SAME_TYPE(decltype(std::strong_order(c1, c2)), std::strong_ordering); + assert(std::strong_order(c1, c2) == std::strong_ordering::less); + assert(c1.touched); + assert(!c2.touched); +} + +template +constexpr bool test_1_3() +{ + // Otherwise, if the decayed type T of E is a floating-point type, + // yields a value of type strong_ordering that is consistent with + // the ordering observed by T's comparison operators, + // and if numeric_limits::is_iec559 is true, is additionally consistent with + // the totalOrder operation as specified in ISO/IEC/IEEE 60559. + + static_assert(std::numeric_limits::is_iec559); + + ASSERT_SAME_TYPE(decltype(std::strong_order(F(0), F(0))), std::strong_ordering); + + F v[] = { + -std::numeric_limits::infinity(), + std::numeric_limits::lowest(), // largest (finite) negative number + F(-1.0), F(-0.1), + -std::numeric_limits::min(), // smallest (normal) negative number + F(-0.0), // negative zero + F(0.0), + std::numeric_limits::min(), // smallest (normal) positive number + F(0.1), F(1.0), F(2.0), F(3.14), + std::numeric_limits::max(), // largest (finite) positive number + std::numeric_limits::infinity(), + }; + + static_assert(std::size(v) == 14); + + // Sanity-check that array 'v' is indeed in the right order. + for (int i=0; i < 14; ++i) { + for (int j=0; j < 14; ++j) { + auto naturalOrder = (v[i] <=> v[j]); + if (v[i] == 0 && v[j] == 0) { + assert(naturalOrder == std::partial_ordering::equivalent); + } else { + assert(naturalOrder == std::partial_ordering::unordered || naturalOrder == (i <=> j)); + } + } + } + + assert(std::strong_order(v[0], v[0]) == std::strong_ordering::equal); + assert(std::strong_order(v[0], v[1]) == std::strong_ordering::less); + assert(std::strong_order(v[0], v[2]) == std::strong_ordering::less); + assert(std::strong_order(v[0], v[3]) == std::strong_ordering::less); + assert(std::strong_order(v[0], v[4]) == std::strong_ordering::less); + assert(std::strong_order(v[0], v[5]) == std::strong_ordering::less); + assert(std::strong_order(v[0], v[6]) == std::strong_ordering::less); + assert(std::strong_order(v[0], v[7]) == std::strong_ordering::less); + assert(std::strong_order(v[0], v[8]) == std::strong_ordering::less); + assert(std::strong_order(v[0], v[9]) == std::strong_ordering::less); + assert(std::strong_order(v[0], v[10]) == std::strong_ordering::less); + assert(std::strong_order(v[0], v[11]) == std::strong_ordering::less); + assert(std::strong_order(v[0], v[12]) == std::strong_ordering::less); + assert(std::strong_order(v[0], v[13]) == std::strong_ordering::less); + assert(std::strong_order(v[1], v[0]) == std::strong_ordering::greater); + assert(std::strong_order(v[1], v[1]) == std::strong_ordering::equal); + assert(std::strong_order(v[1], v[2]) == std::strong_ordering::less); + assert(std::strong_order(v[1], v[3]) == std::strong_ordering::less); + assert(std::strong_order(v[1], v[4]) == std::strong_ordering::less); + assert(std::strong_order(v[1], v[5]) == std::strong_ordering::less); + assert(std::strong_order(v[1], v[6]) == std::strong_ordering::less); + assert(std::strong_order(v[1], v[7]) == std::strong_ordering::less); + assert(std::strong_order(v[1], v[8]) == std::strong_ordering::less); + assert(std::strong_order(v[1], v[9]) == std::strong_ordering::less); + assert(std::strong_order(v[1], v[10]) == std::strong_ordering::less); + assert(std::strong_order(v[1], v[11]) == std::strong_ordering::less); + assert(std::strong_order(v[1], v[12]) == std::strong_ordering::less); + assert(std::strong_order(v[1], v[13]) == std::strong_ordering::less); + assert(std::strong_order(v[2], v[0]) == std::strong_ordering::greater); + assert(std::strong_order(v[2], v[1]) == std::strong_ordering::greater); + assert(std::strong_order(v[2], v[2]) == std::strong_ordering::equal); + assert(std::strong_order(v[2], v[3]) == std::strong_ordering::less); + assert(std::strong_order(v[2], v[4]) == std::strong_ordering::less); + assert(std::strong_order(v[2], v[5]) == std::strong_ordering::less); + assert(std::strong_order(v[2], v[6]) == std::strong_ordering::less); + assert(std::strong_order(v[2], v[7]) == std::strong_ordering::less); + assert(std::strong_order(v[2], v[8]) == std::strong_ordering::less); + assert(std::strong_order(v[2], v[9]) == std::strong_ordering::less); + assert(std::strong_order(v[2], v[10]) == std::strong_ordering::less); + assert(std::strong_order(v[2], v[11]) == std::strong_ordering::less); + assert(std::strong_order(v[2], v[12]) == std::strong_ordering::less); + assert(std::strong_order(v[2], v[13]) == std::strong_ordering::less); + assert(std::strong_order(v[3], v[0]) == std::strong_ordering::greater); + assert(std::strong_order(v[3], v[1]) == std::strong_ordering::greater); + assert(std::strong_order(v[3], v[2]) == std::strong_ordering::greater); + assert(std::strong_order(v[3], v[3]) == std::strong_ordering::equal); + assert(std::strong_order(v[3], v[4]) == std::strong_ordering::less); + assert(std::strong_order(v[3], v[5]) == std::strong_ordering::less); + assert(std::strong_order(v[3], v[6]) == std::strong_ordering::less); + assert(std::strong_order(v[3], v[7]) == std::strong_ordering::less); + assert(std::strong_order(v[3], v[8]) == std::strong_ordering::less); + assert(std::strong_order(v[3], v[9]) == std::strong_ordering::less); + assert(std::strong_order(v[3], v[10]) == std::strong_ordering::less); + assert(std::strong_order(v[3], v[11]) == std::strong_ordering::less); + assert(std::strong_order(v[3], v[12]) == std::strong_ordering::less); + assert(std::strong_order(v[3], v[13]) == std::strong_ordering::less); + assert(std::strong_order(v[4], v[0]) == std::strong_ordering::greater); + assert(std::strong_order(v[4], v[1]) == std::strong_ordering::greater); + assert(std::strong_order(v[4], v[2]) == std::strong_ordering::greater); + assert(std::strong_order(v[4], v[3]) == std::strong_ordering::greater); + assert(std::strong_order(v[4], v[4]) == std::strong_ordering::equal); + assert(std::strong_order(v[4], v[5]) == std::strong_ordering::less); + assert(std::strong_order(v[4], v[6]) == std::strong_ordering::less); + assert(std::strong_order(v[4], v[7]) == std::strong_ordering::less); + assert(std::strong_order(v[4], v[8]) == std::strong_ordering::less); + assert(std::strong_order(v[4], v[9]) == std::strong_ordering::less); + assert(std::strong_order(v[4], v[10]) == std::strong_ordering::less); + assert(std::strong_order(v[4], v[11]) == std::strong_ordering::less); + assert(std::strong_order(v[4], v[12]) == std::strong_ordering::less); + assert(std::strong_order(v[4], v[13]) == std::strong_ordering::less); + assert(std::strong_order(v[5], v[0]) == std::strong_ordering::greater); + assert(std::strong_order(v[5], v[1]) == std::strong_ordering::greater); + assert(std::strong_order(v[5], v[2]) == std::strong_ordering::greater); + assert(std::strong_order(v[5], v[3]) == std::strong_ordering::greater); + assert(std::strong_order(v[5], v[4]) == std::strong_ordering::greater); + assert(std::strong_order(v[5], v[5]) == std::strong_ordering::equal); + assert(std::strong_order(v[5], v[6]) == std::strong_ordering::less); + assert(std::strong_order(v[5], v[7]) == std::strong_ordering::less); + assert(std::strong_order(v[5], v[8]) == std::strong_ordering::less); + assert(std::strong_order(v[5], v[9]) == std::strong_ordering::less); + assert(std::strong_order(v[5], v[10]) == std::strong_ordering::less); + assert(std::strong_order(v[5], v[11]) == std::strong_ordering::less); + assert(std::strong_order(v[5], v[12]) == std::strong_ordering::less); + assert(std::strong_order(v[5], v[13]) == std::strong_ordering::less); + assert(std::strong_order(v[6], v[0]) == std::strong_ordering::greater); + assert(std::strong_order(v[6], v[1]) == std::strong_ordering::greater); + assert(std::strong_order(v[6], v[2]) == std::strong_ordering::greater); + assert(std::strong_order(v[6], v[3]) == std::strong_ordering::greater); + assert(std::strong_order(v[6], v[4]) == std::strong_ordering::greater); + assert(std::strong_order(v[6], v[5]) == std::strong_ordering::greater); + assert(std::strong_order(v[6], v[6]) == std::strong_ordering::equal); + assert(std::strong_order(v[6], v[7]) == std::strong_ordering::less); + assert(std::strong_order(v[6], v[8]) == std::strong_ordering::less); + assert(std::strong_order(v[6], v[9]) == std::strong_ordering::less); + assert(std::strong_order(v[6], v[10]) == std::strong_ordering::less); + assert(std::strong_order(v[6], v[11]) == std::strong_ordering::less); + assert(std::strong_order(v[6], v[12]) == std::strong_ordering::less); + assert(std::strong_order(v[6], v[13]) == std::strong_ordering::less); + assert(std::strong_order(v[7], v[0]) == std::strong_ordering::greater); + assert(std::strong_order(v[7], v[1]) == std::strong_ordering::greater); + assert(std::strong_order(v[7], v[2]) == std::strong_ordering::greater); + assert(std::strong_order(v[7], v[3]) == std::strong_ordering::greater); + assert(std::strong_order(v[7], v[4]) == std::strong_ordering::greater); + assert(std::strong_order(v[7], v[5]) == std::strong_ordering::greater); + assert(std::strong_order(v[7], v[6]) == std::strong_ordering::greater); + assert(std::strong_order(v[7], v[7]) == std::strong_ordering::equal); + assert(std::strong_order(v[7], v[8]) == std::strong_ordering::less); + assert(std::strong_order(v[7], v[9]) == std::strong_ordering::less); + assert(std::strong_order(v[7], v[10]) == std::strong_ordering::less); + assert(std::strong_order(v[7], v[11]) == std::strong_ordering::less); + assert(std::strong_order(v[7], v[12]) == std::strong_ordering::less); + assert(std::strong_order(v[7], v[13]) == std::strong_ordering::less); + assert(std::strong_order(v[8], v[0]) == std::strong_ordering::greater); + assert(std::strong_order(v[8], v[1]) == std::strong_ordering::greater); + assert(std::strong_order(v[8], v[2]) == std::strong_ordering::greater); + assert(std::strong_order(v[8], v[3]) == std::strong_ordering::greater); + assert(std::strong_order(v[8], v[4]) == std::strong_ordering::greater); + assert(std::strong_order(v[8], v[5]) == std::strong_ordering::greater); + assert(std::strong_order(v[8], v[6]) == std::strong_ordering::greater); + assert(std::strong_order(v[8], v[7]) == std::strong_ordering::greater); + assert(std::strong_order(v[8], v[8]) == std::strong_ordering::equal); + assert(std::strong_order(v[8], v[9]) == std::strong_ordering::less); + assert(std::strong_order(v[8], v[10]) == std::strong_ordering::less); + assert(std::strong_order(v[8], v[11]) == std::strong_ordering::less); + assert(std::strong_order(v[8], v[12]) == std::strong_ordering::less); + assert(std::strong_order(v[8], v[13]) == std::strong_ordering::less); + assert(std::strong_order(v[9], v[0]) == std::strong_ordering::greater); + assert(std::strong_order(v[9], v[1]) == std::strong_ordering::greater); + assert(std::strong_order(v[9], v[2]) == std::strong_ordering::greater); + assert(std::strong_order(v[9], v[3]) == std::strong_ordering::greater); + assert(std::strong_order(v[9], v[4]) == std::strong_ordering::greater); + assert(std::strong_order(v[9], v[5]) == std::strong_ordering::greater); + assert(std::strong_order(v[9], v[6]) == std::strong_ordering::greater); + assert(std::strong_order(v[9], v[7]) == std::strong_ordering::greater); + assert(std::strong_order(v[9], v[8]) == std::strong_ordering::greater); + assert(std::strong_order(v[9], v[9]) == std::strong_ordering::equal); + assert(std::strong_order(v[9], v[10]) == std::strong_ordering::less); + assert(std::strong_order(v[9], v[11]) == std::strong_ordering::less); + assert(std::strong_order(v[9], v[12]) == std::strong_ordering::less); + assert(std::strong_order(v[9], v[13]) == std::strong_ordering::less); + assert(std::strong_order(v[10], v[0]) == std::strong_ordering::greater); + assert(std::strong_order(v[10], v[1]) == std::strong_ordering::greater); + assert(std::strong_order(v[10], v[2]) == std::strong_ordering::greater); + assert(std::strong_order(v[10], v[3]) == std::strong_ordering::greater); + assert(std::strong_order(v[10], v[4]) == std::strong_ordering::greater); + assert(std::strong_order(v[10], v[5]) == std::strong_ordering::greater); + assert(std::strong_order(v[10], v[6]) == std::strong_ordering::greater); + assert(std::strong_order(v[10], v[7]) == std::strong_ordering::greater); + assert(std::strong_order(v[10], v[8]) == std::strong_ordering::greater); + assert(std::strong_order(v[10], v[9]) == std::strong_ordering::greater); + assert(std::strong_order(v[10], v[10]) == std::strong_ordering::equal); + assert(std::strong_order(v[10], v[11]) == std::strong_ordering::less); + assert(std::strong_order(v[10], v[12]) == std::strong_ordering::less); + assert(std::strong_order(v[10], v[13]) == std::strong_ordering::less); + assert(std::strong_order(v[11], v[0]) == std::strong_ordering::greater); + assert(std::strong_order(v[11], v[1]) == std::strong_ordering::greater); + assert(std::strong_order(v[11], v[2]) == std::strong_ordering::greater); + assert(std::strong_order(v[11], v[3]) == std::strong_ordering::greater); + assert(std::strong_order(v[11], v[4]) == std::strong_ordering::greater); + assert(std::strong_order(v[11], v[5]) == std::strong_ordering::greater); + assert(std::strong_order(v[11], v[6]) == std::strong_ordering::greater); + assert(std::strong_order(v[11], v[7]) == std::strong_ordering::greater); + assert(std::strong_order(v[11], v[8]) == std::strong_ordering::greater); + assert(std::strong_order(v[11], v[9]) == std::strong_ordering::greater); + assert(std::strong_order(v[11], v[10]) == std::strong_ordering::greater); + assert(std::strong_order(v[11], v[11]) == std::strong_ordering::equal); + assert(std::strong_order(v[11], v[12]) == std::strong_ordering::less); + assert(std::strong_order(v[11], v[13]) == std::strong_ordering::less); + assert(std::strong_order(v[12], v[0]) == std::strong_ordering::greater); + assert(std::strong_order(v[12], v[1]) == std::strong_ordering::greater); + assert(std::strong_order(v[12], v[2]) == std::strong_ordering::greater); + assert(std::strong_order(v[12], v[3]) == std::strong_ordering::greater); + assert(std::strong_order(v[12], v[4]) == std::strong_ordering::greater); + assert(std::strong_order(v[12], v[5]) == std::strong_ordering::greater); + assert(std::strong_order(v[12], v[6]) == std::strong_ordering::greater); + assert(std::strong_order(v[12], v[7]) == std::strong_ordering::greater); + assert(std::strong_order(v[12], v[8]) == std::strong_ordering::greater); + assert(std::strong_order(v[12], v[9]) == std::strong_ordering::greater); + assert(std::strong_order(v[12], v[10]) == std::strong_ordering::greater); + assert(std::strong_order(v[12], v[11]) == std::strong_ordering::greater); + assert(std::strong_order(v[12], v[12]) == std::strong_ordering::equal); + assert(std::strong_order(v[12], v[13]) == std::strong_ordering::less); + assert(std::strong_order(v[13], v[0]) == std::strong_ordering::greater); + assert(std::strong_order(v[13], v[1]) == std::strong_ordering::greater); + assert(std::strong_order(v[13], v[2]) == std::strong_ordering::greater); + assert(std::strong_order(v[13], v[3]) == std::strong_ordering::greater); + assert(std::strong_order(v[13], v[4]) == std::strong_ordering::greater); + assert(std::strong_order(v[13], v[5]) == std::strong_ordering::greater); + assert(std::strong_order(v[13], v[6]) == std::strong_ordering::greater); + assert(std::strong_order(v[13], v[7]) == std::strong_ordering::greater); + assert(std::strong_order(v[13], v[8]) == std::strong_ordering::greater); + assert(std::strong_order(v[13], v[9]) == std::strong_ordering::greater); + assert(std::strong_order(v[13], v[10]) == std::strong_ordering::greater); + assert(std::strong_order(v[13], v[11]) == std::strong_ordering::greater); + assert(std::strong_order(v[13], v[12]) == std::strong_ordering::greater); + assert(std::strong_order(v[13], v[13]) == std::strong_ordering::equal); + + + // There's no way to produce a specifically positive or negative NAN + // at compile-time, so the NAN-related tests must be runtime-only. + + if (!std::is_constant_evaluated()) { + F nq = _VSTD::copysign(std::numeric_limits::quiet_NaN(), F(-1)); + F ns = _VSTD::copysign(std::numeric_limits::signaling_NaN(), F(-1)); + F ps = _VSTD::copysign(std::numeric_limits::signaling_NaN(), F(+1)); + F pq = _VSTD::copysign(std::numeric_limits::quiet_NaN(), F(+1)); + + assert(std::strong_order(nq, nq) == std::strong_ordering::equal); + assert(std::strong_order(nq, ns) == std::strong_ordering::less); + for (int i=0; i < 14; ++i) { + assert(std::strong_order(nq, v[i]) == std::strong_ordering::less); + } + assert(std::strong_order(nq, ps) == std::strong_ordering::less); + assert(std::strong_order(nq, pq) == std::strong_ordering::less); + + assert(std::strong_order(ns, nq) == std::strong_ordering::greater); + assert(std::strong_order(ns, ns) == std::strong_ordering::equal); + for (int i=0; i < 14; ++i) { + assert(std::strong_order(ns, v[i]) == std::strong_ordering::less); + } + assert(std::strong_order(ns, ps) == std::strong_ordering::less); + assert(std::strong_order(ns, pq) == std::strong_ordering::less); + + assert(std::strong_order(ps, nq) == std::strong_ordering::greater); + assert(std::strong_order(ps, ns) == std::strong_ordering::greater); + for (int i=0; i < 14; ++i) { + assert(std::strong_order(ps, v[i]) == std::strong_ordering::greater); + } + assert(std::strong_order(ps, ps) == std::strong_ordering::equal); + assert(std::strong_order(ps, pq) == std::strong_ordering::less); + + assert(std::strong_order(pq, nq) == std::strong_ordering::greater); + assert(std::strong_order(pq, ns) == std::strong_ordering::greater); + for (int i=0; i < 14; ++i) { + assert(std::strong_order(pq, v[i]) == std::strong_ordering::greater); + } + assert(std::strong_order(pq, ps) == std::strong_ordering::greater); + assert(std::strong_order(pq, pq) == std::strong_ordering::equal); + } + + return true; +} + +namespace N14 { + // Compare to N12::A. + struct A {}; + bool operator==(const A&, const A&); + constexpr std::strong_ordering operator<=>(A&, A&&) { return std::strong_ordering::less; } + constexpr std::strong_ordering operator<=>(A&&, A&&) { return std::strong_ordering::equal; } + std::strong_ordering operator<=>(const A&, const A&); + static_assert(std::three_way_comparable); + + struct B { + std::strong_ordering operator<=>(const B&) const; // lacks operator== + }; + static_assert(!std::three_way_comparable); + + struct C { + mutable bool touched = false; + bool operator==(const C&) const; + constexpr std::strong_ordering operator<=>(const C& rhs) const { + rhs.touched = true; + return std::strong_ordering::equal; + } + }; + static_assert(std::three_way_comparable); +} + +constexpr bool test_1_4() +{ + // Otherwise, strong_ordering(compare_three_way()(E, F)) if it is a well-formed expression. + + // Test neither strong_order nor compare_three_way const-qualify the forwarded arguments. + N14::A a; + assert(std::strong_order(a, std::move(a)) == std::strong_ordering::less); + assert(std::strong_order(std::move(a), std::move(a)) == std::strong_ordering::equal); + + N14::B b; + static_assert(!has_strong_order(b, b)); + + N14::C c1, c2; + assert(std::strong_order(c1, c2) == std::strong_ordering::equal); + assert(!c1.touched); + assert(c2.touched); + + return true; +} + +int main(int, char**) +{ + test_1_1(); + test_1_2(); + test_1_3(); + test_1_3(); + // test_1_3(); + test_1_4(); + + static_assert(test_1_3()); + static_assert(test_1_3()); + // static_assert(test_1_3()); + static_assert(test_1_4()); + + return 0; +} diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/bit.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/bit.version.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/bit.version.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/bit.version.pass.cpp @@ -81,17 +81,11 @@ #elif TEST_STD_VER == 20 -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_bit_cast -# error "__cpp_lib_bit_cast should be defined in c++20" -# endif -# if __cpp_lib_bit_cast != 201806L -# error "__cpp_lib_bit_cast should have the value 201806L in c++20" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_bit_cast -# error "__cpp_lib_bit_cast should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_bit_cast +# error "__cpp_lib_bit_cast should be defined in c++20" +# endif +# if __cpp_lib_bit_cast != 201806L +# error "__cpp_lib_bit_cast should have the value 201806L in c++20" # endif # if !defined(_LIBCPP_VERSION) @@ -123,17 +117,11 @@ #elif TEST_STD_VER > 20 -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_bit_cast -# error "__cpp_lib_bit_cast should be defined in c++2b" -# endif -# if __cpp_lib_bit_cast != 201806L -# error "__cpp_lib_bit_cast should have the value 201806L in c++2b" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_bit_cast -# error "__cpp_lib_bit_cast should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_bit_cast +# error "__cpp_lib_bit_cast should be defined in c++2b" +# endif +# if __cpp_lib_bit_cast != 201806L +# error "__cpp_lib_bit_cast should have the value 201806L in c++2b" # endif # if !defined(_LIBCPP_VERSION) diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp @@ -2264,17 +2264,11 @@ # error "__cpp_lib_bind_front should have the value 201907L in c++20" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_bit_cast -# error "__cpp_lib_bit_cast should be defined in c++20" -# endif -# if __cpp_lib_bit_cast != 201806L -# error "__cpp_lib_bit_cast should have the value 201806L in c++20" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_bit_cast -# error "__cpp_lib_bit_cast should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_bit_cast +# error "__cpp_lib_bit_cast should be defined in c++20" +# endif +# if __cpp_lib_bit_cast != 201806L +# error "__cpp_lib_bit_cast should have the value 201806L in c++20" # endif # if !defined(_LIBCPP_VERSION) @@ -3421,17 +3415,11 @@ # error "__cpp_lib_bind_front should have the value 201907L in c++2b" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_bit_cast -# error "__cpp_lib_bit_cast should be defined in c++2b" -# endif -# if __cpp_lib_bit_cast != 201806L -# error "__cpp_lib_bit_cast should have the value 201806L in c++2b" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_bit_cast -# error "__cpp_lib_bit_cast should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_bit_cast +# error "__cpp_lib_bit_cast should be defined in c++2b" +# endif +# if __cpp_lib_bit_cast != 201806L +# error "__cpp_lib_bit_cast should have the value 201806L in c++2b" # endif # if !defined(_LIBCPP_VERSION) diff --git a/libcxx/test/std/library/description/conventions/type.descriptions/customization.point.object/cpo.pass.cpp b/libcxx/test/std/library/description/conventions/type.descriptions/customization.point.object/cpo.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/library/description/conventions/type.descriptions/customization.point.object/cpo.pass.cpp @@ -0,0 +1,97 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// [customization.point.object] +// [range.adaptor.object] "A range adaptor object is a customization point object..." + +#include +#include +#include +#include + +template +constexpr bool test(CPO& o, Args&&...) +{ + auto p = o; + using T = decltype(p); + + // The type of a customization point object, ignoring cv-qualifiers, shall model semiregular. + static_assert(std::semiregular); + + // All instances of a specific customization point object type shall be equal. + // (However, they need not support operator==, so there's nothing to test here.) + + // The type T of a customization point object, ignoring cv-qualifiers, shall model... + static_assert(std::invocable); + static_assert(std::invocable); + static_assert(std::invocable); + static_assert(std::invocable); + + return true; +} + +int main(int, char**) +{ + int a[10]; +// int arrays[10][10]; +// std::pair pairs[10]; + + // [iterator.cust] + static_assert(test(std::ranges::iter_move, a+0)); + static_assert(test(std::ranges::iter_swap, a+0, a+1)); + + // [cmp.alg] + static_assert(test(std::strong_order, 1, 2)); + static_assert(test(std::weak_order, 1, 2)); + static_assert(test(std::partial_order, 1, 2)); +// static_assert(test(std::compare_strong_order_fallback, 1, 2)); +// static_assert(test(std::compare_weak_order_fallback, 1, 2)); +// static_assert(test(std::compare_partial_order_fallback, 1, 2)); + + // [range.access] + static_assert(test(std::ranges::begin, a)); + static_assert(test(std::ranges::end, a)); + static_assert(test(std::ranges::cbegin, a)); + static_assert(test(std::ranges::cend, a)); +// static_assert(test(std::ranges::rbegin, a)); +// static_assert(test(std::ranges::rend, a)); +// static_assert(test(std::ranges::crbegin, a)); +// static_assert(test(std::ranges::crend, a)); + static_assert(test(std::ranges::size, a)); + static_assert(test(std::ranges::ssize, a)); + static_assert(test(std::ranges::empty, a)); + static_assert(test(std::ranges::data, a)); +// static_assert(test(std::ranges::cdata, a)); + + // [range.factories] + // views::empty is not a CPO +// static_assert(test(std::views::single, 4)); + static_assert(test(std::views::iota, 1)); + static_assert(test(std::views::iota, 1, 10)); + // ranges::istream_view is not a CPO + + // [range.adaptors] + static_assert(test(std::views::all, a)); +// static_assert(test(std::views::filter, a, [](int x){ return x < 10; })); + static_assert(test(std::views::transform, a, [](int x){ return x + 1; })); +// static_assert(test(std::views::take, a, 10)); +// static_assert(test(std::views::take_while, a, [](int x){ return x < 10; })); +// static_assert(test(std::views::drop, a, 10)); +// static_assert(test(std::views::drop_while, a, [](int x){ return x < 10; })); +// static_assert(test(std::views::join, arrays)); +// static_assert(test(std::views::lazy_split, a, 4)); +// static_assert(test(std::views::split, a, 4)); + static_assert(test(std::views::counted, a, 10)); +// static_assert(test(std::views::common, a)); +// static_assert(test(std::views::reverse, a)); +// static_assert(test(std::views::elements<0>, pairs)); + + return 0; +} diff --git a/libcxx/test/std/numerics/bit/bit.cast/bit_cast.compile.pass.cpp b/libcxx/test/std/numerics/bit/bit.cast/bit_cast.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/numerics/bit/bit.cast/bit_cast.compile.pass.cpp @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts + +// +// +// template +// constexpr To bit_cast(const From& from) noexcept; // C++20 + +// This test makes sure that std::bit_cast fails when any of the following +// constraints are violated: +// +// (1.1) sizeof(To) == sizeof(From) is true; +// (1.2) is_trivially_copyable_v is true; +// (1.3) is_trivially_copyable_v is true. + +#include +#include + +template +concept bit_cast_is_valid = requires(From from) { + { std::bit_cast(from) } -> std::same_as; +}; + +// Types are not the same size +namespace ns1 { + struct To { char a; }; + struct From { char a; char b; }; + static_assert(!bit_cast_is_valid); + + static_assert(!bit_cast_is_valid); // makes bit_cast's return type invalid + static_assert(!bit_cast_is_valid); // duh, but might as well check + static_assert(bit_cast_is_valid); // OK, right? + static_assert(!bit_cast_is_valid); // Not OK??? +} + +// To is not trivially copyable +namespace ns2 { + struct To { char a; To(const To&); }; + struct From { char a; }; + static_assert(!bit_cast_is_valid); +} + +// From is not trivially copyable +namespace ns3 { + struct To { char a; }; + struct From { char a; From(const From&); }; + static_assert(!bit_cast_is_valid); +} diff --git a/libcxx/test/std/numerics/bit/bit.cast/bit_cast.pass.cpp b/libcxx/test/std/numerics/bit/bit.cast/bit_cast.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/numerics/bit/bit.cast/bit_cast.pass.cpp @@ -0,0 +1,258 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// +// +// template +// constexpr To bit_cast(const From& from) noexcept; // C++20 + +#include +#include +#include +#include +#include +#include +#include + +// std::bit_cast does not preserve padding bits, so if T has +// padding bits then the results might not memcmp cleanly. +// Naively, std::has_unique_object_representations would +// tell us whether T has no padding bits; but it turns out that +// std::has_unique_object_representations is false, +// so let's just never trust its answer. +// +template +void test_roundtrip_through_buffer(T from) { + struct Buffer { char buffer[sizeof(T)]; }; + Buffer middle = std::bit_cast(from); + T to = std::bit_cast(middle); + Buffer middle2 = std::bit_cast(to); + + assert((from == to) == (from == from)); // because NaN + + if constexpr (HasUniqueObjectRepresentations) { + assert(std::memcmp(&from, &middle, sizeof(T)) == 0); + assert(std::memcmp(&middle, &to, sizeof(T)) == 0); + assert(std::memcmp(&middle, &middle2, sizeof(Buffer)) == 0); + } +} + +template +void test_roundtrip_through_nested_T(T from) { + struct Nested { T x; }; + static_assert(sizeof(Nested) == sizeof(T)); + + Nested middle = std::bit_cast(from); + T to = std::bit_cast(middle); + Nested middle2 = std::bit_cast(to); + + assert((from == to) == (from == from)); // because NaN + + if constexpr (HasUniqueObjectRepresentations) { + assert(std::memcmp(&from, &middle, sizeof(T)) == 0); + assert(std::memcmp(&middle, &to, sizeof(T)) == 0); + assert(std::memcmp(&middle, &middle2, sizeof(T)) == 0); + } +} + +template +void test_roundtrip_through(T from) { + static_assert(sizeof(Intermediate) == sizeof(T)); + + Intermediate middle = std::bit_cast(from); + T to = std::bit_cast(middle); + Intermediate middle2 = std::bit_cast(to); + + assert((from == to) == (from == from)); // because NaN + + if constexpr (HasUniqueObjectRepresentations) { + assert(std::memcmp(&from, &middle, sizeof(T)) == 0); + assert(std::memcmp(&to, &middle, sizeof(T)) == 0); + assert(std::memcmp(&middle, &middle2, sizeof(Intermediate)) == 0); + } +} + +template +constexpr std::array generate_signed_integral_values() { + return {std::numeric_limits::min(), + std::numeric_limits::min() + 1, + static_cast(-2), static_cast(-1), + static_cast(0), static_cast(1), + static_cast(2), static_cast(3), + std::numeric_limits::max() - 1, + std::numeric_limits::max()}; +} + +template +constexpr std::array generate_unsigned_integral_values() { + return {static_cast(0), static_cast(1), + static_cast(2), static_cast(3), + std::numeric_limits::max() - 1, + std::numeric_limits::max()}; +} + +constexpr bool test() { + for (bool b : {false, true}) { + test_roundtrip_through_nested_T(b); + test_roundtrip_through_buffer(b); + test_roundtrip_through(b); + } + + for (char c : {'\0', 'a', 'b', 'c', 'd'}) { + test_roundtrip_through_nested_T(c); + test_roundtrip_through_buffer(c); + } + + // Fundamental signed integer types + for (signed char i : generate_signed_integral_values()) { + test_roundtrip_through_nested_T(i); + test_roundtrip_through_buffer(i); + } + + for (short i : generate_signed_integral_values()) { + test_roundtrip_through_nested_T(i); + test_roundtrip_through_buffer(i); + } + + for (int i : generate_signed_integral_values()) { + test_roundtrip_through_nested_T(i); + test_roundtrip_through_buffer(i); + test_roundtrip_through(i); + } + + for (long i : generate_signed_integral_values()) { + test_roundtrip_through_nested_T(i); + test_roundtrip_through_buffer(i); + } + + for (long long i : generate_signed_integral_values()) { + test_roundtrip_through_nested_T(i); + test_roundtrip_through_buffer(i); + test_roundtrip_through(i); + } + + // Fundamental unsigned integer types + for (unsigned char i : generate_unsigned_integral_values()) { + test_roundtrip_through_nested_T(i); + test_roundtrip_through_buffer(i); + } + + for (unsigned short i : generate_unsigned_integral_values()) { + test_roundtrip_through_nested_T(i); + test_roundtrip_through_buffer(i); + } + + for (unsigned int i : generate_unsigned_integral_values()) { + test_roundtrip_through_nested_T(i); + test_roundtrip_through_buffer(i); + test_roundtrip_through(i); + } + + for (unsigned long i : generate_unsigned_integral_values()) { + test_roundtrip_through_nested_T(i); + test_roundtrip_through_buffer(i); + } + + for (unsigned long long i : generate_unsigned_integral_values()) { + test_roundtrip_through_nested_T(i); + test_roundtrip_through_buffer(i); + test_roundtrip_through(i); + } + + // Fixed width signed integer types + for (std::int32_t i : generate_signed_integral_values()) { + test_roundtrip_through_nested_T(i); + test_roundtrip_through_buffer(i); + test_roundtrip_through(i); + test_roundtrip_through(i); + test_roundtrip_through(i); + } + + for (std::int64_t i : generate_signed_integral_values()) { + test_roundtrip_through_nested_T(i); + test_roundtrip_through_buffer(i); + test_roundtrip_through(i); + test_roundtrip_through(i); + test_roundtrip_through(i); + } + + // Fixed width unsigned integer types + for (std::uint32_t i : generate_unsigned_integral_values()) { + test_roundtrip_through_nested_T(i); + test_roundtrip_through_buffer(i); + test_roundtrip_through(i); + test_roundtrip_through(i); + test_roundtrip_through(i); + } + + for (std::uint64_t i : generate_unsigned_integral_values()) { + test_roundtrip_through_nested_T(i); + test_roundtrip_through_buffer(i); + test_roundtrip_through(i); + test_roundtrip_through(i); + test_roundtrip_through(i); + } + + // Floating point types + for (float i : {0.0f, 1.0f, -1.0f, 10.0f, -10.0f, 1e10f, 1e-10f, 1e20f, 1e-20f, 2.71828f, 3.14159f, + std::nanf(""), + __builtin_nanf("0x55550001"), // NaN with a payload + std::numeric_limits::signaling_NaN(), + std::numeric_limits::quiet_NaN()}) { + test_roundtrip_through_nested_T(i); + test_roundtrip_through_buffer(i); + test_roundtrip_through(i); + } + + for (double i : {0.0, 1.0, -1.0, 10.0, -10.0, 1e10, 1e-10, 1e100, 1e-100, + 2.718281828459045, + 3.141592653589793238462643383279502884197169399375105820974944, + std::nan(""), + std::numeric_limits::signaling_NaN(), + std::numeric_limits::quiet_NaN()}) { + test_roundtrip_through_nested_T(i); + test_roundtrip_through_buffer(i); + test_roundtrip_through(i); + } + + for (long double i : {0.0l, 1.0l, -1.0l, 10.0l, -10.0l, 1e10l, 1e-10l, 1e100l, 1e-100l, + 2.718281828459045l, + 3.141592653589793238462643383279502884197169399375105820974944l, + std::nanl(""), + std::numeric_limits::signaling_NaN(), + std::numeric_limits::quiet_NaN()}) { + // Note that x86's "long double" has 80 value bits and 48 padding bits. + test_roundtrip_through_nested_T(i); + test_roundtrip_through_buffer(i); +#ifndef _LIBCPP_HAS_NO_INT128 + test_roundtrip_through<__int128_t, false>(i); + test_roundtrip_through<__uint128_t, false>(i); +#endif + } + + return true; +} + +// TODO: There doesn't seem to be a way to perform non-trivial correctness +// tests inside constexpr. +constexpr bool basic_constexpr_test() { + struct Nested { char buffer[sizeof(int)]; }; + int from = 3; + Nested middle = std::bit_cast(from); + int to = std::bit_cast(middle); + assert(from == to); + return true; +} + +int main(int, char**) { + test(); + static_assert(basic_constexpr_test()); + return 0; +} diff --git a/libcxx/test/std/utilities/function.objects/comparisons/compare_three_way.pass.cpp b/libcxx/test/std/utilities/function.objects/comparisons/compare_three_way.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/comparisons/compare_three_way.pass.cpp @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// +// + +// compare_three_way + +#include +#include +#include + +#include "pointer_comparison_test_helper.h" + +template +constexpr auto test_sfinae(T t, U u) + -> decltype(std::compare_three_way()(t, u), std::true_type{}) + { return std::true_type{}; } + +constexpr auto test_sfinae(...) + { return std::false_type{}; } + +struct NotThreeWayComparable { + std::strong_ordering operator<=>(const NotThreeWayComparable&) const; +}; +ASSERT_SAME_TYPE(std::compare_three_way_result_t, std::strong_ordering); +static_assert(!std::three_way_comparable); // it lacks operator== + +constexpr bool test() +{ + ASSERT_SAME_TYPE(decltype(std::compare_three_way()(1, 1)), std::strong_ordering); + assert(std::compare_three_way()(1, 1) == std::strong_ordering::equal); + assert(std::compare_three_way()(1, 2) == std::strong_ordering::less); + assert(std::compare_three_way()(2, 1) == std::strong_ordering::greater); + + ASSERT_SAME_TYPE(decltype(std::compare_three_way()(1.0, 1.0)), std::partial_ordering); + assert(std::compare_three_way()(1.0, 1.0) == std::partial_ordering::equivalent); + assert(std::compare_three_way()(1.0, 2.0) == std::partial_ordering::less); + assert(std::compare_three_way()(2.0, 1.0) == std::partial_ordering::greater); + + // Try heterogeneous comparison. + ASSERT_SAME_TYPE(decltype(std::compare_three_way()(42.0, 42)), std::partial_ordering); + assert(std::compare_three_way()(42.0, 42) == std::partial_ordering::equivalent); + + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + do_pointer_comparison_test(std::compare_three_way()); + + static_assert(test_sfinae(1, 2)); + static_assert(!test_sfinae(1, nullptr)); + static_assert(!test_sfinae(NotThreeWayComparable(), NotThreeWayComparable())); + + return 0; +} diff --git a/libcxx/test/std/utilities/function.objects/comparisons/transparent.pass.cpp b/libcxx/test/std/utilities/function.objects/comparisons/transparent.pass.cpp --- a/libcxx/test/std/utilities/function.objects/comparisons/transparent.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/comparisons/transparent.pass.cpp @@ -56,5 +56,9 @@ static_assert ( is_transparent>::value, "" ); static_assert ( is_transparent>::value, "" ); +#if TEST_STD_VER > 17 + static_assert( is_transparent::value, "" ); +#endif + return 0; } diff --git a/libcxx/test/std/utilities/memory/pointer.conversion/to_address.pass.cpp b/libcxx/test/std/utilities/memory/pointer.conversion/to_address.pass.cpp --- a/libcxx/test/std/utilities/memory/pointer.conversion/to_address.pass.cpp +++ b/libcxx/test/std/utilities/memory/pointer.conversion/to_address.pass.cpp @@ -139,6 +139,18 @@ assert(std::to_address(p8b) == p8_nil); ASSERT_SAME_TYPE(decltype(std::to_address(p8b)), decltype(p8_nil)); + int p9[2] = {}; + assert(std::to_address(p9) == p9); + ASSERT_SAME_TYPE(decltype(std::to_address(p9)), int*); + + const int p10[2] = {}; + assert(std::to_address(p10) == p10); + ASSERT_SAME_TYPE(decltype(std::to_address(p10)), const int*); + + int (*p11)() = nullptr; + assert(std::to_address(&p11) == &p11); + ASSERT_SAME_TYPE(decltype(std::to_address(&p11)), int(**)()); + return true; } diff --git a/libcxx/test/std/utilities/memory/pointer.conversion/to_address_on_funcptr.verify.cpp b/libcxx/test/std/utilities/memory/pointer.conversion/to_address_on_funcptr.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/memory/pointer.conversion/to_address_on_funcptr.verify.cpp @@ -0,0 +1,22 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// template constexpr T* to_address(T* p) noexcept; +// Mandates: T is not a function type. + +#include + +int (*pf)(); + +void test() { + (void)std::to_address(pf); // expected-error@*:* {{is a function type}} +} diff --git a/libcxx/test/std/utilities/memory/pointer.conversion/to_address_on_function.verify.cpp b/libcxx/test/std/utilities/memory/pointer.conversion/to_address_on_function.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/memory/pointer.conversion/to_address_on_function.verify.cpp @@ -0,0 +1,22 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// template constexpr T* to_address(T* p) noexcept; +// Mandates: T is not a function type. + +#include + +int f(); + +void test() { + (void)std::to_address(f); // expected-error@*:* {{is a function type}} +} diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -156,7 +156,6 @@ "name": "__cpp_lib_bit_cast", "values": { "c++20": 201806 }, "headers": ["bit"], - "unimplemented": True, }, { "name": "__cpp_lib_bitops", "values": { "c++20": 201907 },