aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3
diff options
context:
space:
mode:
Diffstat (limited to 'libstdc++-v3')
-rw-r--r--libstdc++-v3/include/std/type_traits25
-rw-r--r--libstdc++-v3/include/std/version4
-rw-r--r--libstdc++-v3/testsuite/20_util/is_layout_compatible/is_corresponding_member.cc19
-rw-r--r--libstdc++-v3/testsuite/20_util/is_layout_compatible/value.cc56
-rw-r--r--libstdc++-v3/testsuite/20_util/is_layout_compatible/version.cc10
-rw-r--r--libstdc++-v3/testsuite/20_util/is_pointer_interconvertible/with_class.cc29
-rw-r--r--libstdc++-v3/testsuite/23_containers/span/layout_compat.cc19
7 files changed, 153 insertions, 9 deletions
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 1571800..a0010d9 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 925f277..70d573b 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 0000000..69b359a
--- /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 0000000..7686b34
--- /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 0000000..1a32275
--- /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 0000000..28de9b4
--- /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 04947e9..bb560fe 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>);
}