Author: ericwf Date: Thu Apr 21 18:38:59 2016 New Revision: 267079 URL: http://llvm.org/viewvc/llvm-project?rev=267079&view=rev Log: Add is_swappable/is_nothrow_swappable traits
Added: libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_nothrow_swappable.pass.cpp libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_nothrow_swappable_with.pass.cpp libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_swappable.pass.cpp libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_swappable_include_order.pass.cpp libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_swappable_with.pass.cpp Modified: libcxx/trunk/include/algorithm libcxx/trunk/include/array libcxx/trunk/include/map libcxx/trunk/include/memory libcxx/trunk/include/queue libcxx/trunk/include/stack libcxx/trunk/include/type_traits libcxx/trunk/include/utility libcxx/trunk/test/std/containers/sequences/array/array.special/swap.pass.cpp libcxx/trunk/test/std/containers/sequences/array/array.swap/swap.pass.cpp libcxx/trunk/test/std/utilities/memory/unique.ptr/unique.ptr.special/swap.pass.cpp libcxx/trunk/test/std/utilities/utility/utility.swap/swap.pass.cpp libcxx/trunk/test/std/utilities/utility/utility.swap/swap_array.pass.cpp libcxx/trunk/www/cxx1z_status.html Modified: libcxx/trunk/include/algorithm URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/algorithm?rev=267079&r1=267078&r2=267079&view=diff ============================================================================== --- libcxx/trunk/include/algorithm (original) +++ libcxx/trunk/include/algorithm Thu Apr 21 18:38:59 2016 @@ -630,7 +630,7 @@ template <class BidirectionalIterator, c #include <initializer_list> #include <type_traits> #include <cstring> -#include <utility> +#include <utility> // needed to provide swap_ranges. #include <memory> #include <iterator> #include <cstddef> Modified: libcxx/trunk/include/array URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/array?rev=267079&r1=267078&r2=267079&view=diff ============================================================================== --- libcxx/trunk/include/array (original) +++ libcxx/trunk/include/array Thu Apr 21 18:38:59 2016 @@ -34,7 +34,7 @@ struct array // No explicit construct/copy/destroy for aggregate type void fill(const T& u); - void swap(array& a) noexcept(noexcept(swap(declval<T&>(), declval<T&>()))); + void swap(array& a) noexcept(is_nothrow_swappable_v<T>); // iterators: iterator begin() noexcept; @@ -141,8 +141,15 @@ struct _LIBCPP_TYPE_VIS_ONLY array _LIBCPP_INLINE_VISIBILITY void fill(const value_type& __u) {_VSTD::fill_n(__elems_, _Size, __u);} _LIBCPP_INLINE_VISIBILITY - void swap(array& __a) _NOEXCEPT_(__is_nothrow_swappable<_Tp>::value) - {_VSTD::swap_ranges(__elems_, __elems_ + _Size, __a.__elems_);} + void swap(array& __a) _NOEXCEPT_(_Size == 0 || __is_nothrow_swappable<_Tp>::value) + { __swap_dispatch((std::integral_constant<bool, _Size == 0>()), __a); } + + _LIBCPP_INLINE_VISIBILITY + void __swap_dispatch(std::true_type, array&) {} + + _LIBCPP_INLINE_VISIBILITY + void __swap_dispatch(std::false_type, array& __a) + { _VSTD::swap_ranges(__elems_, __elems_ + _Size, __a.__elems_);} // iterators: _LIBCPP_INLINE_VISIBILITY @@ -276,11 +283,12 @@ template <class _Tp, size_t _Size> inline _LIBCPP_INLINE_VISIBILITY typename enable_if < + _Size == 0 || __is_swappable<_Tp>::value, void >::type swap(array<_Tp, _Size>& __x, array<_Tp, _Size>& __y) - _NOEXCEPT_(__is_nothrow_swappable<_Tp>::value) + _NOEXCEPT_(noexcept(__x.swap(__y))) { __x.swap(__y); } Modified: libcxx/trunk/include/map URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/map?rev=267079&r1=267078&r2=267079&view=diff ============================================================================== --- libcxx/trunk/include/map (original) +++ libcxx/trunk/include/map Thu Apr 21 18:38:59 2016 @@ -162,7 +162,7 @@ public: void swap(map& m) noexcept(allocator_traits<allocator_type>::is_always_equal::value && - __is_nothrow_swappable<key_compare>::value); // C++17 + is_nothrow_swappable<key_compare>::value); // C++17 // observers: allocator_type get_allocator() const noexcept; @@ -357,7 +357,7 @@ public: void swap(multimap& m) noexcept(allocator_traits<allocator_type>::is_always_equal::value && - __is_nothrow_swappable<key_compare>::value); // C++17 + is_nothrow_swappable<key_compare>::value); // C++17 // observers: allocator_type get_allocator() const noexcept; Modified: libcxx/trunk/include/memory URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/memory?rev=267079&r1=267078&r2=267079&view=diff ============================================================================== --- libcxx/trunk/include/memory (original) +++ libcxx/trunk/include/memory Thu Apr 21 18:38:59 2016 @@ -2974,7 +2974,10 @@ private: template <class _Tp, class _Dp> inline _LIBCPP_INLINE_VISIBILITY -void +typename enable_if< + __is_swappable<_Dp>::value, + void +>::type swap(unique_ptr<_Tp, _Dp>& __x, unique_ptr<_Tp, _Dp>& __y) _NOEXCEPT {__x.swap(__y);} template <class _T1, class _D1, class _T2, class _D2> Modified: libcxx/trunk/include/queue URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/queue?rev=267079&r1=267078&r2=267079&view=diff ============================================================================== --- libcxx/trunk/include/queue (original) +++ libcxx/trunk/include/queue Thu Apr 21 18:38:59 2016 @@ -66,7 +66,7 @@ public: template <class... Args> void emplace(Args&&... args); void pop(); - void swap(queue& q) noexcept(noexcept(swap(c, q.c))); + void swap(queue& q) noexcept(is_nothrow_swappable_v<Container>) }; template <class T, class Container> @@ -153,7 +153,8 @@ public: void pop(); void swap(priority_queue& q) - noexcept(noexcept(swap(c, q.c)) && noexcept(swap(comp.q.comp))); + noexcept(is_nothrow_swappable_v<Container> && + is_nothrow_swappable_v<Comp>) }; template <class T, class Container, class Compare> @@ -369,7 +370,10 @@ operator<=(const queue<_Tp, _Container>& template <class _Tp, class _Container> inline _LIBCPP_INLINE_VISIBILITY -void +typename enable_if< + __is_swappable<_Container>::value, + void +>::type swap(queue<_Tp, _Container>& __x, queue<_Tp, _Container>& __y) _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) { @@ -700,7 +704,11 @@ priority_queue<_Tp, _Container, _Compare template <class _Tp, class _Container, class _Compare> inline _LIBCPP_INLINE_VISIBILITY -void +typename enable_if< + __is_swappable<_Container>::value + && __is_swappable<_Compare>::value, + void +>::type swap(priority_queue<_Tp, _Container, _Compare>& __x, priority_queue<_Tp, _Container, _Compare>& __y) _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) Modified: libcxx/trunk/include/stack URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/stack?rev=267079&r1=267078&r2=267079&view=diff ============================================================================== --- libcxx/trunk/include/stack (original) +++ libcxx/trunk/include/stack Thu Apr 21 18:38:59 2016 @@ -58,7 +58,7 @@ public: template <class... Args> void emplace(Args&&... args); void pop(); - void swap(stack& c) noexcept(noexcept(swap(c, q.c))); + void swap(stack& c) noexcept(is_nothrow_swappable_v<Container>) }; template <class T, class Container> @@ -275,7 +275,10 @@ operator<=(const stack<_Tp, _Container>& template <class _Tp, class _Container> inline _LIBCPP_INLINE_VISIBILITY -void +typename enable_if< + __is_swappable<_Container>::value, + void +>::type swap(stack<_Tp, _Container>& __x, stack<_Tp, _Container>& __y) _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) { Modified: libcxx/trunk/include/type_traits URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/type_traits?rev=267079&r1=267078&r2=267079&view=diff ============================================================================== --- libcxx/trunk/include/type_traits (original) +++ libcxx/trunk/include/type_traits Thu Apr 21 18:38:59 2016 @@ -105,6 +105,8 @@ namespace std template <class T, class U> struct is_assignable; template <class T> struct is_copy_assignable; template <class T> struct is_move_assignable; + template <class T, class U> struct is_swappable_with; // C++17 + template <class T> struct is_swappable; // C++17 template <class T> struct is_destructible; template <class T, class... Args> struct is_trivially_constructible; @@ -123,6 +125,8 @@ namespace std template <class T, class U> struct is_nothrow_assignable; template <class T> struct is_nothrow_copy_assignable; template <class T> struct is_nothrow_move_assignable; + template <class T, class U> struct is_nothrow_swappable_with; // C++17 + template <class T> struct is_nothrow_swappable; // C++17 template <class T> struct is_nothrow_destructible; template <class T> struct has_virtual_destructor; @@ -300,6 +304,10 @@ namespace std = is_copy_assignable<T>::value; // C++17 template <class T> constexpr bool is_move_assignable_v = is_move_assignable<T>::value; // C++17 + template <class T, class U> constexpr bool is_swappable_with_v + = is_swappable_with<T, U>::value; // C++17 + template <class T> constexpr bool is_swappable_v + = is_swappable<T>::value; // C++17 template <class T> constexpr bool is_destructible_v = is_destructible<T>::value; // C++17 template <class T, class... Args> constexpr bool is_trivially_constructible_v @@ -332,6 +340,10 @@ namespace std = is_nothrow_copy_assignable<T>::value; // C++17 template <class T> constexpr bool is_nothrow_move_assignable_v = is_nothrow_move_assignable<T>::value; // C++17 + template <class T, class U> constexpr bool is_nothrow_swappable_with_v + = is_nothrow_swappable_with<T, U>::value; // C++17 + template <class T> constexpr bool is_nothrow_swappable_v + = is_nothrow_swappable<T>::value; // C++17 template <class T> constexpr bool is_nothrow_destructible_v = is_nothrow_destructible<T>::value; // C++17 template <class T> constexpr bool has_virtual_destructor_v @@ -4421,6 +4433,9 @@ constexpr bool is_nothrow_callable_v = i #endif // !defined(_LIBCPP_CXX03_LANG) +template <class _Tp> struct __is_swappable; +template <class _Tp> struct __is_nothrow_swappable; + template <class _Tp> inline _LIBCPP_INLINE_VISIBILITY #ifndef _LIBCPP_HAS_NO_ADVANCED_SFINAE @@ -4440,6 +4455,13 @@ swap(_Tp& __x, _Tp& __y) _NOEXCEPT_(is_n __y = _VSTD::move(__t); } +template<class _Tp, size_t _Np> +inline _LIBCPP_INLINE_VISIBILITY +typename enable_if< + __is_swappable<_Tp>::value +>::type +swap(_Tp (&__a)[_Np], _Tp (&__b)[_Np]) _NOEXCEPT_(__is_nothrow_swappable<_Tp>::value); + template <class _ForwardIterator1, class _ForwardIterator2> inline _LIBCPP_INLINE_VISIBILITY void @@ -4455,55 +4477,103 @@ iter_swap(_ForwardIterator1 __a, _Forwar namespace __detail { - +// ALL generic swap overloads MUST already have a declaration available at this point. using _VSTD::swap; __nat swap(__any, __any); -template <class _Tp> -struct __swappable +template <class _Tp, class _Up = _Tp, + bool _NotVoid = !is_void<_Tp>::value && !is_void<_Up>::value> +struct __swappable_with { - typedef decltype(swap(_VSTD::declval<_Tp&>(), _VSTD::declval<_Tp&>())) type; - static const bool value = !is_same<type, __nat>::value; + typedef decltype(swap(_VSTD::declval<_Tp>(), _VSTD::declval<_Up>())) __swap1; + typedef decltype(swap(_VSTD::declval<_Up>(), _VSTD::declval<_Tp>())) __swap2; + + static const bool value = !is_same<__swap1, __nat>::value + && !is_same<__swap2, __nat>::value; }; +template <class _Tp, class _Up> +struct __swappable_with<_Tp, _Up, false> : false_type {}; + +template <class _Tp, class _Up = _Tp, bool _Swappable = __swappable_with<_Tp, _Up>::value> +struct __nothrow_swappable_with { + static const bool value = +#ifndef _LIBCPP_HAS_NO_NOEXCEPT + noexcept(swap(_VSTD::declval<_Tp>(), _VSTD::declval<_Up>())) + && noexcept(swap(_VSTD::declval<_Up>(), _VSTD::declval<_Tp>())); +#else + false; +#endif +}; + +template <class _Tp, class _Up> +struct __nothrow_swappable_with<_Tp, _Up, false> : false_type {}; + } // __detail template <class _Tp> struct __is_swappable - : public integral_constant<bool, __detail::__swappable<_Tp>::value> + : public integral_constant<bool, __detail::__swappable_with<_Tp&>::value> { }; -#if __has_feature(cxx_noexcept) || (_GNUC_VER >= 407 && __cplusplus >= 201103L) - -template <bool, class _Tp> -struct __is_nothrow_swappable_imp - : public integral_constant<bool, noexcept(swap(_VSTD::declval<_Tp&>(), - _VSTD::declval<_Tp&>()))> +template <class _Tp> +struct __is_nothrow_swappable + : public integral_constant<bool, __detail::__nothrow_swappable_with<_Tp&>::value> { }; -template <class _Tp> -struct __is_nothrow_swappable_imp<false, _Tp> - : public false_type +#if _LIBCPP_STD_VER > 14 + +template <class _Tp, class _Up> +struct _LIBCPP_TYPE_VIS_ONLY is_swappable_with + : public integral_constant<bool, __detail::__swappable_with<_Tp, _Up>::value> { }; template <class _Tp> -struct __is_nothrow_swappable - : public __is_nothrow_swappable_imp<__is_swappable<_Tp>::value, _Tp> +struct _LIBCPP_TYPE_VIS_ONLY is_swappable + : public conditional< + __is_referenceable<_Tp>::value, + is_swappable_with< + typename add_lvalue_reference<_Tp>::type, + typename add_lvalue_reference<_Tp>::type>, + false_type + >::type { }; -#else // __has_feature(cxx_noexcept) +template <class _Tp, class _Up> +struct _LIBCPP_TYPE_VIS_ONLY is_nothrow_swappable_with + : public integral_constant<bool, __detail::__nothrow_swappable_with<_Tp, _Up>::value> +{ +}; template <class _Tp> -struct __is_nothrow_swappable - : public false_type +struct _LIBCPP_TYPE_VIS_ONLY is_nothrow_swappable + : public conditional< + __is_referenceable<_Tp>::value, + is_nothrow_swappable_with< + typename add_lvalue_reference<_Tp>::type, + typename add_lvalue_reference<_Tp>::type>, + false_type + >::type { }; -#endif // __has_feature(cxx_noexcept) +template <class _Tp, class _Up> +constexpr bool is_swappable_with_v = is_swappable_with<_Tp, _Up>::value; + +template <class _Tp> +constexpr bool is_swappable_v = is_swappable<_Tp>::value; + +template <class _Tp, class _Up> +constexpr bool is_nothrow_swappable_with_v = is_nothrow_swappable_with<_Tp, _Up>::value; + +template <class _Tp> +constexpr bool is_nothrow_swappable_v = is_nothrow_swappable<_Tp>::value; + +#endif // _LIBCPP_STD_VER > 14 #ifdef _LIBCPP_UNDERLYING_TYPE Modified: libcxx/trunk/include/utility URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?rev=267079&r1=267078&r2=267079&view=diff ============================================================================== --- libcxx/trunk/include/utility (original) +++ libcxx/trunk/include/utility Thu Apr 21 18:38:59 2016 @@ -82,8 +82,8 @@ struct pair is_nothrow_move_assignable<T2>::value); template <class U, class V> pair& operator=(pair<U, V>&& p); - void swap(pair& p) noexcept(noexcept(swap(first, p.first)) && - noexcept(swap(second, p.second))); + void swap(pair& p) noexcept(is_nothrow_swappable_v<T1> && + is_nothrow_swappable_v<T2>); }; template <class T1, class T2> bool operator==(const pair<T1,T2>&, const pair<T1,T2>&); // constexpr in C++14 @@ -225,10 +225,6 @@ operator>=(const _Tp& __x, const _Tp& __ // swap_ranges -// forward -template<class _Tp, size_t _Np> -inline _LIBCPP_INLINE_VISIBILITY -void swap(_Tp (&__a)[_Np], _Tp (&__b)[_Np]) _NOEXCEPT_(__is_nothrow_swappable<_Tp>::value); template <class _ForwardIterator1, class _ForwardIterator2> inline _LIBCPP_INLINE_VISIBILITY @@ -240,9 +236,12 @@ swap_ranges(_ForwardIterator1 __first1, return __first2; } +// forward declared in <type_traits> template<class _Tp, size_t _Np> inline _LIBCPP_INLINE_VISIBILITY -void +typename enable_if< + __is_swappable<_Tp>::value +>::type swap(_Tp (&__a)[_Np], _Tp (&__b)[_Np]) _NOEXCEPT_(__is_nothrow_swappable<_Tp>::value) { _VSTD::swap_ranges(__a, __a + _Np, __b); Modified: libcxx/trunk/test/std/containers/sequences/array/array.special/swap.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/containers/sequences/array/array.special/swap.pass.cpp?rev=267079&r1=267078&r2=267079&view=diff ============================================================================== --- libcxx/trunk/test/std/containers/sequences/array/array.special/swap.pass.cpp (original) +++ libcxx/trunk/test/std/containers/sequences/array/array.special/swap.pass.cpp Thu Apr 21 18:38:59 2016 @@ -14,10 +14,28 @@ #include <array> #include <cassert> +#include "test_macros.h" // std::array is explicitly allowed to be initialized with A a = { init-list };. // Disable the missing braces warning for this reason. #include "disable_missing_braces_warning.h" +struct NonSwappable { + NonSwappable() {} +private: + NonSwappable(NonSwappable const&); + NonSwappable& operator=(NonSwappable const&); +}; + +template <class Tp> +decltype(swap(std::declval<Tp>(), std::declval<Tp>())) +can_swap_imp(int); + +template <class Tp> +std::false_type can_swap_imp(...); + +template <class Tp> +struct can_swap : std::is_same<decltype(can_swap_imp<Tp>(0)), void> {}; + int main() { { @@ -44,4 +62,17 @@ int main() assert(c1.size() == 0); assert(c2.size() == 0); } + { + typedef NonSwappable T; + typedef std::array<T, 42> C1; + typedef std::array<T, 0> C0; + static_assert(!can_swap<C1&>::value, ""); + static_assert(can_swap<C0&>::value, ""); + C0 l = {}; + C0 r = {}; + swap(l, r); +#if TEST_STD_VER >= 11 + static_assert(noexcept(swap(l, r)), ""); +#endif + } } Modified: libcxx/trunk/test/std/containers/sequences/array/array.swap/swap.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/containers/sequences/array/array.swap/swap.pass.cpp?rev=267079&r1=267078&r2=267079&view=diff ============================================================================== --- libcxx/trunk/test/std/containers/sequences/array/array.swap/swap.pass.cpp (original) +++ libcxx/trunk/test/std/containers/sequences/array/array.swap/swap.pass.cpp Thu Apr 21 18:38:59 2016 @@ -15,10 +15,19 @@ #include <cassert> #include <array> +#include "test_macros.h" + // std::array is explicitly allowed to be initialized with A a = { init-list };. // Disable the missing braces warning for this reason. #include "disable_missing_braces_warning.h" +struct NonSwappable { + NonSwappable() {} +private: + NonSwappable(NonSwappable const&); + NonSwappable& operator=(NonSwappable const&); +}; + int main() { { @@ -70,5 +79,15 @@ int main() assert(c1.size() == 0); assert(c2.size() == 0); } + { + typedef NonSwappable T; + typedef std::array<T, 0> C0; + C0 l = {}; + C0 r = {}; + l.swap(r); +#if TEST_STD_VER >= 11 + static_assert(noexcept(l.swap(r)), ""); +#endif + } } Modified: libcxx/trunk/test/std/utilities/memory/unique.ptr/unique.ptr.special/swap.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/memory/unique.ptr/unique.ptr.special/swap.pass.cpp?rev=267079&r1=267078&r2=267079&view=diff ============================================================================== --- libcxx/trunk/test/std/utilities/memory/unique.ptr/unique.ptr.special/swap.pass.cpp (original) +++ libcxx/trunk/test/std/utilities/memory/unique.ptr/unique.ptr.special/swap.pass.cpp Thu Apr 21 18:38:59 2016 @@ -16,6 +16,7 @@ #include <memory> #include <cassert> +#include "test_macros.h" #include "../deleter.h" struct A @@ -34,6 +35,16 @@ struct A int A::count = 0; +template <class T> +struct NonSwappableDeleter { + explicit NonSwappableDeleter(int) {} + NonSwappableDeleter& operator=(NonSwappableDeleter const&) { return *this; } + void operator()(T*) const {} +private: + NonSwappableDeleter(NonSwappableDeleter const&); + +}; + int main() { { @@ -74,4 +85,18 @@ int main() assert(A::count == 6); } assert(A::count == 0); +#if TEST_STD_VER >= 11 + { + // test that unique_ptr's specialized swap is disabled when the deleter + // is non-swappable. Instead we should pick up the generic swap(T, T) + // and perform 3 move constructions. + typedef NonSwappableDeleter<int> D; + D d(42); + int x = 42; + int y = 43; + std::unique_ptr<int, D&> p(&x, d); + std::unique_ptr<int, D&> p2(&y, d); + std::swap(p, p2); + } +#endif } Added: libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_nothrow_swappable.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_nothrow_swappable.pass.cpp?rev=267079&view=auto ============================================================================== --- libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_nothrow_swappable.pass.cpp (added) +++ libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_nothrow_swappable.pass.cpp Thu Apr 21 18:38:59 2016 @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// type_traits + +// is_swappable + +#include <type_traits> +#include <vector> +#include "test_macros.h" + +namespace MyNS { + +// Make the test types non-copyable so that generic std::swap is not valid. +struct A { + A(A const&) = delete; + A& operator=(A const&) = delete; +}; + +struct B { + B(B const&) = delete; + B& operator=(B const&) = delete; +}; + +void swap(A&, A&) noexcept {} +void swap(B&, B&) {} + +struct M { + M(M const&) = delete; + M& operator=(M const&) = delete; +}; + +void swap(M&&, M&&) noexcept {} + +struct ThrowingMove { + ThrowingMove(ThrowingMove&&){} + ThrowingMove& operator=(ThrowingMove&&) {} +}; + +} // namespace MyNS + +int main() +{ + using namespace MyNS; + { + // Test that is_swappable applies an lvalue reference to the type. + static_assert(std::is_nothrow_swappable<int>::value, ""); + static_assert(std::is_nothrow_swappable<int&>::value, ""); + static_assert(!std::is_nothrow_swappable<M>::value, ""); + static_assert(!std::is_nothrow_swappable<M&&>::value, ""); + } + { + // Test that it correctly deduces the noexcept of swap. + static_assert(std::is_nothrow_swappable<A>::value, ""); + static_assert(!std::is_nothrow_swappable<B>::value + && std::is_swappable<B>::value, ""); + static_assert(!std::is_nothrow_swappable<ThrowingMove>::value + && std::is_swappable<ThrowingMove>::value); + } + { + // Test that it doesn't drop the qualifiers + static_assert(!std::is_nothrow_swappable<const A>::value, ""); + } + { + // test non-referenceable types + static_assert(!std::is_nothrow_swappable<void>::value, ""); + static_assert(!std::is_nothrow_swappable<int() const>::value, ""); + static_assert(!std::is_nothrow_swappable<int(int, ...) const &>::value, ""); + } + { + // test for presence of is_nothrow_swappable_v + static_assert(std::is_nothrow_swappable_v<int>); + static_assert(!std::is_nothrow_swappable_v<void>); + } +} Added: libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_nothrow_swappable_with.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_nothrow_swappable_with.pass.cpp?rev=267079&view=auto ============================================================================== --- libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_nothrow_swappable_with.pass.cpp (added) +++ libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_nothrow_swappable_with.pass.cpp Thu Apr 21 18:38:59 2016 @@ -0,0 +1,81 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// type_traits + +// is_nothrow_swappable_with + +#include <type_traits> +#include <vector> +#include "test_macros.h" + +namespace MyNS { + +struct A { + A(A const&) = delete; + A& operator=(A const&) = delete; +}; + +struct B { + B(B const&) = delete; + B& operator=(B const&) = delete; +}; + +struct C {}; +struct D {}; + +void swap(A&, A&) {} + +void swap(A&, B&) noexcept {} +void swap(B&, A&) noexcept {} + +void swap(A&, C&) noexcept {} +void swap(C&, A&) {} + +struct M {}; + +void swap(M&&, M&&) noexcept {} + +} // namespace MyNS + +int main() +{ + using namespace MyNS; + { + // Test that is_swappable_with doesn't apply an lvalue reference + // to the type. Instead it is up to the user. + static_assert(!std::is_nothrow_swappable_with<int, int>::value, ""); + static_assert(std::is_nothrow_swappable_with<int&, int&>::value, ""); + static_assert(std::is_nothrow_swappable_with<M, M>::value, ""); + static_assert(std::is_swappable_with<A&, A&>::value && + !std::is_nothrow_swappable_with<A&, A&>::value, ""); + } + { + // test that hetrogenius swap is allowed only if both 'swap(A, B)' and + // 'swap(B, A)' are valid. + static_assert(std::is_nothrow_swappable_with<A&, B&>::value, ""); + static_assert(!std::is_nothrow_swappable_with<A&, C&>::value && + std::is_swappable_with<A&, C&>::value, ""); + static_assert(!std::is_nothrow_swappable_with<D&, C&>::value, ""); + } + { + // test we guard against cv void inputs as required. + static_assert(!std::is_nothrow_swappable_with_v<void, int>); + static_assert(!std::is_nothrow_swappable_with_v<int, void>); + static_assert(!std::is_nothrow_swappable_with_v<const void, const volatile void>); + + } + { + // test for presense of is_nothrow_swappable_with_v + static_assert(std::is_nothrow_swappable_with_v<int&, int&>); + static_assert(!std::is_nothrow_swappable_with_v<int&&, int&&>); + } +} Added: libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_swappable.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_swappable.pass.cpp?rev=267079&view=auto ============================================================================== --- libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_swappable.pass.cpp (added) +++ libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_swappable.pass.cpp Thu Apr 21 18:38:59 2016 @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// type_traits + +// is_swappable + +#include <type_traits> +#include <utility> +#include <vector> +#include "test_macros.h" + +namespace MyNS { + +// Make the test types non-copyable so that generic std::swap is not valid. +struct A { + A(A const&) = delete; + A& operator=(A const&) = delete; +}; + +struct B { + B(B const&) = delete; + B& operator=(B const&) = delete; +}; + +struct C {}; +struct D {}; + +void swap(A&, A&) {} + +void swap(A&, B&) {} +void swap(B&, A&) {} + +void swap(A&, C&) {} // missing swap(C, A) +void swap(D&, C&) {} + +struct M { + M(M const&) = delete; + M& operator=(M const&) = delete; +}; + +void swap(M&&, M&&) {} + +} // namespace MyNS + +int main() +{ + using namespace MyNS; + { + // Test that is_swappable applies an lvalue reference to the type. + static_assert(std::is_swappable<A>::value, ""); + static_assert(std::is_swappable<A&>::value, ""); + static_assert(!std::is_swappable<M>::value, ""); + static_assert(!std::is_swappable<M&&>::value, ""); + } + static_assert(!std::is_swappable<B>::value, ""); + static_assert(std::is_swappable<C>::value, ""); + { + // test non-referencable types + static_assert(!std::is_swappable<void>::value, ""); + static_assert(!std::is_swappable<int() const>::value, ""); + static_assert(!std::is_swappable<int() &>::value, ""); + } + { + // test for presense of is_swappable_v + static_assert(std::is_swappable_v<int>); + static_assert(!std::is_swappable_v<M>); + } +} Added: libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_swappable_include_order.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_swappable_include_order.pass.cpp?rev=267079&view=auto ============================================================================== --- libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_swappable_include_order.pass.cpp (added) +++ libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_swappable_include_order.pass.cpp Thu Apr 21 18:38:59 2016 @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// type_traits + +// is_swappable + +// IMPORTANT: The include order is part of the test. We want to pick up +// the following definitions in this order: +// 1) is_swappable, is_nothrow_swappable +// 2) iter_swap, swap_ranges +// 3) swap(T (&)[N], T(&)[N] +// This test checks that (1) and (2) see forward declarations +// for (3). +#include <type_traits> +#include <algorithm> +#include <utility> + +#include "test_macros.h" + +int main() +{ + // Use a builtin type so we don't get ADL lookup. + typedef double T[42][50]; + { + static_assert(std::__is_swappable<T>::value, ""); +#if TEST_STD_VER > 14 + static_assert(std::is_swappable_v<T>); +#endif + } + { + T t1 = {}; + T t2 = {}; + std::iter_swap(t1, t2); + std::swap_ranges(t1, t1 + 42, t2); + } +} Added: libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_swappable_with.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_swappable_with.pass.cpp?rev=267079&view=auto ============================================================================== --- libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_swappable_with.pass.cpp (added) +++ libcxx/trunk/test/std/utilities/meta/meta.unary/meta.unary.prop/is_swappable_with.pass.cpp Thu Apr 21 18:38:59 2016 @@ -0,0 +1,78 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// type_traits + +// is_swappable_with + +#include <type_traits> +#include <vector> +#include "test_macros.h" + +namespace MyNS { + +struct A { + A(A const&) = delete; + A& operator=(A const&) = delete; +}; + +struct B { + B(B const&) = delete; + B& operator=(B const&) = delete; +}; + +struct C {}; +struct D {}; + +void swap(A&, A&) {} + +void swap(A&, B&) {} +void swap(B&, A&) {} + +void swap(A&, C&) {} // missing swap(C, A) +void swap(D&, C&) {} + +struct M {}; + +void swap(M&&, M&&) {} + +} // namespace MyNS + +int main() +{ + using namespace MyNS; + { + // Test that is_swappable_with doesn't apply an lvalue reference + // to the type. Instead it is up to the user. + static_assert(!std::is_swappable_with<int, int>::value, ""); + static_assert(std::is_swappable_with<int&, int&>::value, ""); + static_assert(std::is_swappable_with<M, M>::value, ""); + static_assert(std::is_swappable_with<A&, A&>::value, ""); + } + { + // test that heterogeneous swap is allowed only if both 'swap(A, B)' and + // 'swap(B, A)' are valid. + static_assert(std::is_swappable_with<A&, B&>::value, ""); + static_assert(!std::is_swappable_with<A&, C&>::value, ""); + static_assert(!std::is_swappable_with<D&, C&>::value, ""); + } + { + // test that cv void is guarded against as required. + static_assert(!std::is_swappable_with_v<void, int>); + static_assert(!std::is_swappable_with_v<int, void>); + static_assert(!std::is_swappable_with_v<const void, const volatile void>); + } + { + // test for presence of is_swappable_with_v + static_assert(std::is_swappable_with_v<int&, int&>); + static_assert(!std::is_swappable_with_v<D&, C&>); + } +} Modified: libcxx/trunk/test/std/utilities/utility/utility.swap/swap.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/utility/utility.swap/swap.pass.cpp?rev=267079&r1=267078&r2=267079&view=diff ============================================================================== --- libcxx/trunk/test/std/utilities/utility/utility.swap/swap.pass.cpp (original) +++ libcxx/trunk/test/std/utilities/utility/utility.swap/swap.pass.cpp Thu Apr 21 18:38:59 2016 @@ -16,38 +16,88 @@ #include <utility> #include <cassert> -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES #include <memory> -#endif - -void -test() -{ - int i = 1; - int j = 2; - std::swap(i, j); - assert(i == 2); - assert(j == 1); -} -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES +#include "test_macros.h" -void -test1() -{ - std::unique_ptr<int> i(new int(1)); - std::unique_ptr<int> j(new int(2)); - std::swap(i, j); - assert(*i == 2); - assert(*j == 1); +#if TEST_STD_VER >= 11 +struct CopyOnly { + CopyOnly() {} + CopyOnly(CopyOnly const&) noexcept {} + CopyOnly& operator=(CopyOnly const&) { return *this; } +}; + +struct MoveOnly { + MoveOnly() {} + MoveOnly(MoveOnly&&) {} + MoveOnly& operator=(MoveOnly&&) noexcept { return *this; } +}; + +struct NoexceptMoveOnly { + NoexceptMoveOnly() {} + NoexceptMoveOnly(NoexceptMoveOnly&&) noexcept {} + NoexceptMoveOnly& operator=(NoexceptMoveOnly&&) noexcept { return *this; } +}; + +struct NotMoveConstructible { + NotMoveConstructible& operator=(NotMoveConstructible&&) { return *this; } +private: + NotMoveConstructible(NotMoveConstructible&&); +}; + +struct NotMoveAssignable { + NotMoveAssignable(NotMoveAssignable&&); +private: + NotMoveAssignable& operator=(NotMoveAssignable&&); +}; + +template <class Tp> +auto can_swap_test(int) -> decltype(std::swap(std::declval<Tp>(), std::declval<Tp>())); + +template <class Tp> +auto can_swap_test(...) -> std::false_type; + +template <class Tp> +constexpr bool can_swap() { + return std::is_same<decltype(can_swap_test<Tp>(0)), void>::value; } - -#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES +#endif int main() { - test(); -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES - test1(); + + { + int i = 1; + int j = 2; + std::swap(i, j); + assert(i == 2); + assert(j == 1); + } +#if TEST_STD_VER >= 11 + { + + std::unique_ptr<int> i(new int(1)); + std::unique_ptr<int> j(new int(2)); + std::swap(i, j); + assert(*i == 2); + assert(*j == 1); + + } + { + // test that the swap + static_assert(can_swap<CopyOnly&>(), ""); + static_assert(can_swap<MoveOnly&>(), ""); + static_assert(can_swap<NoexceptMoveOnly&>(), ""); + + static_assert(!can_swap<NotMoveConstructible&>(), ""); + static_assert(!can_swap<NotMoveAssignable&>(), ""); + + CopyOnly c; + MoveOnly m; + NoexceptMoveOnly nm; + static_assert(!noexcept(std::swap(c, c)), ""); + static_assert(!noexcept(std::swap(m, m)), ""); + static_assert(noexcept(std::swap(nm, nm)), ""); + } #endif } Modified: libcxx/trunk/test/std/utilities/utility/utility.swap/swap_array.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/utility/utility.swap/swap_array.pass.cpp?rev=267079&r1=267078&r2=267079&view=diff ============================================================================== --- libcxx/trunk/test/std/utilities/utility/utility.swap/swap_array.pass.cpp (original) +++ libcxx/trunk/test/std/utilities/utility/utility.swap/swap_array.pass.cpp Thu Apr 21 18:38:59 2016 @@ -16,50 +16,86 @@ #include <utility> #include <cassert> -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES #include <memory> -#endif -void -test() -{ - int i[3] = {1, 2, 3}; - int j[3] = {4, 5, 6}; - std::swap(i, j); - assert(i[0] == 4); - assert(i[1] == 5); - assert(i[2] == 6); - assert(j[0] == 1); - assert(j[1] == 2); - assert(j[2] == 3); -} +#include "test_macros.h" -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES -void -test1() -{ - std::unique_ptr<int> i[3]; - for (int k = 0; k < 3; ++k) - i[k].reset(new int(k+1)); - std::unique_ptr<int> j[3]; - for (int k = 0; k < 3; ++k) - j[k].reset(new int(k+4)); - std::swap(i, j); - assert(*i[0] == 4); - assert(*i[1] == 5); - assert(*i[2] == 6); - assert(*j[0] == 1); - assert(*j[1] == 2); - assert(*j[2] == 3); +#if TEST_STD_VER >= 11 +struct CopyOnly { + CopyOnly() {} + CopyOnly(CopyOnly const&) noexcept {} + CopyOnly& operator=(CopyOnly const&) { return *this; } +}; + + +struct NoexceptMoveOnly { + NoexceptMoveOnly() {} + NoexceptMoveOnly(NoexceptMoveOnly&&) noexcept {} + NoexceptMoveOnly& operator=(NoexceptMoveOnly&&) noexcept { return *this; } +}; + +struct NotMoveConstructible { + NotMoveConstructible() {} + NotMoveConstructible& operator=(NotMoveConstructible&&) { return *this; } +private: + NotMoveConstructible(NotMoveConstructible&&); +}; + +template <class Tp> +auto can_swap_test(int) -> decltype(std::swap(std::declval<Tp>(), std::declval<Tp>())); + +template <class Tp> +auto can_swap_test(...) -> std::false_type; + +template <class Tp> +constexpr bool can_swap() { + return std::is_same<decltype(can_swap_test<Tp>(0)), void>::value; } +#endif -#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES int main() { - test(); -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES - test1(); + { + int i[3] = {1, 2, 3}; + int j[3] = {4, 5, 6}; + std::swap(i, j); + assert(i[0] == 4); + assert(i[1] == 5); + assert(i[2] == 6); + assert(j[0] == 1); + assert(j[1] == 2); + assert(j[2] == 3); + } +#if TEST_STD_VER >= 11 + { + std::unique_ptr<int> i[3]; + for (int k = 0; k < 3; ++k) + i[k].reset(new int(k+1)); + std::unique_ptr<int> j[3]; + for (int k = 0; k < 3; ++k) + j[k].reset(new int(k+4)); + std::swap(i, j); + assert(*i[0] == 4); + assert(*i[1] == 5); + assert(*i[2] == 6); + assert(*j[0] == 1); + assert(*j[1] == 2); + assert(*j[2] == 3); + } + { + using CA = CopyOnly[42]; + using MA = NoexceptMoveOnly[42]; + using NA = NotMoveConstructible[42]; + static_assert(can_swap<CA&>(), ""); + static_assert(can_swap<MA&>(), ""); + static_assert(!can_swap<NA&>(), ""); + + CA ca; + MA ma; + static_assert(!noexcept(std::swap(ca, ca)), ""); + static_assert(noexcept(std::swap(ma, ma)), ""); + } #endif } Modified: libcxx/trunk/www/cxx1z_status.html URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/www/cxx1z_status.html?rev=267079&r1=267078&r2=267079&view=diff ============================================================================== --- libcxx/trunk/www/cxx1z_status.html (original) +++ libcxx/trunk/www/cxx1z_status.html Thu Apr 21 18:38:59 2016 @@ -85,7 +85,7 @@ <tr><td><a href="http://wg21.link/P0033R1">P0033R1</a></td><td>LWG</td><td>Re-enabling shared_from_this</td><td>Jacksonville</td><td></td><td></td></tr> <tr><td><a href="http://wg21.link/P0005R4">P0005R4</a></td><td>LWG</td><td>Adopt not_fn from Library Fundamentals 2 for C++17</td><td>Jacksonville</td><td></td><td></td></tr> <tr><td><a href="http://wg21.link/P0152R1">P0152R1</a></td><td>LWG</td><td>constexpr atomic::is_always_lock_free</td><td>Jacksonville</td><td>Complete</td><td>3.9</td></tr> - <tr><td><a href="http://wg21.link/P0185R1">P0185R1</a></td><td>LWG</td><td>Adding [nothrow-]swappable traits</td><td>Jacksonville</td><td></td><td></td></tr> + <tr><td><a href="http://wg21.link/P0185R1">P0185R1</a></td><td>LWG</td><td>Adding [nothrow-]swappable traits</td><td>Jacksonville</td><td>Complete</td><td>3.9</td></tr> <tr><td><a href="http://wg21.link/P0253R1">P0253R1</a></td><td>LWG</td><td>Fixing a design mistake in the searchers interface</td><td>Jacksonville</td><td>Complete</td><td>3.9</td></tr> <tr><td><a href="http://wg21.link/P0025R0">P0025R0</a></td><td>LWG</td><td>An algorithm to "clamp" a value between a pair of boundary values</td><td>Jacksonville</td><td>Complete</td><td>3.9</td></tr> <tr><td><a href="http://wg21.link/P0154R1">P0154R1</a></td><td>LWG</td><td>constexpr std::hardware_{constructive,destructive}_interference_size</td><td>Jacksonville</td><td></td><td></td></tr> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits