forked from OSchip/llvm-project
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 llvm-svn: 283944
This commit is contained in:
parent
a58f92f09d
commit
9595fb21dd
|
@ -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 <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 @@ 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<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
|
||||
|
|
|
@ -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 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 <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 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(!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<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(HasNonTrivialABI<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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue