public inbox for libstdc++-cvs@sourceware.org help / color / mirror / Atom feed
From: Jonathan Wakely <redi@gcc.gnu.org> 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 Date: Tue, 24 Aug 2021 15:13:10 +0000 (GMT) [thread overview] Message-ID: <20210824151310.B9DF03858401@sourceware.org> (raw) https://gcc.gnu.org/g:037ef219b27c26d4c125368e685a89da7f8cc701 commit r12-3122-g037ef219b27c26d4c125368e685a89da7f8cc701 Author: Jonathan Wakely <jwakely@redhat.com> Date: Tue Aug 24 14:42:37 2021 +0100 libstdc++: Add std::is_layout_compatible trait for C++20 Signed-off-by: Jonathan Wakely <jwakely@redhat.com> 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<typename _Ret, typename _Fn, typename... _Args> inline constexpr bool is_unbounded_array_v = is_unbounded_array<_Tp>::value; +#if __has_builtin(__is_layout_compatible) + + /// @since C++20 + template<typename _Tp, typename _Up> + struct is_layout_compatible + : bool_constant<__is_layout_compatible(_Tp, _Up)> + { }; + + /// @ingroup variable_templates + /// @since C++20 + template<typename _Tp, typename _Up> + 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<typename _S1, typename _S2, typename _M1, typename _M2> + 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 <type_traits> + +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 <type_traits> + +#ifndef __cpp_lib_is_layout_compatible +# error "Feature test macro for is_layout_compatible is missing in <type_traits>" +#elif __cpp_lib_is_layout_compatible < 201907L +# error "Feature test macro for is_layout_compatible has wrong value in <type_traits>" +#endif + +template<typename T, typename U> +concept variable_template_is_correct + = std::is_layout_compatible_v<T, U> == std::is_layout_compatible<T, U>::value; + +template<typename T, typename U> +requires variable_template_is_correct<T, U> +constexpr bool is_layout_compatible = std::is_layout_compatible_v<T, U>; + +static_assert( is_layout_compatible<void, void> ); +static_assert( is_layout_compatible<int, int> ); +static_assert( ! is_layout_compatible<int, int[]> ); +static_assert( ! is_layout_compatible<int, int[1]> ); +static_assert( is_layout_compatible<int[], int[]> ); +static_assert( is_layout_compatible<int[1], int[1]> ); +static_assert( ! is_layout_compatible<int[1], int[]> ); +static_assert( ! is_layout_compatible<int[1], int[2]> ); + +struct Incomplete; +// The standard says these are undefined, but they should work really: +// static_assert( is_layout_compatible<Incomplete, Incomplete> ); +// static_assert( ! is_layout_compatible<Incomplete[], Incomplete> ); +static_assert( is_layout_compatible<Incomplete[], Incomplete[]> ); + +enum E1 : int { }; +enum E2 : int; +static_assert( is_layout_compatible<E1, E2> ); +enum E3 : unsigned int; +static_assert( ! is_layout_compatible<E1, E3> ); +enum E4 : char { }; +enum E5 : signed char { }; +enum E6 : unsigned char { }; +static_assert( ! is_layout_compatible<E4, E5> ); +static_assert( ! is_layout_compatible<E4, E6> ); +static_assert( ! is_layout_compatible<E5, E6> ); + +struct A { int a; }; +struct B { const int b; }; +static_assert( is_layout_compatible<A, B> ); +static_assert( is_layout_compatible<B, A> ); + +struct C : A { }; +struct D : B { }; +static_assert( is_layout_compatible<C, D> ); + +struct E : A { int i; }; // not standard-layout +static_assert( ! is_layout_compatible<E, A> ); 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 <version> + +#ifndef __cpp_lib_is_layout_compatible +# error "Feature test macro for is_layout_compatible is missing in <version>" +#elif __cpp_lib_is_pointer_interconvertible < 201907L +# error "Feature test macro for is_layout_compatible has wrong value in <version>" +#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 <type_traits> + +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<void> 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<typename T, typename U> - constexpr bool is_layout_compatible_v + constexpr bool same_size_and_alignment = std::is_standard_layout_v<T> && std::is_standard_layout_v<U> && sizeof(T) == sizeof(U) && alignof(T) == alignof(U); -#endif void test_pr95609() { using rbuf = std::span<const std::byte>; - using wbuf = std::span<std::byte>; + static_assert(same_size_and_alignment<rbuf, struct iovec>); - static_assert(is_layout_compatible_v<rbuf, struct iovec>); - static_assert(is_layout_compatible_v<wbuf, struct iovec>); + using wbuf = std::span<std::byte>; + static_assert(same_size_and_alignment<wbuf, struct iovec>); }
reply other threads:[~2021-08-24 15:13 UTC|newest] Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20210824151310.B9DF03858401@sourceware.org \ --to=redi@gcc.gnu.org \ --cc=gcc-cvs@gcc.gnu.org \ --cc=libstdc++-cvs@gcc.gnu.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).