Message ID | 20211108200307.4192716-1-wjwray@gmail.com |
---|---|
State | New |
Headers | show |
Series | c++: __builtin_bit_cast To C array target type [PR103140] | expand |
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 <wjwray@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 >
On Mon, Nov 15, 2021 at 12:12:22PM -0500, will wray via Gcc-patches wrote: > 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; > } IMNSHO people shouldn't use this builtin directly, and we shouldn't encourage such uses, the standard interface is std::bit_cast. For the above, I don't see a reason to do it that way, you can instead portably: struct bytes { unsigned char data[sizeof(A)]; }; bytes ab = std::bit_cast(bytes, a); bytes bb = std::bit_cast(bytes, a); for (size_t i = 0; i < sizeof(A); ++i) if (ab.data[i] != bb.data[i]) return false; return true; - __builtin_memcmp isn't portable either and memcmp isn't constexpr. If P1997 is in, it is easy to support it in std::bit_cast and easy to explain what __builtin_bit_cast does for array types, but otherwise it is quite unclear what it exactly does... Jakub
Yes - direct use of any builtin is not to be encouraged, in user code. This __builtin_bit_cast patch is intended to encourage experimentation with array copy semantics now, on truck, in preparation for P1997. The builtin bit_cast is strictly more powerful than the std::bit_cast library function that it helps implement, is available in any -std mode and might also be useful in C, independent of any standardization effort. The semantics of bit_cast is clear - it's just the resulting rvalue array itself is unfamiliar and tricky to handle within current language rules. On Mon, Nov 15, 2021 at 12:21 PM Jakub Jelinek <jakub@redhat.com> wrote: > > On Mon, Nov 15, 2021 at 12:12:22PM -0500, will wray via Gcc-patches wrote: > > 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; > > } > > IMNSHO people shouldn't use this builtin directly, and we shouldn't > encourage such uses, the standard interface is std::bit_cast. > > For the above, I don't see a reason to do it that way, you can > instead portably: > struct bytes { unsigned char data[sizeof(A)]; }; > bytes ab = std::bit_cast(bytes, a); > bytes bb = std::bit_cast(bytes, a); > for (size_t i = 0; i < sizeof(A); ++i) > if (ab.data[i] != bb.data[i]) > return false; > return true; > - __builtin_memcmp isn't portable either and memcmp isn't constexpr. > > If P1997 is in, it is easy to support it in std::bit_cast and easy to > explain what __builtin_bit_cast does for array types, but otherwise > it is quite unclear what it exactly does... > > Jakub >
Ping. Another use case; casting arrays of char to arrays of unsigned char (useful in some crypto APIs). On Mon, Nov 15, 2021 at 6:32 PM will wray <wjwray@gmail.com> wrote: > > Yes - direct use of any builtin is not to be encouraged, in user code. > > This __builtin_bit_cast patch is intended to encourage experimentation > with array copy semantics now, on truck, in preparation for P1997. > > The builtin bit_cast is strictly more powerful than the std::bit_cast > library function that it helps implement, is available in any -std mode > and might also be useful in C, independent of any standardization effort. > > The semantics of bit_cast is clear - it's just the resulting rvalue array > itself is unfamiliar and tricky to handle within current language rules. > > On Mon, Nov 15, 2021 at 12:21 PM Jakub Jelinek <jakub@redhat.com> wrote: > > > > On Mon, Nov 15, 2021 at 12:12:22PM -0500, will wray via Gcc-patches wrote: > > > 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; > > > } > > > > IMNSHO people shouldn't use this builtin directly, and we shouldn't > > encourage such uses, the standard interface is std::bit_cast. > > > > For the above, I don't see a reason to do it that way, you can > > instead portably: > > struct bytes { unsigned char data[sizeof(A)]; }; > > bytes ab = std::bit_cast(bytes, a); > > bytes bb = std::bit_cast(bytes, a); > > for (size_t i = 0; i < sizeof(A); ++i) > > if (ab.data[i] != bb.data[i]) > > return false; > > return true; > > - __builtin_memcmp isn't portable either and memcmp isn't constexpr. > > > > If P1997 is in, it is easy to support it in std::bit_cast and easy to > > explain what __builtin_bit_cast does for array types, but otherwise > > it is quite unclear what it exactly does... > > > > Jakub > >
On 11/8/21 15:03, Will Wray via Gcc-patches 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); Null TYPE_DOMAIN doesn't mean VLA, it means unknown length. Probably better to check for null or non-constant TYPE_SIZE rather than specifically for VLA. > 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); > } >
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); }