xref: /llvm-project/libcxx/test/std/numerics/bit/bit.cast/bit_cast.pass.cpp (revision c792de28dfaf3a13703e83e4eb09dd44574b3a3e)
1b1fb3d75SLouis Dionne //===----------------------------------------------------------------------===//
2b1fb3d75SLouis Dionne //
3b1fb3d75SLouis Dionne // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4b1fb3d75SLouis Dionne // See https://llvm.org/LICENSE.txt for license information.
5b1fb3d75SLouis Dionne // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b1fb3d75SLouis Dionne //
7b1fb3d75SLouis Dionne //===----------------------------------------------------------------------===//
8b1fb3d75SLouis Dionne 
9b1fb3d75SLouis Dionne // UNSUPPORTED: c++03, c++11, c++14, c++17
10b1fb3d75SLouis Dionne 
11b1fb3d75SLouis Dionne // <bit>
12b1fb3d75SLouis Dionne //
13b1fb3d75SLouis Dionne // template<class To, class From>
14b1fb3d75SLouis Dionne //   constexpr To bit_cast(const From& from) noexcept; // C++20
15b1fb3d75SLouis Dionne 
16b1fb3d75SLouis Dionne #include <array>
17b1fb3d75SLouis Dionne #include <bit>
18b1fb3d75SLouis Dionne #include <cassert>
19b1fb3d75SLouis Dionne #include <cmath>
20b1fb3d75SLouis Dionne #include <cstdint>
21b1fb3d75SLouis Dionne #include <cstring>
22b1fb3d75SLouis Dionne #include <limits>
23b1fb3d75SLouis Dionne 
24bf0d6136SVitaly Buka #include "test_macros.h"
25bf0d6136SVitaly Buka 
26b1fb3d75SLouis Dionne // std::bit_cast does not preserve padding bits, so if T has padding bits,
27b1fb3d75SLouis Dionne // the results might not memcmp cleanly.
28b1fb3d75SLouis Dionne template<bool HasUniqueObjectRepresentations = true, typename T>
29b1fb3d75SLouis Dionne void test_roundtrip_through_buffer(T from) {
30b1fb3d75SLouis Dionne     struct Buffer { char buffer[sizeof(T)]; };
31b1fb3d75SLouis Dionne     Buffer middle = std::bit_cast<Buffer>(from);
32b1fb3d75SLouis Dionne     T to = std::bit_cast<T>(middle);
33b1fb3d75SLouis Dionne     Buffer middle2 = std::bit_cast<Buffer>(to);
34b1fb3d75SLouis Dionne 
35b1fb3d75SLouis Dionne     assert((from == to) == (from == from)); // because NaN
36b1fb3d75SLouis Dionne 
37b1fb3d75SLouis Dionne     if constexpr (HasUniqueObjectRepresentations) {
38b1fb3d75SLouis Dionne         assert(std::memcmp(&from, &middle, sizeof(T)) == 0);
39b1fb3d75SLouis Dionne         assert(std::memcmp(&to, &middle, sizeof(T)) == 0);
40b1fb3d75SLouis Dionne         assert(std::memcmp(&middle, &middle2, sizeof(T)) == 0);
41b1fb3d75SLouis Dionne     }
42b1fb3d75SLouis Dionne }
43b1fb3d75SLouis Dionne 
44b1fb3d75SLouis Dionne template<bool HasUniqueObjectRepresentations = true, typename T>
45b1fb3d75SLouis Dionne void test_roundtrip_through_nested_T(T from) {
46b1fb3d75SLouis Dionne     struct Nested { T x; };
47b1fb3d75SLouis Dionne     static_assert(sizeof(Nested) == sizeof(T));
48b1fb3d75SLouis Dionne 
49b1fb3d75SLouis Dionne     Nested middle = std::bit_cast<Nested>(from);
50b1fb3d75SLouis Dionne     T to = std::bit_cast<T>(middle);
51b1fb3d75SLouis Dionne     Nested middle2 = std::bit_cast<Nested>(to);
52b1fb3d75SLouis Dionne 
53b1fb3d75SLouis Dionne     assert((from == to) == (from == from)); // because NaN
54b1fb3d75SLouis Dionne 
55b1fb3d75SLouis Dionne     if constexpr (HasUniqueObjectRepresentations) {
56b1fb3d75SLouis Dionne         assert(std::memcmp(&from, &middle, sizeof(T)) == 0);
57b1fb3d75SLouis Dionne         assert(std::memcmp(&to, &middle, sizeof(T)) == 0);
58b1fb3d75SLouis Dionne         assert(std::memcmp(&middle, &middle2, sizeof(T)) == 0);
59b1fb3d75SLouis Dionne     }
60b1fb3d75SLouis Dionne }
61b1fb3d75SLouis Dionne 
62b1fb3d75SLouis Dionne template <typename Intermediate, bool HasUniqueObjectRepresentations = true, typename T>
63b1fb3d75SLouis Dionne void test_roundtrip_through(T from) {
64b1fb3d75SLouis Dionne     static_assert(sizeof(Intermediate) == sizeof(T));
65b1fb3d75SLouis Dionne 
66b1fb3d75SLouis Dionne     Intermediate middle = std::bit_cast<Intermediate>(from);
67b1fb3d75SLouis Dionne     T to = std::bit_cast<T>(middle);
68b1fb3d75SLouis Dionne     Intermediate middle2 = std::bit_cast<Intermediate>(to);
69b1fb3d75SLouis Dionne 
70b1fb3d75SLouis Dionne     assert((from == to) == (from == from)); // because NaN
71b1fb3d75SLouis Dionne 
72b1fb3d75SLouis Dionne     if constexpr (HasUniqueObjectRepresentations) {
73b1fb3d75SLouis Dionne         assert(std::memcmp(&from, &middle, sizeof(T)) == 0);
74b1fb3d75SLouis Dionne         assert(std::memcmp(&to, &middle, sizeof(T)) == 0);
75b1fb3d75SLouis Dionne         assert(std::memcmp(&middle, &middle2, sizeof(T)) == 0);
76b1fb3d75SLouis Dionne     }
77b1fb3d75SLouis Dionne }
78b1fb3d75SLouis Dionne 
79b1fb3d75SLouis Dionne template <typename T>
80b1fb3d75SLouis Dionne constexpr std::array<T, 10> generate_signed_integral_values() {
81b1fb3d75SLouis Dionne     return {std::numeric_limits<T>::min(),
82b1fb3d75SLouis Dionne             std::numeric_limits<T>::min() + 1,
83b1fb3d75SLouis Dionne             static_cast<T>(-2), static_cast<T>(-1),
84b1fb3d75SLouis Dionne             static_cast<T>(0), static_cast<T>(1),
85b1fb3d75SLouis Dionne             static_cast<T>(2), static_cast<T>(3),
86b1fb3d75SLouis Dionne             std::numeric_limits<T>::max() - 1,
87b1fb3d75SLouis Dionne             std::numeric_limits<T>::max()};
88b1fb3d75SLouis Dionne }
89b1fb3d75SLouis Dionne 
90b1fb3d75SLouis Dionne template <typename T>
91b1fb3d75SLouis Dionne constexpr std::array<T, 6> generate_unsigned_integral_values() {
92b1fb3d75SLouis Dionne     return {static_cast<T>(0), static_cast<T>(1),
93b1fb3d75SLouis Dionne             static_cast<T>(2), static_cast<T>(3),
94b1fb3d75SLouis Dionne             std::numeric_limits<T>::max() - 1,
95b1fb3d75SLouis Dionne             std::numeric_limits<T>::max()};
96b1fb3d75SLouis Dionne }
97b1fb3d75SLouis Dionne 
98b1fb3d75SLouis Dionne bool tests() {
99b1fb3d75SLouis Dionne     for (bool b : {false, true}) {
100b1fb3d75SLouis Dionne         test_roundtrip_through_nested_T(b);
101b1fb3d75SLouis Dionne         test_roundtrip_through_buffer(b);
102b1fb3d75SLouis Dionne         test_roundtrip_through<char>(b);
103b1fb3d75SLouis Dionne     }
104b1fb3d75SLouis Dionne 
105b1fb3d75SLouis Dionne     for (char c : {'\0', 'a', 'b', 'c', 'd'}) {
106b1fb3d75SLouis Dionne         test_roundtrip_through_nested_T(c);
107b1fb3d75SLouis Dionne         test_roundtrip_through_buffer(c);
108b1fb3d75SLouis Dionne     }
109b1fb3d75SLouis Dionne 
110b1fb3d75SLouis Dionne     // Fundamental signed integer types
111b1fb3d75SLouis Dionne     for (signed char i : generate_signed_integral_values<signed char>()) {
112b1fb3d75SLouis Dionne         test_roundtrip_through_nested_T(i);
113b1fb3d75SLouis Dionne         test_roundtrip_through_buffer(i);
114b1fb3d75SLouis Dionne     }
115b1fb3d75SLouis Dionne 
116b1fb3d75SLouis Dionne     for (short i : generate_signed_integral_values<short>()) {
117b1fb3d75SLouis Dionne         test_roundtrip_through_nested_T(i);
118b1fb3d75SLouis Dionne         test_roundtrip_through_buffer(i);
119b1fb3d75SLouis Dionne     }
120b1fb3d75SLouis Dionne 
121b1fb3d75SLouis Dionne     for (int i : generate_signed_integral_values<int>()) {
122b1fb3d75SLouis Dionne         test_roundtrip_through_nested_T(i);
123b1fb3d75SLouis Dionne         test_roundtrip_through_buffer(i);
124b1fb3d75SLouis Dionne         test_roundtrip_through<float>(i);
125b1fb3d75SLouis Dionne     }
126b1fb3d75SLouis Dionne 
127b1fb3d75SLouis Dionne     for (long i : generate_signed_integral_values<long>()) {
128b1fb3d75SLouis Dionne         test_roundtrip_through_nested_T(i);
129b1fb3d75SLouis Dionne         test_roundtrip_through_buffer(i);
130b1fb3d75SLouis Dionne     }
131b1fb3d75SLouis Dionne 
132b1fb3d75SLouis Dionne     for (long long i : generate_signed_integral_values<long long>()) {
133b1fb3d75SLouis Dionne         test_roundtrip_through_nested_T(i);
134b1fb3d75SLouis Dionne         test_roundtrip_through_buffer(i);
135b1fb3d75SLouis Dionne         test_roundtrip_through<double>(i);
136b1fb3d75SLouis Dionne     }
137b1fb3d75SLouis Dionne 
138b1fb3d75SLouis Dionne     // Fundamental unsigned integer types
139b1fb3d75SLouis Dionne     for (unsigned char i : generate_unsigned_integral_values<unsigned char>()) {
140b1fb3d75SLouis Dionne         test_roundtrip_through_nested_T(i);
141b1fb3d75SLouis Dionne         test_roundtrip_through_buffer(i);
142b1fb3d75SLouis Dionne     }
143b1fb3d75SLouis Dionne 
144b1fb3d75SLouis Dionne     for (unsigned short i : generate_unsigned_integral_values<unsigned short>()) {
145b1fb3d75SLouis Dionne         test_roundtrip_through_nested_T(i);
146b1fb3d75SLouis Dionne         test_roundtrip_through_buffer(i);
147b1fb3d75SLouis Dionne     }
148b1fb3d75SLouis Dionne 
149b1fb3d75SLouis Dionne     for (unsigned int i : generate_unsigned_integral_values<unsigned int>()) {
150b1fb3d75SLouis Dionne         test_roundtrip_through_nested_T(i);
151b1fb3d75SLouis Dionne         test_roundtrip_through_buffer(i);
152b1fb3d75SLouis Dionne         test_roundtrip_through<float>(i);
153b1fb3d75SLouis Dionne     }
154b1fb3d75SLouis Dionne 
155b1fb3d75SLouis Dionne     for (unsigned long i : generate_unsigned_integral_values<unsigned long>()) {
156b1fb3d75SLouis Dionne         test_roundtrip_through_nested_T(i);
157b1fb3d75SLouis Dionne         test_roundtrip_through_buffer(i);
158b1fb3d75SLouis Dionne     }
159b1fb3d75SLouis Dionne 
160b1fb3d75SLouis Dionne     for (unsigned long long i : generate_unsigned_integral_values<unsigned long long>()) {
161b1fb3d75SLouis Dionne         test_roundtrip_through_nested_T(i);
162b1fb3d75SLouis Dionne         test_roundtrip_through_buffer(i);
163b1fb3d75SLouis Dionne         test_roundtrip_through<double>(i);
164b1fb3d75SLouis Dionne     }
165b1fb3d75SLouis Dionne 
166b1fb3d75SLouis Dionne     // Fixed width signed integer types
167b1fb3d75SLouis Dionne     for (std::int32_t i : generate_signed_integral_values<std::int32_t>()) {
168b1fb3d75SLouis Dionne         test_roundtrip_through_nested_T(i);
169b1fb3d75SLouis Dionne         test_roundtrip_through_buffer(i);
170b1fb3d75SLouis Dionne         test_roundtrip_through<int>(i);
171b1fb3d75SLouis Dionne         test_roundtrip_through<std::uint32_t>(i);
172b1fb3d75SLouis Dionne         test_roundtrip_through<float>(i);
173b1fb3d75SLouis Dionne     }
174b1fb3d75SLouis Dionne 
175b1fb3d75SLouis Dionne     for (std::int64_t i : generate_signed_integral_values<std::int64_t>()) {
176b1fb3d75SLouis Dionne         test_roundtrip_through_nested_T(i);
177b1fb3d75SLouis Dionne         test_roundtrip_through_buffer(i);
178b1fb3d75SLouis Dionne         test_roundtrip_through<long long>(i);
179b1fb3d75SLouis Dionne         test_roundtrip_through<std::uint64_t>(i);
180b1fb3d75SLouis Dionne         test_roundtrip_through<double>(i);
181b1fb3d75SLouis Dionne     }
182b1fb3d75SLouis Dionne 
183b1fb3d75SLouis Dionne     // Fixed width unsigned integer types
184b1fb3d75SLouis Dionne     for (std::uint32_t i : generate_unsigned_integral_values<std::uint32_t>()) {
185b1fb3d75SLouis Dionne         test_roundtrip_through_nested_T(i);
186b1fb3d75SLouis Dionne         test_roundtrip_through_buffer(i);
187b1fb3d75SLouis Dionne         test_roundtrip_through<int>(i);
188b1fb3d75SLouis Dionne         test_roundtrip_through<std::int32_t>(i);
189b1fb3d75SLouis Dionne         test_roundtrip_through<float>(i);
190b1fb3d75SLouis Dionne     }
191b1fb3d75SLouis Dionne 
192b1fb3d75SLouis Dionne     for (std::uint64_t i : generate_unsigned_integral_values<std::uint64_t>()) {
193b1fb3d75SLouis Dionne         test_roundtrip_through_nested_T(i);
194b1fb3d75SLouis Dionne         test_roundtrip_through_buffer(i);
195b1fb3d75SLouis Dionne         test_roundtrip_through<long long>(i);
196b1fb3d75SLouis Dionne         test_roundtrip_through<std::int64_t>(i);
197b1fb3d75SLouis Dionne         test_roundtrip_through<double>(i);
198b1fb3d75SLouis Dionne     }
199b1fb3d75SLouis Dionne 
200b1fb3d75SLouis Dionne     // Floating point types
201b1fb3d75SLouis Dionne     for (float i : {0.0f, 1.0f, -1.0f, 10.0f, -10.0f, 1e10f, 1e-10f, 1e20f, 1e-20f, 2.71828f, 3.14159f,
202b1fb3d75SLouis Dionne                     std::nanf(""),
203b1fb3d75SLouis Dionne                     __builtin_nanf("0x55550001"), // NaN with a payload
204b1fb3d75SLouis Dionne                     std::numeric_limits<float>::signaling_NaN(),
205b1fb3d75SLouis Dionne                     std::numeric_limits<float>::quiet_NaN()}) {
206b1fb3d75SLouis Dionne         test_roundtrip_through_nested_T(i);
207b1fb3d75SLouis Dionne         test_roundtrip_through_buffer(i);
208b1fb3d75SLouis Dionne         test_roundtrip_through<int>(i);
209b1fb3d75SLouis Dionne     }
210b1fb3d75SLouis Dionne 
211b1fb3d75SLouis Dionne     for (double i : {0.0, 1.0, -1.0, 10.0, -10.0, 1e10, 1e-10, 1e100, 1e-100,
212b1fb3d75SLouis Dionne                      2.718281828459045,
213b1fb3d75SLouis Dionne                      3.141592653589793238462643383279502884197169399375105820974944,
214b1fb3d75SLouis Dionne                      std::nan(""),
215b1fb3d75SLouis Dionne                      std::numeric_limits<double>::signaling_NaN(),
216b1fb3d75SLouis Dionne                      std::numeric_limits<double>::quiet_NaN()}) {
217b1fb3d75SLouis Dionne         test_roundtrip_through_nested_T(i);
218b1fb3d75SLouis Dionne         test_roundtrip_through_buffer(i);
219b1fb3d75SLouis Dionne         test_roundtrip_through<long long>(i);
220b1fb3d75SLouis Dionne     }
221b1fb3d75SLouis Dionne 
222b1fb3d75SLouis Dionne     for (long double i : {0.0l, 1.0l, -1.0l, 10.0l, -10.0l, 1e10l, 1e-10l, 1e100l, 1e-100l,
223b1fb3d75SLouis Dionne                           2.718281828459045l,
224b1fb3d75SLouis Dionne                           3.141592653589793238462643383279502884197169399375105820974944l,
225b1fb3d75SLouis Dionne                           std::nanl(""),
226b1fb3d75SLouis Dionne                           std::numeric_limits<long double>::signaling_NaN(),
227b1fb3d75SLouis Dionne                           std::numeric_limits<long double>::quiet_NaN()}) {
228b1fb3d75SLouis Dionne         // Note that x86's `long double` has 80 value bits and 48 padding bits.
229b1fb3d75SLouis Dionne         test_roundtrip_through_nested_T<false>(i);
230b1fb3d75SLouis Dionne         test_roundtrip_through_buffer<false>(i);
231b1fb3d75SLouis Dionne 
232*c792de28SDavid Spickett #ifdef TEST_LONG_DOUBLE_IS_DOUBLE
233b1fb3d75SLouis Dionne         test_roundtrip_through<double, false>(i);
234a03e17d4SMartin Storsjö #endif
235bf0d6136SVitaly Buka #if defined(__SIZEOF_INT128__) && __SIZEOF_LONG_DOUBLE__ == __SIZEOF_INT128__ &&                                       \
236bf0d6136SVitaly Buka     !TEST_HAS_FEATURE(memory_sanitizer) // Some bits are just padding.
237b1fb3d75SLouis Dionne         test_roundtrip_through<__int128_t, false>(i);
238b1fb3d75SLouis Dionne         test_roundtrip_through<__uint128_t, false>(i);
239b1fb3d75SLouis Dionne #endif
240b1fb3d75SLouis Dionne     }
241b1fb3d75SLouis Dionne 
2421c834112SLouis Dionne     // Test pointers
2431c834112SLouis Dionne     {
2441c834112SLouis Dionne         {
2451c834112SLouis Dionne             int obj = 3;
2461c834112SLouis Dionne             void* p = &obj;
2471c834112SLouis Dionne             test_roundtrip_through_nested_T(p);
2481c834112SLouis Dionne             test_roundtrip_through_buffer(p);
2491c834112SLouis Dionne             test_roundtrip_through<void*>(p);
2501c834112SLouis Dionne             test_roundtrip_through<char*>(p);
2511c834112SLouis Dionne             test_roundtrip_through<int*>(p);
2521c834112SLouis Dionne         }
2531c834112SLouis Dionne         {
2541c834112SLouis Dionne             int obj = 3;
2551c834112SLouis Dionne             int* p = &obj;
2561c834112SLouis Dionne             test_roundtrip_through_nested_T(p);
2571c834112SLouis Dionne             test_roundtrip_through_buffer(p);
2581c834112SLouis Dionne             test_roundtrip_through<int*>(p);
2591c834112SLouis Dionne             test_roundtrip_through<char*>(p);
2601c834112SLouis Dionne             test_roundtrip_through<void*>(p);
2611c834112SLouis Dionne         }
2621c834112SLouis Dionne     }
2631c834112SLouis Dionne 
264b1fb3d75SLouis Dionne     return true;
265b1fb3d75SLouis Dionne }
266b1fb3d75SLouis Dionne 
267b1fb3d75SLouis Dionne // TODO: There doesn't seem to be a way to perform non-trivial correctness
268b1fb3d75SLouis Dionne //       tests inside constexpr.
269b1fb3d75SLouis Dionne constexpr bool basic_constexpr_test() {
270b1fb3d75SLouis Dionne     struct Nested { char buffer[sizeof(int)]; };
271b1fb3d75SLouis Dionne     int from = 3;
272b1fb3d75SLouis Dionne     Nested middle = std::bit_cast<Nested>(from);
273b1fb3d75SLouis Dionne     int to = std::bit_cast<int>(middle);
274b1fb3d75SLouis Dionne     assert(from == to);
275b1fb3d75SLouis Dionne     return true;
276b1fb3d75SLouis Dionne }
277b1fb3d75SLouis Dionne 
278b1fb3d75SLouis Dionne int main(int, char**) {
279b1fb3d75SLouis Dionne     tests();
280b1fb3d75SLouis Dionne     static_assert(basic_constexpr_test());
281b1fb3d75SLouis Dionne     return 0;
282b1fb3d75SLouis Dionne }
283