public inbox for libstdc++@gcc.gnu.org
 help / color / mirror / Atom feed
* [committed] libstdc++: Add std::is_layout_compatible trait for C++20
@ 2021-08-24 15:13 Jonathan Wakely
  2021-08-24 15:17 ` Jonathan Wakely
  0 siblings, 1 reply; 2+ messages in thread
From: Jonathan Wakely @ 2021-08-24 15:13 UTC (permalink / raw)
  To: libstdc++, gcc-patches; +Cc: Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 681 bytes --]

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.

Tested powerpc64le-linux. Committed to trunk.


[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 9959 bytes --]

commit 037ef219b27c26d4c125368e685a89da7f8cc701
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue Aug 24 14:42:37 2021

    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 --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] 2+ messages in thread

* Re: [committed] libstdc++: Add std::is_layout_compatible trait for C++20
  2021-08-24 15:13 [committed] libstdc++: Add std::is_layout_compatible trait for C++20 Jonathan Wakely
@ 2021-08-24 15:17 ` Jonathan Wakely
  0 siblings, 0 replies; 2+ messages in thread
From: Jonathan Wakely @ 2021-08-24 15:17 UTC (permalink / raw)
  To: libstdc++, gcc-patches; +Cc: Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 742 bytes --]

On 24/08/21 16:13 +0100, Jonathan Wakely wrote:
>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.
>

And the doc patch, also pushed to trunk.



[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 1373 bytes --]

commit 6d692ef43b2b3368c92c3fb757c7884fc94ee627
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue Aug 24 16:15:48 2021

    libstdc++: Update C++20 status table for layout-compatibility traits
    
    Signed-off-by: Jonathan Wakely <jwakely@redhat.com>
    
    libstdc++-v3/ChangeLog:
    
            * doc/xml/manual/status_cxx2020.xml: Update table.
            * doc/html/manual/status.html: Regenerate.

diff --git a/libstdc++-v3/doc/xml/manual/status_cxx2020.xml b/libstdc++-v3/doc/xml/manual/status_cxx2020.xml
index a729ddd3ada..26c882907f3 100644
--- a/libstdc++-v3/doc/xml/manual/status_cxx2020.xml
+++ b/libstdc++-v3/doc/xml/manual/status_cxx2020.xml
@@ -294,13 +294,12 @@ or any notes about the implementation.
     </row>
 
     <row>
-      <?dbhtml bgcolor="#C8B0B0" ?>
       <entry> Layout-compatibility and pointer-interconvertibility traits </entry>
       <entry>
         <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0466r5.pdf">
         P0466R5 </link>
       </entry>
-      <entry align="center"> </entry>
+      <entry align="center"> 12 </entry>
       <entry>
         <informaltable colsep="0" rowsep="0" rowheader="norowheader" frame="none"><tgroup cols="1"><tbody>
         <row><entry> <code>__cpp_lib_is_layout_compatible &gt;= 201907L</code> </entry></row>

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2021-08-24 15:17 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-24 15:13 [committed] libstdc++: Add std::is_layout_compatible trait for C++20 Jonathan Wakely
2021-08-24 15:17 ` 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).