From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2181) id B9DF03858401; Tue, 24 Aug 2021 15:13:10 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B9DF03858401 MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jonathan Wakely To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r12-3122] libstdc++: Add std::is_layout_compatible trait for C++20 X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/heads/master X-Git-Oldrev: 8ce18a29ef717f5920ebf5dc1d9e84570a1827d4 X-Git-Newrev: 037ef219b27c26d4c125368e685a89da7f8cc701 Message-Id: <20210824151310.B9DF03858401@sourceware.org> Date: Tue, 24 Aug 2021 15:13:10 +0000 (GMT) X-BeenThere: libstdc++-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 24 Aug 2021 15:13:10 -0000 https://gcc.gnu.org/g:037ef219b27c26d4c125368e685a89da7f8cc701 commit r12-3122-g037ef219b27c26d4c125368e685a89da7f8cc701 Author: Jonathan Wakely Date: Tue Aug 24 14:42:37 2021 +0100 libstdc++: Add std::is_layout_compatible trait for C++20 Signed-off-by: Jonathan Wakely libstdc++-v3/ChangeLog: * include/std/type_traits (is_layout_compatible): Define. (is_corresponding_member): Define. * include/std/version (__cpp_lib_is_layout_compatible): Define. * testsuite/20_util/is_layout_compatible/is_corresponding_member.cc: New test. * testsuite/20_util/is_layout_compatible/value.cc: New test. * testsuite/20_util/is_layout_compatible/version.cc: New test. * testsuite/20_util/is_pointer_interconvertible/with_class.cc: New test. * testsuite/23_containers/span/layout_compat.cc: Do not use real std::is_layout_compatible trait if available. Diff: --- libstdc++-v3/include/std/type_traits | 25 ++++++++++ libstdc++-v3/include/std/version | 4 ++ .../is_corresponding_member.cc | 19 ++++++++ .../20_util/is_layout_compatible/value.cc | 56 ++++++++++++++++++++++ .../20_util/is_layout_compatible/version.cc | 10 ++++ .../is_pointer_interconvertible/with_class.cc | 29 +++++++++++ .../testsuite/23_containers/span/layout_compat.cc | 19 ++++---- 7 files changed, 153 insertions(+), 9 deletions(-) diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index 15718000800..a0010d960b2 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -3414,6 +3414,31 @@ template inline constexpr bool is_unbounded_array_v = is_unbounded_array<_Tp>::value; +#if __has_builtin(__is_layout_compatible) + + /// @since C++20 + template + struct is_layout_compatible + : bool_constant<__is_layout_compatible(_Tp, _Up)> + { }; + + /// @ingroup variable_templates + /// @since C++20 + template + constexpr bool is_layout_compatible_v + = __is_layout_compatible(_Tp, _Up); + +#if __has_builtin(__builtin_is_corresponding_member) +#define __cpp_lib_is_layout_compatible 201907L + + /// @since C++20 + template + constexpr bool + is_corresponding_member(_M1 _S1::*__m1, _M2 _S2::*__m2) noexcept + { return __builtin_is_corresponding_member(__m1, __m2); } +#endif +#endif + #if __has_builtin(__is_pointer_interconvertible_base_of) /// True if `_Derived` is standard-layout and has a base class of type `_Base` /// @since C++20 diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version index 925f27704c4..70d573bb517 100644 --- a/libstdc++-v3/include/std/version +++ b/libstdc++-v3/include/std/version @@ -236,6 +236,10 @@ #ifdef _GLIBCXX_HAS_GTHREADS # define __cpp_lib_jthread 201911L #endif +#if __has_builtin(__is_layout_compatible) \ + && __has_builtin(__builtin_is_corresponding_member) +# define __cpp_lib_is_layout_compatible 201907L +#endif #if __has_builtin(__is_pointer_interconvertible_base_of) \ && __has_builtin(__builtin_is_pointer_interconvertible_with_class) # define __cpp_lib_is_pointer_interconvertible 201907L diff --git a/libstdc++-v3/testsuite/20_util/is_layout_compatible/is_corresponding_member.cc b/libstdc++-v3/testsuite/20_util/is_layout_compatible/is_corresponding_member.cc new file mode 100644 index 00000000000..69b359aa1d5 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/is_layout_compatible/is_corresponding_member.cc @@ -0,0 +1,19 @@ +// { dg-options "-std=gnu++20" } +// { dg-do compile { target c++20 } } +#include + +using std::is_corresponding_member; + +struct A { int a; }; +struct B { int b; }; +struct C: public A, public B { }; // not a standard-layout class + +static_assert( is_corresponding_member( &C::a, &C::b ) ); +// Succeeds because arguments have types int A::* and int B::* + +constexpr int C::*a = &C::a; +constexpr int C::*b = &C::b; +static_assert( ! is_corresponding_member( a, b ) ); +// Not corresponding members, because arguments both have type int C::* + +static_assert( noexcept(!is_corresponding_member(a, b)) ); diff --git a/libstdc++-v3/testsuite/20_util/is_layout_compatible/value.cc b/libstdc++-v3/testsuite/20_util/is_layout_compatible/value.cc new file mode 100644 index 00000000000..7686b34fc5a --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/is_layout_compatible/value.cc @@ -0,0 +1,56 @@ +// { dg-options "-std=gnu++20" } +// { dg-do compile { target c++20 } } +#include + +#ifndef __cpp_lib_is_layout_compatible +# error "Feature test macro for is_layout_compatible is missing in " +#elif __cpp_lib_is_layout_compatible < 201907L +# error "Feature test macro for is_layout_compatible has wrong value in " +#endif + +template +concept variable_template_is_correct + = std::is_layout_compatible_v == std::is_layout_compatible::value; + +template +requires variable_template_is_correct +constexpr bool is_layout_compatible = std::is_layout_compatible_v; + +static_assert( is_layout_compatible ); +static_assert( is_layout_compatible ); +static_assert( ! is_layout_compatible ); +static_assert( ! is_layout_compatible ); +static_assert( is_layout_compatible ); +static_assert( is_layout_compatible ); +static_assert( ! is_layout_compatible ); +static_assert( ! is_layout_compatible ); + +struct Incomplete; +// The standard says these are undefined, but they should work really: +// static_assert( is_layout_compatible ); +// static_assert( ! is_layout_compatible ); +static_assert( is_layout_compatible ); + +enum E1 : int { }; +enum E2 : int; +static_assert( is_layout_compatible ); +enum E3 : unsigned int; +static_assert( ! is_layout_compatible ); +enum E4 : char { }; +enum E5 : signed char { }; +enum E6 : unsigned char { }; +static_assert( ! is_layout_compatible ); +static_assert( ! is_layout_compatible ); +static_assert( ! is_layout_compatible ); + +struct A { int a; }; +struct B { const int b; }; +static_assert( is_layout_compatible ); +static_assert( is_layout_compatible ); + +struct C : A { }; +struct D : B { }; +static_assert( is_layout_compatible ); + +struct E : A { int i; }; // not standard-layout +static_assert( ! is_layout_compatible ); diff --git a/libstdc++-v3/testsuite/20_util/is_layout_compatible/version.cc b/libstdc++-v3/testsuite/20_util/is_layout_compatible/version.cc new file mode 100644 index 00000000000..1a32275fdf5 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/is_layout_compatible/version.cc @@ -0,0 +1,10 @@ +// { dg-options "-std=gnu++20" } +// { dg-do compile { target c++20 } } + +#include + +#ifndef __cpp_lib_is_layout_compatible +# error "Feature test macro for is_layout_compatible is missing in " +#elif __cpp_lib_is_pointer_interconvertible < 201907L +# error "Feature test macro for is_layout_compatible has wrong value in " +#endif diff --git a/libstdc++-v3/testsuite/20_util/is_pointer_interconvertible/with_class.cc b/libstdc++-v3/testsuite/20_util/is_pointer_interconvertible/with_class.cc new file mode 100644 index 00000000000..28de9b416fc --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/is_pointer_interconvertible/with_class.cc @@ -0,0 +1,29 @@ +// { dg-options "-std=gnu++20" } +// { dg-do compile { target c++20 } } +#include + +struct A { int i; long l; }; + +static_assert( std::is_pointer_interconvertible_with_class(&A::i) ); +static_assert( ! std::is_pointer_interconvertible_with_class(&A::l) ); + +constexpr int A::*a = nullptr; +static_assert( ! std::is_pointer_interconvertible_with_class(a) ); +static_assert( noexcept( std::is_pointer_interconvertible_with_class(a) ) ); + +struct B { const int i; }; +static_assert( std::is_pointer_interconvertible_with_class(&B::i) ); + +struct C { int f(); }; +static_assert( ! std::is_pointer_interconvertible_with_class(&C::f) ); + +struct D : A { }; +static_assert( std::is_pointer_interconvertible_with_class(&D::i) ); + +struct E : A { int j; }; +// This works because the type of &E::i is int A::* and A is standard-layout: +static_assert( std::is_pointer_interconvertible_with_class(&E::i) ); +constexpr int E::*e = a; +// This fails because E is not standard-layout: +static_assert( ! std::is_pointer_interconvertible_with_class(e) ); +static_assert( ! std::is_pointer_interconvertible_with_class(&E::j) ); diff --git a/libstdc++-v3/testsuite/23_containers/span/layout_compat.cc b/libstdc++-v3/testsuite/23_containers/span/layout_compat.cc index 04947e93dbc..bb560fe5e6c 100644 --- a/libstdc++-v3/testsuite/23_containers/span/layout_compat.cc +++ b/libstdc++-v3/testsuite/23_containers/span/layout_compat.cc @@ -27,22 +27,23 @@ struct iovec { void* iov_base; std::size_t iov_len; }; #endif -#if __cpp_lib_is_layout_compatible -using std::is_layout_compatible_v; -#else -// A poor substitute for is_layout_compatible_v +// std::span cannot possibly be layout-compatible with struct iovec because +// iovec::iov_base is a void* and span is ill-formed. Additionally, +// the libstdc++ std::span uses [[no_unique_address]] on the second member, +// so that it's not present for a span of static extent, and that affects +// layout-compatibility too. +// Use this to check the size and alignment are compatible. template - constexpr bool is_layout_compatible_v + constexpr bool same_size_and_alignment = std::is_standard_layout_v && std::is_standard_layout_v && sizeof(T) == sizeof(U) && alignof(T) == alignof(U); -#endif void test_pr95609() { using rbuf = std::span; - using wbuf = std::span; + static_assert(same_size_and_alignment); - static_assert(is_layout_compatible_v); - static_assert(is_layout_compatible_v); + using wbuf = std::span; + static_assert(same_size_and_alignment); }