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,13 +94,16 @@ __algorithm/upper_bound.h __availability __bit_reference + __bit/bit_cast.h __bits __bsd_locale_defaults.h __bsd_locale_fallbacks.h __charconv/chars_format.h __charconv/from_chars_result.h __charconv/to_chars_result.h + __compare/cmp_alg.h __compare/common_comparison_category.h + __compare/compare_three_way.h __compare/compare_three_way_result.h __compare/ordering.h __compare/three_way_comparable.h @@ -284,6 +287,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_HIDE_FROM_ABI _LIBCPP_NODISCARD_EXT +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/cmp_alg.h b/libcxx/include/__compare/cmp_alg.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__compare/cmp_alg.h @@ -0,0 +1,136 @@ +// -*- C++ -*- +//===-------------------------- compare -----------------------------------===// +// +// 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_CMP_ALG +#define _LIBCPP___COMPARE_CMP_ALG + +#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 +#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 __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 + { + struct _Intermediate { unsigned char __rest_[16]; }; + struct _Parts { signed char __hi_; unsigned char __rest_[15]; auto operator<=>(const _Parts&) const = default; }; + 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 (__e == 0) { + return _VSTD::signbit(__f) <=> _VSTD::signbit(__e); + } else if (_VSTD::isinf(__e)) { + return strong_ordering::equal; + } 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::greater : strong_ordering::less; + } else { + return __f_is_negative ? strong_ordering::less : strong_ordering::greater; + } + } + } + + 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 + +#endif // _LIBCPP___COMPARE_CMP_ALG 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/__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); @@ -132,28 +135,12 @@ } */ +#include <__compare/cmp_alg.h> #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/three_way_comparable.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" @@ -367,7 +371,9 @@ export * module __compare { + module cmp_alg { private header "__compare/cmp_alg.h" } 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 three_way_comparable { private header "__compare/three_way_comparable.h" } @@ -818,6 +824,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/cmp_alg.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/compare/cmp_alg.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/compare/cmp_alg.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/cmp_alg.h'}} +#include <__compare/cmp_alg.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/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/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,234 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +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(std::memcmp(&from, &middle, sizeof(T)) == 0); + assert(std::memcmp(&to, &middle, sizeof(T)) == 0); + assert(std::memcmp(&from, &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; }; + Nested middle = std::bit_cast(from); + T to = std::bit_cast(middle); + Nested middle2 = std::bit_cast(to); + + assert(std::memcmp(&from, &middle, sizeof(T)) == 0); + assert(std::memcmp(&to, &middle, sizeof(T)) == 0); + assert(std::memcmp(&from, &to, sizeof(T)) == 0); + assert(std::memcmp(&middle, &middle2, sizeof(Nested)) == 0); +} + +template +void test_roundtrip_through(T from) { + Intermediate middle = std::bit_cast(from); + T to = std::bit_cast(middle); + Intermediate middle2 = std::bit_cast(to); + + assert(std::memcmp(&from, &middle, sizeof(T)) == 0); + assert(std::memcmp(&to, &middle, sizeof(T)) == 0); + assert(std::memcmp(&from, &to, 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()}; +} + +bool tests() { + 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); + test_roundtrip_through(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()}) { + test_roundtrip_through_nested_T(i); + test_roundtrip_through_buffer(i); + } + + 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**) { + tests(); + 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/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 },