From 79ff53453e88e40c4f2ecf6f7f7409afc41b46fc Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 16 Apr 2024 09:39:19 +0200 Subject: [PATCH] c++: Handle ARRAY_TYPE in check_bit_cast_type [PR114706] https://eel.is/c++draft/bit.cast#3 says that std::bit_cast isn't constexpr if To, From and the types of all subobjects have certain properties which the check_bit_cast_type checks (such as it isn't a pointer, reference, union, member pointer, volatile). The function doesn't cp_walk_tree though, so I've missed one important case, for ARRAY_TYPEs we need to recurse on the element type. I think we don't need to handle VECTOR_TYPEs/COMPLEX_TYPEs, because those will not have a pointer/reference/union/member pointer in the element type and if the element type is volatile, I think the whole derived type is volatile as well. 2024-04-16 Jakub Jelinek PR c++/114706 * constexpr.cc (check_bit_cast_type): Handle ARRAY_TYPE. * g++.dg/cpp2a/bit-cast17.C: New test. --- gcc/cp/constexpr.cc | 2 ++ gcc/testsuite/g++.dg/cpp2a/bit-cast17.C | 31 +++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 gcc/testsuite/g++.dg/cpp2a/bit-cast17.C diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index fcc847d85df..302b266809f 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -4843,6 +4843,8 @@ check_bit_cast_type (const constexpr_ctx *ctx, location_t loc, tree type, if (TREE_CODE (field) == FIELD_DECL && check_bit_cast_type (ctx, loc, TREE_TYPE (field), orig_type)) return true; + if (TREE_CODE (type) == ARRAY_TYPE) + return check_bit_cast_type (ctx, loc, TREE_TYPE (type), orig_type); return false; } diff --git a/gcc/testsuite/g++.dg/cpp2a/bit-cast17.C b/gcc/testsuite/g++.dg/cpp2a/bit-cast17.C new file mode 100644 index 00000000000..0ccb8cb4f38 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/bit-cast17.C @@ -0,0 +1,31 @@ +// PR c++/114706 +// { dg-do compile { target c++20 } } + +namespace std { +template +constexpr T +bit_cast (const F& f) noexcept +{ + return __builtin_bit_cast (T, f); +} +} +// { dg-error "'__builtin_bit_cast' is not a constant expression because 'const A' contains a union type" "" { target *-*-* } .-3 } +// { dg-error "'__builtin_bit_cast' is not a constant expression because 'A' contains a union type" "" { target *-*-* } .-4 } +// { dg-error "'__builtin_bit_cast' is not a constant expression because 'const C' contains a union type" "" { target *-*-* } .-5 } +// { dg-error "'__builtin_bit_cast' is not a constant expression because 'C' contains a union type" "" { target *-*-* } .-6 } +// { dg-error "'__builtin_bit_cast' is not a constant expression because 'const E' contains a pointer type" "" { target *-*-* } .-7 } +// { dg-error "'__builtin_bit_cast' is not a constant expression because 'E' contains a pointer type" "" { target *-*-* } .-8 } + +union U { int a; int b; }; +struct A { U c[2]; }; +struct B { int d[2]; }; +struct C { U e[2][2]; }; +struct D { int f[2][2]; }; +struct E { int *g[3]; }; +struct F { char h[sizeof (int *) * 3]; }; +constexpr B i = std::bit_cast (A{}); // { dg-message "in 'constexpr' expansion of 'std::bit_cast<" } +constexpr A j = std::bit_cast (B{}); // { dg-message "in 'constexpr' expansion of 'std::bit_cast<" } +constexpr D k = std::bit_cast (C{}); // { dg-message "in 'constexpr' expansion of 'std::bit_cast<" } +constexpr C l = std::bit_cast (D{}); // { dg-message "in 'constexpr' expansion of 'std::bit_cast<" } +constexpr F m = std::bit_cast (E{}); // { dg-message "in 'constexpr' expansion of 'std::bit_cast<" } +constexpr E n = std::bit_cast (F{}); // { dg-message "in 'constexpr' expansion of 'std::bit_cast<" }