[libcxx] r283944 - Fix std::pair on FreeBSD
Eric Fiselier via cfe-commits
cfe-commits at lists.llvm.org
Tue Oct 11 14:22:22 PDT 2016
Author: ericwf
Date: Tue Oct 11 16:22:21 2016
New Revision: 283944
URL: http://llvm.org/viewvc/llvm-project?rev=283944&view=rev
Log:
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
Modified:
libcxx/trunk/include/utility
libcxx/trunk/test/libcxx/utilities/utility/pairs/pairs.pair/non_trivial_copy_move_ABI.pass.cpp
Modified: libcxx/trunk/include/utility
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?rev=283944&r1=283943&r2=283944&view=diff
==============================================================================
--- libcxx/trunk/include/utility (original)
+++ libcxx/trunk/include/utility Tue Oct 11 16:22:21 2016
@@ -291,9 +291,20 @@ extern const piecewise_construct_t piece
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
Modified: libcxx/trunk/test/libcxx/utilities/utility/pairs/pairs.pair/non_trivial_copy_move_ABI.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/utilities/utility/pairs/pairs.pair/non_trivial_copy_move_ABI.pass.cpp?rev=283944&r1=283943&r2=283944&view=diff
==============================================================================
--- libcxx/trunk/test/libcxx/utilities/utility/pairs/pairs.pair/non_trivial_copy_move_ABI.pass.cpp (original)
+++ libcxx/trunk/test/libcxx/utilities/utility/pairs/pairs.pair/non_trivial_copy_move_ABI.pass.cpp Tue Oct 11 16:22:21 2016
@@ -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
}
More information about the cfe-commits
mailing list