1 //===----------------------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03, c++11, c++14, c++17
13 // template<class To, class From>
14 // constexpr To bit_cast(const From& from) noexcept; // C++20
24 #include "test_macros.h"
26 // std::bit_cast does not preserve padding bits, so if T has padding bits,
27 // the results might not memcmp cleanly.
28 template<bool HasUniqueObjectRepresentations
= true, typename T
>
29 void test_roundtrip_through_buffer(T from
) {
30 struct Buffer
{ char buffer
[sizeof(T
)]; };
31 Buffer middle
= std::bit_cast
<Buffer
>(from
);
32 T to
= std::bit_cast
<T
>(middle
);
33 Buffer middle2
= std::bit_cast
<Buffer
>(to
);
35 assert((from
== to
) == (from
== from
)); // because NaN
37 if constexpr (HasUniqueObjectRepresentations
) {
38 assert(std::memcmp(&from
, &middle
, sizeof(T
)) == 0);
39 assert(std::memcmp(&to
, &middle
, sizeof(T
)) == 0);
40 assert(std::memcmp(&middle
, &middle2
, sizeof(T
)) == 0);
44 template<bool HasUniqueObjectRepresentations
= true, typename T
>
45 void test_roundtrip_through_nested_T(T from
) {
46 struct Nested
{ T x
; };
47 static_assert(sizeof(Nested
) == sizeof(T
));
49 Nested middle
= std::bit_cast
<Nested
>(from
);
50 T to
= std::bit_cast
<T
>(middle
);
51 Nested middle2
= std::bit_cast
<Nested
>(to
);
53 assert((from
== to
) == (from
== from
)); // because NaN
55 if constexpr (HasUniqueObjectRepresentations
) {
56 assert(std::memcmp(&from
, &middle
, sizeof(T
)) == 0);
57 assert(std::memcmp(&to
, &middle
, sizeof(T
)) == 0);
58 assert(std::memcmp(&middle
, &middle2
, sizeof(T
)) == 0);
62 template <typename Intermediate
, bool HasUniqueObjectRepresentations
= true, typename T
>
63 void test_roundtrip_through(T from
) {
64 static_assert(sizeof(Intermediate
) == sizeof(T
));
66 Intermediate middle
= std::bit_cast
<Intermediate
>(from
);
67 T to
= std::bit_cast
<T
>(middle
);
68 Intermediate middle2
= std::bit_cast
<Intermediate
>(to
);
70 assert((from
== to
) == (from
== from
)); // because NaN
72 if constexpr (HasUniqueObjectRepresentations
) {
73 assert(std::memcmp(&from
, &middle
, sizeof(T
)) == 0);
74 assert(std::memcmp(&to
, &middle
, sizeof(T
)) == 0);
75 assert(std::memcmp(&middle
, &middle2
, sizeof(T
)) == 0);
80 constexpr std::array
<T
, 10> generate_signed_integral_values() {
81 return {std::numeric_limits
<T
>::min(),
82 std::numeric_limits
<T
>::min() + 1,
83 static_cast<T
>(-2), static_cast<T
>(-1),
84 static_cast<T
>(0), static_cast<T
>(1),
85 static_cast<T
>(2), static_cast<T
>(3),
86 std::numeric_limits
<T
>::max() - 1,
87 std::numeric_limits
<T
>::max()};
91 constexpr std::array
<T
, 6> generate_unsigned_integral_values() {
92 return {static_cast<T
>(0), static_cast<T
>(1),
93 static_cast<T
>(2), static_cast<T
>(3),
94 std::numeric_limits
<T
>::max() - 1,
95 std::numeric_limits
<T
>::max()};
99 for (bool b
: {false, true}) {
100 test_roundtrip_through_nested_T(b
);
101 test_roundtrip_through_buffer(b
);
102 test_roundtrip_through
<char>(b
);
105 for (char c
: {'\0', 'a', 'b', 'c', 'd'}) {
106 test_roundtrip_through_nested_T(c
);
107 test_roundtrip_through_buffer(c
);
110 // Fundamental signed integer types
111 for (signed char i
: generate_signed_integral_values
<signed char>()) {
112 test_roundtrip_through_nested_T(i
);
113 test_roundtrip_through_buffer(i
);
116 for (short i
: generate_signed_integral_values
<short>()) {
117 test_roundtrip_through_nested_T(i
);
118 test_roundtrip_through_buffer(i
);
121 for (int i
: generate_signed_integral_values
<int>()) {
122 test_roundtrip_through_nested_T(i
);
123 test_roundtrip_through_buffer(i
);
124 test_roundtrip_through
<float>(i
);
127 for (long i
: generate_signed_integral_values
<long>()) {
128 test_roundtrip_through_nested_T(i
);
129 test_roundtrip_through_buffer(i
);
132 for (long long i
: generate_signed_integral_values
<long long>()) {
133 test_roundtrip_through_nested_T(i
);
134 test_roundtrip_through_buffer(i
);
135 test_roundtrip_through
<double>(i
);
138 // Fundamental unsigned integer types
139 for (unsigned char i
: generate_unsigned_integral_values
<unsigned char>()) {
140 test_roundtrip_through_nested_T(i
);
141 test_roundtrip_through_buffer(i
);
144 for (unsigned short i
: generate_unsigned_integral_values
<unsigned short>()) {
145 test_roundtrip_through_nested_T(i
);
146 test_roundtrip_through_buffer(i
);
149 for (unsigned int i
: generate_unsigned_integral_values
<unsigned int>()) {
150 test_roundtrip_through_nested_T(i
);
151 test_roundtrip_through_buffer(i
);
152 test_roundtrip_through
<float>(i
);
155 for (unsigned long i
: generate_unsigned_integral_values
<unsigned long>()) {
156 test_roundtrip_through_nested_T(i
);
157 test_roundtrip_through_buffer(i
);
160 for (unsigned long long i
: generate_unsigned_integral_values
<unsigned long long>()) {
161 test_roundtrip_through_nested_T(i
);
162 test_roundtrip_through_buffer(i
);
163 test_roundtrip_through
<double>(i
);
166 // Fixed width signed integer types
167 for (std::int32_t i
: generate_signed_integral_values
<std::int32_t>()) {
168 test_roundtrip_through_nested_T(i
);
169 test_roundtrip_through_buffer(i
);
170 test_roundtrip_through
<int>(i
);
171 test_roundtrip_through
<std::uint32_t>(i
);
172 test_roundtrip_through
<float>(i
);
175 for (std::int64_t i
: generate_signed_integral_values
<std::int64_t>()) {
176 test_roundtrip_through_nested_T(i
);
177 test_roundtrip_through_buffer(i
);
178 test_roundtrip_through
<long long>(i
);
179 test_roundtrip_through
<std::uint64_t>(i
);
180 test_roundtrip_through
<double>(i
);
183 // Fixed width unsigned integer types
184 for (std::uint32_t i
: generate_unsigned_integral_values
<std::uint32_t>()) {
185 test_roundtrip_through_nested_T(i
);
186 test_roundtrip_through_buffer(i
);
187 test_roundtrip_through
<int>(i
);
188 test_roundtrip_through
<std::int32_t>(i
);
189 test_roundtrip_through
<float>(i
);
192 for (std::uint64_t i
: generate_unsigned_integral_values
<std::uint64_t>()) {
193 test_roundtrip_through_nested_T(i
);
194 test_roundtrip_through_buffer(i
);
195 test_roundtrip_through
<long long>(i
);
196 test_roundtrip_through
<std::int64_t>(i
);
197 test_roundtrip_through
<double>(i
);
200 // Floating point types
201 for (float i
: {0.0f
, 1.0f
, -1.0f
, 10.0f
, -10.0f
, 1e10f
, 1e-10f
, 1e20f
, 1e-20f
, 2.71828f
, 3.14159f
,
203 __builtin_nanf("0x55550001"), // NaN with a payload
204 std::numeric_limits
<float>::signaling_NaN(),
205 std::numeric_limits
<float>::quiet_NaN()}) {
206 test_roundtrip_through_nested_T(i
);
207 test_roundtrip_through_buffer(i
);
208 test_roundtrip_through
<int>(i
);
211 for (double i
: {0.0, 1.0, -1.0, 10.0, -10.0, 1e10
, 1e-10, 1e100
, 1e-100,
213 3.141592653589793238462643383279502884197169399375105820974944,
215 std::numeric_limits
<double>::signaling_NaN(),
216 std::numeric_limits
<double>::quiet_NaN()}) {
217 test_roundtrip_through_nested_T(i
);
218 test_roundtrip_through_buffer(i
);
219 test_roundtrip_through
<long long>(i
);
222 for (long double i
: {0.0l, 1.0l, -1.0l, 10.0l, -10.0l, 1e10l
, 1e-10l, 1e100l
, 1e-100l,
224 3.141592653589793238462643383279502884197169399375105820974944l,
226 std::numeric_limits
<long double>::signaling_NaN(),
227 std::numeric_limits
<long double>::quiet_NaN()}) {
228 // Note that x86's `long double` has 80 value bits and 48 padding bits.
229 test_roundtrip_through_nested_T
<false>(i
);
230 test_roundtrip_through_buffer
<false>(i
);
232 #if __SIZEOF_LONG_DOUBLE__ == __SIZEOF_DOUBLE__
233 test_roundtrip_through
<double, false>(i
);
235 #if defined(__SIZEOF_INT128__) && __SIZEOF_LONG_DOUBLE__ == __SIZEOF_INT128__ && \
236 !TEST_HAS_FEATURE(memory_sanitizer) // Some bits are just padding.
237 test_roundtrip_through
<__int128_t
, false>(i
);
238 test_roundtrip_through
<__uint128_t
, false>(i
);
247 test_roundtrip_through_nested_T(p
);
248 test_roundtrip_through_buffer(p
);
249 test_roundtrip_through
<void*>(p
);
250 test_roundtrip_through
<char*>(p
);
251 test_roundtrip_through
<int*>(p
);
256 test_roundtrip_through_nested_T(p
);
257 test_roundtrip_through_buffer(p
);
258 test_roundtrip_through
<int*>(p
);
259 test_roundtrip_through
<char*>(p
);
260 test_roundtrip_through
<void*>(p
);
267 // TODO: There doesn't seem to be a way to perform non-trivial correctness
268 // tests inside constexpr.
269 constexpr bool basic_constexpr_test() {
270 struct Nested
{ char buffer
[sizeof(int)]; };
272 Nested middle
= std::bit_cast
<Nested
>(from
);
273 int to
= std::bit_cast
<int>(middle
);
278 int main(int, char**) {
280 static_assert(basic_constexpr_test());