summaryrefslogtreecommitdiffstats
path: root/clang/test
diff options
context:
space:
mode:
Diffstat (limited to 'clang/test')
-rw-r--r--clang/test/CodeGenCXX/builtin-bit-cast-no-tbaa.cpp19
-rw-r--r--clang/test/CodeGenCXX/builtin-bit-cast.cpp106
-rw-r--r--clang/test/SemaCXX/builtin-bit-cast.cpp39
-rw-r--r--clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp383
4 files changed, 547 insertions, 0 deletions
diff --git a/clang/test/CodeGenCXX/builtin-bit-cast-no-tbaa.cpp b/clang/test/CodeGenCXX/builtin-bit-cast-no-tbaa.cpp
new file mode 100644
index 00000000000..3f0e490a5f9
--- /dev/null
+++ b/clang/test/CodeGenCXX/builtin-bit-cast-no-tbaa.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -O3 -std=c++2a -S -emit-llvm -o - -disable-llvm-passes -triple x86_64-apple-macos10.14 %s | FileCheck %s
+
+void test_scalar() {
+ // CHECK-LABEL: define void @_Z11test_scalarv
+ __builtin_bit_cast(float, 42);
+
+ // CHECK: load float, float* {{.*}}, align 4, !tbaa ![[MAY_ALIAS_TBAA:.*]]
+}
+
+void test_scalar2() {
+ // CHECK-LABEL: define void @_Z12test_scalar2v
+ struct S {int m;};
+ __builtin_bit_cast(int, S{42});
+
+ // CHECK: load i32, i32* {{.*}}, align 4, !tbaa ![[MAY_ALIAS_TBAA]]
+}
+
+// CHECK: ![[CHAR_TBAA:.*]] = !{!"omnipotent char", {{.*}}, i64 0}
+// CHECK: ![[MAY_ALIAS_TBAA]] = !{![[CHAR_TBAA]], ![[CHAR_TBAA]], i64 0}
diff --git a/clang/test/CodeGenCXX/builtin-bit-cast.cpp b/clang/test/CodeGenCXX/builtin-bit-cast.cpp
new file mode 100644
index 00000000000..49f8ec3ad4b
--- /dev/null
+++ b/clang/test/CodeGenCXX/builtin-bit-cast.cpp
@@ -0,0 +1,106 @@
+// RUN: %clang_cc1 -std=c++2a -S -emit-llvm -o - -disable-llvm-passes -triple x86_64-apple-macos10.14 %s | FileCheck %s
+
+void test_scalar(int &oper) {
+ // CHECK-LABEL: define void @_Z11test_scalarRi
+ __builtin_bit_cast(float, oper);
+
+ // CHECK: [[OPER:%.*]] = alloca i32*
+ // CHECK: [[REF:%.*]] = load i32*, i32**
+ // CHECK-NEXT: [[CASTED:%.*]] = bitcast i32* [[REF]] to float*
+ // CHECK-NEXT: load float, float* [[CASTED]]
+}
+
+struct two_ints {
+ int x;
+ int y;
+};
+
+unsigned long test_aggregate_to_scalar(two_ints &ti) {
+ // CHECK-LABEL: define i64 @_Z24test_aggregate_to_scalarR8two_ints
+ return __builtin_bit_cast(unsigned long, ti);
+
+ // CHECK: [[TI_ADDR:%.*]] = alloca %struct.two_ints*, align 8
+ // CHECK: [[TI_LOAD:%.*]] = load %struct.two_ints*, %struct.two_ints** [[TI_ADDR]]
+ // CHECK-NEXT: [[CASTED:%.*]] = bitcast %struct.two_ints* [[TI_LOAD]] to i64*
+ // CHECK-NEXT: load i64, i64* [[CASTED]]
+}
+
+struct two_floats {
+ float x;
+ float y;
+};
+
+two_floats test_aggregate_record(two_ints& ti) {
+ // CHECK-LABEL: define <2 x float> @_Z21test_aggregate_recordR8two_int
+ return __builtin_bit_cast(two_floats, ti);
+
+ // CHECK: [[RETVAL:%.*]] = alloca %struct.two_floats, align 4
+ // CHECK: [[TI:%.*]] = alloca %struct.two_ints*, align 8
+
+ // CHECK: [[LOAD_TI:%.*]] = load %struct.two_ints*, %struct.two_ints** [[TI]]
+ // CHECK: [[MEMCPY_SRC:%.*]] = bitcast %struct.two_ints* [[LOAD_TI]] to i8*
+ // CHECK: [[MEMCPY_DST:%.*]] = bitcast %struct.two_floats* [[RETVAL]] to i8*
+ // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 [[MEMCPY_DST]], i8* align 4 [[MEMCPY_SRC]]
+}
+
+two_floats test_aggregate_array(int (&ary)[2]) {
+ // CHECK-LABEL: define <2 x float> @_Z20test_aggregate_arrayRA2_i
+ return __builtin_bit_cast(two_floats, ary);
+
+ // CHECK: [[RETVAL:%.*]] = alloca %struct.two_floats, align 4
+ // CHECK: [[ARY:%.*]] = alloca [2 x i32]*, align 8
+
+ // CHECK: [[LOAD_ARY:%.*]] = load [2 x i32]*, [2 x i32]** [[ARY]]
+ // CHECK: [[MEMCPY_SRC:%.*]] = bitcast [2 x i32]* [[LOAD_ARY]] to i8*
+ // CHECK: [[MEMCPY_DST:%.*]] = bitcast %struct.two_floats* [[RETVAL]] to i8*
+ // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 [[MEMCPY_DST]], i8* align 4 [[MEMCPY_SRC]]
+}
+
+two_ints test_scalar_to_aggregate(unsigned long ul) {
+ // CHECK-LABEL: define i64 @_Z24test_scalar_to_aggregatem
+ return __builtin_bit_cast(two_ints, ul);
+
+ // CHECK: [[TI:%.*]] = alloca %struct.two_ints, align 4
+ // CHECK: [[TITMP:%.*]] = bitcast %struct.two_ints* [[TI]] to i8*
+ // CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 [[TITMP]]
+}
+
+unsigned long test_complex(_Complex unsigned &cu) {
+ // CHECK-LABEL: define i64 @_Z12test_complexRCj
+ return __builtin_bit_cast(unsigned long, cu);
+
+ // CHECK: [[REF_ALLOCA:%.*]] = alloca { i32, i32 }*, align 8
+ // CHECK-NEXT: store { i32, i32 }* {{.*}}, { i32, i32 }** [[REF_ALLOCA]]
+ // CHECK-NEXT: [[REF:%.*]] = load { i32, i32 }*, { i32, i32 }** [[REF_ALLOCA]]
+ // CHECK-NEXT: [[CASTED:%.*]] = bitcast { i32, i32 }* [[REF]] to i64*
+ // CHECK-NEXT: load i64, i64* [[CASTED]], align 4
+}
+
+_Complex unsigned test_to_complex(unsigned long &ul) {
+ // CHECK-LABEL: define i64 @_Z15test_to_complexRm
+
+ return __builtin_bit_cast(_Complex unsigned, ul);
+
+ // CHECK: [[REF:%.*]] = alloca i64*
+ // CHECK: [[LOAD_REF:%.*]] = load i64*, i64** [[REF]]
+ // CHECK: [[CASTED:%.*]] = bitcast i64* [[LOAD_REF]] to { i32, i32 }*
+}
+
+unsigned long test_array(int (&ary)[2]) {
+ // CHECK-LABEL: define i64 @_Z10test_arrayRA2_i
+ return __builtin_bit_cast(unsigned long, ary);
+
+ // CHECK: [[REF_ALLOCA:%.*]] = alloca [2 x i32]*
+ // CHECK: [[LOAD_REF:%.*]] = load [2 x i32]*, [2 x i32]** [[REF_ALLOCA]]
+ // CHECK: [[CASTED:%.*]] = bitcast [2 x i32]* [[LOAD_REF]] to i64*
+ // CHECK: load i64, i64* [[CASTED]], align 4
+}
+
+two_ints test_rvalue_aggregate() {
+ // CHECK-LABEL: define i64 @_Z21test_rvalue_aggregate
+ return __builtin_bit_cast(two_ints, 42ul);
+
+ // CHECK: [[TI:%.*]] = alloca %struct.two_ints, align 4
+ // CHECK: [[CASTED:%.*]] = bitcast %struct.two_ints* [[TI]] to i8*
+ // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 [[CASTED]]
+}
diff --git a/clang/test/SemaCXX/builtin-bit-cast.cpp b/clang/test/SemaCXX/builtin-bit-cast.cpp
new file mode 100644
index 00000000000..3dddadc5617
--- /dev/null
+++ b/clang/test/SemaCXX/builtin-bit-cast.cpp
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -verify -std=c++2a -fsyntax-only -triple x86_64-apple-macosx10.14.0 %s
+// RUN: %clang_cc1 -verify -std=c++2a -fsyntax-only -triple x86_64-apple-macosx10.14.0 %s -fno-signed-char
+
+#if !__has_builtin(__builtin_bit_cast)
+#error
+#endif
+
+template <class T, T v>
+T instantiate() {
+ return __builtin_bit_cast(T, v);
+}
+
+int x = instantiate<int, 32>();
+
+struct secret_ctor {
+ char member;
+
+private: secret_ctor() = default;
+};
+
+void test1() {
+ secret_ctor c = __builtin_bit_cast(secret_ctor, (char)0);
+}
+
+void test2() {
+ constexpr int i = 0;
+ // expected-error@+1{{__builtin_bit_cast source size does not equal destination size (4 vs 1)}}
+ constexpr char c = __builtin_bit_cast(char, i);
+}
+
+struct not_trivially_copyable {
+ virtual void foo() {}
+};
+
+// expected-error@+1{{__builtin_bit_cast source type must be trivially copyable}}
+constexpr unsigned long ul = __builtin_bit_cast(unsigned long, not_trivially_copyable{});
+
+// expected-error@+1 {{__builtin_bit_cast destination type must be trivially copyable}}
+constexpr long us = __builtin_bit_cast(unsigned long &, 0L);
diff --git a/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp b/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp
new file mode 100644
index 00000000000..d48ee03dcce
--- /dev/null
+++ b/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp
@@ -0,0 +1,383 @@
+// RUN: %clang_cc1 -verify -std=c++2a -fsyntax-only -triple x86_64-apple-macosx10.14.0 %s
+// RUN: %clang_cc1 -verify -std=c++2a -fsyntax-only -triple x86_64-apple-macosx10.14.0 %s -fno-signed-char
+// RUN: %clang_cc1 -verify -std=c++2a -fsyntax-only -triple aarch64_be-linux-gnu %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
+
+template <class T, class V> struct is_same {
+ static constexpr bool value = false;
+};
+template <class T> struct is_same<T, T> {
+ static constexpr bool value = true;
+};
+
+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));
+#ifdef __CHAR_UNSIGNED__
+ // expected-note@+4 2 {{indeterminate value can only initialize an object of type 'unsigned char', 'char', or 'std::byte'; 'signed char' is invalid}}
+#else
+ // expected-note@+2 2 {{indeterminate value can only initialize an object of type 'unsigned char' or 'std::byte'; 'signed char' is invalid}}
+#endif
+ return __builtin_bit_cast(To, from);
+}
+
+template <class Intermediate, class Init>
+constexpr bool round_trip(const Init &init) {
+ return bit_cast<Init>(bit_cast<Intermediate>(init)) == init;
+}
+
+void test_int() {
+ static_assert(round_trip<unsigned>((int)-1));
+ static_assert(round_trip<unsigned>((int)0x12345678));
+ static_assert(round_trip<unsigned>((int)0x87654321));
+ static_assert(round_trip<unsigned>((int)0x0C05FEFE));
+}
+
+void test_array() {
+ constexpr unsigned char input[] = {0xCA, 0xFE, 0xBA, 0xBE};
+ constexpr unsigned expected = LITTLE_END ? 0xBEBAFECA : 0xCAFEBABE;
+ static_assert(bit_cast<unsigned>(input) == expected);
+}
+
+void test_record() {
+ struct int_splicer {
+ unsigned x;
+ unsigned y;
+
+ constexpr bool operator==(const int_splicer &other) const {
+ return other.x == x && other.y == y;
+ }
+ };
+
+ constexpr int_splicer splice{0x0C05FEFE, 0xCAFEBABE};
+
+ static_assert(bit_cast<unsigned long long>(splice) == LITTLE_END
+ ? 0xCAFEBABE0C05FEFE
+ : 0x0C05FEFECAFEBABE);
+
+ static_assert(bit_cast<int_splicer>(0xCAFEBABE0C05FEFE).x == LITTLE_END
+ ? 0x0C05FEFE
+ : 0xCAFEBABE);
+
+ static_assert(round_trip<unsigned long long>(splice));
+ static_assert(round_trip<long long>(splice));
+
+ struct base2 {
+ };
+
+ struct base3 {
+ unsigned z;
+ };
+
+ struct bases : int_splicer, base2, base3 {
+ unsigned doublez;
+ };
+
+ struct tuple4 {
+ unsigned x, y, z, doublez;
+
+ constexpr bool operator==(tuple4 const &other) const {
+ return x == other.x && y == other.y &&
+ z == other.z && doublez == other.doublez;
+ }
+ };
+ constexpr bases b = {{1, 2}, {}, {3}, 4};
+ constexpr tuple4 t4 = bit_cast<tuple4>(b);
+ static_assert(t4 == tuple4{1, 2, 3, 4});
+ static_assert(round_trip<tuple4>(b));
+}
+
+void test_partially_initialized() {
+ struct pad {
+ signed char x;
+ int y;
+ };
+
+ struct no_pad {
+ signed char x;
+ signed char p1, p2, p3;
+ int y;
+ };
+
+ static_assert(sizeof(pad) == sizeof(no_pad));
+
+ constexpr pad pir{4, 4};
+ // expected-error@+2 {{constexpr variable 'piw' must be initialized by a constant expression}}
+ // expected-note@+1 {{in call to 'bit_cast(pir)'}}
+ constexpr int piw = bit_cast<no_pad>(pir).x;
+
+ // expected-error@+2 {{constexpr variable 'bad' must be initialized by a constant expression}}
+ // expected-note@+1 {{in call to 'bit_cast(pir)'}}
+ constexpr no_pad bad = bit_cast<no_pad>(pir);
+
+ constexpr pad fine = bit_cast<pad>(no_pad{1, 2, 3, 4, 5});
+ static_assert(fine.x == 1 && fine.y == 5);
+}
+
+void no_bitfields() {
+ // FIXME!
+ struct S {
+ unsigned char x : 8;
+ };
+
+ struct G {
+ unsigned char x : 8;
+ };
+
+ constexpr S s{0};
+ // expected-error@+2 {{constexpr variable 'g' must be initialized by a constant expression}}
+ // expected-note@+1 {{constexpr bit_cast involving bit-field is not yet supported}}
+ constexpr G g = __builtin_bit_cast(G, s);
+}
+
+void array_members() {
+ struct S {
+ int ar[3];
+
+ constexpr bool operator==(const S &rhs) {
+ return ar[0] == rhs.ar[0] && ar[1] == rhs.ar[1] && ar[2] == rhs.ar[2];
+ }
+ };
+
+ struct G {
+ int a, b, c;
+
+ constexpr bool operator==(const G &rhs) {
+ return a == rhs.a && b == rhs.b && c == rhs.c;
+ }
+ };
+
+ constexpr S s{{1, 2, 3}};
+ constexpr G g = bit_cast<G>(s);
+ static_assert(g.a == 1 && g.b == 2 && g.c == 3);
+
+ static_assert(round_trip<G>(s));
+ static_assert(round_trip<S>(g));
+}
+
+void bad_types() {
+ union X {
+ int x;
+ };
+
+ struct G {
+ int g;
+ };
+ // expected-error@+2 {{constexpr variable 'g' must be initialized by a constant expression}}
+ // expected-note@+1 {{bit_cast from a union type is not allowed in a constant expression}}
+ constexpr G g = __builtin_bit_cast(G, X{0});
+ // expected-error@+2 {{constexpr variable 'x' must be initialized by a constant expression}}
+ // expected-note@+1 {{bit_cast to a union type is not allowed in a constant expression}}
+ constexpr X x = __builtin_bit_cast(X, G{0});
+
+ struct has_pointer {
+ // expected-note@+1 2 {{invalid type 'int *' is a member of 'has_pointer'}}
+ int *ptr;
+ };
+
+ // expected-error@+2 {{constexpr variable 'ptr' must be initialized by a constant expression}}
+ // expected-note@+1 {{bit_cast from a pointer type is not allowed in a constant expression}}
+ constexpr unsigned long ptr = __builtin_bit_cast(unsigned long, has_pointer{0});
+ // expected-error@+2 {{constexpr variable 'hptr' must be initialized by a constant expression}}
+ // expected-note@+1 {{bit_cast to a pointer type is not allowed in a constant expression}}
+ constexpr has_pointer hptr = __builtin_bit_cast(has_pointer, 0ul);
+}
+
+void backtrace() {
+ struct A {
+ // expected-note@+1 {{invalid type 'int *' is a member of 'A'}}
+ int *ptr;
+ };
+
+ struct B {
+ // expected-note@+1 {{invalid type 'A [10]' is a member of 'B'}}
+ A as[10];
+ };
+
+ // expected-note@+1 {{invalid type 'B' is a base of 'C'}}
+ struct C : B {
+ };
+
+ struct E {
+ unsigned long ar[10];
+ };
+
+ // expected-error@+2 {{constexpr variable 'e' must be initialized by a constant expression}}
+ // expected-note@+1 {{bit_cast from a pointer type is not allowed in a constant expression}}
+ constexpr E e = __builtin_bit_cast(E, C{});
+}
+
+void test_array_fill() {
+ constexpr unsigned char a[4] = {1, 2};
+ constexpr unsigned int i = bit_cast<unsigned int>(a);
+ static_assert(i == LITTLE_END ? 0x00000201 : 0x01020000, "");
+}
+
+typedef decltype(nullptr) nullptr_t;
+
+#ifdef __CHAR_UNSIGNED__
+// expected-note@+5 {{indeterminate value can only initialize an object of type 'unsigned char', 'char', or 'std::byte'; 'unsigned long' is invalid}}
+#else
+// expected-note@+3 {{indeterminate value can only initialize an object of type 'unsigned char' or 'std::byte'; 'unsigned long' is invalid}}
+#endif
+// expected-error@+1 {{constexpr variable 'test_from_nullptr' must be initialized by a constant expression}}
+constexpr unsigned long test_from_nullptr = __builtin_bit_cast(unsigned long, nullptr);
+
+constexpr int test_from_nullptr_pass = (__builtin_bit_cast(unsigned char[8], nullptr), 0);
+
+constexpr int test_to_nullptr() {
+ nullptr_t npt = __builtin_bit_cast(nullptr_t, 0ul);
+
+ struct indet_mem {
+ unsigned char data[sizeof(void *)];
+ };
+ indet_mem im = __builtin_bit_cast(indet_mem, nullptr);
+ nullptr_t npt2 = __builtin_bit_cast(nullptr_t, im);
+
+ return 0;
+}
+
+constexpr int ttn = test_to_nullptr();
+
+// expected-warning@+2 {{returning reference to local temporary object}}
+// expected-note@+1 {{temporary created here}}
+constexpr const long &returns_local() { return 0L; }
+
+// expected-error@+2 {{constexpr variable 'test_nullptr_bad' must be initialized by a constant expression}}
+// expected-note@+1 {{read of temporary whose lifetime has ended}}
+constexpr nullptr_t test_nullptr_bad = __builtin_bit_cast(nullptr_t, returns_local());
+
+constexpr int test_indeterminate(bool read_indet) {
+ struct pad {
+ char a;
+ int b;
+ };
+
+ struct no_pad {
+ char a;
+ unsigned char p1, p2, p3;
+ int b;
+ };
+
+ pad p{1, 2};
+ no_pad np = bit_cast<no_pad>(p);
+
+ int tmp = np.a + np.b;
+
+ unsigned char& indet_ref = np.p1;
+
+ if (read_indet) {
+ // expected-note@+1 {{read of uninitialized object is not allowed in a constant expression}}
+ tmp = indet_ref;
+ }
+
+ indet_ref = 0;
+
+ return 0;
+}
+
+constexpr int run_test_indeterminate = test_indeterminate(false);
+// expected-error@+2 {{constexpr variable 'run_test_indeterminate2' must be initialized by a constant expression}}
+// expected-note@+1 {{in call to 'test_indeterminate(true)'}}
+constexpr int run_test_indeterminate2 = test_indeterminate(true);
+
+struct ref_mem {
+ const int &rm;
+};
+
+constexpr int global_int = 0;
+
+// expected-error@+2 {{constexpr variable 'run_ref_mem' must be initialized by a constant expression}}
+// expected-note@+1 {{bit_cast from a type with a reference member is not allowed in a constant expression}}
+constexpr unsigned long run_ref_mem = __builtin_bit_cast(
+ unsigned long, ref_mem{global_int});
+
+union u {
+ int im;
+};
+
+// expected-error@+2 {{constexpr variable 'run_u' must be initialized by a constant expression}}
+// expected-note@+1 {{bit_cast from a union type is not allowed in a constant expression}}
+constexpr int run_u = __builtin_bit_cast(int, u{32});
+
+struct vol_mem {
+ volatile int x;
+};
+
+// expected-error@+2 {{constexpr variable 'run_vol_mem' must be initialized by a constant expression}}
+// expected-note@+1 {{non-literal type 'vol_mem' cannot be used in a constant expression}}
+constexpr int run_vol_mem = __builtin_bit_cast(int, vol_mem{43});
+
+struct mem_ptr {
+ int vol_mem::*x; // expected-note{{invalid type 'int vol_mem::*' is a member of 'mem_ptr'}}
+};
+// expected-error@+2 {{constexpr variable 'run_mem_ptr' must be initialized by a constant expression}}
+// expected-note@+1 {{bit_cast from a member pointer type is not allowed in a constant expression}}
+constexpr int run_mem_ptr = __builtin_bit_cast(unsigned long, mem_ptr{nullptr});
+
+struct A { char c; /* char padding : 8; */ short s; };
+struct B { unsigned char x[4]; };
+
+constexpr B one() {
+ A a = {1, 2};
+ return bit_cast<B>(a);
+}
+constexpr char good_one = one().x[0] + one().x[2] + one().x[3];
+// expected-error@+2 {{constexpr variable 'bad_one' must be initialized by a constant expression}}
+// expected-note@+1 {{read of uninitialized object is not allowed in a constant expression}}
+constexpr char bad_one = one().x[1];
+
+constexpr A two() {
+ B b = one(); // b.x[1] is indeterminate.
+ b.x[0] = 'a';
+ b.x[2] = 1;
+ b.x[3] = 2;
+ return bit_cast<A>(b);
+}
+constexpr short good_two = two().c + two().s;
+
+namespace std {
+enum byte : unsigned char {};
+}
+
+enum my_byte : unsigned char {};
+
+struct pad {
+ char a;
+ int b;
+};
+
+constexpr int ok_byte = (__builtin_bit_cast(std::byte[8], pad{1, 2}), 0);
+constexpr int ok_uchar = (__builtin_bit_cast(unsigned char[8], pad{1, 2}), 0);
+
+#ifdef __CHAR_UNSIGNED__
+// expected-note@+5 {{indeterminate value can only initialize an object of type 'unsigned char', 'char', or 'std::byte'; 'my_byte' is invalid}}}}
+#else
+// expected-note@+3 {{indeterminate value can only initialize an object of type 'unsigned char' or 'std::byte'; 'my_byte' is invalid}}
+#endif
+// expected-error@+1 {{constexpr variable 'bad_my_byte' must be initialized by a constant expression}}
+constexpr int bad_my_byte = (__builtin_bit_cast(my_byte[8], pad{1, 2}), 0);
+#ifndef __CHAR_UNSIGNED__
+// expected-error@+3 {{constexpr variable 'bad_char' must be initialized by a constant expression}}
+// expected-note@+2 {{indeterminate value can only initialize an object of type 'unsigned char' or 'std::byte'; 'char' is invalid}}
+#endif
+constexpr int bad_char = (__builtin_bit_cast(char[8], pad{1, 2}), 0);
+
+struct pad_buffer { unsigned char data[sizeof(pad)]; };
+constexpr bool test_pad_buffer() {
+ pad x = {1, 2};
+ pad_buffer y = __builtin_bit_cast(pad_buffer, x);
+ pad z = __builtin_bit_cast(pad, y);
+ return x.a == z.a && x.b == z.b;
+}
+static_assert(test_pad_buffer());
OpenPOWER on IntegriCloud