1//===----------------------------------------------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
9// UNSUPPORTED: c++03, c++11, c++14, c++17
10
11// <bit>
12//
13// template<class To, class From>
14// constexpr To bit_cast(const From& from) noexcept; // C++20
15
16#include <array>
17#include <bit>
18#include <cassert>
19#include <cmath>
20#include <cstdint>
21#include <cstring>
22#include <limits>
23
24#include "test_macros.h"
25
26// std::bit_cast does not preserve padding bits, so if T has padding bits,
27// the results might not memcmp cleanly.
28template<bool HasUniqueObjectRepresentations = true, typename T>
29void 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);
34
35 assert((from == to) == (from == from)); // because NaN
36
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);
41 }
42}
43
44template<bool HasUniqueObjectRepresentations = true, typename T>
45void test_roundtrip_through_nested_T(T from) {
46 struct Nested { T x; };
47 static_assert(sizeof(Nested) == sizeof(T));
48
49 Nested middle = std::bit_cast<Nested>(from);
50 T to = std::bit_cast<T>(middle);
51 Nested middle2 = std::bit_cast<Nested>(to);
52
53 assert((from == to) == (from == from)); // because NaN
54
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);
59 }
60}
61
62template <typename Intermediate, bool HasUniqueObjectRepresentations = true, typename T>
63void test_roundtrip_through(T from) {
64 static_assert(sizeof(Intermediate) == sizeof(T));
65
66 Intermediate middle = std::bit_cast<Intermediate>(from);
67 T to = std::bit_cast<T>(middle);
68 Intermediate middle2 = std::bit_cast<Intermediate>(to);
69
70 assert((from == to) == (from == from)); // because NaN
71
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);
76 }
77}
78
79template <typename T>
80constexpr 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()};
88}
89
90template <typename T>
91constexpr 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()};
96}
97
98bool tests() {
99 for (bool b : {false, true}) {
100 test_roundtrip_through_nested_T(from: b);
101 test_roundtrip_through_buffer(from: b);
102 test_roundtrip_through<char>(from: b);
103 }
104
105 for (char c : {'\0', 'a', 'b', 'c', 'd'}) {
106 test_roundtrip_through_nested_T(from: c);
107 test_roundtrip_through_buffer(from: c);
108 }
109
110 // Fundamental signed integer types
111 for (signed char i : generate_signed_integral_values<signed char>()) {
112 test_roundtrip_through_nested_T(from: i);
113 test_roundtrip_through_buffer(from: i);
114 }
115
116 for (short i : generate_signed_integral_values<short>()) {
117 test_roundtrip_through_nested_T(from: i);
118 test_roundtrip_through_buffer(from: i);
119 }
120
121 for (int i : generate_signed_integral_values<int>()) {
122 test_roundtrip_through_nested_T(from: i);
123 test_roundtrip_through_buffer(from: i);
124 test_roundtrip_through<float>(from: i);
125 }
126
127 for (long i : generate_signed_integral_values<long>()) {
128 test_roundtrip_through_nested_T(from: i);
129 test_roundtrip_through_buffer(from: i);
130 }
131
132 for (long long i : generate_signed_integral_values<long long>()) {
133 test_roundtrip_through_nested_T(from: i);
134 test_roundtrip_through_buffer(from: i);
135 test_roundtrip_through<double>(from: i);
136 }
137
138 // Fundamental unsigned integer types
139 for (unsigned char i : generate_unsigned_integral_values<unsigned char>()) {
140 test_roundtrip_through_nested_T(from: i);
141 test_roundtrip_through_buffer(from: i);
142 }
143
144 for (unsigned short i : generate_unsigned_integral_values<unsigned short>()) {
145 test_roundtrip_through_nested_T(from: i);
146 test_roundtrip_through_buffer(from: i);
147 }
148
149 for (unsigned int i : generate_unsigned_integral_values<unsigned int>()) {
150 test_roundtrip_through_nested_T(from: i);
151 test_roundtrip_through_buffer(from: i);
152 test_roundtrip_through<float>(from: i);
153 }
154
155 for (unsigned long i : generate_unsigned_integral_values<unsigned long>()) {
156 test_roundtrip_through_nested_T(from: i);
157 test_roundtrip_through_buffer(from: i);
158 }
159
160 for (unsigned long long i : generate_unsigned_integral_values<unsigned long long>()) {
161 test_roundtrip_through_nested_T(from: i);
162 test_roundtrip_through_buffer(from: i);
163 test_roundtrip_through<double>(from: i);
164 }
165
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(from: i);
169 test_roundtrip_through_buffer(from: i);
170 test_roundtrip_through<int>(from: i);
171 test_roundtrip_through<std::uint32_t>(from: i);
172 test_roundtrip_through<float>(from: i);
173 }
174
175 for (std::int64_t i : generate_signed_integral_values<std::int64_t>()) {
176 test_roundtrip_through_nested_T(from: i);
177 test_roundtrip_through_buffer(from: i);
178 test_roundtrip_through<long long>(from: i);
179 test_roundtrip_through<std::uint64_t>(from: i);
180 test_roundtrip_through<double>(from: i);
181 }
182
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(from: i);
186 test_roundtrip_through_buffer(from: i);
187 test_roundtrip_through<int>(from: i);
188 test_roundtrip_through<std::int32_t>(from: i);
189 test_roundtrip_through<float>(from: i);
190 }
191
192 for (std::uint64_t i : generate_unsigned_integral_values<std::uint64_t>()) {
193 test_roundtrip_through_nested_T(from: i);
194 test_roundtrip_through_buffer(from: i);
195 test_roundtrip_through<long long>(from: i);
196 test_roundtrip_through<std::int64_t>(from: i);
197 test_roundtrip_through<double>(from: i);
198 }
199
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,
202 std::nanf(tagb: ""),
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(from: i);
207 test_roundtrip_through_buffer(from: i);
208 test_roundtrip_through<int>(from: i);
209 }
210
211 for (double i : {0.0, 1.0, -1.0, 10.0, -10.0, 1e10, 1e-10, 1e100, 1e-100,
212 2.718281828459045,
213 3.141592653589793238462643383279502884197169399375105820974944,
214 std::nan(tagb: ""),
215 std::numeric_limits<double>::signaling_NaN(),
216 std::numeric_limits<double>::quiet_NaN()}) {
217 test_roundtrip_through_nested_T(from: i);
218 test_roundtrip_through_buffer(from: i);
219 test_roundtrip_through<long long>(from: i);
220 }
221
222 for (long double i : {0.0l, 1.0l, -1.0l, 10.0l, -10.0l, 1e10l, 1e-10l, 1e100l, 1e-100l,
223 2.718281828459045l,
224 3.141592653589793238462643383279502884197169399375105820974944l,
225 std::nanl(tagb: ""),
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>(from: i);
230 test_roundtrip_through_buffer<false>(from: i);
231
232#if __SIZEOF_LONG_DOUBLE__ == __SIZEOF_DOUBLE__
233 test_roundtrip_through<double, false>(i);
234#endif
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);
239#endif
240 }
241
242 // Test pointers
243 {
244 {
245 int obj = 3;
246 void* p = &obj;
247 test_roundtrip_through_nested_T(from: p);
248 test_roundtrip_through_buffer(from: p);
249 test_roundtrip_through<void*>(from: p);
250 test_roundtrip_through<char*>(from: p);
251 test_roundtrip_through<int*>(from: p);
252 }
253 {
254 int obj = 3;
255 int* p = &obj;
256 test_roundtrip_through_nested_T(from: p);
257 test_roundtrip_through_buffer(from: p);
258 test_roundtrip_through<int*>(from: p);
259 test_roundtrip_through<char*>(from: p);
260 test_roundtrip_through<void*>(from: p);
261 }
262 }
263
264 return true;
265}
266
267// TODO: There doesn't seem to be a way to perform non-trivial correctness
268// tests inside constexpr.
269constexpr bool basic_constexpr_test() {
270 struct Nested { char buffer[sizeof(int)]; };
271 int from = 3;
272 Nested middle = std::bit_cast<Nested>(from);
273 int to = std::bit_cast<int>(middle);
274 assert(from == to);
275 return true;
276}
277
278int main(int, char**) {
279 tests();
280 static_assert(basic_constexpr_test());
281 return 0;
282}
283

source code of libcxx/test/std/numerics/bit/bit.cast/bit_cast.pass.cpp