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 | // <type_traits> |
10 | // |
11 | // UNSUPPORTED: c++03, c++11, c++14, c++17 |
12 | // |
13 | // __is_always_bitcastable<_From, _To> |
14 | |
15 | #include "test_macros.h" |
16 | TEST_CLANG_DIAGNOSTIC_IGNORED("-Wprivate-header" ) |
17 | #include <__type_traits/is_always_bitcastable.h> |
18 | |
19 | #include <climits> |
20 | #include <cstdint> |
21 | #ifndef TEST_HAS_NO_WIDE_CHARACTERS |
22 | #include <cwchar> |
23 | #endif |
24 | #include "type_algorithms.h" |
25 | |
26 | // To test pointers to functions. |
27 | void Func1() {} |
28 | using FuncPtr1 = decltype(&Func1); |
29 | int Func2() { return 0; } |
30 | using FuncPtr2 = decltype(&Func2); |
31 | |
32 | template <bool Expected, class T, class U> |
33 | constexpr void check_one() { |
34 | static_assert(std::__is_always_bitcastable<T, U>::value == Expected); |
35 | } |
36 | |
37 | template <bool Expected, class T, class U> |
38 | constexpr void check_with_volatile() { |
39 | check_one<Expected, T, U>(); |
40 | check_one<Expected, volatile T, U>(); |
41 | check_one<Expected, T, volatile U>(); |
42 | check_one<Expected, volatile T, volatile U>(); |
43 | } |
44 | |
45 | template <bool Expected, class T, class U> |
46 | constexpr void check_with_cv() { |
47 | check_with_volatile<Expected, T, U>(); |
48 | check_with_volatile<Expected, const T, U>(); |
49 | check_with_volatile<Expected, T, const U>(); |
50 | check_with_volatile<Expected, const T, const U>(); |
51 | } |
52 | |
53 | template <bool Expected, class Types1, class Types2 = Types1> |
54 | constexpr void check() { |
55 | types::for_each(Types1{}, []<class T>() { |
56 | types::for_each(Types2{}, []<class U>() { |
57 | check_with_cv<Expected, T, U>(); |
58 | }); |
59 | }); |
60 | } |
61 | |
62 | template <bool Expected, class Types1, class Types2> |
63 | constexpr void check_both_ways() { |
64 | check<Expected, Types1, Types2>(); |
65 | check<Expected, Types2, Types1>(); |
66 | } |
67 | |
68 | constexpr void test() { |
69 | // Arithmetic types. |
70 | { |
71 | // Bit-castable arithmetic types. |
72 | |
73 | // 8-bit types. |
74 | using integral_8 = types::type_list<char8_t, std::int8_t, std::uint8_t>; |
75 | using chars = types::type_list<char, unsigned char, signed char>; |
76 | #if CHAR_BIT == 8 |
77 | check<true, types::concatenate_t<integral_8, chars>>(); |
78 | #else |
79 | check<true, integral_8>(); |
80 | check<true, chars>(); |
81 | #endif |
82 | |
83 | // 16-bit types. |
84 | using integral_16 = types::type_list<char16_t, std::int16_t, std::uint16_t>; |
85 | #if !defined(TEST_HAS_NO_WIDE_CHARACTERS) && __WCHAR_WIDTH__ == 16 |
86 | check<true, types::concatenate_t<integral_16, types::type_list<wchar_t>>>(); |
87 | #else |
88 | check<true, integral_16>(); |
89 | #endif |
90 | |
91 | // 32-bit types. |
92 | using integral_32 = types::type_list<char32_t, std::int32_t, std::uint32_t>; |
93 | #if !defined(TEST_HAS_NO_WIDE_CHARACTERS) && __WCHAR_WIDTH__ == 32 |
94 | check<true, types::concatenate_t<integral_32, types::type_list<wchar_t>>>(); |
95 | #else |
96 | check<true, integral_32>(); |
97 | #endif |
98 | |
99 | // 64-bit types. |
100 | using integral_64 = types::type_list<std::int64_t, std::uint64_t>; |
101 | check<true, integral_64>(); |
102 | |
103 | // 128-bit types. |
104 | #ifndef TEST_HAS_NO_INT128 |
105 | check<true, types::type_list<__int128_t, __uint128_t>>(); |
106 | #endif |
107 | |
108 | // Bool. |
109 | check<true, types::type_list<bool>, types::concatenate_t<types::type_list<bool>, integral_8>>(); |
110 | |
111 | // Non-bit-castable arithmetic types. |
112 | |
113 | // Floating-point. |
114 | check_both_ways<false, types::floating_point_types, types::integral_types>(); |
115 | check_both_ways<false, types::type_list<float>, types::type_list<double, long double>>(); |
116 | check_both_ways<false, types::type_list<double>, types::type_list<float, long double>>(); |
117 | check_both_ways<false, types::type_list<long double>, types::type_list<float, double>>(); |
118 | |
119 | // Different sizes. |
120 | check_both_ways<false, integral_8, types::concatenate_t<integral_16, integral_32, integral_64>>(); |
121 | check_both_ways<false, integral_16, types::concatenate_t<integral_8, integral_32, integral_64>>(); |
122 | check_both_ways<false, integral_32, types::concatenate_t<integral_8, integral_16, integral_64>>(); |
123 | check_both_ways<false, integral_64, types::concatenate_t<integral_8, integral_16, integral_32>>(); |
124 | |
125 | // Different representations -- can convert from bool to other integral types, but not vice versa. |
126 | check<true, types::type_list<bool>, integral_8>(); |
127 | using larger_than_bool = types::concatenate_t< |
128 | integral_16, |
129 | integral_32, |
130 | integral_64, |
131 | types::floating_point_types>; |
132 | check<false, types::type_list<bool>, larger_than_bool>(); |
133 | check<false, types::concatenate_t<integral_8, larger_than_bool>, types::type_list<bool>>(); |
134 | |
135 | // Different representations -- floating point vs. integral. |
136 | check_both_ways<false, types::floating_point_types, types::integral_types>(); |
137 | } |
138 | |
139 | // Enumerations. |
140 | { |
141 | enum E1 { Value1 }; |
142 | enum E2 { Value2 }; |
143 | check<true, types::type_list<E1>>(); |
144 | check_both_ways<false, types::type_list<E1>, types::type_list<E2>>(); |
145 | |
146 | enum class ScopedE1 { Value1 }; |
147 | enum class ScopedE2 { Value1 }; |
148 | check<true, types::type_list<ScopedE1>>(); |
149 | check_both_ways<false, types::type_list<ScopedE1>, types::type_list<ScopedE2>>(); |
150 | } |
151 | |
152 | // Pointers. |
153 | { |
154 | check<true, types::type_list<int*>>(); |
155 | check_both_ways<false, types::type_list<int*>, types::type_list<const int*, long*, void*>>(); |
156 | |
157 | check<true, types::type_list<FuncPtr1>>(); |
158 | check_both_ways<false, types::type_list<FuncPtr1>, types::type_list<FuncPtr2>>(); |
159 | } |
160 | |
161 | // Pointers to members. |
162 | { |
163 | struct S { |
164 | int mem_obj1 = 0; |
165 | long mem_obj2 = 0; |
166 | void MemFunc1() {} |
167 | int MemFunc2() { return 0; } |
168 | }; |
169 | using MemObjPtr1 = decltype(&S::mem_obj1); |
170 | using MemObjPtr2 = decltype(&S::mem_obj2); |
171 | using MemFuncPtr1 = decltype(&S::MemFunc1); |
172 | using MemFuncPtr2 = decltype(&S::MemFunc2); |
173 | |
174 | check<true, types::type_list<MemObjPtr1>>(); |
175 | check<true, types::type_list<MemFuncPtr1>>(); |
176 | check_both_ways<false, types::type_list<MemObjPtr1>, types::type_list<MemObjPtr2>>(); |
177 | check_both_ways<false, types::type_list<MemFuncPtr1>, types::type_list<MemFuncPtr2>>(); |
178 | } |
179 | |
180 | // Trivial classes. |
181 | { |
182 | struct S1 {}; |
183 | check<true, types::type_list<S1>>(); |
184 | |
185 | struct S2 {}; |
186 | check_both_ways<false, types::type_list<S1>, types::type_list<S2>>(); |
187 | |
188 | // Having a `volatile` member doesn't prevent a class type from being considered trivially copyable. This is |
189 | // unfortunate behavior but it is consistent with the Standard. |
190 | struct { |
191 | volatile int x; |
192 | }; |
193 | check<true, types::type_list<VolatileMembersS>>(); |
194 | } |
195 | |
196 | // Trivial unions. |
197 | { |
198 | union U1 {}; |
199 | check<true, types::type_list<U1>>(); |
200 | |
201 | union U2 {}; |
202 | check_both_ways<false, types::type_list<U1>, types::type_list<U2>>(); |
203 | |
204 | union VolatileMembersU { |
205 | volatile int x; |
206 | }; |
207 | check<true, types::type_list<VolatileMembersU>>(); |
208 | } |
209 | |
210 | // References are not objects, and thus are not bit-castable. |
211 | { |
212 | check_both_ways<false, types::type_list<int&>, types::type_list<int&>>(); |
213 | } |
214 | |
215 | // Arrays. |
216 | { |
217 | check<true, types::type_list<int[8]>>(); |
218 | } |
219 | } |
220 | |