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 <[email protected]> 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
>