From 7d914d1bfffac32da13a44871fc17b8ba3ade57a Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Mon, 13 Jul 2015 20:04:56 +0000 Subject: [PATCH] Implement the first part of N4258: 'Cleaning up noexcept in the Library'. This patch deals with swapping containers, and implements a more strict noexcept specification (a conforming extension) than the standard mandates. git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@242056 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/__hash_table | 64 +++------ include/__split_buffer | 21 +-- include/__tree | 41 ++---- include/deque | 79 +++++------ include/forward_list | 46 +++--- include/list | 43 +++--- include/map | 36 +++-- include/memory | 32 +++++ include/string | 40 ++---- include/unordered_map | 44 ++++++ include/unordered_set | 16 +-- include/vector | 86 +++++------ .../map/map.special/swap_noexcept.pass.cpp | 88 ++++++++++++ .../multimap.special/swap_noexcept.pass.cpp | 88 ++++++++++++ .../multiset.special/swap_noexcept.pass.cpp | 88 ++++++++++++ .../set/set.special/swap_noexcept.pass.cpp | 88 ++++++++++++ .../deque.special/swap_noexcept.pass.cpp | 30 ++++ .../forwardlist.spec/swap_noexcept.pass.cpp | 30 ++++ .../list/list.special/swap_noexcept.pass.cpp | 30 ++++ .../vector.bool/swap_noexcept.pass.cpp | 31 ++++ .../vector.special/swap_noexcept.pass.cpp | 31 ++++ .../unord.map.swap/swap_noexcept.pass.cpp | 134 +++++++++++++++++- .../swap_noexcept.pass.cpp | 133 ++++++++++++++++- .../swap_noexcept.pass.cpp | 129 ++++++++++++++++- .../unord.set.swap/swap_noexcept.pass.cpp | 129 ++++++++++++++++- .../string.special/swap_noexcept.pass.cpp | 31 ++++ 26 files changed, 1311 insertions(+), 297 deletions(-) diff --git a/include/__hash_table b/include/__hash_table index d089bcefc..f3a20309d 100644 --- a/include/__hash_table +++ b/include/__hash_table @@ -985,12 +985,14 @@ public: void swap(__hash_table& __u) _NOEXCEPT_( - (!allocator_traits<__pointer_allocator>::propagate_on_container_swap::value || - __is_nothrow_swappable<__pointer_allocator>::value) && - (!__node_traits::propagate_on_container_swap::value || - __is_nothrow_swappable<__node_allocator>::value) && - __is_nothrow_swappable::value && - __is_nothrow_swappable::value); + __is_nothrow_swappable::value && __is_nothrow_swappable::value +#if _LIBCPP_STD_VER <= 11 + && (!allocator_traits<__pointer_allocator>::propagate_on_container_swap::value + || __is_nothrow_swappable<__pointer_allocator>::value) + && (!__node_traits::propagate_on_container_swap::value + || __is_nothrow_swappable<__node_allocator>::value) +#endif + ); _LIBCPP_INLINE_VISIBILITY size_type max_bucket_count() const _NOEXCEPT @@ -1118,38 +1120,6 @@ private: _LIBCPP_INLINE_VISIBILITY void __move_assign_alloc(__hash_table&, false_type) _NOEXCEPT {} - template - _LIBCPP_INLINE_VISIBILITY - static - void - __swap_alloc(_Ap& __x, _Ap& __y) - _NOEXCEPT_( - !allocator_traits<_Ap>::propagate_on_container_swap::value || - __is_nothrow_swappable<_Ap>::value) - { - __swap_alloc(__x, __y, - integral_constant::propagate_on_container_swap::value - >()); - } - - template - _LIBCPP_INLINE_VISIBILITY - static - void - __swap_alloc(_Ap& __x, _Ap& __y, true_type) - _NOEXCEPT_(__is_nothrow_swappable<_Ap>::value) - { - using _VSTD::swap; - swap(__x, __y); - } - - template - _LIBCPP_INLINE_VISIBILITY - static - void - __swap_alloc(_Ap&, _Ap&, false_type) _NOEXCEPT {} - void __deallocate(__node_pointer __np) _NOEXCEPT; __node_pointer __detach() _NOEXCEPT; @@ -2382,12 +2352,14 @@ template void __hash_table<_Tp, _Hash, _Equal, _Alloc>::swap(__hash_table& __u) _NOEXCEPT_( - (!allocator_traits<__pointer_allocator>::propagate_on_container_swap::value || - __is_nothrow_swappable<__pointer_allocator>::value) && - (!__node_traits::propagate_on_container_swap::value || - __is_nothrow_swappable<__node_allocator>::value) && - __is_nothrow_swappable::value && - __is_nothrow_swappable::value) + __is_nothrow_swappable::value && __is_nothrow_swappable::value +#if _LIBCPP_STD_VER <= 11 + && (!allocator_traits<__pointer_allocator>::propagate_on_container_swap::value + || __is_nothrow_swappable<__pointer_allocator>::value) + && (!__node_traits::propagate_on_container_swap::value + || __is_nothrow_swappable<__node_allocator>::value) +#endif + ) { { __node_pointer_pointer __npp = __bucket_list_.release(); @@ -2395,9 +2367,9 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::swap(__hash_table& __u) __u.__bucket_list_.reset(__npp); } _VSTD::swap(__bucket_list_.get_deleter().size(), __u.__bucket_list_.get_deleter().size()); - __swap_alloc(__bucket_list_.get_deleter().__alloc(), + __swap_allocator(__bucket_list_.get_deleter().__alloc(), __u.__bucket_list_.get_deleter().__alloc()); - __swap_alloc(__node_alloc(), __u.__node_alloc()); + __swap_allocator(__node_alloc(), __u.__node_alloc()); _VSTD::swap(__p1_.first().__next_, __u.__p1_.first().__next_); __p2_.swap(__u.__p2_); __p3_.swap(__u.__p3_); diff --git a/include/__split_buffer b/include/__split_buffer index 1d529cbe2..727b1b6b5 100644 --- a/include/__split_buffer +++ b/include/__split_buffer @@ -156,25 +156,6 @@ private: _LIBCPP_INLINE_VISIBILITY void __move_assign_alloc(__split_buffer&, false_type) _NOEXCEPT {} - - _LIBCPP_INLINE_VISIBILITY - static void __swap_alloc(__alloc_rr& __x, __alloc_rr& __y) - _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value|| - __is_nothrow_swappable<__alloc_rr>::value) - {__swap_alloc(__x, __y, integral_constant());} - - _LIBCPP_INLINE_VISIBILITY - static void __swap_alloc(__alloc_rr& __x, __alloc_rr& __y, true_type) - _NOEXCEPT_(__is_nothrow_swappable<__alloc_rr>::value) - { - using _VSTD::swap; - swap(__x, __y); - } - - _LIBCPP_INLINE_VISIBILITY - static void __swap_alloc(__alloc_rr&, __alloc_rr&, false_type) _NOEXCEPT - {} }; template @@ -431,7 +412,7 @@ __split_buffer<_Tp, _Allocator>::swap(__split_buffer& __x) _VSTD::swap(__begin_, __x.__begin_); _VSTD::swap(__end_, __x.__end_); _VSTD::swap(__end_cap(), __x.__end_cap()); - __swap_alloc(__alloc(), __x.__alloc()); + __swap_allocator(__alloc(), __x.__alloc()); } template diff --git a/include/__tree b/include/__tree index 588f43807..574e74baf 100644 --- a/include/__tree +++ b/include/__tree @@ -926,9 +926,12 @@ public: void swap(__tree& __t) _NOEXCEPT_( - __is_nothrow_swappable::value && - (!__node_traits::propagate_on_container_swap::value || - __is_nothrow_swappable<__node_allocator>::value)); + __is_nothrow_swappable::value +#if _LIBCPP_STD_VER <= 11 + && (!__node_traits::propagate_on_container_swap::value || + __is_nothrow_swappable<__node_allocator>::value) +#endif + ); #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES #ifndef _LIBCPP_HAS_NO_VARIADICS @@ -1096,25 +1099,6 @@ private: _LIBCPP_INLINE_VISIBILITY void __move_assign_alloc(__tree& __t, false_type) _NOEXCEPT {} - _LIBCPP_INLINE_VISIBILITY - static void __swap_alloc(__node_allocator& __x, __node_allocator& __y) - _NOEXCEPT_( - !__node_traits::propagate_on_container_swap::value || - __is_nothrow_swappable<__node_allocator>::value) - {__swap_alloc(__x, __y, integral_constant());} - _LIBCPP_INLINE_VISIBILITY - static void __swap_alloc(__node_allocator& __x, __node_allocator& __y, true_type) - _NOEXCEPT_(__is_nothrow_swappable<__node_allocator>::value) - { - using _VSTD::swap; - swap(__x, __y); - } - _LIBCPP_INLINE_VISIBILITY - static void __swap_alloc(__node_allocator& __x, __node_allocator& __y, false_type) - _NOEXCEPT - {} - __node_pointer __detach(); static __node_pointer __detach(__node_pointer); @@ -1452,15 +1436,18 @@ __tree<_Tp, _Compare, _Allocator>::destroy(__node_pointer __nd) _NOEXCEPT template void __tree<_Tp, _Compare, _Allocator>::swap(__tree& __t) - _NOEXCEPT_( - __is_nothrow_swappable::value && - (!__node_traits::propagate_on_container_swap::value || - __is_nothrow_swappable<__node_allocator>::value)) + _NOEXCEPT_( + __is_nothrow_swappable::value +#if _LIBCPP_STD_VER <= 11 + && (!__node_traits::propagate_on_container_swap::value || + __is_nothrow_swappable<__node_allocator>::value) +#endif + ) { using _VSTD::swap; swap(__begin_node_, __t.__begin_node_); swap(__pair1_.first(), __t.__pair1_.first()); - __swap_alloc(__node_alloc(), __t.__node_alloc()); + __swap_allocator(__node_alloc(), __t.__node_alloc()); __pair3_.swap(__t.__pair3_); if (size() == 0) __begin_node() = __end_node(); diff --git a/include/deque b/include/deque index a372560f6..5e152e425 100644 --- a/include/deque +++ b/include/deque @@ -124,8 +124,7 @@ public: iterator erase(const_iterator p); iterator erase(const_iterator f, const_iterator l); void swap(deque& c) - noexcept(!allocator_type::propagate_on_container_swap::value || - __is_nothrow_swappable::value); + noexcept(allocator_traits::is_always_equal::value); // C++17 void clear() noexcept; }; @@ -954,8 +953,12 @@ public: #endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES void swap(__deque_base& __c) - _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || - __is_nothrow_swappable::value); +#if _LIBCPP_STD_VER >= 14 + _NOEXCEPT; +#else + _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || + __is_nothrow_swappable::value); +#endif protected: void clear() _NOEXCEPT; @@ -991,26 +994,6 @@ private: _LIBCPP_INLINE_VISIBILITY void __move_assign_alloc(__deque_base&, false_type) _NOEXCEPT {} - - _LIBCPP_INLINE_VISIBILITY - static void __swap_alloc(allocator_type& __x, allocator_type& __y) - _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || - __is_nothrow_swappable::value) - {__swap_alloc(__x, __y, integral_constant());} - - _LIBCPP_INLINE_VISIBILITY - static void __swap_alloc(allocator_type& __x, allocator_type& __y, true_type) - _NOEXCEPT_(__is_nothrow_swappable::value) - { - using _VSTD::swap; - swap(__x, __y); - } - - _LIBCPP_INLINE_VISIBILITY - static void __swap_alloc(allocator_type&, allocator_type&, false_type) - _NOEXCEPT - {} }; template @@ -1134,13 +1117,17 @@ __deque_base<_Tp, _Allocator>::__deque_base(__deque_base&& __c, const allocator_ template void __deque_base<_Tp, _Allocator>::swap(__deque_base& __c) - _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value|| - __is_nothrow_swappable::value) +#if _LIBCPP_STD_VER >= 14 + _NOEXCEPT +#else + _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || + __is_nothrow_swappable::value) +#endif { __map_.swap(__c.__map_); _VSTD::swap(__start_, __c.__start_); _VSTD::swap(size(), __c.size()); - __swap_alloc(__alloc(), __c.__alloc()); + __swap_allocator(__alloc(), __c.__alloc()); } template @@ -1342,8 +1329,12 @@ public: iterator erase(const_iterator __f, const_iterator __l); void swap(deque& __c) +#if _LIBCPP_STD_VER >= 14 + _NOEXCEPT; +#else _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable::value); +#endif void clear() _NOEXCEPT; _LIBCPP_INLINE_VISIBILITY @@ -2277,13 +2268,13 @@ deque<_Tp, _Allocator>::__add_front_capacity() __buf(max(2 * __base::__map_.capacity(), 1), 0, __base::__map_.__alloc()); - typedef __allocator_destructor<_Allocator> _Dp; - unique_ptr __hold( - __alloc_traits::allocate(__a, __base::__block_size), - _Dp(__a, __base::__block_size)); - __buf.push_back(__hold.get()); - __hold.release(); - + typedef __allocator_destructor<_Allocator> _Dp; + unique_ptr __hold( + __alloc_traits::allocate(__a, __base::__block_size), + _Dp(__a, __base::__block_size)); + __buf.push_back(__hold.get()); + __hold.release(); + for (typename __base::__map_pointer __i = __base::__map_.begin(); __i != __base::__map_.end(); ++__i) __buf.push_back(*__i); @@ -2420,12 +2411,12 @@ deque<_Tp, _Allocator>::__add_back_capacity() __base::__map_.size(), __base::__map_.__alloc()); - typedef __allocator_destructor<_Allocator> _Dp; - unique_ptr __hold( - __alloc_traits::allocate(__a, __base::__block_size), - _Dp(__a, __base::__block_size)); - __buf.push_back(__hold.get()); - __hold.release(); + typedef __allocator_destructor<_Allocator> _Dp; + unique_ptr __hold( + __alloc_traits::allocate(__a, __base::__block_size), + _Dp(__a, __base::__block_size)); + __buf.push_back(__hold.get()); + __hold.release(); for (typename __base::__map_pointer __i = __base::__map_.end(); __i != __base::__map_.begin();) @@ -2793,8 +2784,12 @@ template inline _LIBCPP_INLINE_VISIBILITY void deque<_Tp, _Allocator>::swap(deque& __c) - _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || - __is_nothrow_swappable::value) +#if _LIBCPP_STD_VER >= 14 + _NOEXCEPT +#else + _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || + __is_nothrow_swappable::value) +#endif { __base::swap(__c); } diff --git a/include/forward_list b/include/forward_list index fbb850c3b..8a87fc5e1 100644 --- a/include/forward_list +++ b/include/forward_list @@ -107,8 +107,7 @@ public: iterator erase_after(const_iterator first, const_iterator last); void swap(forward_list& x) - noexcept(!allocator_type::propagate_on_container_swap::value || - __is_nothrow_swappable::value); + noexcept(allocator_traits::is_always_equal::value); // C++17 void resize(size_type n); void resize(size_type n, const value_type& v); @@ -431,8 +430,12 @@ protected: public: void swap(__forward_list_base& __x) - _NOEXCEPT_(!__node_traits::propagate_on_container_swap::value || - __is_nothrow_swappable<__node_allocator>::value); +#if _LIBCPP_STD_VER >= 14 + _NOEXCEPT; +#else + _NOEXCEPT_(!__node_traits::propagate_on_container_move_assignment::value || + __is_nothrow_swappable<__node_allocator>::value); +#endif protected: void clear() _NOEXCEPT; @@ -454,26 +457,6 @@ private: void __move_assign_alloc(__forward_list_base& __x, true_type) _NOEXCEPT_(is_nothrow_move_assignable<__node_allocator>::value) {__alloc() = _VSTD::move(__x.__alloc());} - - _LIBCPP_INLINE_VISIBILITY - static void __swap_alloc(__node_allocator& __x, __node_allocator& __y) - _NOEXCEPT_(!__node_traits::propagate_on_container_swap::value || - __is_nothrow_swappable<__node_allocator>::value) - {__swap_alloc(__x, __y, integral_constant());} - _LIBCPP_INLINE_VISIBILITY - static void __swap_alloc(__node_allocator& __x, __node_allocator& __y, - false_type) - _NOEXCEPT - {} - _LIBCPP_INLINE_VISIBILITY - static void __swap_alloc(__node_allocator& __x, __node_allocator& __y, - true_type) - _NOEXCEPT_(__is_nothrow_swappable<__node_allocator>::value) - { - using _VSTD::swap; - swap(__x, __y); - } }; #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES @@ -512,10 +495,15 @@ template inline _LIBCPP_INLINE_VISIBILITY void __forward_list_base<_Tp, _Alloc>::swap(__forward_list_base& __x) - _NOEXCEPT_(!__node_traits::propagate_on_container_swap::value || - __is_nothrow_swappable<__node_allocator>::value) +#if _LIBCPP_STD_VER >= 14 + _NOEXCEPT +#else + _NOEXCEPT_(!__node_traits::propagate_on_container_move_assignment::value || + __is_nothrow_swappable<__node_allocator>::value) +#endif { - __swap_alloc(__alloc(), __x.__alloc()); + __swap_allocator(__alloc(), __x.__alloc(), + integral_constant()); using _VSTD::swap; swap(__before_begin()->__next_, __x.__before_begin()->__next_); } @@ -703,8 +691,12 @@ public: _LIBCPP_INLINE_VISIBILITY void swap(forward_list& __x) +#if _LIBCPP_STD_VER >= 14 + _NOEXCEPT +#else _NOEXCEPT_(!__node_traits::propagate_on_container_swap::value || __is_nothrow_swappable<__node_allocator>::value) +#endif {base::swap(__x);} void resize(size_type __n); diff --git a/include/list b/include/list index d39f07671..14201a80e 100644 --- a/include/list +++ b/include/list @@ -118,8 +118,7 @@ public: void resize(size_type sz, const value_type& c); void swap(list&) - noexcept(!allocator_type::propagate_on_container_swap::value || - __is_nothrow_swappable::value); + noexcept(allocator_traits::is_always_equal::value); // C++17 void clear() noexcept; void splice(const_iterator position, list& x); @@ -593,8 +592,12 @@ protected: } void swap(__list_imp& __c) - _NOEXCEPT_(!__node_alloc_traits::propagate_on_container_swap::value || - __is_nothrow_swappable<__node_allocator>::value); +#if _LIBCPP_STD_VER >= 14 + _NOEXCEPT; +#else + _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || + __is_nothrow_swappable::value); +#endif _LIBCPP_INLINE_VISIBILITY void __copy_assign_alloc(const __list_imp& __c) @@ -610,24 +613,6 @@ protected: __node_alloc_traits::propagate_on_container_move_assignment::value>());} private: - _LIBCPP_INLINE_VISIBILITY - static void __swap_alloc(__node_allocator& __x, __node_allocator& __y) - _NOEXCEPT_(!__node_alloc_traits::propagate_on_container_swap::value || - __is_nothrow_swappable<__node_allocator>::value) - {__swap_alloc(__x, __y, integral_constant());} - _LIBCPP_INLINE_VISIBILITY - static void __swap_alloc(__node_allocator& __x, __node_allocator& __y, true_type) - _NOEXCEPT_(__is_nothrow_swappable<__node_allocator>::value) - { - using _VSTD::swap; - swap(__x, __y); - } - _LIBCPP_INLINE_VISIBILITY - static void __swap_alloc(__node_allocator& __x, __node_allocator& __y, false_type) - _NOEXCEPT - {} - _LIBCPP_INLINE_VISIBILITY void __copy_assign_alloc(const __list_imp& __c, true_type) { @@ -728,15 +713,19 @@ __list_imp<_Tp, _Alloc>::clear() _NOEXCEPT template void __list_imp<_Tp, _Alloc>::swap(__list_imp& __c) - _NOEXCEPT_(!__node_alloc_traits::propagate_on_container_swap::value || - __is_nothrow_swappable<__node_allocator>::value) +#if _LIBCPP_STD_VER >= 14 + _NOEXCEPT +#else + _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || + __is_nothrow_swappable::value) +#endif { _LIBCPP_ASSERT(__alloc_traits::propagate_on_container_swap::value || this->__node_alloc() == __c.__node_alloc(), "list::swap: Either propagate_on_container_swap must be true" " or the allocators must compare equal"); using _VSTD::swap; - __swap_alloc(__node_alloc(), __c.__node_alloc()); + __swap_allocator(__node_alloc(), __c.__node_alloc()); swap(__sz(), __c.__sz()); swap(__end_, __c.__end_); if (__sz() == 0) @@ -972,8 +961,12 @@ public: _LIBCPP_INLINE_VISIBILITY void swap(list& __c) +#if _LIBCPP_STD_VER >= 14 + _NOEXCEPT +#else _NOEXCEPT_(!__node_alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable<__node_allocator>::value) +#endif {base::swap(__c);} _LIBCPP_INLINE_VISIBILITY void clear() _NOEXCEPT {base::clear();} diff --git a/include/map b/include/map index 0f689b7e4..eb6b8ed05 100644 --- a/include/map +++ b/include/map @@ -159,10 +159,8 @@ public: void clear() noexcept; void swap(map& m) - noexcept( - __is_nothrow_swappable::value && - (!allocator_type::propagate_on_container_swap::value || - __is_nothrow_swappable::value)); + noexcept(allocator_traits::is_always_equal::value && + __is_nothrow_swappable::value); // C++17 // observers: allocator_type get_allocator() const noexcept; @@ -354,10 +352,8 @@ public: void clear() noexcept; void swap(multimap& m) - noexcept( - __is_nothrow_swappable::value && - (!allocator_type::propagate_on_container_swap::value || - __is_nothrow_swappable::value)); + noexcept(allocator_traits::is_always_equal::value && + __is_nothrow_swappable::value); // C++17 // observers: allocator_type get_allocator() const noexcept; @@ -479,6 +475,12 @@ public: _LIBCPP_INLINE_VISIBILITY bool operator()(const _Key& __x, const _CP& __y) const {return static_cast(*this)(__x, __y.__cc.first);} + void swap(__map_value_compare&__y) + _NOEXCEPT_(__is_nothrow_swappable<_Compare>::value) + { + using _VSTD::swap; + swap(static_cast(*this), static_cast(__y)); + } #if _LIBCPP_STD_VER > 11 template @@ -521,7 +523,13 @@ public: _LIBCPP_INLINE_VISIBILITY bool operator()(const _Key& __x, const _CP& __y) const {return comp(__x, __y.__cc.first);} - + void swap(__map_value_compare&__y) + _NOEXCEPT_(__is_nothrow_swappable<_Compare>::value) + { + using _VSTD::swap; + swap(comp, __y.comp); + } + #if _LIBCPP_STD_VER > 11 template _LIBCPP_INLINE_VISIBILITY @@ -537,6 +545,16 @@ public: #endif }; +template +inline _LIBCPP_INLINE_VISIBILITY +void +swap(__map_value_compare<_Key, _CP, _Compare, __b>& __x, + __map_value_compare<_Key, _CP, _Compare, __b>& __y) + _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) +{ + __x.swap(__y); +} + template class __map_node_destructor { diff --git a/include/memory b/include/memory index 4f59d804a..9c1eef765 100644 --- a/include/memory +++ b/include/memory @@ -5543,6 +5543,38 @@ undeclare_reachable(_Tp* __p) _LIBCPP_FUNC_VIS void* align(size_t __align, size_t __sz, void*& __ptr, size_t& __space); +// --- Helper for container swap -- +template +_LIBCPP_INLINE_VISIBILITY +void __swap_allocator(_Alloc & __a1, _Alloc & __a2) +#if _LIBCPP_STD_VER >= 14 + _NOEXCEPT +#else + _NOEXCEPT_(__is_nothrow_swappable<_Alloc>::value) +#endif +{ + __swap_allocator(__a1, __a2, + integral_constant::propagate_on_container_swap::value>()); +} + +template +_LIBCPP_INLINE_VISIBILITY +void __swap_allocator(_Alloc & __a1, _Alloc & __a2, true_type) +#if _LIBCPP_STD_VER >= 14 + _NOEXCEPT +#else + _NOEXCEPT_(__is_nothrow_swappable<_Alloc>::value) +#endif +{ + using _VSTD::swap; + swap(__a1, __a2); +} + +template +_LIBCPP_INLINE_VISIBILITY +void __swap_allocator(_Alloc &, _Alloc &, false_type) _NOEXCEPT {} + + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP_MEMORY diff --git a/include/string b/include/string index ac7b30a61..6be21955b 100644 --- a/include/string +++ b/include/string @@ -220,8 +220,8 @@ public: basic_string substr(size_type pos = 0, size_type n = npos) const; void swap(basic_string& str) - noexcept(!allocator_type::propagate_on_container_swap::value || - __is_nothrow_swappable::value) + noexcept(allocator_traits::propagate_on_container_swap::value || + allocator_traits::is_always_equal::value); // C++17 const value_type* c_str() const noexcept; const value_type* data() const noexcept; @@ -1604,8 +1604,12 @@ public: _LIBCPP_INLINE_VISIBILITY void swap(basic_string& __str) - _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || - __is_nothrow_swappable::value); +#if _LIBCPP_STD_VER >= 14 + _NOEXCEPT; +#else + _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || + __is_nothrow_swappable::value); +#endif _LIBCPP_INLINE_VISIBILITY const value_type* c_str() const _NOEXCEPT {return data();} @@ -1868,24 +1872,6 @@ private: _NOEXCEPT {} - _LIBCPP_INLINE_VISIBILITY - static void __swap_alloc(allocator_type& __x, allocator_type& __y) - _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || - __is_nothrow_swappable::value) - {__swap_alloc(__x, __y, integral_constant());} - - _LIBCPP_INLINE_VISIBILITY - static void __swap_alloc(allocator_type& __x, allocator_type& __y, true_type) - _NOEXCEPT_(__is_nothrow_swappable::value) - { - using _VSTD::swap; - swap(__x, __y); - } - _LIBCPP_INLINE_VISIBILITY - static void __swap_alloc(allocator_type&, allocator_type&, false_type) _NOEXCEPT - {} - _LIBCPP_INLINE_VISIBILITY void __invalidate_all_iterators(); _LIBCPP_INLINE_VISIBILITY void __invalidate_iterators_past(size_type); @@ -3366,8 +3352,12 @@ template inline _LIBCPP_INLINE_VISIBILITY void basic_string<_CharT, _Traits, _Allocator>::swap(basic_string& __str) - _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || - __is_nothrow_swappable::value) +#if _LIBCPP_STD_VER >= 14 + _NOEXCEPT +#else + _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || + __is_nothrow_swappable::value) +#endif { #if _LIBCPP_DEBUG_LEVEL >= 2 if (!__is_long()) @@ -3377,7 +3367,7 @@ basic_string<_CharT, _Traits, _Allocator>::swap(basic_string& __str) __get_db()->swap(this, &__str); #endif _VSTD::swap(__r_.first(), __str.__r_.first()); - __swap_alloc(__alloc(), __str.__alloc()); + __swap_allocator(__alloc(), __str.__alloc()); } // find diff --git a/include/unordered_map b/include/unordered_map index fe20bdb64..cf70ab62f 100644 --- a/include/unordered_map +++ b/include/unordered_map @@ -401,6 +401,12 @@ public: _LIBCPP_INLINE_VISIBILITY size_t operator()(const _Key& __x) const {return static_cast(*this)(__x);} + void swap(__unordered_map_hasher&__y) + _NOEXCEPT_(__is_nothrow_swappable<_Hash>::value) + { + using _VSTD::swap; + swap(static_cast(*this), static_cast(__y)); + } }; template @@ -425,8 +431,24 @@ public: _LIBCPP_INLINE_VISIBILITY size_t operator()(const _Key& __x) const {return __hash_(__x);} + void swap(__unordered_map_hasher&__y) + _NOEXCEPT_(__is_nothrow_swappable<_Hash>::value) + { + using _VSTD::swap; + swap(__hash_, __y.__hash_); + } }; +template +inline _LIBCPP_INLINE_VISIBILITY +void +swap(__unordered_map_hasher<_Key, _Cp, _Hash, __b>& __x, + __unordered_map_hasher<_Key, _Cp, _Hash, __b>& __y) + _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) +{ + __x.swap(__y); +} + template ::value && !__libcpp_is_final<_Pred>::value > @@ -453,6 +475,12 @@ public: _LIBCPP_INLINE_VISIBILITY bool operator()(const _Key& __x, const _Cp& __y) const {return static_cast(*this)(__x, __y.__cc.first);} + void swap(__unordered_map_equal&__y) + _NOEXCEPT_(__is_nothrow_swappable<_Pred>::value) + { + using _VSTD::swap; + swap(static_cast(*this), static_cast(__y)); + } }; template @@ -480,8 +508,24 @@ public: _LIBCPP_INLINE_VISIBILITY bool operator()(const _Key& __x, const _Cp& __y) const {return __pred_(__x, __y.__cc.first);} + void swap(__unordered_map_equal&__y) + _NOEXCEPT_(__is_nothrow_swappable<_Pred>::value) + { + using _VSTD::swap; + swap(__pred_, __y.__pred_); + } }; +template +inline _LIBCPP_INLINE_VISIBILITY +void +swap(__unordered_map_equal<_Key, _Cp, _Pred, __b>& __x, + __unordered_map_equal<_Key, _Cp, _Pred, __b>& __y) + _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) +{ + __x.swap(__y); +} + template class __hash_map_node_destructor { diff --git a/include/unordered_set b/include/unordered_set index 26ef6fd6a..f6ccdc373 100644 --- a/include/unordered_set +++ b/include/unordered_set @@ -120,11 +120,9 @@ public: void clear() noexcept; void swap(unordered_set&) - noexcept( - (!allocator_type::propagate_on_container_swap::value || - __is_nothrow_swappable::value) && - __is_nothrow_swappable::value && - __is_nothrow_swappable::value); + noexcept(allocator_traits::is_always_equal::value && + noexcept(swap(declval(), declval())) && + noexcept(swap(declval(), declval()))); // C++17 hasher hash_function() const; key_equal key_eq() const; @@ -270,11 +268,9 @@ public: void clear() noexcept; void swap(unordered_multiset&) - noexcept( - (!allocator_type::propagate_on_container_swap::value || - __is_nothrow_swappable::value) && - __is_nothrow_swappable::value && - __is_nothrow_swappable::value); + noexcept(allocator_traits::is_always_equal::value && + noexcept(swap(declval(), declval())) && + noexcept(swap(declval(), declval()))); // C++17 hasher hash_function() const; key_equal key_eq() const; diff --git a/include/vector b/include/vector index 36001479d..65a087cf8 100644 --- a/include/vector +++ b/include/vector @@ -119,8 +119,8 @@ public: void resize(size_type sz, const value_type& c); void swap(vector&) - noexcept(!allocator_type::propagate_on_container_swap::value || - __is_nothrow_swappable::value); + noexcept(allocator_traits::propagate_on_container_swap::value || + allocator_traits::is_always_equal::value); // C++17 bool __invariants() const; }; @@ -237,8 +237,8 @@ public: void resize(size_type sz, value_type x); void swap(vector&) - noexcept(!allocator_type::propagate_on_container_swap::value || - __is_nothrow_swappable::value); + noexcept(allocator_traits::propagate_on_container_swap::value || + allocator_traits::is_always_equal::value); // C++17 void flip() noexcept; bool __invariants() const; @@ -385,14 +385,6 @@ protected: is_nothrow_move_assignable::value) {__move_assign_alloc(__c, integral_constant());} - - _LIBCPP_INLINE_VISIBILITY - static void __swap_alloc(allocator_type& __x, allocator_type& __y) - _NOEXCEPT_( - !__alloc_traits::propagate_on_container_swap::value || - __is_nothrow_swappable::value) - {__swap_alloc(__x, __y, integral_constant());} private: _LIBCPP_INLINE_VISIBILITY void __copy_assign_alloc(const __vector_base& __c, true_type) @@ -421,18 +413,6 @@ private: void __move_assign_alloc(__vector_base&, false_type) _NOEXCEPT {} - - _LIBCPP_INLINE_VISIBILITY - static void __swap_alloc(allocator_type& __x, allocator_type& __y, true_type) - _NOEXCEPT_(is_nothrow_move_assignable::value) - { - using _VSTD::swap; - swap(__x, __y); - } - _LIBCPP_INLINE_VISIBILITY - static void __swap_alloc(allocator_type&, allocator_type&, false_type) - _NOEXCEPT - {} }; template @@ -760,8 +740,12 @@ public: void resize(size_type __sz, const_reference __x); void swap(vector&) - _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || - __is_nothrow_swappable::value); +#if _LIBCPP_STD_VER >= 14 + _NOEXCEPT; +#else + _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || + __is_nothrow_swappable::value); +#endif bool __invariants() const; @@ -2016,8 +2000,12 @@ vector<_Tp, _Allocator>::resize(size_type __sz, const_reference __x) template void vector<_Tp, _Allocator>::swap(vector& __x) - _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || - __is_nothrow_swappable::value) +#if _LIBCPP_STD_VER >= 14 + _NOEXCEPT +#else + _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || + __is_nothrow_swappable::value) +#endif { _LIBCPP_ASSERT(__alloc_traits::propagate_on_container_swap::value || this->__alloc() == __x.__alloc(), @@ -2026,7 +2014,8 @@ vector<_Tp, _Allocator>::swap(vector& __x) _VSTD::swap(this->__begin_, __x.__begin_); _VSTD::swap(this->__end_, __x.__end_); _VSTD::swap(this->__end_cap(), __x.__end_cap()); - __base::__swap_alloc(this->__alloc(), __x.__alloc()); + __swap_allocator(this->__alloc(), __x.__alloc(), + integral_constant()); #if _LIBCPP_DEBUG_LEVEL >= 2 __get_db()->swap(this, &__x); #endif // _LIBCPP_DEBUG_LEVEL >= 2 @@ -2354,8 +2343,12 @@ public: void clear() _NOEXCEPT {__size_ = 0;} void swap(vector&) - _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || - __is_nothrow_swappable::value); +#if _LIBCPP_STD_VER >= 14 + _NOEXCEPT; +#else + _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || + __is_nothrow_swappable::value); +#endif void resize(size_type __sz, value_type __x = false); void flip() _NOEXCEPT; @@ -2433,26 +2426,6 @@ private: _NOEXCEPT {} - _LIBCPP_INLINE_VISIBILITY - static void __swap_alloc(__storage_allocator& __x, __storage_allocator& __y) - _NOEXCEPT_( - !__storage_traits::propagate_on_container_swap::value || - __is_nothrow_swappable::value) - {__swap_alloc(__x, __y, integral_constant());} - - _LIBCPP_INLINE_VISIBILITY - static void __swap_alloc(__storage_allocator& __x, __storage_allocator& __y, true_type) - _NOEXCEPT_(__is_nothrow_swappable::value) - { - using _VSTD::swap; - swap(__x, __y); - } - _LIBCPP_INLINE_VISIBILITY - static void __swap_alloc(__storage_allocator&, __storage_allocator&, false_type) - _NOEXCEPT - {} - size_t __hash_code() const _NOEXCEPT; friend class __bit_reference; @@ -3155,13 +3128,18 @@ vector::erase(const_iterator __first, const_iterator __last) template void vector::swap(vector& __x) - _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || - __is_nothrow_swappable::value) +#if _LIBCPP_STD_VER >= 14 + _NOEXCEPT +#else + _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || + __is_nothrow_swappable::value) +#endif { _VSTD::swap(this->__begin_, __x.__begin_); _VSTD::swap(this->__size_, __x.__size_); _VSTD::swap(this->__cap(), __x.__cap()); - __swap_alloc(this->__alloc(), __x.__alloc()); + __swap_allocator(this->__alloc(), __x.__alloc(), + integral_constant()); } template diff --git a/test/std/containers/associative/map/map.special/swap_noexcept.pass.cpp b/test/std/containers/associative/map/map.special/swap_noexcept.pass.cpp index c238ed2c4..4598e9945 100644 --- a/test/std/containers/associative/map/map.special/swap_noexcept.pass.cpp +++ b/test/std/containers/associative/map/map.special/swap_noexcept.pass.cpp @@ -12,6 +12,10 @@ // void swap(map& c) // noexcept(!allocator_type::propagate_on_container_swap::value || // __is_nothrow_swappable::value); +// +// In C++17, the standard says that swap shall have: +// noexcept(allocator_traits::is_always_equal::value && +// noexcept(swap(declval(), declval()))); // This tests a conforming extension @@ -33,6 +37,60 @@ struct some_comp typedef std::true_type propagate_on_container_swap; }; +template +struct some_comp2 +{ + typedef T value_type; + + some_comp2() {} + some_comp2(const some_comp2&) {} + void deallocate(void*, unsigned) {} + typedef std::true_type propagate_on_container_swap; +}; + +#if TEST_STD_VER >= 14 +template +void swap(some_comp2&, some_comp2&) noexcept {} +#endif + +template +struct some_alloc +{ + typedef T value_type; + + some_alloc() {} + some_alloc(const some_alloc&); + void deallocate(void*, unsigned) {} + + typedef std::true_type propagate_on_container_swap; +}; + +template +struct some_alloc2 +{ + typedef T value_type; + + some_alloc2() {} + some_alloc2(const some_alloc2&); + void deallocate(void*, unsigned) {} + + typedef std::false_type propagate_on_container_swap; + typedef std::true_type is_always_equal; +}; + +template +struct some_alloc3 +{ + typedef T value_type; + + some_alloc3() {} + some_alloc3(const some_alloc3&); + void deallocate(void*, unsigned) {} + + typedef std::false_type propagate_on_container_swap; + typedef std::false_type is_always_equal; +}; + int main() { #if __has_feature(cxx_noexcept) @@ -56,5 +114,35 @@ int main() C c1, c2; static_assert(!noexcept(swap(c1, c2)), ""); } + +#if TEST_STD_VER >= 14 + { // POCS allocator, throwable swap for comp + typedef std::map, some_alloc > C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // always equal allocator, throwable swap for comp + typedef std::map, some_alloc2> C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // POCS allocator, nothrow swap for comp + typedef std::map, some_alloc > C; + C c1, c2; + static_assert( noexcept(swap(c1, c2)), ""); + } + { // always equal allocator, nothrow swap for comp + typedef std::map, some_alloc2> C; + C c1, c2; + static_assert( noexcept(swap(c1, c2)), ""); + } + + { // NOT always equal allocator, nothrow swap for comp + typedef std::map, some_alloc3> C; + C c1, c2; + static_assert( noexcept(swap(c1, c2)), ""); + } +#endif + #endif } diff --git a/test/std/containers/associative/multimap/multimap.special/swap_noexcept.pass.cpp b/test/std/containers/associative/multimap/multimap.special/swap_noexcept.pass.cpp index 07882a422..1013c6280 100644 --- a/test/std/containers/associative/multimap/multimap.special/swap_noexcept.pass.cpp +++ b/test/std/containers/associative/multimap/multimap.special/swap_noexcept.pass.cpp @@ -12,6 +12,10 @@ // void swap(multimap& c) // noexcept(!allocator_type::propagate_on_container_swap::value || // __is_nothrow_swappable::value); +// +// In C++17, the standard says that swap shall have: +// noexcept(allocator_traits::is_always_equal::value && +// noexcept(swap(declval(), declval()))); // This tests a conforming extension @@ -33,6 +37,60 @@ struct some_comp typedef std::true_type propagate_on_container_swap; }; +template +struct some_comp2 +{ + typedef T value_type; + + some_comp2() {} + some_comp2(const some_comp2&) {} + void deallocate(void*, unsigned) {} + typedef std::true_type propagate_on_container_swap; +}; + +#if TEST_STD_VER >= 14 +template +void swap(some_comp2&, some_comp2&) noexcept {} +#endif + +template +struct some_alloc +{ + typedef T value_type; + + some_alloc() {} + some_alloc(const some_alloc&); + void deallocate(void*, unsigned) {} + + typedef std::true_type propagate_on_container_swap; +}; + +template +struct some_alloc2 +{ + typedef T value_type; + + some_alloc2() {} + some_alloc2(const some_alloc2&); + void deallocate(void*, unsigned) {} + + typedef std::false_type propagate_on_container_swap; + typedef std::true_type is_always_equal; +}; + +template +struct some_alloc3 +{ + typedef T value_type; + + some_alloc3() {} + some_alloc3(const some_alloc3&); + void deallocate(void*, unsigned) {} + + typedef std::false_type propagate_on_container_swap; + typedef std::false_type is_always_equal; +}; + int main() { #if __has_feature(cxx_noexcept) @@ -56,5 +114,35 @@ int main() C c1, c2; static_assert(!noexcept(swap(c1, c2)), ""); } + +#if TEST_STD_VER >= 14 + { // POCS allocator, throwable swap for comp + typedef std::multimap, some_alloc > C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // always equal allocator, throwable swap for comp + typedef std::multimap, some_alloc2> C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // POCS allocator, nothrow swap for comp + typedef std::multimap, some_alloc > C; + C c1, c2; + static_assert( noexcept(swap(c1, c2)), ""); + } + { // always equal allocator, nothrow swap for comp + typedef std::multimap, some_alloc2> C; + C c1, c2; + static_assert( noexcept(swap(c1, c2)), ""); + } + + { // NOT always equal allocator, nothrow swap for comp + typedef std::map, some_alloc3> C; + C c1, c2; + static_assert( noexcept(swap(c1, c2)), ""); + } +#endif + #endif } diff --git a/test/std/containers/associative/multiset/multiset.special/swap_noexcept.pass.cpp b/test/std/containers/associative/multiset/multiset.special/swap_noexcept.pass.cpp index cd5be791c..8e2c67c9b 100644 --- a/test/std/containers/associative/multiset/multiset.special/swap_noexcept.pass.cpp +++ b/test/std/containers/associative/multiset/multiset.special/swap_noexcept.pass.cpp @@ -12,6 +12,10 @@ // void swap(multiset& c) // noexcept(!allocator_type::propagate_on_container_swap::value || // __is_nothrow_swappable::value); +// +// In C++17, the standard says that swap shall have: +// noexcept(allocator_traits::is_always_equal::value && +// noexcept(swap(declval(), declval()))); // This tests a conforming extension @@ -33,6 +37,60 @@ struct some_comp typedef std::true_type propagate_on_container_swap; }; +template +struct some_comp2 +{ + typedef T value_type; + + some_comp2() {} + some_comp2(const some_comp2&) {} + void deallocate(void*, unsigned) {} + typedef std::true_type propagate_on_container_swap; +}; + +#if TEST_STD_VER >= 14 +template +void swap(some_comp2&, some_comp2&) noexcept {} +#endif + +template +struct some_alloc +{ + typedef T value_type; + + some_alloc() {} + some_alloc(const some_alloc&); + void deallocate(void*, unsigned) {} + + typedef std::true_type propagate_on_container_swap; +}; + +template +struct some_alloc2 +{ + typedef T value_type; + + some_alloc2() {} + some_alloc2(const some_alloc2&); + void deallocate(void*, unsigned) {} + + typedef std::false_type propagate_on_container_swap; + typedef std::true_type is_always_equal; +}; + +template +struct some_alloc3 +{ + typedef T value_type; + + some_alloc3() {} + some_alloc3(const some_alloc3&); + void deallocate(void*, unsigned) {} + + typedef std::false_type propagate_on_container_swap; + typedef std::false_type is_always_equal; +}; + int main() { #if __has_feature(cxx_noexcept) @@ -56,5 +114,35 @@ int main() C c1, c2; static_assert(!noexcept(swap(c1, c2)), ""); } + +#if TEST_STD_VER >= 14 + { // POCS allocator, throwable swap for comp + typedef std::multiset, some_alloc > C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // always equal allocator, throwable swap for comp + typedef std::multiset, some_alloc2> C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // POCS allocator, nothrow swap for comp + typedef std::multiset, some_alloc > C; + C c1, c2; + static_assert( noexcept(swap(c1, c2)), ""); + } + { // always equal allocator, nothrow swap for comp + typedef std::multiset, some_alloc2> C; + C c1, c2; + static_assert( noexcept(swap(c1, c2)), ""); + } + + { // NOT always equal allocator, nothrow swap for comp + typedef std::multiset, some_alloc3> C; + C c1, c2; + static_assert( noexcept(swap(c1, c2)), ""); + } +#endif + #endif } diff --git a/test/std/containers/associative/set/set.special/swap_noexcept.pass.cpp b/test/std/containers/associative/set/set.special/swap_noexcept.pass.cpp index a478b2549..3ec697612 100644 --- a/test/std/containers/associative/set/set.special/swap_noexcept.pass.cpp +++ b/test/std/containers/associative/set/set.special/swap_noexcept.pass.cpp @@ -12,6 +12,10 @@ // void swap(set& c) // noexcept(!allocator_type::propagate_on_container_swap::value || // __is_nothrow_swappable::value); +// +// In C++17, the standard says that swap shall have: +// noexcept(allocator_traits::is_always_equal::value && +// noexcept(swap(declval(), declval()))); // This tests a conforming extension @@ -33,6 +37,60 @@ struct some_comp typedef std::true_type propagate_on_container_swap; }; +template +struct some_comp2 +{ + typedef T value_type; + + some_comp2() {} + some_comp2(const some_comp2&) {} + void deallocate(void*, unsigned) {} + typedef std::true_type propagate_on_container_swap; +}; + +#if TEST_STD_VER >= 14 +template +void swap(some_comp2&, some_comp2&) noexcept {} +#endif + +template +struct some_alloc +{ + typedef T value_type; + + some_alloc() {} + some_alloc(const some_alloc&); + void deallocate(void*, unsigned) {} + + typedef std::true_type propagate_on_container_swap; +}; + +template +struct some_alloc2 +{ + typedef T value_type; + + some_alloc2() {} + some_alloc2(const some_alloc2&); + void deallocate(void*, unsigned) {} + + typedef std::false_type propagate_on_container_swap; + typedef std::true_type is_always_equal; +}; + +template +struct some_alloc3 +{ + typedef T value_type; + + some_alloc3() {} + some_alloc3(const some_alloc3&); + void deallocate(void*, unsigned) {} + + typedef std::false_type propagate_on_container_swap; + typedef std::false_type is_always_equal; +}; + int main() { #if __has_feature(cxx_noexcept) @@ -56,5 +114,35 @@ int main() C c1, c2; static_assert(!noexcept(swap(c1, c2)), ""); } + +#if TEST_STD_VER >= 14 + { // POCS allocator, throwable swap for comp + typedef std::set, some_alloc > C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // always equal allocator, throwable swap for comp + typedef std::set, some_alloc2> C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // POCS allocator, nothrow swap for comp + typedef std::set, some_alloc > C; + C c1, c2; + static_assert( noexcept(swap(c1, c2)), ""); + } + { // always equal allocator, nothrow swap for comp + typedef std::set, some_alloc2> C; + C c1, c2; + static_assert( noexcept(swap(c1, c2)), ""); + } + + { // NOT always equal allocator, nothrow swap for comp + typedef std::set, some_alloc3> C; + C c1, c2; + static_assert( noexcept(swap(c1, c2)), ""); + } +#endif + #endif } diff --git a/test/std/containers/sequences/deque/deque.special/swap_noexcept.pass.cpp b/test/std/containers/sequences/deque/deque.special/swap_noexcept.pass.cpp index 3c94eb04b..83bcac899 100644 --- a/test/std/containers/sequences/deque/deque.special/swap_noexcept.pass.cpp +++ b/test/std/containers/sequences/deque/deque.special/swap_noexcept.pass.cpp @@ -12,6 +12,9 @@ // void swap(deque& c) // noexcept(!allocator_type::propagate_on_container_swap::value || // __is_nothrow_swappable::value); +// +// In C++17, the standard says that swap shall have: +// noexcept(allocator_traits::is_always_equal::value); // This tests a conforming extension @@ -33,6 +36,19 @@ struct some_alloc typedef std::true_type propagate_on_container_swap; }; +template +struct some_alloc2 +{ + typedef T value_type; + + some_alloc2() {} + some_alloc2(const some_alloc2&); + void deallocate(void*, unsigned) {} + + typedef std::false_type propagate_on_container_swap; + typedef std::true_type is_always_equal; +}; + int main() { #if __has_feature(cxx_noexcept) @@ -54,7 +70,21 @@ int main() { typedef std::deque> C; C c1, c2; +#if TEST_STD_VER >= 14 + // In c++14, if POCS is set, swapping the allocator is required not to throw + static_assert( noexcept(swap(c1, c2)), ""); +#else static_assert(!noexcept(swap(c1, c2)), ""); +#endif + } +#if TEST_STD_VER >= 14 + { + typedef std::deque> C; + C c1, c2; + // if the allocators are always equal, then the swap can be noexcept + static_assert( noexcept(swap(c1, c2)), ""); } #endif + +#endif } diff --git a/test/std/containers/sequences/forwardlist/forwardlist.spec/swap_noexcept.pass.cpp b/test/std/containers/sequences/forwardlist/forwardlist.spec/swap_noexcept.pass.cpp index e36ba5bdd..cbe8142ee 100644 --- a/test/std/containers/sequences/forwardlist/forwardlist.spec/swap_noexcept.pass.cpp +++ b/test/std/containers/sequences/forwardlist/forwardlist.spec/swap_noexcept.pass.cpp @@ -12,6 +12,9 @@ // void swap(forward_list& c) // noexcept(!allocator_type::propagate_on_container_swap::value || // __is_nothrow_swappable::value); +// +// In C++17, the standard says that swap shall have: +// noexcept(is_always_equal::value); // This tests a conforming extension @@ -33,6 +36,19 @@ struct some_alloc typedef std::true_type propagate_on_container_swap; }; +template +struct some_alloc2 +{ + typedef T value_type; + + some_alloc2() {} + some_alloc2(const some_alloc2&); + void deallocate(void*, unsigned) {} + + typedef std::false_type propagate_on_container_swap; + typedef std::true_type is_always_equal; +}; + int main() { #if __has_feature(cxx_noexcept) @@ -54,7 +70,21 @@ int main() { typedef std::forward_list> C; C c1, c2; +#if TEST_STD_VER >= 14 + // In c++14, if POCS is set, swapping the allocator is required not to throw + static_assert( noexcept(swap(c1, c2)), ""); +#else static_assert(!noexcept(swap(c1, c2)), ""); +#endif + } +#if TEST_STD_VER >= 14 + { + typedef std::forward_list> C; + C c1, c2; + // if the allocators are always equal, then the swap can be noexcept + static_assert( noexcept(swap(c1, c2)), ""); } #endif + +#endif } diff --git a/test/std/containers/sequences/list/list.special/swap_noexcept.pass.cpp b/test/std/containers/sequences/list/list.special/swap_noexcept.pass.cpp index 54ae359c2..9c83ad58f 100644 --- a/test/std/containers/sequences/list/list.special/swap_noexcept.pass.cpp +++ b/test/std/containers/sequences/list/list.special/swap_noexcept.pass.cpp @@ -12,6 +12,9 @@ // void swap(list& c) // noexcept(!allocator_type::propagate_on_container_swap::value || // __is_nothrow_swappable::value); +// +// In C++17, the standard says that swap shall have: +// noexcept(allocator_traits::is_always_equal::value); // This tests a conforming extension @@ -33,6 +36,19 @@ struct some_alloc typedef std::true_type propagate_on_container_swap; }; +template +struct some_alloc2 +{ + typedef T value_type; + + some_alloc2() {} + some_alloc2(const some_alloc2&); + void deallocate(void*, unsigned) {} + + typedef std::false_type propagate_on_container_swap; + typedef std::true_type is_always_equal; +}; + int main() { #if __has_feature(cxx_noexcept) @@ -54,7 +70,21 @@ int main() { typedef std::list> C; C c1, c2; +#if TEST_STD_VER >= 14 + // In c++14, if POCS is set, swapping the allocator is required not to throw + static_assert( noexcept(swap(c1, c2)), ""); +#else static_assert(!noexcept(swap(c1, c2)), ""); +#endif + } +#if TEST_STD_VER >= 14 + { + typedef std::list> C; + C c1, c2; + // if the allocators are always equal, then the swap can be noexcept + static_assert( noexcept(swap(c1, c2)), ""); } #endif + +#endif } diff --git a/test/std/containers/sequences/vector.bool/swap_noexcept.pass.cpp b/test/std/containers/sequences/vector.bool/swap_noexcept.pass.cpp index bcaf16111..6f36473fa 100644 --- a/test/std/containers/sequences/vector.bool/swap_noexcept.pass.cpp +++ b/test/std/containers/sequences/vector.bool/swap_noexcept.pass.cpp @@ -12,6 +12,10 @@ // void swap(vector& c) // noexcept(!allocator_type::propagate_on_container_swap::value || // __is_nothrow_swappable::value); +// +// In C++17, the standard says that swap shall have: +// noexcept(allocator_traits::propagate_on_container_swap::value || +// allocator_traits::is_always_equal::value); // This tests a conforming extension @@ -32,6 +36,19 @@ struct some_alloc typedef std::true_type propagate_on_container_swap; }; +template +struct some_alloc2 +{ + typedef T value_type; + + some_alloc2() {} + some_alloc2(const some_alloc2&); + void deallocate(void*, unsigned) {} + + typedef std::false_type propagate_on_container_swap; + typedef std::true_type is_always_equal; +}; + int main() { #if __has_feature(cxx_noexcept) @@ -53,7 +70,21 @@ int main() { typedef std::vector> C; C c1, c2; +#if TEST_STD_VER >= 14 + // In c++14, if POCS is set, swapping the allocator is required not to throw + static_assert( noexcept(swap(c1, c2)), ""); +#else static_assert(!noexcept(swap(c1, c2)), ""); +#endif + } +#if TEST_STD_VER >= 14 + { + typedef std::vector> C; + C c1, c2; + // if the allocators are always equal, then the swap can be noexcept + static_assert( noexcept(swap(c1, c2)), ""); } #endif + +#endif } diff --git a/test/std/containers/sequences/vector/vector.special/swap_noexcept.pass.cpp b/test/std/containers/sequences/vector/vector.special/swap_noexcept.pass.cpp index 92d87568f..1d00ff387 100644 --- a/test/std/containers/sequences/vector/vector.special/swap_noexcept.pass.cpp +++ b/test/std/containers/sequences/vector/vector.special/swap_noexcept.pass.cpp @@ -12,6 +12,10 @@ // void swap(vector& c) // noexcept(!allocator_type::propagate_on_container_swap::value || // __is_nothrow_swappable::value); +// +// In C++17, the standard says that swap shall have: +// noexcept(allocator_traits::propagate_on_container_swap::value || +// allocator_traits::is_always_equal::value); // This tests a conforming extension @@ -33,6 +37,19 @@ struct some_alloc typedef std::true_type propagate_on_container_swap; }; +template +struct some_alloc2 +{ + typedef T value_type; + + some_alloc2() {} + some_alloc2(const some_alloc2&); + void deallocate(void*, unsigned) {} + + typedef std::false_type propagate_on_container_swap; + typedef std::true_type is_always_equal; +}; + int main() { #if __has_feature(cxx_noexcept) @@ -54,7 +71,21 @@ int main() { typedef std::vector> C; C c1, c2; +#if TEST_STD_VER >= 14 + // In c++14, if POCS is set, swapping the allocator is required not to throw + static_assert( noexcept(swap(c1, c2)), ""); +#else static_assert(!noexcept(swap(c1, c2)), ""); +#endif + } +#if TEST_STD_VER >= 14 + { + typedef std::vector> C; + C c1, c2; + // if the allocators are always equal, then the swap can be noexcept + static_assert( noexcept(swap(c1, c2)), ""); } #endif + +#endif } diff --git a/test/std/containers/unord/unord.map/unord.map.swap/swap_noexcept.pass.cpp b/test/std/containers/unord/unord.map/unord.map.swap/swap_noexcept.pass.cpp index a986882ea..1056c231f 100644 --- a/test/std/containers/unord/unord.map/unord.map.swap/swap_noexcept.pass.cpp +++ b/test/std/containers/unord/unord.map/unord.map.swap/swap_noexcept.pass.cpp @@ -10,8 +10,16 @@ // // void swap(unordered_map& c) -// noexcept(!allocator_type::propagate_on_container_swap::value || -// __is_nothrow_swappable::value); +// noexcept( +// (!allocator_type::propagate_on_container_swap::value || +// __is_nothrow_swappable::value) && +// __is_nothrow_swappable::value && +// __is_nothrow_swappable::value); +// +// In C++17, the standard says that swap shall have: +// noexcept(allocator_traits::is_always_equal::value && +// noexcept(swap(declval(), declval())) && +// noexcept(swap(declval(), declval()))); // This tests a conforming extension @@ -30,6 +38,22 @@ struct some_comp some_comp(const some_comp&) {} }; +template +struct some_comp2 +{ + typedef T value_type; + + some_comp2() {} + some_comp2(const some_comp2&) {} + void deallocate(void*, unsigned) {} + typedef std::true_type propagate_on_container_swap; +}; + +#if TEST_STD_VER >= 14 +template +void swap(some_comp2&, some_comp2&) noexcept {} +#endif + template struct some_hash { @@ -38,9 +62,62 @@ struct some_hash some_hash(const some_hash&); }; +template +struct some_hash2 +{ + typedef T value_type; + some_hash2() {} + some_hash2(const some_hash2&); +}; + +#if TEST_STD_VER >= 14 +template +void swap(some_hash2&, some_hash2&) noexcept {} +#endif + +template +struct some_alloc +{ + typedef T value_type; + + some_alloc() {} + some_alloc(const some_alloc&); + void deallocate(void*, unsigned) {} + + typedef std::true_type propagate_on_container_swap; +}; + +template +struct some_alloc2 +{ + typedef T value_type; + + some_alloc2() {} + some_alloc2(const some_alloc2&); + void deallocate(void*, unsigned) {} + + typedef std::false_type propagate_on_container_swap; + typedef std::true_type is_always_equal; +}; + +template +struct some_alloc3 +{ + typedef T value_type; + + some_alloc3() {} + some_alloc3(const some_alloc3&); + void deallocate(void*, unsigned) {} + + typedef std::false_type propagate_on_container_swap; + typedef std::false_type is_always_equal; +}; + + int main() { #if __has_feature(cxx_noexcept) + typedef std::pair MapType; { typedef std::unordered_map C; C c1, c2; @@ -48,13 +125,13 @@ int main() } { typedef std::unordered_map, - std::equal_to, test_allocator>> C; + std::equal_to, test_allocator> C; C c1, c2; static_assert(noexcept(swap(c1, c2)), ""); } { typedef std::unordered_map, - std::equal_to, other_allocator>> C; + std::equal_to, other_allocator> C; C c1, c2; static_assert(noexcept(swap(c1, c2)), ""); } @@ -69,5 +146,54 @@ int main() C c1, c2; static_assert(!noexcept(swap(c1, c2)), ""); } + +#if TEST_STD_VER >= 14 + { // POCS allocator, throwable swap for hash, throwable swap for comp + typedef std::unordered_map, some_comp , some_alloc > C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // always equal allocator, throwable swap for hash, throwable swap for comp + typedef std::unordered_map, some_comp , some_alloc2> C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // POCS allocator, throwable swap for hash, nothrow swap for comp + typedef std::unordered_map, some_comp2, some_alloc > C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // always equal allocator, throwable swap for hash, nothrow swap for comp + typedef std::unordered_map, some_comp2, some_alloc2> C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // POCS allocator, nothrow swap for hash, throwable swap for comp + typedef std::unordered_map, some_comp , some_alloc > C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // always equal allocator, nothrow swap for hash, throwable swap for comp + typedef std::unordered_map, some_comp , some_alloc2> C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // POCS allocator, nothrow swap for hash, nothrow swap for comp + typedef std::unordered_map, some_comp2, some_alloc > C; + C c1, c2; + static_assert( noexcept(swap(c1, c2)), ""); + } + { // always equal allocator, nothrow swap for hash, nothrow swap for comp + typedef std::unordered_map, some_comp2, some_alloc2> C; + C c1, c2; + static_assert( noexcept(swap(c1, c2)), ""); + } + + { // NOT always equal allocator, nothrow swap for hash, nothrow swap for comp + typedef std::unordered_map, some_comp2, some_alloc3> C; + C c1, c2; + static_assert( noexcept(swap(c1, c2)), ""); + } +#endif #endif } diff --git a/test/std/containers/unord/unord.multimap/unord.multimap.swap/swap_noexcept.pass.cpp b/test/std/containers/unord/unord.multimap/unord.multimap.swap/swap_noexcept.pass.cpp index c690bb61b..37c811906 100644 --- a/test/std/containers/unord/unord.multimap/unord.multimap.swap/swap_noexcept.pass.cpp +++ b/test/std/containers/unord/unord.multimap/unord.multimap.swap/swap_noexcept.pass.cpp @@ -10,8 +10,16 @@ // // void swap(unordered_multimap& c) -// noexcept(!allocator_type::propagate_on_container_swap::value || -// __is_nothrow_swappable::value); +// noexcept( +// (!allocator_type::propagate_on_container_swap::value || +// __is_nothrow_swappable::value) && +// __is_nothrow_swappable::value && +// __is_nothrow_swappable::value); +// +// In C++17, the standard says that swap shall have: +// noexcept(allocator_traits::is_always_equal::value && +// __is_nothrow_swappable::value && +// __is_nothrow_swappable::value); // This tests a conforming extension @@ -30,6 +38,22 @@ struct some_comp some_comp(const some_comp&) {} }; +template +struct some_comp2 +{ + typedef T value_type; + + some_comp2() {} + some_comp2(const some_comp2&) {} + void deallocate(void*, unsigned) {} + typedef std::true_type propagate_on_container_swap; +}; + +#if TEST_STD_VER >= 14 +template +void swap(some_comp2&, some_comp2&) noexcept {} +#endif + template struct some_hash { @@ -38,9 +62,61 @@ struct some_hash some_hash(const some_hash&); }; +template +struct some_hash2 +{ + typedef T value_type; + some_hash2() {} + some_hash2(const some_hash2&); +}; + +#if TEST_STD_VER >= 14 +template +void swap(some_hash2&, some_hash2&) noexcept {} +#endif + +template +struct some_alloc +{ + typedef T value_type; + + some_alloc() {} + some_alloc(const some_alloc&); + void deallocate(void*, unsigned) {} + + typedef std::true_type propagate_on_container_swap; +}; + +template +struct some_alloc2 +{ + typedef T value_type; + + some_alloc2() {} + some_alloc2(const some_alloc2&); + void deallocate(void*, unsigned) {} + + typedef std::false_type propagate_on_container_swap; + typedef std::true_type is_always_equal; +}; + +template +struct some_alloc3 +{ + typedef T value_type; + + some_alloc3() {} + some_alloc3(const some_alloc3&); + void deallocate(void*, unsigned) {} + + typedef std::false_type propagate_on_container_swap; + typedef std::false_type is_always_equal; +}; + int main() { #if __has_feature(cxx_noexcept) + typedef std::pair MapType; { typedef std::unordered_multimap C; C c1, c2; @@ -48,13 +124,13 @@ int main() } { typedef std::unordered_multimap, - std::equal_to, test_allocator>> C; + std::equal_to, test_allocator> C; C c1, c2; static_assert(noexcept(swap(c1, c2)), ""); } { typedef std::unordered_multimap, - std::equal_to, other_allocator>> C; + std::equal_to, other_allocator> C; C c1, c2; static_assert(noexcept(swap(c1, c2)), ""); } @@ -69,5 +145,54 @@ int main() C c1, c2; static_assert(!noexcept(swap(c1, c2)), ""); } + +#if TEST_STD_VER >= 14 + { // POCS allocator, throwable swap for hash, throwable swap for comp + typedef std::unordered_multimap, some_comp , some_alloc > C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // always equal allocator, throwable swap for hash, throwable swap for comp + typedef std::unordered_multimap, some_comp , some_alloc2> C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // POCS allocator, throwable swap for hash, nothrow swap for comp + typedef std::unordered_multimap, some_comp2, some_alloc > C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // always equal allocator, throwable swap for hash, nothrow swap for comp + typedef std::unordered_multimap, some_comp2, some_alloc2> C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // POCS allocator, nothrow swap for hash, throwable swap for comp + typedef std::unordered_multimap, some_comp , some_alloc > C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // always equal allocator, nothrow swap for hash, throwable swap for comp + typedef std::unordered_multimap, some_comp , some_alloc2> C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // POCS allocator, nothrow swap for hash, nothrow swap for comp + typedef std::unordered_multimap, some_comp2, some_alloc > C; + C c1, c2; + static_assert( noexcept(swap(c1, c2)), ""); + } + { // always equal allocator, nothrow swap for hash, nothrow swap for comp + typedef std::unordered_multimap, some_comp2, some_alloc2> C; + C c1, c2; + static_assert( noexcept(swap(c1, c2)), ""); + } + { // NOT always equal allocator, nothrow swap for hash, nothrow swap for comp + typedef std::unordered_multimap, some_comp2, some_alloc3> C; + C c1, c2; + static_assert( noexcept(swap(c1, c2)), ""); + } +#endif + #endif } diff --git a/test/std/containers/unord/unord.multiset/unord.multiset.swap/swap_noexcept.pass.cpp b/test/std/containers/unord/unord.multiset/unord.multiset.swap/swap_noexcept.pass.cpp index 7dc653bca..63642fcd7 100644 --- a/test/std/containers/unord/unord.multiset/unord.multiset.swap/swap_noexcept.pass.cpp +++ b/test/std/containers/unord/unord.multiset/unord.multiset.swap/swap_noexcept.pass.cpp @@ -10,8 +10,16 @@ // // void swap(unordered_multiset& c) -// noexcept(!allocator_type::propagate_on_container_swap::value || -// __is_nothrow_swappable::value); +// noexcept( +// (!allocator_type::propagate_on_container_swap::value || +// __is_nothrow_swappable::value) && +// __is_nothrow_swappable::value && +// __is_nothrow_swappable::value); +// +// In C++17, the standard says that swap shall have: +// noexcept(allocator_traits::is_always_equal::value && +// noexcept(swap(declval(), declval())) && +// noexcept(swap(declval(), declval()))); // This tests a conforming extension @@ -30,6 +38,22 @@ struct some_comp some_comp(const some_comp&) {} }; +template +struct some_comp2 +{ + typedef T value_type; + + some_comp2() {} + some_comp2(const some_comp2&) {} + void deallocate(void*, unsigned) {} + typedef std::true_type propagate_on_container_swap; +}; + +#if TEST_STD_VER >= 14 +template +void swap(some_comp2&, some_comp2&) noexcept {} +#endif + template struct some_hash { @@ -38,6 +62,57 @@ struct some_hash some_hash(const some_hash&); }; +template +struct some_hash2 +{ + typedef T value_type; + some_hash2() {} + some_hash2(const some_hash2&); +}; + +#if TEST_STD_VER >= 14 +template +void swap(some_hash2&, some_hash2&) noexcept {} +#endif + +template +struct some_alloc +{ + typedef T value_type; + + some_alloc() {} + some_alloc(const some_alloc&); + void deallocate(void*, unsigned) {} + + typedef std::true_type propagate_on_container_swap; +}; + +template +struct some_alloc2 +{ + typedef T value_type; + + some_alloc2() {} + some_alloc2(const some_alloc2&); + void deallocate(void*, unsigned) {} + + typedef std::false_type propagate_on_container_swap; + typedef std::true_type is_always_equal; +}; + +template +struct some_alloc3 +{ + typedef T value_type; + + some_alloc3() {} + some_alloc3(const some_alloc3&); + void deallocate(void*, unsigned) {} + + typedef std::false_type propagate_on_container_swap; + typedef std::false_type is_always_equal; +}; + int main() { #if __has_feature(cxx_noexcept) @@ -69,5 +144,55 @@ int main() C c1, c2; static_assert(!noexcept(swap(c1, c2)), ""); } + +#if TEST_STD_VER >= 14 + { // POCS allocator, throwable swap for hash, throwable swap for comp + typedef std::unordered_multiset, some_comp , some_alloc > C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // always equal allocator, throwable swap for hash, throwable swap for comp + typedef std::unordered_multiset, some_comp , some_alloc2> C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // POCS allocator, throwable swap for hash, nothrow swap for comp + typedef std::unordered_multiset, some_comp2, some_alloc > C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // always equal allocator, throwable swap for hash, nothrow swap for comp + typedef std::unordered_multiset, some_comp2, some_alloc2> C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // POCS allocator, nothrow swap for hash, throwable swap for comp + typedef std::unordered_multiset, some_comp , some_alloc > C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // always equal allocator, nothrow swap for hash, throwable swap for comp + typedef std::unordered_multiset, some_comp , some_alloc2> C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // POCS allocator, nothrow swap for hash, nothrow swap for comp + typedef std::unordered_multiset, some_comp2, some_alloc > C; + C c1, c2; + static_assert( noexcept(swap(c1, c2)), ""); + } + { // always equal allocator, nothrow swap for hash, nothrow swap for comp + typedef std::unordered_multiset, some_comp2, some_alloc2> C; + C c1, c2; + static_assert( noexcept(swap(c1, c2)), ""); + } + + { // NOT always equal allocator, nothrow swap for hash, nothrow swap for comp + typedef std::unordered_multiset, some_comp2, some_alloc3> C; + C c1, c2; + static_assert( noexcept(swap(c1, c2)), ""); + } +#endif + #endif } diff --git a/test/std/containers/unord/unord.set/unord.set.swap/swap_noexcept.pass.cpp b/test/std/containers/unord/unord.set/unord.set.swap/swap_noexcept.pass.cpp index cba092319..5d746407a 100644 --- a/test/std/containers/unord/unord.set/unord.set.swap/swap_noexcept.pass.cpp +++ b/test/std/containers/unord/unord.set/unord.set.swap/swap_noexcept.pass.cpp @@ -10,8 +10,16 @@ // // void swap(unordered_set& c) -// noexcept(!allocator_type::propagate_on_container_swap::value || -// __is_nothrow_swappable::value); +// noexcept( +// (!allocator_type::propagate_on_container_swap::value || +// __is_nothrow_swappable::value) && +// __is_nothrow_swappable::value && +// __is_nothrow_swappable::value); +// +// In C++17, the standard says that swap shall have: +// noexcept(allocator_traits::is_always_equal::value && +// noexcept(swap(declval(), declval())) && +// noexcept(swap(declval(), declval()))); // This tests a conforming extension @@ -30,6 +38,22 @@ struct some_comp some_comp(const some_comp&) {} }; +template +struct some_comp2 +{ + typedef T value_type; + + some_comp2() {} + some_comp2(const some_comp2&) {} + void deallocate(void*, unsigned) {} + typedef std::true_type propagate_on_container_swap; +}; + +#if TEST_STD_VER >= 14 +template +void swap(some_comp2&, some_comp2&) noexcept {} +#endif + template struct some_hash { @@ -38,6 +62,57 @@ struct some_hash some_hash(const some_hash&); }; +template +struct some_hash2 +{ + typedef T value_type; + some_hash2() {} + some_hash2(const some_hash2&); +}; + +#if TEST_STD_VER >= 14 +template +void swap(some_hash2&, some_hash2&) noexcept {} +#endif + +template +struct some_alloc +{ + typedef T value_type; + + some_alloc() {} + some_alloc(const some_alloc&); + void deallocate(void*, unsigned) {} + + typedef std::true_type propagate_on_container_swap; +}; + +template +struct some_alloc2 +{ + typedef T value_type; + + some_alloc2() {} + some_alloc2(const some_alloc2&); + void deallocate(void*, unsigned) {} + + typedef std::false_type propagate_on_container_swap; + typedef std::true_type is_always_equal; +}; + +template +struct some_alloc3 +{ + typedef T value_type; + + some_alloc3() {} + some_alloc3(const some_alloc3&); + void deallocate(void*, unsigned) {} + + typedef std::false_type propagate_on_container_swap; + typedef std::false_type is_always_equal; +}; + int main() { #if __has_feature(cxx_noexcept) @@ -69,5 +144,55 @@ int main() C c1, c2; static_assert(!noexcept(swap(c1, c2)), ""); } + +#if TEST_STD_VER >= 14 + { // POCS allocator, throwable swap for hash, throwable swap for comp + typedef std::unordered_set, some_comp , some_alloc > C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // always equal allocator, throwable swap for hash, throwable swap for comp + typedef std::unordered_set, some_comp , some_alloc2> C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // POCS allocator, throwable swap for hash, nothrow swap for comp + typedef std::unordered_set, some_comp2, some_alloc > C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // always equal allocator, throwable swap for hash, nothrow swap for comp + typedef std::unordered_set, some_comp2, some_alloc2> C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // POCS allocator, nothrow swap for hash, throwable swap for comp + typedef std::unordered_set, some_comp , some_alloc > C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // always equal allocator, nothrow swap for hash, throwable swap for comp + typedef std::unordered_set, some_comp , some_alloc2> C; + C c1, c2; + static_assert(!noexcept(swap(c1, c2)), ""); + } + { // POCS allocator, nothrow swap for hash, nothrow swap for comp + typedef std::unordered_set, some_comp2, some_alloc > C; + C c1, c2; + static_assert( noexcept(swap(c1, c2)), ""); + } + { // always equal allocator, nothrow swap for hash, nothrow swap for comp + typedef std::unordered_set, some_comp2, some_alloc2> C; + C c1, c2; + static_assert( noexcept(swap(c1, c2)), ""); + } + + { // NOT always equal allocator, nothrow swap for hash, nothrow swap for comp + typedef std::unordered_set, some_comp2, some_alloc3> C; + C c1, c2; + static_assert( noexcept(swap(c1, c2)), ""); + } +#endif + #endif } diff --git a/test/std/strings/basic.string/string.nonmembers/string.special/swap_noexcept.pass.cpp b/test/std/strings/basic.string/string.nonmembers/string.special/swap_noexcept.pass.cpp index 4d5d79693..cfe03655a 100644 --- a/test/std/strings/basic.string/string.nonmembers/string.special/swap_noexcept.pass.cpp +++ b/test/std/strings/basic.string/string.nonmembers/string.special/swap_noexcept.pass.cpp @@ -12,6 +12,10 @@ // void swap(basic_string& c) // noexcept(!allocator_type::propagate_on_container_swap::value || // __is_nothrow_swappable::value); +// +// In C++17, the standard says that swap shall have: +// noexcept(allocator_traits::propagate_on_container_swap::value || +// allocator_traits::is_always_equal::value); // This tests a conforming extension @@ -32,6 +36,19 @@ struct some_alloc typedef std::true_type propagate_on_container_swap; }; +template +struct some_alloc2 +{ + typedef T value_type; + + some_alloc2() {} + some_alloc2(const some_alloc2&); + void deallocate(void*, unsigned) {} + + typedef std::false_type propagate_on_container_swap; + typedef std::true_type is_always_equal; +}; + int main() { #if __has_feature(cxx_noexcept) @@ -48,7 +65,21 @@ int main() { typedef std::basic_string, some_alloc> C; C c1, c2; +#if TEST_STD_VER >= 14 + // In c++14, if POCS is set, swapping the allocator is required not to throw + static_assert( noexcept(swap(c1, c2)), ""); +#else static_assert(!noexcept(swap(c1, c2)), ""); +#endif + } +#if TEST_STD_VER >= 14 + { + typedef std::basic_string, some_alloc2> C; + C c1, c2; + // if the allocators are always equal, then the swap can be noexcept + static_assert( noexcept(swap(c1, c2)), ""); } #endif + +#endif }