xref: /llvm-project/clang/test/AST/ByteCode/builtin-bit-cast-bitfields.cpp (revision b4150ed128a136409a2510ee00003bd318f703fb)
117dfdd3aSTimm Bäder // RUN: %clang_cc1 -verify=expected,both -std=c++2a -fsyntax-only -triple x86_64-linux-gnu -fexperimental-new-constant-interpreter %s
212ca72baSTimm Bäder // RUN: %clang_cc1 -verify=expected,both -std=c++2a -fsyntax-only -triple armv8 -fexperimental-new-constant-interpreter %s
312ca72baSTimm Bäder // RUN: %clang_cc1 -verify=expected,both -std=c++2a -fsyntax-only -triple aarch64_be-linux-gnu -fexperimental-new-constant-interpreter %s
412ca72baSTimm Bäder // RUN: %clang_cc1 -verify=expected,both -std=c++2a -fsyntax-only -fexperimental-new-constant-interpreter -triple powerpc64le-unknown-unknown -mabi=ieeelongdouble %s
512ca72baSTimm Bäder // RUN: %clang_cc1 -verify=expected,both -std=c++2a -fsyntax-only -fexperimental-new-constant-interpreter -triple powerpc64-unknown-unknown -mabi=ieeelongdouble %s
612ca72baSTimm Bäder 
712ca72baSTimm Bäder #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
812ca72baSTimm Bäder #  define LITTLE_END 1
912ca72baSTimm Bäder #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
1012ca72baSTimm Bäder #  define LITTLE_END 0
1112ca72baSTimm Bäder #else
1212ca72baSTimm Bäder #  error "huh?"
1312ca72baSTimm Bäder #endif
1412ca72baSTimm Bäder 
1512ca72baSTimm Bäder typedef decltype(nullptr) nullptr_t;
1612ca72baSTimm Bäder typedef __INTPTR_TYPE__ intptr_t;
1712ca72baSTimm Bäder typedef unsigned __INT16_TYPE__ uint16_t;
1812ca72baSTimm Bäder typedef unsigned __INT32_TYPE__ uint32_t;
1912ca72baSTimm Bäder typedef unsigned __INT64_TYPE__ uint64_t;
2012ca72baSTimm Bäder 
2112ca72baSTimm Bäder static_assert(sizeof(int) == 4);
2212ca72baSTimm Bäder static_assert(sizeof(long long) == 8);
2312ca72baSTimm Bäder 
2412ca72baSTimm Bäder template <class To, class From>
2512ca72baSTimm Bäder constexpr To bit_cast(const From &from) {
2612ca72baSTimm Bäder   static_assert(sizeof(To) == sizeof(From));
2712ca72baSTimm Bäder   return __builtin_bit_cast(To, from);
2812ca72baSTimm Bäder }
2912ca72baSTimm Bäder 
3012ca72baSTimm Bäder template <class Intermediate, class Init>
3112ca72baSTimm Bäder constexpr bool check_round_trip(const Init &init) {
3212ca72baSTimm Bäder   return bit_cast<Init>(bit_cast<Intermediate>(init)) == init;
3312ca72baSTimm Bäder }
3412ca72baSTimm Bäder 
3512ca72baSTimm Bäder template <class Intermediate, class Init>
3612ca72baSTimm Bäder constexpr Init round_trip(const Init &init) {
3712ca72baSTimm Bäder   return bit_cast<Init>(bit_cast<Intermediate>(init));
3812ca72baSTimm Bäder }
3912ca72baSTimm Bäder 
4012ca72baSTimm Bäder namespace std {
4112ca72baSTimm Bäder enum byte : unsigned char {};
4212ca72baSTimm Bäder } // namespace std
4312ca72baSTimm Bäder 
4412ca72baSTimm Bäder template <int N, typename T = unsigned char, int Pad = 0>
4512ca72baSTimm Bäder struct bits {
4612ca72baSTimm Bäder   T : Pad;
4712ca72baSTimm Bäder   T bits : N;
4812ca72baSTimm Bäder 
4912ca72baSTimm Bäder   constexpr bool operator==(const T& rhs) const {
5012ca72baSTimm Bäder     return bits == rhs;
5112ca72baSTimm Bäder   }
5212ca72baSTimm Bäder };
5312ca72baSTimm Bäder 
5412ca72baSTimm Bäder template <int N, typename T, int P>
5512ca72baSTimm Bäder constexpr bool operator==(const struct bits<N, T, P>& lhs, const struct bits<N, T, P>& rhs) {
5612ca72baSTimm Bäder   return lhs.bits == rhs.bits;
5712ca72baSTimm Bäder }
5812ca72baSTimm Bäder 
5912ca72baSTimm Bäder template<int N>
6012ca72baSTimm Bäder struct bytes {
6112ca72baSTimm Bäder   using size_t = unsigned int;
6212ca72baSTimm Bäder   unsigned char d[N];
6312ca72baSTimm Bäder 
6412ca72baSTimm Bäder   constexpr unsigned char operator[](size_t index) {
6512ca72baSTimm Bäder     if (index < N)
66*b4150ed1STimm Baeder       return d[index]; // expected-note {{read of uninitialized object}}
6712ca72baSTimm Bäder     return -1;
6812ca72baSTimm Bäder   }
6912ca72baSTimm Bäder };
7012ca72baSTimm Bäder 
7112ca72baSTimm Bäder namespace Sanity {
7212ca72baSTimm Bäder   /// This is just one byte, and we extract 2 bits from it.
7312ca72baSTimm Bäder   ///
7412ca72baSTimm Bäder   /// 3 is 0000'0011.
7512ca72baSTimm Bäder   /// For both LE and BE, the buffer will contain exactly that
7612ca72baSTimm Bäder   /// byte, unaltered and not reordered in any way. It contains all 8 bits.
7712ca72baSTimm Bäder   static_assert(__builtin_bit_cast(bits<2>, (unsigned char)3) == (LITTLE_END ? 3 : 0));
7812ca72baSTimm Bäder 
7912ca72baSTimm Bäder   /// Similarly, we have one full byte of data, with the two most-significant
8012ca72baSTimm Bäder   /// bits set:
8112ca72baSTimm Bäder   /// 192 is 1100'0000
8212ca72baSTimm Bäder   static_assert(__builtin_bit_cast(bits<2>, (unsigned char)192) == (LITTLE_END ? 0 : 3));
8312ca72baSTimm Bäder 
8412ca72baSTimm Bäder 
8512ca72baSTimm Bäder   /// Here we are instead bitcasting two 1-bits into a destination of 8 bits.
8612ca72baSTimm Bäder   /// On LE, we should pick the two least-significant bits. On BE, the opposite.
8712ca72baSTimm Bäder   /// NOTE: Can't verify this with gcc.
8812ca72baSTimm Bäder   constexpr auto B1 = bits<2>{3};
8912ca72baSTimm Bäder   static_assert(__builtin_bit_cast(unsigned char, B1) == (LITTLE_END ? 3 : 192));
9012ca72baSTimm Bäder 
9112ca72baSTimm Bäder   /// This should be 0000'0110.
9212ca72baSTimm Bäder   /// On LE, this should result in 6.
9312ca72baSTimm Bäder   /// On BE, 1100'0000 = 192.
9412ca72baSTimm Bäder   constexpr auto B2 = bits<3>{6};
9512ca72baSTimm Bäder   static_assert(__builtin_bit_cast(unsigned char, B2) == (LITTLE_END ? 6 : 192));
9612ca72baSTimm Bäder 
9712ca72baSTimm Bäder   constexpr auto B3 = bits<4>{6};
9812ca72baSTimm Bäder   static_assert(__builtin_bit_cast(unsigned char, B3) == (LITTLE_END ? 6 : 96));
9912ca72baSTimm Bäder 
10012ca72baSTimm Bäder   struct B {
10112ca72baSTimm Bäder     std::byte b0 : 4;
10212ca72baSTimm Bäder     std::byte b1 : 4;
10312ca72baSTimm Bäder   };
10412ca72baSTimm Bäder 
10512ca72baSTimm Bäder   /// We can properly decompose one byte (8 bit) int two 4-bit bitfields.
10612ca72baSTimm Bäder   constexpr struct { unsigned char b0; } T = {0xee};
10712ca72baSTimm Bäder   constexpr B MB = __builtin_bit_cast(B, T);
10812ca72baSTimm Bäder   static_assert(MB.b0 == 0xe);
10912ca72baSTimm Bäder   static_assert(MB.b1 == 0xe);
11012ca72baSTimm Bäder }
11112ca72baSTimm Bäder 
11212ca72baSTimm Bäder namespace BitFields {
11312ca72baSTimm Bäder   struct BitFields {
11412ca72baSTimm Bäder     unsigned a : 2;
11512ca72baSTimm Bäder     unsigned b : 30;
11612ca72baSTimm Bäder   };
11712ca72baSTimm Bäder 
11812ca72baSTimm Bäder   constexpr unsigned A = __builtin_bit_cast(unsigned, BitFields{3, 16});
11912ca72baSTimm Bäder   static_assert(A == (LITTLE_END ? 67 : 3221225488));
12012ca72baSTimm Bäder 
12112ca72baSTimm Bäder   struct S {
12212ca72baSTimm Bäder     unsigned a : 2;
12312ca72baSTimm Bäder     unsigned b : 28;
12412ca72baSTimm Bäder     unsigned c : 2;
12512ca72baSTimm Bäder   };
12612ca72baSTimm Bäder 
12712ca72baSTimm Bäder   constexpr S s = __builtin_bit_cast(S, 0xFFFFFFFF);
12812ca72baSTimm Bäder   static_assert(s.a == 3);
12912ca72baSTimm Bäder   static_assert(s.b == 268435455);
13012ca72baSTimm Bäder   static_assert(s.c == 3);
13112ca72baSTimm Bäder 
13212ca72baSTimm Bäder   void bitfield_indeterminate() {
13312ca72baSTimm Bäder     struct BF { unsigned char z : 2; };
13412ca72baSTimm Bäder     enum byte : unsigned char {};
13512ca72baSTimm Bäder 
13612ca72baSTimm Bäder     constexpr BF bf = {0x3};
13712ca72baSTimm Bäder     static_assert(bit_cast<bits<2>>(bf).bits == bf.z);
13812ca72baSTimm Bäder     static_assert(bit_cast<unsigned char>(bf));
13912ca72baSTimm Bäder 
1402f9cd43aSTimm Baeder     static_assert(__builtin_bit_cast(byte, bf)); // expected-error {{not an integral constant expression}} \
1412f9cd43aSTimm Baeder                                                  // expected-note {{indeterminate value can only initialize an object of type 'unsigned char' or 'std::byte'; 'byte' is invalid}}
14212ca72baSTimm Bäder 
14312ca72baSTimm Bäder     struct M {
144*b4150ed1STimm Baeder       // expected-note@+1 {{subobject declared here}}
14512ca72baSTimm Bäder       unsigned char mem[sizeof(BF)];
14612ca72baSTimm Bäder     };
147*b4150ed1STimm Baeder     // expected-error@+2 {{initialized by a constant expression}}
148*b4150ed1STimm Baeder     // expected-note@+1 {{not initialized}}
14912ca72baSTimm Bäder     constexpr M m = bit_cast<M>(bf);
15012ca72baSTimm Bäder 
15112ca72baSTimm Bäder     constexpr auto f = []() constexpr {
15212ca72baSTimm Bäder       // bits<24, unsigned int, LITTLE_END ? 0 : 8> B = {0xc0ffee};
15312ca72baSTimm Bäder       constexpr struct { unsigned short b1; unsigned char b0;  } B = {0xc0ff, 0xee};
15412ca72baSTimm Bäder       return bit_cast<bytes<4>>(B);
15512ca72baSTimm Bäder     };
15612ca72baSTimm Bäder 
15712ca72baSTimm Bäder     static_assert(f()[0] + f()[1] + f()[2] == 0xc0 + 0xff + 0xee);
15812ca72baSTimm Bäder     {
159*b4150ed1STimm Baeder       // expected-error@+2 {{initialized by a constant expression}}
160*b4150ed1STimm Baeder       // expected-note@+1 {{in call to}}
16112ca72baSTimm Bäder       constexpr auto _bad = f()[3];
16212ca72baSTimm Bäder     }
16312ca72baSTimm Bäder 
16412ca72baSTimm Bäder     struct B {
16512ca72baSTimm Bäder       unsigned short s0 : 8;
16612ca72baSTimm Bäder       unsigned short s1 : 8;
16712ca72baSTimm Bäder       std::byte b0 : 4;
16812ca72baSTimm Bäder       std::byte b1 : 4;
16912ca72baSTimm Bäder       std::byte b2 : 4;
17012ca72baSTimm Bäder     };
17112ca72baSTimm Bäder     constexpr auto g = [f]() constexpr {
17212ca72baSTimm Bäder       return bit_cast<B>(f());
17312ca72baSTimm Bäder     };
17412ca72baSTimm Bäder     static_assert(g().s0 + g().s1 + g().b0 + g().b1 == 0xc0 + 0xff + 0xe + 0xe);
17512ca72baSTimm Bäder     {
176*b4150ed1STimm Baeder       // expected-error@+2 {{initialized by a constant expression}}
177*b4150ed1STimm Baeder       // expected-note@+1 {{read of uninitialized object is not allowed in a constant expression}}
17812ca72baSTimm Bäder       constexpr auto _bad = g().b2;
17912ca72baSTimm Bäder     }
18012ca72baSTimm Bäder   }
18112ca72baSTimm Bäder }
18212ca72baSTimm Bäder 
18312ca72baSTimm Bäder namespace BoolVectors {
18412ca72baSTimm Bäder   typedef bool bool32 __attribute__((ext_vector_type(32)));
18512ca72baSTimm Bäder   constexpr auto v = bit_cast<bool32>(0xa1c0ffee);
18612ca72baSTimm Bäder #if LITTLE_END
18712ca72baSTimm Bäder   static_assert(!v[0]);
18812ca72baSTimm Bäder   static_assert(v[1]);
18912ca72baSTimm Bäder   static_assert(v[2]);
19012ca72baSTimm Bäder   static_assert(v[3]);
19112ca72baSTimm Bäder   static_assert(!v[4]);
19212ca72baSTimm Bäder   static_assert(v[5]);
19312ca72baSTimm Bäder   static_assert(v[6]);
19412ca72baSTimm Bäder   static_assert(v[7]);
19512ca72baSTimm Bäder 
19612ca72baSTimm Bäder   static_assert(v[8]);
19712ca72baSTimm Bäder   static_assert(v[9]);
19812ca72baSTimm Bäder   static_assert(v[10]);
19912ca72baSTimm Bäder   static_assert(v[11]);
20012ca72baSTimm Bäder   static_assert(v[12]);
20112ca72baSTimm Bäder   static_assert(v[13]);
20212ca72baSTimm Bäder   static_assert(v[14]);
20312ca72baSTimm Bäder   static_assert(v[15]);
20412ca72baSTimm Bäder 
20512ca72baSTimm Bäder   static_assert(!v[16]);
20612ca72baSTimm Bäder   static_assert(!v[17]);
20712ca72baSTimm Bäder   static_assert(!v[18]);
20812ca72baSTimm Bäder   static_assert(!v[19]);
20912ca72baSTimm Bäder   static_assert(!v[20]);
21012ca72baSTimm Bäder   static_assert(!v[21]);
21112ca72baSTimm Bäder   static_assert(v[22]);
21212ca72baSTimm Bäder   static_assert(v[23]);
21312ca72baSTimm Bäder 
21412ca72baSTimm Bäder   static_assert(v[24]);
21512ca72baSTimm Bäder   static_assert(!v[25]);
21612ca72baSTimm Bäder   static_assert(!v[26]);
21712ca72baSTimm Bäder   static_assert(!v[27]);
21812ca72baSTimm Bäder   static_assert(!v[28]);
21912ca72baSTimm Bäder   static_assert(v[29]);
22012ca72baSTimm Bäder   static_assert(!v[30]);
22112ca72baSTimm Bäder   static_assert(v[31]);
22212ca72baSTimm Bäder 
22312ca72baSTimm Bäder #else
22412ca72baSTimm Bäder   static_assert(v[0]);
22512ca72baSTimm Bäder   static_assert(!v[1]);
22612ca72baSTimm Bäder   static_assert(v[2]);
22712ca72baSTimm Bäder   static_assert(!v[3]);
22812ca72baSTimm Bäder   static_assert(!v[4]);
22912ca72baSTimm Bäder   static_assert(!v[5]);
23012ca72baSTimm Bäder   static_assert(!v[6]);
23112ca72baSTimm Bäder   static_assert(v[7]);
23212ca72baSTimm Bäder 
23312ca72baSTimm Bäder   static_assert(v[8]);
23412ca72baSTimm Bäder   static_assert(v[9]);
23512ca72baSTimm Bäder   static_assert(!v[10]);
23612ca72baSTimm Bäder   static_assert(!v[11]);
23712ca72baSTimm Bäder   static_assert(!v[12]);
23812ca72baSTimm Bäder   static_assert(!v[13]);
23912ca72baSTimm Bäder   static_assert(!v[14]);
24012ca72baSTimm Bäder   static_assert(!v[15]);
24112ca72baSTimm Bäder 
24212ca72baSTimm Bäder   static_assert(v[16]);
24312ca72baSTimm Bäder   static_assert(v[17]);
24412ca72baSTimm Bäder   static_assert(v[18]);
24512ca72baSTimm Bäder   static_assert(v[19]);
24612ca72baSTimm Bäder   static_assert(v[20]);
24712ca72baSTimm Bäder   static_assert(v[21]);
24812ca72baSTimm Bäder   static_assert(v[22]);
24912ca72baSTimm Bäder   static_assert(v[23]);
25012ca72baSTimm Bäder 
25112ca72baSTimm Bäder   static_assert(v[24]);
25212ca72baSTimm Bäder   static_assert(v[25]);
25312ca72baSTimm Bäder   static_assert(v[26]);
25412ca72baSTimm Bäder   static_assert(!v[27]);
25512ca72baSTimm Bäder   static_assert(v[28]);
25612ca72baSTimm Bäder   static_assert(v[29]);
25712ca72baSTimm Bäder   static_assert(v[30]);
25812ca72baSTimm Bäder   static_assert(!v[31]);
25912ca72baSTimm Bäder #endif
26012ca72baSTimm Bäder 
26112ca72baSTimm Bäder   struct pad {
26212ca72baSTimm Bäder     unsigned short s;
26312ca72baSTimm Bäder     unsigned char c;
26412ca72baSTimm Bäder   };
26512ca72baSTimm Bäder 
26612ca72baSTimm Bäder   constexpr auto p = bit_cast<pad>(v);
26712ca72baSTimm Bäder   static_assert(p.s == (LITTLE_END ? 0xffee : 0xa1c0));
26812ca72baSTimm Bäder   static_assert(p.c == (LITTLE_END ? 0xc0 : 0xff));
26912ca72baSTimm Bäder }
27012ca72baSTimm Bäder 
27112ca72baSTimm Bäder namespace TwoShorts {
27212ca72baSTimm Bäder   struct B {
27312ca72baSTimm Bäder     unsigned short s0 : 8;
27412ca72baSTimm Bäder     unsigned short s1 : 8;
27512ca72baSTimm Bäder   };
27612ca72baSTimm Bäder   constexpr struct { unsigned short b1;} T = {0xc0ff};
27712ca72baSTimm Bäder   constexpr B MB = __builtin_bit_cast(B, T);
27812ca72baSTimm Bäder #if LITTLE_END
27912ca72baSTimm Bäder     static_assert(MB.s0 == 0xff);
28012ca72baSTimm Bäder     static_assert(MB.s1 == 0xc0);
28112ca72baSTimm Bäder #else
28212ca72baSTimm Bäder     static_assert(MB.s0 == 0xc0);
28312ca72baSTimm Bäder     static_assert(MB.s1 == 0xff);
28412ca72baSTimm Bäder 
28512ca72baSTimm Bäder #endif
28612ca72baSTimm Bäder }
28712ca72baSTimm Bäder 
28812ca72baSTimm Bäder typedef bool bool8 __attribute__((ext_vector_type(8)));
28912ca72baSTimm Bäder typedef bool bool9 __attribute__((ext_vector_type(9)));
29012ca72baSTimm Bäder typedef bool bool16 __attribute__((ext_vector_type(16)));
29112ca72baSTimm Bäder typedef bool bool17 __attribute__((ext_vector_type(17)));
29212ca72baSTimm Bäder typedef bool bool32 __attribute__((ext_vector_type(32)));
29312ca72baSTimm Bäder typedef bool bool128 __attribute__((ext_vector_type(128)));
29412ca72baSTimm Bäder 
29512ca72baSTimm Bäder static_assert(bit_cast<unsigned char>(bool8{1,0,1,0,1,0,1,0}) == (LITTLE_END ? 0x55 : 0xAA), "");
29612ca72baSTimm Bäder constexpr bool8 b8 = __builtin_bit_cast(bool8, 0x55); // both-error {{'__builtin_bit_cast' source type 'int' does not match destination type 'bool8' (vector of 8 'bool' values) (4 vs 1 bytes)}}
29712ca72baSTimm Bäder static_assert(check_round_trip<bool8>(static_cast<unsigned char>(0)), "");
29812ca72baSTimm Bäder static_assert(check_round_trip<bool8>(static_cast<unsigned char>(1)), "");
29912ca72baSTimm Bäder static_assert(check_round_trip<bool8>(static_cast<unsigned char>(0x55)), "");
30012ca72baSTimm Bäder 
30112ca72baSTimm Bäder static_assert(bit_cast<unsigned short>(bool16{1,1,1,1,1,0,0,0, 1,1,1,1,0,1,0,0}) == (LITTLE_END ? 0x2F1F : 0xF8F4), "");
30212ca72baSTimm Bäder 
30312ca72baSTimm Bäder static_assert(check_round_trip<bool16>(static_cast<short>(0xCAFE)), "");
30412ca72baSTimm Bäder static_assert(check_round_trip<bool32>(static_cast<int>(0xCAFEBABE)), "");
30512ca72baSTimm Bäder 
30612ca72baSTimm Bäder #ifdef __SIZEOF_INT128__
30712ca72baSTimm Bäder static_assert(check_round_trip<bool128>(static_cast<__int128_t>(0xCAFEBABE0C05FEFEULL)), "");
30812ca72baSTimm Bäder #endif
30912ca72baSTimm Bäder 
31012ca72baSTimm Bäder static_assert(bit_cast<bits<8, uint16_t, 7>, uint16_t>(0xcafe) == (LITTLE_END ? 0x95 : 0x7f));
31112ca72baSTimm Bäder static_assert(bit_cast<bits<4, uint16_t, 10>, uint16_t>(0xcafe) == (LITTLE_END ? 0x2 : 0xf));
31212ca72baSTimm Bäder static_assert(bit_cast<bits<4, uint32_t, 19>, uint32_t>(0xa1cafe) == (LITTLE_END ? 0x4 : 0x5));
31312ca72baSTimm Bäder 
31412ca72baSTimm Bäder struct S {
31512ca72baSTimm Bäder   // little endian:
31612ca72baSTimm Bäder   //    MSB .... .... LSB
31712ca72baSTimm Bäder   //        |y|   |x|
31812ca72baSTimm Bäder   //
31912ca72baSTimm Bäder   // big endian
32012ca72baSTimm Bäder   //    MSB .... .... LSB
32112ca72baSTimm Bäder   //        |x|   |y|
32212ca72baSTimm Bäder 
32312ca72baSTimm Bäder   unsigned char x : 4;
32412ca72baSTimm Bäder   unsigned char y : 4;
32512ca72baSTimm Bäder 
32612ca72baSTimm Bäder   constexpr bool operator==(S const &other) const {
32712ca72baSTimm Bäder     return x == other.x && y == other.y;
32812ca72baSTimm Bäder   }
32912ca72baSTimm Bäder };
33012ca72baSTimm Bäder 
33112ca72baSTimm Bäder constexpr S s{0xa, 0xb};
33212ca72baSTimm Bäder static_assert(bit_cast<bits<8>>(s) == (LITTLE_END ? 0xba : 0xab));
33312ca72baSTimm Bäder static_assert(bit_cast<bits<7>>(s) == (LITTLE_END
33412ca72baSTimm Bäder                                             ? 0xba & 0x7f
33512ca72baSTimm Bäder                                             : (0xab & 0xfe) >> 1));
33612ca72baSTimm Bäder 
33712ca72baSTimm Bäder static_assert(round_trip<bits<8>>(s) == s);
33812ca72baSTimm Bäder 
33912ca72baSTimm Bäder struct R {
34012ca72baSTimm Bäder   unsigned int r : 31;
34112ca72baSTimm Bäder   unsigned int : 0;
34212ca72baSTimm Bäder   unsigned int : 32;
34312ca72baSTimm Bäder   constexpr bool operator==(R const &other) const {
34412ca72baSTimm Bäder     return r == other.r;
34512ca72baSTimm Bäder   }
34612ca72baSTimm Bäder  };
34712ca72baSTimm Bäder using T = bits<31, signed long long>;
34812ca72baSTimm Bäder constexpr R r{0x4ac0ffee};
34912ca72baSTimm Bäder constexpr T t = bit_cast<T>(r);
35012ca72baSTimm Bäder static_assert(t == ((0xFFFFFFFF8 << 28) | 0x4ac0ffee)); // sign extension
35112ca72baSTimm Bäder 
35212ca72baSTimm Bäder static_assert(round_trip<T>(r) == r);
35312ca72baSTimm Bäder static_assert(round_trip<R>(t) == t);
35412ca72baSTimm Bäder 
35512ca72baSTimm Bäder 
35612ca72baSTimm Bäder /// The oversized bitfield is an error on Windows and not just a warning.
35712ca72baSTimm Bäder #if !defined(_WIN32)
35812ca72baSTimm Bäder struct U {
35912ca72baSTimm Bäder   // expected-warning@+1 {{exceeds the width of its type}}
36012ca72baSTimm Bäder   uint32_t trunc : 33;
36112ca72baSTimm Bäder   uint32_t u : 31;
36212ca72baSTimm Bäder   constexpr bool operator==(U const &other) const {
36312ca72baSTimm Bäder     return trunc == other.trunc && u == other.u;
36412ca72baSTimm Bäder   }
36512ca72baSTimm Bäder };
36612ca72baSTimm Bäder struct V {
36712ca72baSTimm Bäder   uint64_t notrunc : 32;
36812ca72baSTimm Bäder   uint64_t : 1;
36912ca72baSTimm Bäder   uint64_t v : 31;
37012ca72baSTimm Bäder   constexpr bool operator==(V const &other) const {
37112ca72baSTimm Bäder     return notrunc == other.notrunc && v == other.v;
37212ca72baSTimm Bäder   }
37312ca72baSTimm Bäder };
37412ca72baSTimm Bäder 
37512ca72baSTimm Bäder constexpr U u{static_cast<unsigned int>(~0), 0x4ac0ffee};
37612ca72baSTimm Bäder constexpr V v = bit_cast<V>(u);
37712ca72baSTimm Bäder static_assert(v.v == 0x4ac0ffee);
37812ca72baSTimm Bäder 
37912ca72baSTimm Bäder static_assert(round_trip<V>(u) == u);
38012ca72baSTimm Bäder static_assert(round_trip<U>(v) == v);
38112ca72baSTimm Bäder 
38212ca72baSTimm Bäder constexpr auto w = bit_cast<bits<12, unsigned long, 33>>(u);
38312ca72baSTimm Bäder static_assert(w == (LITTLE_END
38412ca72baSTimm Bäder                     ? 0x4ac0ffee & 0xFFF
38512ca72baSTimm Bäder                     : (0x4ac0ffee & (0xFFF << (31 - 12))) >> (31-12)
38612ca72baSTimm Bäder                   ));
38712ca72baSTimm Bäder #endif
38812ca72baSTimm Bäder 
38912ca72baSTimm Bäder 
39012ca72baSTimm Bäder namespace NestedStructures {
39112ca72baSTimm Bäder   struct J {
39212ca72baSTimm Bäder     struct {
39312ca72baSTimm Bäder       uint16_t  k : 12;
39412ca72baSTimm Bäder     } K;
39512ca72baSTimm Bäder     struct {
39612ca72baSTimm Bäder       uint16_t  l : 4;
39712ca72baSTimm Bäder     } L;
39812ca72baSTimm Bäder   };
39912ca72baSTimm Bäder 
40012ca72baSTimm Bäder   static_assert(sizeof(J) == 4);
40112ca72baSTimm Bäder   constexpr J j = bit_cast<J>(0x8c0ffee5);
40212ca72baSTimm Bäder 
40312ca72baSTimm Bäder   static_assert(j.K.k == (LITTLE_END ? 0xee5 : 0x8c0));
40412ca72baSTimm Bäder   static_assert(j.L.l == 0xf /* yay symmetry */);
40512ca72baSTimm Bäder   static_assert(bit_cast<bits<4, uint16_t, 16>>(j) == 0xf);
40612ca72baSTimm Bäder   struct N {
40712ca72baSTimm Bäder     bits<12, uint16_t> k;
40812ca72baSTimm Bäder     uint16_t : 16;
40912ca72baSTimm Bäder   };
41012ca72baSTimm Bäder   static_assert(bit_cast<N>(j).k == j.K.k);
41112ca72baSTimm Bäder 
41212ca72baSTimm Bäder   struct M {
41312ca72baSTimm Bäder     bits<4, uint16_t, 0> m[2];
41412ca72baSTimm Bäder     constexpr bool operator==(const M& rhs) const {
41512ca72baSTimm Bäder       return m[0] == rhs.m[0] && m[1] == rhs.m[1];
41612ca72baSTimm Bäder     };
41712ca72baSTimm Bäder   };
41812ca72baSTimm Bäder   #if LITTLE_END == 1
41912ca72baSTimm Bäder   constexpr uint16_t want[2] = {0x5, 0xf};
42012ca72baSTimm Bäder   #else
42112ca72baSTimm Bäder   constexpr uint16_t want[2] = {0x8000, 0xf000};
42212ca72baSTimm Bäder   #endif
42312ca72baSTimm Bäder 
42412ca72baSTimm Bäder   static_assert(bit_cast<M>(j) == bit_cast<M>(want));
42512ca72baSTimm Bäder }
42612ca72baSTimm Bäder 
42712ca72baSTimm Bäder namespace Enums {
42812ca72baSTimm Bäder   // ensure we're packed into the top 2 bits
42912ca72baSTimm Bäder   constexpr int pad = LITTLE_END ? 6 : 0;
43012ca72baSTimm Bäder   struct X
43112ca72baSTimm Bäder   {
43212ca72baSTimm Bäder     char : pad;
43312ca72baSTimm Bäder     enum class direction: char { left, right, up, down } direction : 2;
43412ca72baSTimm Bäder   };
43512ca72baSTimm Bäder 
43612ca72baSTimm Bäder   constexpr X x = { X::direction::down };
43712ca72baSTimm Bäder   static_assert(bit_cast<bits<2, signed char, pad>>(x) == -1);
43812ca72baSTimm Bäder   static_assert(bit_cast<bits<2, unsigned char, pad>>(x) == 3);
43912ca72baSTimm Bäder   static_assert(
44012ca72baSTimm Bäder     bit_cast<X>((unsigned char)0x40).direction == X::direction::right);
44112ca72baSTimm Bäder }
4422f9cd43aSTimm Baeder 
4432f9cd43aSTimm Baeder namespace IndeterminateBits {
4442f9cd43aSTimm Baeder   struct S {
4452f9cd43aSTimm Baeder     unsigned a : 13;
4462f9cd43aSTimm Baeder     unsigned   : 17;
4472f9cd43aSTimm Baeder     unsigned b : 2;
4482f9cd43aSTimm Baeder   };
4492f9cd43aSTimm Baeder   constexpr unsigned A = __builtin_bit_cast(unsigned, S{12, 3}); // expected-error {{must be initialized by a constant expression}} \
4502f9cd43aSTimm Baeder                                                                  // expected-note {{indeterminate value can only initialize an object of type 'unsigned char' or 'std::byte'; 'unsigned int' is invalid}}
4512f9cd43aSTimm Baeder 
4522f9cd43aSTimm Baeder 
4532f9cd43aSTimm Baeder   /// GCC refuses to compile this as soon as we access the indeterminate bits
4542f9cd43aSTimm Baeder   /// in the static_assert. MSVC accepts it.
4552f9cd43aSTimm Baeder   struct S2 {
4562f9cd43aSTimm Baeder     unsigned char a : 2;
4572f9cd43aSTimm Baeder   };
4582f9cd43aSTimm Baeder   constexpr unsigned char B = __builtin_bit_cast(unsigned char, S2{3});
4592f9cd43aSTimm Baeder   static_assert(B == (LITTLE_END ? 3 : 192));
460*b4150ed1STimm Baeder 
461*b4150ed1STimm Baeder 
462*b4150ed1STimm Baeder 
463*b4150ed1STimm Baeder   struct S3 {
464*b4150ed1STimm Baeder     unsigned a : 13;
465*b4150ed1STimm Baeder     unsigned   : 17;
466*b4150ed1STimm Baeder     unsigned b : 2;
467*b4150ed1STimm Baeder   };
468*b4150ed1STimm Baeder 
469*b4150ed1STimm Baeder   struct D {
470*b4150ed1STimm Baeder     unsigned a;
471*b4150ed1STimm Baeder   };
472*b4150ed1STimm Baeder   constexpr D s = __builtin_bit_cast(D, S3{12, 3}); // expected-error {{must be initialized by a constant expression}} \
473*b4150ed1STimm Baeder                                                     // expected-note {{indeterminate value can only initialize an object of type 'unsigned char' or 'std::byte'; 'unsigned int' is invalid}}
474*b4150ed1STimm Baeder 
4752f9cd43aSTimm Baeder }
476