public inbox for libstdc++-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-3122] libstdc++: Add std::is_layout_compatible trait for C++20
@ 2021-08-24 15:13 Jonathan Wakely
  0 siblings, 0 replies; only message in thread
From: Jonathan Wakely @ 2021-08-24 15:13 UTC (permalink / raw)
  To: gcc-cvs, libstdc++-cvs

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>);
 }


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-08-24 15:13 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-24 15:13 [gcc r12-3122] libstdc++: Add std::is_layout_compatible trait for C++20 Jonathan Wakely

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).