Ping. One motivation for allowing builtin bit_cast to builtin array is that it enables direct bitwise constexpr comparisons via memcmp:
template<class A, class B> constexpr int bit_equal(A const& a, B const& b) { static_assert( sizeof a == sizeof b, "bit_equal(a,b) requires same sizeof" ); using bytes = unsigned char[sizeof(A)]; return __builtin_memcmp( __builtin_bit_cast(bytes,a), __builtin_bit_cast(bytes,b), sizeof(A)) == 0; } On Mon, Nov 8, 2021 at 3:03 PM Will Wray <wjw...@gmail.com> wrote: > > This patch allows __builtin_bit_cast to materialize a C array as its To type. > > It was developed as part of an implementation of P1997, array copy-semantics, > but is independent, so makes sense to submit, review and merge ahead of it. > > gcc/cp/ChangeLog: > > * constexpr.c (check_bit_cast_type): handle ARRAY_TYPE check, > (cxx_eval_bit_cast): handle ARRAY_TYPE copy. > * semantics.c (cp_build_bit_cast): warn only on unbounded/VLA. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp2a/bit-cast2.C: update XFAIL tests. > * g++.dg/cpp2a/bit-cast-to-array1.C: New test. > --- > gcc/cp/constexpr.c | 8 ++++- > gcc/cp/semantics.c | 7 ++--- > gcc/testsuite/g++.dg/cpp2a/bit-cast-to-array1.C | 40 > +++++++++++++++++++++++++ > gcc/testsuite/g++.dg/cpp2a/bit-cast2.C | 8 ++--- > 4 files changed, 53 insertions(+), 10 deletions(-) > > diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c > index 453007c686b..be1cdada6f8 100644 > --- a/gcc/cp/constexpr.c > +++ b/gcc/cp/constexpr.c > @@ -4124,6 +4124,11 @@ static bool > check_bit_cast_type (const constexpr_ctx *ctx, location_t loc, tree type, > tree orig_type) > { > + if (TREE_CODE (type) == ARRAY_TYPE) > + return check_bit_cast_type (ctx, loc, > + TYPE_MAIN_VARIANT (TREE_TYPE (type)), > + orig_type); > + > if (TREE_CODE (type) == UNION_TYPE) > { > if (!ctx->quiet) > @@ -4280,7 +4285,8 @@ cxx_eval_bit_cast (const constexpr_ctx *ctx, tree t, > bool *non_constant_p, > tree r = NULL_TREE; > if (can_native_interpret_type_p (TREE_TYPE (t))) > r = native_interpret_expr (TREE_TYPE (t), ptr, len); > - else if (TREE_CODE (TREE_TYPE (t)) == RECORD_TYPE) > + else if (TREE_CODE (TREE_TYPE (t)) == RECORD_TYPE > + || TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) > { > r = native_interpret_aggregate (TREE_TYPE (t), ptr, 0, len); > if (r != NULL_TREE) > diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c > index 2443d032749..b3126b12abc 100644 > --- a/gcc/cp/semantics.c > +++ b/gcc/cp/semantics.c > @@ -11562,13 +11562,10 @@ cp_build_bit_cast (location_t loc, tree type, tree > arg, > { > if (!complete_type_or_maybe_complain (type, NULL_TREE, complain)) > return error_mark_node; > - if (TREE_CODE (type) == ARRAY_TYPE) > + if (TREE_CODE (type) == ARRAY_TYPE && !TYPE_DOMAIN (type)) > { > - /* std::bit_cast for destination ARRAY_TYPE is not possible, > - as functions may not return an array, so don't bother trying > - to support this (and then deal with VLAs etc.). */ > error_at (loc, "%<__builtin_bit_cast%> destination type %qT " > - "is an array type", type); > + "is a VLA variable-length array type", type); > return error_mark_node; > } > if (!trivially_copyable_p (type)) > diff --git a/gcc/testsuite/g++.dg/cpp2a/bit-cast-to-array1.C > b/gcc/testsuite/g++.dg/cpp2a/bit-cast-to-array1.C > new file mode 100644 > index 00000000000..e6e50c06389 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/bit-cast-to-array1.C > @@ -0,0 +1,40 @@ > +// { dg-do compile } > + > +class S { int s; }; > +S s(); > +class U { int a, b; }; > +U u(); > + > +void > +foo (int *q) > +{ > + __builtin_bit_cast (int [1], 0); > + __builtin_bit_cast (S [1], 0); > + __builtin_bit_cast (U [1], u); > +} > + > +template <int N> > +void > +bar (int *q) > +{ > + int intN[N] = {}; > + int int2N[2*N] = {}; > + __builtin_bit_cast (int [N], intN); > + __builtin_bit_cast (S [N], intN); > + __builtin_bit_cast (U [N], int2N); > +} > + > +template <typename T1, typename T2, typename T3> > +void > +baz (T1 ia, T2 sa, T3 ua) > +{ > + __builtin_bit_cast (T1, *ia); > + __builtin_bit_cast (T2, *sa); > + __builtin_bit_cast (T3, *ua); > +} > + > +void > +qux (S* sp, int *ip, U* up) > +{ > + baz <int[1], S[1], U[1]> (ip, sp, up); > +} > diff --git a/gcc/testsuite/g++.dg/cpp2a/bit-cast2.C > b/gcc/testsuite/g++.dg/cpp2a/bit-cast2.C > index 6bb1760e621..7f1836ee4e9 100644 > --- a/gcc/testsuite/g++.dg/cpp2a/bit-cast2.C > +++ b/gcc/testsuite/g++.dg/cpp2a/bit-cast2.C > @@ -14,7 +14,7 @@ foo (int *q) > __builtin_bit_cast (int, s); // { dg-error "'__builtin_bit_cast' > source type 'S' is not trivially copyable" } > __builtin_bit_cast (S, 0); // { dg-error "'__builtin_bit_cast' > destination type 'S' is not trivially copyable" } > __builtin_bit_cast (int &, q); // { dg-error "'__builtin_bit_cast' > destination type 'int&' is not trivially copyable" } > - __builtin_bit_cast (int [1], 0); // { dg-error "'__builtin_bit_cast' > destination type \[^\n\r]* is an array type" } > + __builtin_bit_cast (S [1], 0); // { dg-error "'__builtin_bit_cast' > destination type \[^\n\r]* is not trivially copyable" } > __builtin_bit_cast (V, 0); // { dg-error "invalid use of > incomplete type 'struct V'" } > __builtin_bit_cast (int, v); > __builtin_bit_cast (int, *p); // { dg-error "invalid use of > incomplete type 'struct V'" } > @@ -29,7 +29,7 @@ bar (int *q) > __builtin_bit_cast (int, s); // { dg-error "'__builtin_bit_cast' > source type 'S' is not trivially copyable" } > __builtin_bit_cast (S, 0); // { dg-error "'__builtin_bit_cast' > destination type 'S' is not trivially copyable" } > __builtin_bit_cast (int &, q); // { dg-error "'__builtin_bit_cast' > destination type 'int&' is not trivially copyable" } > - __builtin_bit_cast (int [1], 0); // { dg-error "'__builtin_bit_cast' > destination type \[^\n\r]* is an array type" } > + __builtin_bit_cast (S [1], 0); // { dg-error "'__builtin_bit_cast' > destination type \[^\n\r]* is not trivially copyable" } > __builtin_bit_cast (V, 0); // { dg-error "invalid use of > incomplete type 'struct V'" } > __builtin_bit_cast (int, *p); // { dg-error "invalid use of > incomplete type 'struct V'" } > __builtin_bit_cast (U, 0); // { dg-error "'__builtin_bit_cast' > source size '\[0-9]*' not equal to destination type size '\[0-9]*'" } > @@ -43,7 +43,7 @@ baz (T3 s, T4 *p, T1 *q) > __builtin_bit_cast (int, s); // { dg-error "'__builtin_bit_cast' > source type 'S' is not trivially copyable" } > __builtin_bit_cast (T3, 0); // { dg-error "'__builtin_bit_cast' > destination type 'S' is not trivially copyable" } > __builtin_bit_cast (T1 &, q); // { dg-error > "'__builtin_bit_cast' destination type 'int&' is not trivially copyable" } > - __builtin_bit_cast (T2, 0); // { dg-error "'__builtin_bit_cast' > destination type \[^\n\r]* is an array type" } > + __builtin_bit_cast (T2, 0); // { dg-error "'__builtin_bit_cast' > destination type \[^\n\r]* is not trivially copyable" } > __builtin_bit_cast (T4, 0); // { dg-error "invalid use of > incomplete type 'struct V'" } > __builtin_bit_cast (int, *p); // { dg-error "invalid use of > incomplete type 'struct V'" } > __builtin_bit_cast (U, (T1) 0); // { dg-error "'__builtin_bit_cast' > source size '\[0-9]*' not equal to destination type size '\[0-9]*'" } > @@ -53,5 +53,5 @@ baz (T3 s, T4 *p, T1 *q) > void > qux (int *q) > { > - baz <int, int [1], S, V> (s, p, q); > + baz <int, S [1], S, V> (s, p, q); > } > -- > 2.31.1 >