Skip to content

[libcxx] makes pair conditionally trivially copyable for C++20 #84811

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions libcxx/include/__config
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,9 @@
// requires code not to make these assumptions.
# define _LIBCPP_ABI_USE_WRAP_ITER_IN_STD_ARRAY
# define _LIBCPP_ABI_USE_WRAP_ITER_IN_STD_STRING_VIEW
// Allows std::pair's copy assignment and move assignment operators to be trivial
// when both its element types' respective assignment operators are trivial.
# define _LIBCPP_ABI_PAIR_TRIVIALLY_COPYABLE
# elif _LIBCPP_ABI_VERSION == 1
# if !(defined(_LIBCPP_OBJECT_FORMAT_COFF) || defined(_LIBCPP_OBJECT_FORMAT_XCOFF))
// Enable compiling copies of now inline methods into the dylib to support
Expand Down
36 changes: 36 additions & 0 deletions libcxx/include/__utility/pair.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <__compare/common_comparison_category.h>
#include <__compare/synth_three_way.h>
#include <__concepts/assignable.h>
#include <__concepts/different_from.h>
#include <__config>
#include <__fwd/array.h>
Expand All @@ -26,6 +27,7 @@
#include <__type_traits/common_type.h>
#include <__type_traits/conditional.h>
#include <__type_traits/decay.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/integral_constant.h>
#include <__type_traits/is_assignable.h>
#include <__type_traits/is_constructible.h>
Expand All @@ -40,8 +42,11 @@
#include <__type_traits/is_nothrow_copy_constructible.h>
#include <__type_traits/is_nothrow_default_constructible.h>
#include <__type_traits/is_nothrow_move_assignable.h>
#include <__type_traits/is_object.h>
#include <__type_traits/is_same.h>
#include <__type_traits/is_swappable.h>
#include <__type_traits/is_trivially_copy_assignable.h>
#include <__type_traits/is_trivially_move_assignable.h>
#include <__type_traits/nat.h>
#include <__type_traits/remove_cvref.h>
#include <__type_traits/unwrap_ref.h>
Expand All @@ -67,6 +72,14 @@ struct __non_trivially_copyable_base {
__non_trivially_copyable_base(__non_trivially_copyable_base const&) _NOEXCEPT {}
};

#if _LIBCPP_STD_VER >= 20
template <class _Tp>
concept __trivially_copy_assignable_object = is_trivially_copy_assignable_v<_Tp> && is_object_v<_Tp>;

template <class _Tp>
concept __trivially_move_assignable_object = is_trivially_move_assignable_v<_Tp> && is_object_v<_Tp>;
#endif

#if _LIBCPP_STD_VER >= 23
template <class _Tp>
struct __is_specialization_of_subrange : false_type {};
Expand Down Expand Up @@ -236,6 +249,28 @@ struct _LIBCPP_TEMPLATE_VIS pair
typename __make_tuple_indices<sizeof...(_Args1)>::type(),
typename __make_tuple_indices<sizeof...(_Args2) >::type()) {}

# if _LIBCPP_STD_VER >= 20 && defined(_LIBCPP_ABI_PAIR_TRIVIALLY_COPYABLE)
_LIBCPP_HIDE_FROM_ABI pair& operator=(pair const& __p) = default;
_LIBCPP_HIDE_FROM_ABI pair& operator=(pair&& __p) = default;

_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair& operator=(pair const& __p)
_NOEXCEPT_(is_nothrow_copy_assignable<first_type>::value&& is_nothrow_copy_assignable<second_type>::value)
requires is_copy_assignable_v<first_type> && is_copy_assignable_v<second_type> && (!(__trivially_copy_assignable_object<first_type> && __trivially_copy_assignable_object<second_type>))
{
first = __p.first;
second = __p.second;
return *this;
}

_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair& operator=(pair&& __p)
_NOEXCEPT_(is_nothrow_move_assignable<first_type>::value&& is_nothrow_move_assignable<second_type>::value)
requires is_move_assignable_v<first_type> && is_move_assignable_v<second_type> && (!(__trivially_move_assignable_object<first_type> && __trivially_move_assignable_object<second_type>))
{
first = std::forward<first_type>(__p.first);
second = std::forward<second_type>(__p.second);
return *this;
}
# else
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair&
operator=(__conditional_t< is_copy_assignable<first_type>::value && is_copy_assignable<second_type>::value,
pair,
Expand All @@ -254,6 +289,7 @@ struct _LIBCPP_TEMPLATE_VIS pair
second = std::forward<second_type>(__p.second);
return *this;
}
# endif

template <
class _U1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,16 @@ TEST_CONSTEXPR_CXX20 bool test() {
assert(&p.second == &inc_obj);
}

#if TEST_STD_VER >= 20 && defined(_LIBCPP_ABI_PAIR_TRIVIALLY_COPYABLE)
static_assert(std::is_trivially_copy_assignable<std::pair<int, int>>::value, "");
#else
static_assert(!std::is_trivially_copy_assignable<std::pair<int, int>>::value, "");
#endif

static_assert(!std::is_trivially_copy_assignable<std::pair<CountAssign, int>>::value, "");
static_assert(!std::is_trivially_copy_assignable<std::pair<int, CountAssign>>::value, "");
static_assert(!std::is_trivially_copy_assignable<std::pair<CountAssign, CountAssign>>::value, "");

return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ int main(int, char**)
assert(p.second == 'x');
}

return 0;
static_assert(!std::is_trivially_copy_assignable<std::pair<int, int> >::value, "");

return 0;
}

struct Incomplete {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,17 @@ TEST_CONSTEXPR_CXX20 bool test() {
static_assert(!std::is_move_assignable<P5>::value, "");
static_assert(!std::is_move_assignable<P6>::value, "");
}

#if TEST_STD_VER >= 20 && defined(_LIBCPP_ABI_PAIR_TRIVIALLY_COPYABLE)
static_assert(std::is_trivially_move_assignable<std::pair<int, int>>::value, "");
#else
static_assert(!std::is_trivially_move_assignable<std::pair<int, int>>::value, "");
#endif

static_assert(!std::is_trivially_move_assignable<std::pair<CountAssign, int>>::value, "");
static_assert(!std::is_trivially_move_assignable<std::pair<int, CountAssign>>::value, "");
static_assert(!std::is_trivially_move_assignable<std::pair<CountAssign, CountAssign>>::value, "");

return true;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++03, c++11, c++14, c++17

// <utility>

// template <class T1, class T2> struct pair

// Checks that `std::pair` is actually trivially copyable.

#include <type_traits>
#include <utility>

#if defined(_LIBCPP_ABI_PAIR_TRIVIALLY_COPYABLE)
static_assert(std::is_trivially_copyable_v<std::pair<int, int>>);
static_assert(std::is_trivially_copyable_v<std::pair<int, int const>>);
static_assert(std::is_trivially_copyable_v<std::pair<int const, int>>);
static_assert(std::is_trivially_copyable_v<std::pair<int const, int const>>);

static_assert(!std::is_trivially_copyable_v<std::pair<int, int&>>);
static_assert(!std::is_trivially_copyable_v<std::pair<int&, int>>);
static_assert(!std::is_trivially_copyable_v<std::pair<int&, int&>>);

enum E {};
static_assert(std::is_trivially_copyable_v<std::pair<E, E>>);
static_assert(std::is_trivially_copyable_v<std::pair<E, E const>>);
static_assert(std::is_trivially_copyable_v<std::pair<E const, E>>);
static_assert(std::is_trivially_copyable_v<std::pair<E const, E const>>);

static_assert(std::is_trivially_copyable_v<std::pair<E, int>>);
static_assert(std::is_trivially_copyable_v<std::pair<E, int const>>);
static_assert(std::is_trivially_copyable_v<std::pair<E const, int>>);
static_assert(std::is_trivially_copyable_v<std::pair<E const, int const>>);

struct S {};
static_assert(std::is_trivially_copyable_v<std::pair<S, S>>);
static_assert(std::is_trivially_copyable_v<std::pair<S, int>>);
static_assert(std::is_trivially_copyable_v<std::pair<S, E>>);
#endif