From e2bd16c9d218dd9474d16f421a987ce1bc16cacf Mon Sep 17 00:00:00 2001 From: Eric Fiselier Date: Tue, 11 Oct 2016 21:22:21 +0000 Subject: [PATCH] Fix std::pair on FreeBSD Summary: FreeBSD ships an old ABI for std::pair which requires that it have non-trivial copy/move constructors. Currently the non-trivial copy/move is achieved by providing explicit definitions of the constructors. This is problematic because it means the constructors don't SFINAE properly. In order to SFINAE copy/move constructors they have to be explicitly defaulted and hense non-trivial. This patch attempts to provide SFINAE'ing copy/move constructors for std::pair while still making them non-trivial. It does this by adding a base class with a non-trivial copy constructor and then allowing pair's constructors to be generated by the compiler. This also allows the constructors to be constexpr. Reviewers: emaste, theraven, rsmith, dim Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D25389 git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@283944 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/utility | 32 ++--- .../non_trivial_copy_move_ABI.pass.cpp | 133 +++++++++++++++--- 2 files changed, 125 insertions(+), 40 deletions(-) diff --git a/include/utility b/include/utility index 095748d86..cfab350cb 100644 --- a/include/utility +++ b/include/utility @@ -291,9 +291,20 @@ extern const piecewise_construct_t piecewise_construct;// = piecewise_construct_ 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 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 @@ struct _LIBCPP_TYPE_VIS_ONLY pair _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::value && - is_nothrow_copy_constructible::value) - : first(__p.first), - second(__p.second) - { - } - -# ifndef _LIBCPP_CXX03_LANG - _LIBCPP_INLINE_VISIBILITY - pair(pair&& __p) _NOEXCEPT_(is_nothrow_move_constructible::value && - is_nothrow_move_constructible::value) - : first(_VSTD::forward(__p.first)), - second(_VSTD::forward(__p.second)) - { - } -# endif -#elif !defined(_LIBCPP_CXX03_LANG) +#if !defined(_LIBCPP_CXX03_LANG) pair(pair const&) = default; pair(pair&&) = default; #else diff --git a/test/libcxx/utilities/utility/pairs/pairs.pair/non_trivial_copy_move_ABI.pass.cpp b/test/libcxx/utilities/utility/pairs/pairs.pair/non_trivial_copy_move_ABI.pass.cpp index c012ac626..070312931 100644 --- a/test/libcxx/utilities/utility/pairs/pairs.pair/non_trivial_copy_move_ABI.pass.cpp +++ b/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 + // // template 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 +#include +#include #include #include "test_macros.h" -#if TEST_STD_VER >= 11 -struct Dummy { - Dummy(Dummy const&) = delete; - Dummy(Dummy &&) = default; -}; +#if !defined(_LIBCPP_DEPRECATED_ABI_DISABLE_PAIR_TRIVIAL_COPY_CTOR) +#error trivial ctor ABI macro defined #endif +template +struct HasNonTrivialABI : std::integral_constant::value + || (std::is_copy_constructible::value && !std::is_trivially_copy_constructible::value) +#if TEST_STD_VER >= 11 + || (std::is_move_constructible::value && !std::is_trivially_move_constructible::value) +#endif +> {}; + +#if TEST_STD_VER >= 11 +struct NonTrivialDtor { + NonTrivialDtor(NonTrivialDtor const&) = default; + ~NonTrivialDtor(); +}; +NonTrivialDtor::~NonTrivialDtor() {} +static_assert(HasNonTrivialABI::value, ""); + +struct NonTrivialCopy { + NonTrivialCopy(NonTrivialCopy const&); +}; +NonTrivialCopy::NonTrivialCopy(NonTrivialCopy const&) {} +static_assert(HasNonTrivialABI::value, ""); + +struct NonTrivialMove { + NonTrivialMove(NonTrivialMove const&) = default; + NonTrivialMove(NonTrivialMove&&); +}; +NonTrivialMove::NonTrivialMove(NonTrivialMove&&) {} +static_assert(HasNonTrivialABI::value, ""); + +struct DeletedCopy { + DeletedCopy(DeletedCopy const&) = delete; + DeletedCopy(DeletedCopy&&) = default; +}; +static_assert(!HasNonTrivialABI::value, ""); + +struct TrivialMove { + TrivialMove(TrivialMove &&) = default; +}; +static_assert(!HasNonTrivialABI::value, ""); + +struct Trivial { + Trivial(Trivial const&) = default; +}; +static_assert(!HasNonTrivialABI::value, ""); +#endif + + int main() { - typedef std::pair P; { + typedef std::pair P; static_assert(std::is_copy_constructible

::value, ""); - static_assert(!std::is_trivially_copy_constructible

::value, ""); - static_assert(!std::is_trivially_copyable

::value, ""); + static_assert(HasNonTrivialABI

::value, ""); } #if TEST_STD_VER >= 11 { + typedef std::pair P; static_assert(std::is_move_constructible

::value, ""); - static_assert(!std::is_trivially_move_constructible

::value, ""); - static_assert(!std::is_trivially_copyable

::value, ""); + static_assert(HasNonTrivialABI

::value, ""); } { - using P1 = std::pair; - // These lines fail because the non-trivial constructors do not provide - // SFINAE. - // static_assert(!std::is_copy_constructible::value, ""); - // static_assert(!std::is_trivially_copy_constructible::value, ""); - static_assert(std::is_move_constructible::value, ""); - static_assert(!std::is_trivially_move_constructible::value, ""); - static_assert(!std::is_trivially_copyable

::value, ""); + using P = std::pair; + static_assert(!std::is_trivially_destructible

::value, ""); + static_assert(std::is_copy_constructible

::value, ""); + static_assert(!std::is_trivially_copy_constructible

::value, ""); + static_assert(std::is_move_constructible

::value, ""); + static_assert(!std::is_trivially_move_constructible

::value, ""); + static_assert(HasNonTrivialABI

::value, ""); + } + { + using P = std::pair; + static_assert(std::is_copy_constructible

::value, ""); + static_assert(!std::is_trivially_copy_constructible

::value, ""); + static_assert(std::is_move_constructible

::value, ""); + static_assert(!std::is_trivially_move_constructible

::value, ""); + static_assert(HasNonTrivialABI

::value, ""); + } + { + using P = std::pair; + static_assert(std::is_copy_constructible

::value, ""); + static_assert(!std::is_trivially_copy_constructible

::value, ""); + static_assert(std::is_move_constructible

::value, ""); + static_assert(!std::is_trivially_move_constructible

::value, ""); + static_assert(HasNonTrivialABI

::value, ""); + } + { + using P = std::pair; + static_assert(!std::is_copy_constructible

::value, ""); + static_assert(!std::is_trivially_copy_constructible

::value, ""); + static_assert(std::is_move_constructible

::value, ""); + static_assert(!std::is_trivially_move_constructible

::value, ""); + static_assert(HasNonTrivialABI

::value, ""); + } + { + using P = std::pair; + static_assert(std::is_copy_constructible

::value, ""); + static_assert(!std::is_trivially_copy_constructible

::value, ""); + static_assert(std::is_move_constructible

::value, ""); + static_assert(!std::is_trivially_move_constructible

::value, ""); + static_assert(HasNonTrivialABI

::value, ""); + } + { + using P = std::pair; + static_assert(!std::is_copy_constructible

::value, ""); + static_assert(!std::is_trivially_copy_constructible

::value, ""); + static_assert(std::is_move_constructible

::value, ""); + static_assert(!std::is_trivially_move_constructible

::value, ""); + static_assert(HasNonTrivialABI

::value, ""); } #endif }