diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -172,7 +172,7 @@ ------------------------------------------------- ----------------- ``__cpp_lib_bind_front`` *unimplemented* ------------------------------------------------- ----------------- - ``__cpp_lib_bit_cast`` *unimplemented* + ``__cpp_lib_bit_cast`` ``201806L`` ------------------------------------------------- ----------------- ``__cpp_lib_char8_t`` ``201811L`` ------------------------------------------------- ----------------- diff --git a/libcxx/include/__config b/libcxx/include/__config --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -1300,6 +1300,10 @@ #define _LIBCPP_HAS_NO_BUILTIN_IS_CONSTANT_EVALUATED #endif +#if !__has_builtin(__builtin_bit_cast) +# define _LIBCPP_HAS_NO_BUILTIN_BIT_CAST +#endif + #if !defined(_LIBCPP_HAS_NO_OFF_T_FUNCTIONS) # if defined(_LIBCPP_MSVCRT) || defined(_NEWLIB_VERSION) # define _LIBCPP_HAS_NO_OFF_T_FUNCTIONS diff --git a/libcxx/include/bit b/libcxx/include/bit --- a/libcxx/include/bit +++ b/libcxx/include/bit @@ -14,7 +14,11 @@ 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 constexpr bool ispow2(T x) noexcept; // C++20 template @@ -24,13 +28,13 @@ template constexpr T log2p1(T x) noexcept; // C++20 - // 23.20.2, rotating + // [bit.rotate], rotating template constexpr T rotl(T x, unsigned int s) noexcept; // C++20 template constexpr T rotr(T x, unsigned int s) noexcept; // C++20 - // 23.20.3, counting + // [bit.count], counting template constexpr int countl_zero(T x) noexcept; // C++20 template @@ -42,7 +46,7 @@ template constexpr int popcount(T x) noexcept; // C++20 - // 20.15.9, endian + // [bit.endian], endian enum class endian { little = see below, // C++20 big = see below, // C++20 @@ -350,12 +354,24 @@ bool __ispow2(_Tp __t) _NOEXCEPT { static_assert(__bitop_unsigned_integer<_Tp>::value, "__ispow2 requires unsigned"); - return __t != 0 && (((__t & (__t - 1)) == 0)); + return __t != 0 && (((__t & (__t - 1)) == 0)); } #if _LIBCPP_STD_VER > 17 +#if !defined(_LIBCPP_HAS_NO_BUILTIN_BIT_CAST) +template +_LIBCPP_INLINE_VISIBILITY +constexpr _ToType bit_cast(_FromType const& __from) noexcept +{ + static_assert(sizeof(_ToType) == sizeof(_FromType)); + static_assert(is_trivially_copyable_v<_ToType>); + static_assert(is_trivially_copyable_v<_FromType>); + return __builtin_bit_cast(_ToType, __from); +} +#endif + template _LIBCPP_INLINE_VISIBILITY constexpr enable_if_t<__bitop_unsigned_integer<_Tp>::value, _Tp> diff --git a/libcxx/include/version b/libcxx/include/version --- a/libcxx/include/version +++ b/libcxx/include/version @@ -215,7 +215,9 @@ // # define __cpp_lib_atomic_ref 201806L # endif // # define __cpp_lib_bind_front 201811L -// # define __cpp_lib_bit_cast 201806L +# if !defined(_LIBCPP_HAS_NO_BUILTIN_BIT_CAST) +# define __cpp_lib_bit_cast 201806L +# endif # if !defined(_LIBCPP_NO_HAS_CHAR8_T) # define __cpp_lib_char8_t 201811L # endif @@ -234,8 +236,8 @@ # endif // # define __cpp_lib_list_remove_return_type 201806L // # define __cpp_lib_ranges 201811L -# define __cpp_lib_to_array 201907L // # define __cpp_lib_three_way_comparison 201711L +# define __cpp_lib_to_array 201907L #endif #endif // _LIBCPP_VERSIONH 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 @@ -53,16 +53,16 @@ #elif TEST_STD_VER > 17 -# if !defined(_LIBCPP_VERSION) +# if TEST_HAS_BUILTIN(__builtin_bit_cast) # ifndef __cpp_lib_bit_cast # error "__cpp_lib_bit_cast should be defined in c++2a" # endif # if __cpp_lib_bit_cast != 201806L # error "__cpp_lib_bit_cast should have the value 201806L in c++2a" # endif -# else // _LIBCPP_VERSION +# else # ifdef __cpp_lib_bit_cast -# error "__cpp_lib_bit_cast should not be defined because it is unimplemented in libc++!" +# error "__cpp_lib_bit_cast should not be defined when TEST_HAS_BUILTIN(__builtin_bit_cast) is not defined!" # endif # endif 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 @@ -1568,16 +1568,16 @@ # endif # endif -# if !defined(_LIBCPP_VERSION) +# if TEST_HAS_BUILTIN(__builtin_bit_cast) # ifndef __cpp_lib_bit_cast # error "__cpp_lib_bit_cast should be defined in c++2a" # endif # if __cpp_lib_bit_cast != 201806L # error "__cpp_lib_bit_cast should have the value 201806L in c++2a" # endif -# else // _LIBCPP_VERSION +# else # ifdef __cpp_lib_bit_cast -# error "__cpp_lib_bit_cast should not be defined because it is unimplemented in libc++!" +# error "__cpp_lib_bit_cast should not be defined when TEST_HAS_BUILTIN(__builtin_bit_cast) is not defined!" # endif # endif diff --git a/libcxx/test/std/numerics/bit/bit.cast/bit_cast.fail.cpp b/libcxx/test/std/numerics/bit/bit.cast/bit_cast.fail.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/numerics/bit/bit.cast/bit_cast.fail.cpp @@ -0,0 +1,61 @@ +//===----------------------------------------------------------------------===// +// +// 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++98, c++03, c++11, c++14, c++17 +// REQUIRES: verify-support + +// +// +// 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 +#include + +#include "test_macros.h" + +int main(int, char**) +{ + // Not the same size + { + struct To { char a; }; + struct From { char a; char b; }; + From from; + (void)std::bit_cast(from); // expected-error@bit:* {{static_assert failed due to requirement 'sizeof(To) == sizeof(From)'}} + } + + // To is not trivially copyable + { + struct To { char a; To(To const& x) : a(x.a) { } }; + struct From { char a; }; + From from; + (void)std::bit_cast(from); // expected-error@bit:* {{static_assert failed due to requirement 'is_trivially_copyable_v'}} + } + + // From is not trivially copyable + { + struct To { char a; }; + struct From { char a; From() { } From(From const& x) : a(x.a) { } }; + From from; + (void)std::bit_cast(from); // expected-error@bit:* {{static_assert failed due to requirement 'is_trivially_copyable_v'}} + } + + // Disregard the error messages given by __builtin_bit_cast, if any. + // __builtin_bit_cast is an implementation detail of libc++. + // expected-error@* 0-3 {{__builtin_bit_cast}} + + return 0; +} 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,33 @@ +//===----------------------------------------------------------------------===// +// +// 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++98, c++03, c++11, c++14, c++17 + +// +// +// template +// constexpr To bit_cast(const From& from) noexcept; // C++20 + +#include +#include +#include + +#include "test_macros.h" + +constexpr bool tests() { + // TODO fun stuff + return true; +} + +static_assert(tests()); + +int main(int, char**) +{ + tests(); + 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 @@ -563,7 +563,8 @@ "c++2a": int(201806), }, "headers": ["bit"], - "unimplemented": True, + "depends": "TEST_HAS_BUILTIN(__builtin_bit_cast)", + "internal_depends": "!defined(_LIBCPP_HAS_NO_BUILTIN_BIT_CAST)", }, {"name": "__cpp_lib_atomic_ref", "values": { diff --git a/libcxx/www/cxx2a_status.html b/libcxx/www/cxx2a_status.html --- a/libcxx/www/cxx2a_status.html +++ b/libcxx/www/cxx2a_status.html @@ -85,7 +85,7 @@ P0019R8LWGAtomic RefRapperswil P0458R2LWGChecking for Existence of an Element in Associative ContainersRapperswilComplete P0475R1LWGLWG 2511: guaranteed copy elision for piecewise constructionRapperswil - P0476R2LWGBit-casting object representationsRapperswil + P0476R2LWGBit-casting object representationsRapperswilComplete10.0 P0528R3CWGThe Curious Case of Padding Bits, Featuring Atomic Compare-and-ExchangeRapperswil P0542R5CWGSupport for contract based programming in C++Rapperswil P0556R3LWGIntegral power-of-2 operationsRapperswilComplete9.0