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.
Func1()27 void Func1() {}
28 using FuncPtr1 = decltype(&Func1);
Func2()29 int Func2() { return 0; }
30 using FuncPtr2 = decltype(&Func2);
31 
32 template <bool Expected, class T, class U>
check_one()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>
check_with_volatile()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>
check_with_cv()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>
check()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>
check_both_ways()63 constexpr void check_both_ways() {
64   check<Expected, Types1, Types2>();
65   check<Expected, Types2, Types1>();
66 }
67 
test()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 VolatileMembersS {
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