| // RUN: %clang_cc1 -verify=expected,both -std=c++2a -fsyntax-only -triple x86_64-linux-gnu -fexperimental-new-constant-interpreter %s |
| // RUN: %clang_cc1 -verify=expected,both -std=c++2a -fsyntax-only -triple armv8 -fexperimental-new-constant-interpreter %s |
| // RUN: %clang_cc1 -verify=expected,both -std=c++2a -fsyntax-only -triple aarch64_be-linux-gnu -fexperimental-new-constant-interpreter %s |
| // RUN: %clang_cc1 -verify=expected,both -std=c++2a -fsyntax-only -fexperimental-new-constant-interpreter -triple powerpc64le-unknown-unknown -mabi=ieeelongdouble %s |
| // RUN: %clang_cc1 -verify=expected,both -std=c++2a -fsyntax-only -fexperimental-new-constant-interpreter -triple powerpc64-unknown-unknown -mabi=ieeelongdouble %s |
| |
| #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ |
| # define LITTLE_END 1 |
| #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ |
| # define LITTLE_END 0 |
| #else |
| # error "huh?" |
| #endif |
| |
| typedef decltype(nullptr) nullptr_t; |
| typedef __INTPTR_TYPE__ intptr_t; |
| typedef unsigned __INT16_TYPE__ uint16_t; |
| typedef unsigned __INT32_TYPE__ uint32_t; |
| typedef unsigned __INT64_TYPE__ uint64_t; |
| |
| static_assert(sizeof(int) == 4); |
| static_assert(sizeof(long long) == 8); |
| |
| template <class To, class From> |
| constexpr To bit_cast(const From &from) { |
| static_assert(sizeof(To) == sizeof(From)); |
| return __builtin_bit_cast(To, from); |
| } |
| |
| template <class Intermediate, class Init> |
| constexpr bool check_round_trip(const Init &init) { |
| return bit_cast<Init>(bit_cast<Intermediate>(init)) == init; |
| } |
| |
| template <class Intermediate, class Init> |
| constexpr Init round_trip(const Init &init) { |
| return bit_cast<Init>(bit_cast<Intermediate>(init)); |
| } |
| |
| namespace std { |
| enum byte : unsigned char {}; |
| } // namespace std |
| |
| template <int N, typename T = unsigned char, int Pad = 0> |
| struct bits { |
| T : Pad; |
| T bits : N; |
| |
| constexpr bool operator==(const T& rhs) const { |
| return bits == rhs; |
| } |
| }; |
| |
| template <int N, typename T, int P> |
| constexpr bool operator==(const struct bits<N, T, P>& lhs, const struct bits<N, T, P>& rhs) { |
| return lhs.bits == rhs.bits; |
| } |
| |
| template<int N> |
| struct bytes { |
| using size_t = unsigned int; |
| unsigned char d[N]; |
| |
| constexpr unsigned char operator[](size_t index) { |
| if (index < N) |
| return d[index]; // expected-note {{read of uninitialized object}} |
| return -1; |
| } |
| }; |
| |
| namespace Sanity { |
| /// This is just one byte, and we extract 2 bits from it. |
| /// |
| /// 3 is 0000'0011. |
| /// For both LE and BE, the buffer will contain exactly that |
| /// byte, unaltered and not reordered in any way. It contains all 8 bits. |
| static_assert(__builtin_bit_cast(bits<2>, (unsigned char)3) == (LITTLE_END ? 3 : 0)); |
| |
| /// Similarly, we have one full byte of data, with the two most-significant |
| /// bits set: |
| /// 192 is 1100'0000 |
| static_assert(__builtin_bit_cast(bits<2>, (unsigned char)192) == (LITTLE_END ? 0 : 3)); |
| |
| |
| /// Here we are instead bitcasting two 1-bits into a destination of 8 bits. |
| /// On LE, we should pick the two least-significant bits. On BE, the opposite. |
| /// NOTE: Can't verify this with gcc. |
| constexpr auto B1 = bits<2>{3}; |
| static_assert(__builtin_bit_cast(unsigned char, B1) == (LITTLE_END ? 3 : 192)); |
| |
| /// This should be 0000'0110. |
| /// On LE, this should result in 6. |
| /// On BE, 1100'0000 = 192. |
| constexpr auto B2 = bits<3>{6}; |
| static_assert(__builtin_bit_cast(unsigned char, B2) == (LITTLE_END ? 6 : 192)); |
| |
| constexpr auto B3 = bits<4>{6}; |
| static_assert(__builtin_bit_cast(unsigned char, B3) == (LITTLE_END ? 6 : 96)); |
| |
| struct B { |
| std::byte b0 : 4; |
| std::byte b1 : 4; |
| }; |
| |
| /// We can properly decompose one byte (8 bit) int two 4-bit bitfields. |
| constexpr struct { unsigned char b0; } T = {0xee}; |
| constexpr B MB = __builtin_bit_cast(B, T); |
| static_assert(MB.b0 == 0xe); |
| static_assert(MB.b1 == 0xe); |
| } |
| |
| namespace BitFields { |
| struct BitFields { |
| unsigned a : 2; |
| unsigned b : 30; |
| }; |
| |
| constexpr unsigned A = __builtin_bit_cast(unsigned, BitFields{3, 16}); |
| static_assert(A == (LITTLE_END ? 67 : 3221225488)); |
| |
| struct S { |
| unsigned a : 2; |
| unsigned b : 28; |
| unsigned c : 2; |
| }; |
| |
| constexpr S s = __builtin_bit_cast(S, 0xFFFFFFFF); |
| static_assert(s.a == 3); |
| static_assert(s.b == 268435455); |
| static_assert(s.c == 3); |
| |
| void bitfield_indeterminate() { |
| struct BF { unsigned char z : 2; }; |
| enum byte : unsigned char {}; |
| |
| constexpr BF bf = {0x3}; |
| static_assert(bit_cast<bits<2>>(bf).bits == bf.z); |
| static_assert(bit_cast<unsigned char>(bf)); |
| |
| static_assert(__builtin_bit_cast(byte, bf)); // expected-error {{not an integral constant expression}} \ |
| // expected-note {{indeterminate value can only initialize an object of type 'unsigned char' or 'std::byte'; 'byte' is invalid}} |
| |
| struct M { |
| // expected-note@+1 {{subobject declared here}} |
| unsigned char mem[sizeof(BF)]; |
| }; |
| // expected-error@+2 {{initialized by a constant expression}} |
| // expected-note@+1 {{not initialized}} |
| constexpr M m = bit_cast<M>(bf); |
| |
| constexpr auto f = []() constexpr { |
| // bits<24, unsigned int, LITTLE_END ? 0 : 8> B = {0xc0ffee}; |
| constexpr struct { unsigned short b1; unsigned char b0; } B = {0xc0ff, 0xee}; |
| return bit_cast<bytes<4>>(B); |
| }; |
| |
| static_assert(f()[0] + f()[1] + f()[2] == 0xc0 + 0xff + 0xee); |
| { |
| // expected-error@+2 {{initialized by a constant expression}} |
| // expected-note@+1 {{in call to}} |
| constexpr auto _bad = f()[3]; |
| } |
| |
| struct B { |
| unsigned short s0 : 8; |
| unsigned short s1 : 8; |
| std::byte b0 : 4; |
| std::byte b1 : 4; |
| std::byte b2 : 4; |
| }; |
| constexpr auto g = [f]() constexpr { |
| return bit_cast<B>(f()); |
| }; |
| static_assert(g().s0 + g().s1 + g().b0 + g().b1 == 0xc0 + 0xff + 0xe + 0xe); |
| { |
| // expected-error@+2 {{initialized by a constant expression}} |
| // expected-note@+1 {{read of uninitialized object is not allowed in a constant expression}} |
| constexpr auto _bad = g().b2; |
| } |
| } |
| } |
| |
| namespace BoolVectors { |
| typedef bool bool32 __attribute__((ext_vector_type(32))); |
| constexpr auto v = bit_cast<bool32>(0xa1c0ffee); |
| #if LITTLE_END |
| static_assert(!v[0]); |
| static_assert(v[1]); |
| static_assert(v[2]); |
| static_assert(v[3]); |
| static_assert(!v[4]); |
| static_assert(v[5]); |
| static_assert(v[6]); |
| static_assert(v[7]); |
| |
| static_assert(v[8]); |
| static_assert(v[9]); |
| static_assert(v[10]); |
| static_assert(v[11]); |
| static_assert(v[12]); |
| static_assert(v[13]); |
| static_assert(v[14]); |
| static_assert(v[15]); |
| |
| static_assert(!v[16]); |
| static_assert(!v[17]); |
| static_assert(!v[18]); |
| static_assert(!v[19]); |
| static_assert(!v[20]); |
| static_assert(!v[21]); |
| static_assert(v[22]); |
| static_assert(v[23]); |
| |
| static_assert(v[24]); |
| static_assert(!v[25]); |
| static_assert(!v[26]); |
| static_assert(!v[27]); |
| static_assert(!v[28]); |
| static_assert(v[29]); |
| static_assert(!v[30]); |
| static_assert(v[31]); |
| |
| #else |
| static_assert(v[0]); |
| static_assert(!v[1]); |
| static_assert(v[2]); |
| static_assert(!v[3]); |
| static_assert(!v[4]); |
| static_assert(!v[5]); |
| static_assert(!v[6]); |
| static_assert(v[7]); |
| |
| static_assert(v[8]); |
| static_assert(v[9]); |
| static_assert(!v[10]); |
| static_assert(!v[11]); |
| static_assert(!v[12]); |
| static_assert(!v[13]); |
| static_assert(!v[14]); |
| static_assert(!v[15]); |
| |
| static_assert(v[16]); |
| static_assert(v[17]); |
| static_assert(v[18]); |
| static_assert(v[19]); |
| static_assert(v[20]); |
| static_assert(v[21]); |
| static_assert(v[22]); |
| static_assert(v[23]); |
| |
| static_assert(v[24]); |
| static_assert(v[25]); |
| static_assert(v[26]); |
| static_assert(!v[27]); |
| static_assert(v[28]); |
| static_assert(v[29]); |
| static_assert(v[30]); |
| static_assert(!v[31]); |
| #endif |
| |
| struct pad { |
| unsigned short s; |
| unsigned char c; |
| }; |
| |
| constexpr auto p = bit_cast<pad>(v); |
| static_assert(p.s == (LITTLE_END ? 0xffee : 0xa1c0)); |
| static_assert(p.c == (LITTLE_END ? 0xc0 : 0xff)); |
| } |
| |
| namespace TwoShorts { |
| struct B { |
| unsigned short s0 : 8; |
| unsigned short s1 : 8; |
| }; |
| constexpr struct { unsigned short b1;} T = {0xc0ff}; |
| constexpr B MB = __builtin_bit_cast(B, T); |
| #if LITTLE_END |
| static_assert(MB.s0 == 0xff); |
| static_assert(MB.s1 == 0xc0); |
| #else |
| static_assert(MB.s0 == 0xc0); |
| static_assert(MB.s1 == 0xff); |
| |
| #endif |
| } |
| |
| typedef bool bool8 __attribute__((ext_vector_type(8))); |
| typedef bool bool9 __attribute__((ext_vector_type(9))); |
| typedef bool bool16 __attribute__((ext_vector_type(16))); |
| typedef bool bool17 __attribute__((ext_vector_type(17))); |
| typedef bool bool32 __attribute__((ext_vector_type(32))); |
| typedef bool bool128 __attribute__((ext_vector_type(128))); |
| |
| static_assert(bit_cast<unsigned char>(bool8{1,0,1,0,1,0,1,0}) == (LITTLE_END ? 0x55 : 0xAA), ""); |
| 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)}} |
| static_assert(check_round_trip<bool8>(static_cast<unsigned char>(0)), ""); |
| static_assert(check_round_trip<bool8>(static_cast<unsigned char>(1)), ""); |
| static_assert(check_round_trip<bool8>(static_cast<unsigned char>(0x55)), ""); |
| |
| 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), ""); |
| |
| static_assert(check_round_trip<bool16>(static_cast<short>(0xCAFE)), ""); |
| static_assert(check_round_trip<bool32>(static_cast<int>(0xCAFEBABE)), ""); |
| |
| #ifdef __SIZEOF_INT128__ |
| static_assert(check_round_trip<bool128>(static_cast<__int128_t>(0xCAFEBABE0C05FEFEULL)), ""); |
| #endif |
| |
| static_assert(bit_cast<bits<8, uint16_t, 7>, uint16_t>(0xcafe) == (LITTLE_END ? 0x95 : 0x7f)); |
| static_assert(bit_cast<bits<4, uint16_t, 10>, uint16_t>(0xcafe) == (LITTLE_END ? 0x2 : 0xf)); |
| static_assert(bit_cast<bits<4, uint32_t, 19>, uint32_t>(0xa1cafe) == (LITTLE_END ? 0x4 : 0x5)); |
| |
| struct S { |
| // little endian: |
| // MSB .... .... LSB |
| // |y| |x| |
| // |
| // big endian |
| // MSB .... .... LSB |
| // |x| |y| |
| |
| unsigned char x : 4; |
| unsigned char y : 4; |
| |
| constexpr bool operator==(S const &other) const { |
| return x == other.x && y == other.y; |
| } |
| }; |
| |
| constexpr S s{0xa, 0xb}; |
| static_assert(bit_cast<bits<8>>(s) == (LITTLE_END ? 0xba : 0xab)); |
| static_assert(bit_cast<bits<7>>(s) == (LITTLE_END |
| ? 0xba & 0x7f |
| : (0xab & 0xfe) >> 1)); |
| |
| static_assert(round_trip<bits<8>>(s) == s); |
| |
| struct R { |
| unsigned int r : 31; |
| unsigned int : 0; |
| unsigned int : 32; |
| constexpr bool operator==(R const &other) const { |
| return r == other.r; |
| } |
| }; |
| using T = bits<31, signed long long>; |
| constexpr R r{0x4ac0ffee}; |
| constexpr T t = bit_cast<T>(r); |
| static_assert(t == ((0xFFFFFFFF8 << 28) | 0x4ac0ffee)); // sign extension |
| |
| static_assert(round_trip<T>(r) == r); |
| static_assert(round_trip<R>(t) == t); |
| |
| |
| /// The oversized bitfield is an error on Windows and not just a warning. |
| #if !defined(_WIN32) |
| struct U { |
| // expected-warning@+1 {{exceeds the width of its type}} |
| uint32_t trunc : 33; |
| uint32_t u : 31; |
| constexpr bool operator==(U const &other) const { |
| return trunc == other.trunc && u == other.u; |
| } |
| }; |
| struct V { |
| uint64_t notrunc : 32; |
| uint64_t : 1; |
| uint64_t v : 31; |
| constexpr bool operator==(V const &other) const { |
| return notrunc == other.notrunc && v == other.v; |
| } |
| }; |
| |
| constexpr U u{static_cast<unsigned int>(~0), 0x4ac0ffee}; |
| constexpr V v = bit_cast<V>(u); |
| static_assert(v.v == 0x4ac0ffee); |
| |
| static_assert(round_trip<V>(u) == u); |
| static_assert(round_trip<U>(v) == v); |
| |
| constexpr auto w = bit_cast<bits<12, unsigned long, 33>>(u); |
| static_assert(w == (LITTLE_END |
| ? 0x4ac0ffee & 0xFFF |
| : (0x4ac0ffee & (0xFFF << (31 - 12))) >> (31-12) |
| )); |
| #endif |
| |
| |
| namespace NestedStructures { |
| struct J { |
| struct { |
| uint16_t k : 12; |
| } K; |
| struct { |
| uint16_t l : 4; |
| } L; |
| }; |
| |
| static_assert(sizeof(J) == 4); |
| constexpr J j = bit_cast<J>(0x8c0ffee5); |
| |
| static_assert(j.K.k == (LITTLE_END ? 0xee5 : 0x8c0)); |
| static_assert(j.L.l == 0xf /* yay symmetry */); |
| static_assert(bit_cast<bits<4, uint16_t, 16>>(j) == 0xf); |
| struct N { |
| bits<12, uint16_t> k; |
| uint16_t : 16; |
| }; |
| static_assert(bit_cast<N>(j).k == j.K.k); |
| |
| struct M { |
| bits<4, uint16_t, 0> m[2]; |
| constexpr bool operator==(const M& rhs) const { |
| return m[0] == rhs.m[0] && m[1] == rhs.m[1]; |
| }; |
| }; |
| #if LITTLE_END == 1 |
| constexpr uint16_t want[2] = {0x5, 0xf}; |
| #else |
| constexpr uint16_t want[2] = {0x8000, 0xf000}; |
| #endif |
| |
| static_assert(bit_cast<M>(j) == bit_cast<M>(want)); |
| } |
| |
| namespace Enums { |
| // ensure we're packed into the top 2 bits |
| constexpr int pad = LITTLE_END ? 6 : 0; |
| struct X |
| { |
| char : pad; |
| enum class direction: char { left, right, up, down } direction : 2; |
| }; |
| |
| constexpr X x = { X::direction::down }; |
| static_assert(bit_cast<bits<2, signed char, pad>>(x) == -1); |
| static_assert(bit_cast<bits<2, unsigned char, pad>>(x) == 3); |
| static_assert( |
| bit_cast<X>((unsigned char)0x40).direction == X::direction::right); |
| } |
| |
| namespace IndeterminateBits { |
| struct S { |
| unsigned a : 13; |
| unsigned : 17; |
| unsigned b : 2; |
| }; |
| constexpr unsigned A = __builtin_bit_cast(unsigned, S{12, 3}); // expected-error {{must be initialized by a constant expression}} \ |
| // expected-note {{indeterminate value can only initialize an object of type 'unsigned char' or 'std::byte'; 'unsigned int' is invalid}} |
| |
| |
| /// GCC refuses to compile this as soon as we access the indeterminate bits |
| /// in the static_assert. MSVC accepts it. |
| struct S2 { |
| unsigned char a : 2; |
| }; |
| constexpr unsigned char B = __builtin_bit_cast(unsigned char, S2{3}); |
| static_assert(B == (LITTLE_END ? 3 : 192)); |
| |
| |
| |
| struct S3 { |
| unsigned a : 13; |
| unsigned : 17; |
| unsigned b : 2; |
| }; |
| |
| struct D { |
| unsigned a; |
| }; |
| constexpr D s = __builtin_bit_cast(D, S3{12, 3}); // expected-error {{must be initialized by a constant expression}} \ |
| // expected-note {{indeterminate value can only initialize an object of type 'unsigned char' or 'std::byte'; 'unsigned int' is invalid}} |
| |
| } |