Index: include/utility =================================================================== --- include/utility +++ include/utility @@ -291,9 +291,20 @@ constexpr piecewise_construct_t piecewise_construct = piecewise_construct_t(); #endif +#if defined(_LIBCPP_DEPRECATED_ABI_DISABLE_PAIR_TRIVIAL_COPY_CTOR) +struct __non_trivially_copyable_base { + _LIBCPP_CONSTEXPR _LIBCPP_INLINE_VISIBILITY + __non_trivially_copyable_base() _NOEXCEPT {} + _LIBCPP_CONSTEXPR_AFTER_CXX11 _LIBCPP_INLINE_VISIBILITY + __non_trivially_copyable_base(__non_trivially_copyable_base const&) _NOEXCEPT {} +}; +#endif template <class _T1, class _T2> struct _LIBCPP_TYPE_VIS_ONLY pair +#if defined(_LIBCPP_DEPRECATED_ABI_DISABLE_PAIR_TRIVIAL_COPY_CTOR) +: private __non_trivially_copyable_base +#endif { typedef _T1 first_type; typedef _T2 second_type; @@ -301,26 +312,7 @@ _T1 first; _T2 second; -#if defined(_LIBCPP_DEPRECATED_ABI_DISABLE_PAIR_TRIVIAL_COPY_CTOR) - _LIBCPP_INLINE_VISIBILITY - pair(const pair& __p) - _NOEXCEPT_(is_nothrow_copy_constructible<first_type>::value && - is_nothrow_copy_constructible<second_type>::value) - : first(__p.first), - second(__p.second) - { - } - -# ifndef _LIBCPP_CXX03_LANG - _LIBCPP_INLINE_VISIBILITY - pair(pair&& __p) _NOEXCEPT_(is_nothrow_move_constructible<first_type>::value && - is_nothrow_move_constructible<second_type>::value) - : first(_VSTD::forward<first_type>(__p.first)), - second(_VSTD::forward<second_type>(__p.second)) - { - } -# endif -#elif !defined(_LIBCPP_CXX03_LANG) +#if !defined(_LIBCPP_CXX03_LANG) pair(pair const&) = default; pair(pair&&) = default; #else Index: test/libcxx/utilities/utility/pairs/pairs.pair/non_trivial_copy_move_ABI.pass.cpp =================================================================== --- test/libcxx/utilities/utility/pairs/pairs.pair/non_trivial_copy_move_ABI.pass.cpp +++ test/libcxx/utilities/utility/pairs/pairs.pair/non_trivial_copy_move_ABI.pass.cpp @@ -7,49 +7,142 @@ // //===----------------------------------------------------------------------===// +// The test fails due to the missing is_trivially_constructible intrinsic. +// XFAIL: gcc-4.9 + // <utility> // template <class T1, class T2> struct pair -// Test that we properly provide the old non-trivial copy operations -// when the ABI macro is defined. +// Test that we properly provide the trivial copy operations by default. +// FreeBSD provides the old ABI. This test checks the new ABI so we need +// to manually turn it on. +#undef _LIBCPP_ABI_UNSTABLE +#undef _LIBCPP_ABI_VERSION +#define _LIBCPP_ABI_VERSION 1 #define _LIBCPP_DEPRECATED_ABI_DISABLE_PAIR_TRIVIAL_COPY_CTOR + #include <utility> +#include <type_traits> +#include <cstdlib> #include <cassert> #include "test_macros.h" +#if !defined(_LIBCPP_DEPRECATED_ABI_DISABLE_PAIR_TRIVIAL_COPY_CTOR) +#error trivial ctor ABI macro defined +#endif + +template <class T> +struct HasNonTrivialABI : std::integral_constant<bool, + !std::is_trivially_destructible<T>::value + || (std::is_copy_constructible<T>::value && !std::is_trivially_copy_constructible<T>::value) +#if TEST_STD_VER >= 11 + || (std::is_move_constructible<T>::value && !std::is_trivially_move_constructible<T>::value) +#endif +> {}; + #if TEST_STD_VER >= 11 -struct Dummy { - Dummy(Dummy const&) = delete; - Dummy(Dummy &&) = default; +struct NonTrivialDtor { + NonTrivialDtor(NonTrivialDtor const&) = default; + ~NonTrivialDtor(); +}; +NonTrivialDtor::~NonTrivialDtor() {} +static_assert(HasNonTrivialABI<NonTrivialDtor>::value, ""); + +struct NonTrivialCopy { + NonTrivialCopy(NonTrivialCopy const&); +}; +NonTrivialCopy::NonTrivialCopy(NonTrivialCopy const&) {} +static_assert(HasNonTrivialABI<NonTrivialCopy>::value, ""); + +struct NonTrivialMove { + NonTrivialMove(NonTrivialMove const&) = default; + NonTrivialMove(NonTrivialMove&&); +}; +NonTrivialMove::NonTrivialMove(NonTrivialMove&&) {} +static_assert(HasNonTrivialABI<NonTrivialMove>::value, ""); + +struct DeletedCopy { + DeletedCopy(DeletedCopy const&) = delete; + DeletedCopy(DeletedCopy&&) = default; }; +static_assert(!HasNonTrivialABI<DeletedCopy>::value, ""); + +struct TrivialMove { + TrivialMove(TrivialMove &&) = default; +}; +static_assert(!HasNonTrivialABI<TrivialMove>::value, ""); + +struct Trivial { + Trivial(Trivial const&) = default; +}; +static_assert(!HasNonTrivialABI<Trivial>::value, ""); #endif + int main() { - typedef std::pair<int, short> P; { + typedef std::pair<int, short> P; static_assert(std::is_copy_constructible<P>::value, ""); - static_assert(!std::is_trivially_copy_constructible<P>::value, ""); - static_assert(!std::is_trivially_copyable<P>::value, ""); + static_assert(HasNonTrivialABI<P>::value, ""); } #if TEST_STD_VER >= 11 { + typedef std::pair<int, short> P; + static_assert(std::is_move_constructible<P>::value, ""); + static_assert(HasNonTrivialABI<P>::value, ""); + } + { + using P = std::pair<NonTrivialDtor, int>; + static_assert(!std::is_trivially_destructible<P>::value, ""); + static_assert(std::is_copy_constructible<P>::value, ""); + static_assert(!std::is_trivially_copy_constructible<P>::value, ""); + static_assert(std::is_move_constructible<P>::value, ""); + static_assert(!std::is_trivially_move_constructible<P>::value, ""); + static_assert(HasNonTrivialABI<P>::value, ""); + } + { + using P = std::pair<NonTrivialCopy, int>; + static_assert(std::is_copy_constructible<P>::value, ""); + static_assert(!std::is_trivially_copy_constructible<P>::value, ""); static_assert(std::is_move_constructible<P>::value, ""); static_assert(!std::is_trivially_move_constructible<P>::value, ""); - static_assert(!std::is_trivially_copyable<P>::value, ""); + static_assert(HasNonTrivialABI<P>::value, ""); } { - using P1 = std::pair<Dummy, int>; - // These lines fail because the non-trivial constructors do not provide - // SFINAE. - // static_assert(!std::is_copy_constructible<P1>::value, ""); - // static_assert(!std::is_trivially_copy_constructible<P1>::value, ""); - static_assert(std::is_move_constructible<P1>::value, ""); - static_assert(!std::is_trivially_move_constructible<P1>::value, ""); - static_assert(!std::is_trivially_copyable<P>::value, ""); + using P = std::pair<NonTrivialMove, int>; + static_assert(std::is_copy_constructible<P>::value, ""); + static_assert(!std::is_trivially_copy_constructible<P>::value, ""); + static_assert(std::is_move_constructible<P>::value, ""); + static_assert(!std::is_trivially_move_constructible<P>::value, ""); + static_assert(HasNonTrivialABI<P>::value, ""); + } + { + using P = std::pair<DeletedCopy, int>; + static_assert(!std::is_copy_constructible<P>::value, ""); + static_assert(!std::is_trivially_copy_constructible<P>::value, ""); + static_assert(std::is_move_constructible<P>::value, ""); + static_assert(!std::is_trivially_move_constructible<P>::value, ""); + static_assert(HasNonTrivialABI<P>::value, ""); + } + { + using P = std::pair<Trivial, int>; + static_assert(std::is_copy_constructible<P>::value, ""); + static_assert(!std::is_trivially_copy_constructible<P>::value, ""); + static_assert(std::is_move_constructible<P>::value, ""); + static_assert(!std::is_trivially_move_constructible<P>::value, ""); + static_assert(HasNonTrivialABI<P>::value, ""); + } + { + using P = std::pair<TrivialMove, int>; + static_assert(!std::is_copy_constructible<P>::value, ""); + static_assert(!std::is_trivially_copy_constructible<P>::value, ""); + static_assert(std::is_move_constructible<P>::value, ""); + static_assert(!std::is_trivially_move_constructible<P>::value, ""); + static_assert(HasNonTrivialABI<P>::value, ""); } #endif }