Author: marshall Date: Tue Aug 18 13:57:00 2015 New Revision: 245330 URL: http://llvm.org/viewvc/llvm-project?rev=245330&view=rev Log: implement more of N4258 - Cleaning up noexcept in the standard library. Specifically add new noexcept stuff to vector and string's move-assignment operations
Modified: libcxx/trunk/include/memory libcxx/trunk/include/string libcxx/trunk/include/vector libcxx/trunk/test/std/containers/sequences/vector.bool/move_assign_noexcept.pass.cpp libcxx/trunk/test/std/containers/sequences/vector/vector.cons/move_assign_noexcept.pass.cpp libcxx/trunk/test/std/strings/basic.string/string.cons/move_assign_noexcept.pass.cpp Modified: libcxx/trunk/include/memory URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/memory?rev=245330&r1=245329&r2=245330&view=diff ============================================================================== --- libcxx/trunk/include/memory (original) +++ libcxx/trunk/include/memory Tue Aug 18 13:57:00 2015 @@ -5574,6 +5574,15 @@ template <typename _Alloc> _LIBCPP_INLINE_VISIBILITY void __swap_allocator(_Alloc &, _Alloc &, false_type) _NOEXCEPT {} +template <typename _Alloc, typename _Traits=allocator_traits<_Alloc>> +struct __noexcept_move_assign_container : public integral_constant<bool, + _Traits::propagate_on_container_move_assignment::value +#if _LIBCPP_STD_VER > 14 + || _Traits::is_always_equal::value +#else + && is_nothrow_move_assignable<_Alloc>::value +#endif + > {}; _LIBCPP_END_NAMESPACE_STD Modified: libcxx/trunk/include/string URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/string?rev=245330&r1=245329&r2=245330&view=diff ============================================================================== --- libcxx/trunk/include/string (original) +++ libcxx/trunk/include/string Tue Aug 18 13:57:00 2015 @@ -115,8 +115,8 @@ public: basic_string& operator=(const basic_string& str); basic_string& operator=(basic_string&& str) noexcept( - allocator_type::propagate_on_container_move_assignment::value && - is_nothrow_move_assignable<allocator_type>::value); + allocator_type::propagate_on_container_move_assignment::value || + allocator_type::is_always_equal::value ); // C++17 basic_string& operator=(const value_type* s); basic_string& operator=(value_type c); basic_string& operator=(initializer_list<value_type>); @@ -1377,8 +1377,7 @@ public: #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES _LIBCPP_INLINE_VISIBILITY basic_string& operator=(basic_string&& __str) - _NOEXCEPT_(__alloc_traits::propagate_on_container_move_assignment::value && - is_nothrow_move_assignable<allocator_type>::value); + _NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value)); #endif _LIBCPP_INLINE_VISIBILITY basic_string& operator=(const value_type* __s) {return assign(__s);} basic_string& operator=(value_type __c); @@ -1845,11 +1844,16 @@ private: #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES _LIBCPP_INLINE_VISIBILITY - void __move_assign(basic_string& __str, false_type); + void __move_assign(basic_string& __str, false_type) + _NOEXCEPT_(__alloc_traits::is_always_equal::value); _LIBCPP_INLINE_VISIBILITY void __move_assign(basic_string& __str, true_type) +#if _LIBCPP_STD_VER > 14 + _NOEXCEPT; +#else _NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value); #endif +#endif _LIBCPP_INLINE_VISIBILITY void @@ -2430,6 +2434,7 @@ template <class _CharT, class _Traits, c inline _LIBCPP_INLINE_VISIBILITY void basic_string<_CharT, _Traits, _Allocator>::__move_assign(basic_string& __str, false_type) + _NOEXCEPT_(__alloc_traits::is_always_equal::value) { if (__alloc() != __str.__alloc()) assign(__str); @@ -2441,7 +2446,11 @@ template <class _CharT, class _Traits, c inline _LIBCPP_INLINE_VISIBILITY void basic_string<_CharT, _Traits, _Allocator>::__move_assign(basic_string& __str, true_type) +#if _LIBCPP_STD_VER > 14 + _NOEXCEPT +#else _NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value) +#endif { clear(); shrink_to_fit(); @@ -2454,8 +2463,7 @@ template <class _CharT, class _Traits, c inline _LIBCPP_INLINE_VISIBILITY basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::operator=(basic_string&& __str) - _NOEXCEPT_(__alloc_traits::propagate_on_container_move_assignment::value && - is_nothrow_move_assignable<allocator_type>::value) + _NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value)) { __move_assign(__str, integral_constant<bool, __alloc_traits::propagate_on_container_move_assignment::value>()); Modified: libcxx/trunk/include/vector URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/vector?rev=245330&r1=245329&r2=245330&view=diff ============================================================================== --- libcxx/trunk/include/vector (original) +++ libcxx/trunk/include/vector Tue Aug 18 13:57:00 2015 @@ -51,8 +51,8 @@ public: vector& operator=(const vector& x); vector& operator=(vector&& x) noexcept( - allocator_type::propagate_on_container_move_assignment::value && - is_nothrow_move_assignable<allocator_type>::value); + allocator_type::propagate_on_container_move_assignment::value || + allocator_type::is_always_equal::value); // C++17 vector& operator=(initializer_list<value_type> il); template <class InputIterator> void assign(InputIterator first, InputIterator last); @@ -175,8 +175,8 @@ public: vector& operator=(const vector& x); vector& operator=(vector&& x) noexcept( - allocator_type::propagate_on_container_move_assignment::value && - is_nothrow_move_assignable<allocator_type>::value); + allocator_type::propagate_on_container_move_assignment::value || + allocator_type::is_always_equal::value); // C++17 vector& operator=(initializer_list<value_type> il); template <class InputIterator> void assign(InputIterator first, InputIterator last); @@ -562,9 +562,7 @@ public: vector(vector&& __x, const allocator_type& __a); _LIBCPP_INLINE_VISIBILITY vector& operator=(vector&& __x) - _NOEXCEPT_( - __alloc_traits::propagate_on_container_move_assignment::value && - is_nothrow_move_assignable<allocator_type>::value); + _NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value)); #endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES #ifndef _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS _LIBCPP_INLINE_VISIBILITY @@ -787,7 +785,8 @@ private: void __move_range(pointer __from_s, pointer __from_e, pointer __to); void __move_assign(vector& __c, true_type) _NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value); - void __move_assign(vector& __c, false_type); + void __move_assign(vector& __c, false_type) + _NOEXCEPT_(__alloc_traits::is_always_equal::value); _LIBCPP_INLINE_VISIBILITY void __destruct_at_end(pointer __new_last) _NOEXCEPT { @@ -1303,9 +1302,7 @@ template <class _Tp, class _Allocator> inline _LIBCPP_INLINE_VISIBILITY vector<_Tp, _Allocator>& vector<_Tp, _Allocator>::operator=(vector&& __x) - _NOEXCEPT_( - __alloc_traits::propagate_on_container_move_assignment::value && - is_nothrow_move_assignable<allocator_type>::value) + _NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value)) { __move_assign(__x, integral_constant<bool, __alloc_traits::propagate_on_container_move_assignment::value>()); @@ -1315,6 +1312,7 @@ vector<_Tp, _Allocator>::operator=(vecto template <class _Tp, class _Allocator> void vector<_Tp, _Allocator>::__move_assign(vector& __c, false_type) + _NOEXCEPT_(__alloc_traits::is_always_equal::value) { if (__base::__alloc() != __c.__alloc()) { @@ -2213,9 +2211,7 @@ public: vector(vector&& __v, const allocator_type& __a); _LIBCPP_INLINE_VISIBILITY vector& operator=(vector&& __v) - _NOEXCEPT_( - __alloc_traits::propagate_on_container_move_assignment::value && - is_nothrow_move_assignable<allocator_type>::value); + _NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value)); #endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES #ifndef _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS _LIBCPP_INLINE_VISIBILITY @@ -2838,9 +2834,7 @@ template <class _Allocator> inline _LIBCPP_INLINE_VISIBILITY vector<bool, _Allocator>& vector<bool, _Allocator>::operator=(vector&& __v) - _NOEXCEPT_( - __alloc_traits::propagate_on_container_move_assignment::value && - is_nothrow_move_assignable<allocator_type>::value) + _NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value)) { __move_assign(__v, integral_constant<bool, __storage_traits::propagate_on_container_move_assignment::value>()); Modified: libcxx/trunk/test/std/containers/sequences/vector.bool/move_assign_noexcept.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/containers/sequences/vector.bool/move_assign_noexcept.pass.cpp?rev=245330&r1=245329&r2=245330&view=diff ============================================================================== --- libcxx/trunk/test/std/containers/sequences/vector.bool/move_assign_noexcept.pass.cpp (original) +++ libcxx/trunk/test/std/containers/sequences/vector.bool/move_assign_noexcept.pass.cpp Tue Aug 18 13:57:00 2015 @@ -28,6 +28,32 @@ struct some_alloc some_alloc(const some_alloc&); }; +template <class T> +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_move_assignment; + typedef std::true_type is_always_equal; +}; + +template <class T> +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_move_assignment; + typedef std::false_type is_always_equal; +}; + int main() { #if __has_feature(cxx_noexcept) @@ -45,7 +71,22 @@ int main() } { typedef std::vector<bool, some_alloc<bool>> C; +#if TEST_STD_VER > 14 + static_assert( std::is_nothrow_move_assignable<C>::value, ""); +#else static_assert(!std::is_nothrow_move_assignable<C>::value, ""); +#endif } +#if TEST_STD_VER > 14 + { // POCMA false, is_always_equal true + typedef std::vector<bool, some_alloc2<bool>> C; + static_assert( std::is_nothrow_move_assignable<C>::value, ""); + } + { // POCMA false, is_always_equal false + typedef std::vector<bool, some_alloc3<bool>> C; + static_assert(!std::is_nothrow_move_assignable<C>::value, ""); + } +#endif + #endif } Modified: libcxx/trunk/test/std/containers/sequences/vector/vector.cons/move_assign_noexcept.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/containers/sequences/vector/vector.cons/move_assign_noexcept.pass.cpp?rev=245330&r1=245329&r2=245330&view=diff ============================================================================== --- libcxx/trunk/test/std/containers/sequences/vector/vector.cons/move_assign_noexcept.pass.cpp (original) +++ libcxx/trunk/test/std/containers/sequences/vector/vector.cons/move_assign_noexcept.pass.cpp Tue Aug 18 13:57:00 2015 @@ -29,6 +29,33 @@ struct some_alloc some_alloc(const some_alloc&); }; +template <class T> +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_move_assignment; + typedef std::true_type is_always_equal; +}; + +template <class T> +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_move_assignment; + typedef std::false_type is_always_equal; +}; + + int main() { #if __has_feature(cxx_noexcept) @@ -46,7 +73,24 @@ int main() } { typedef std::vector<MoveOnly, some_alloc<MoveOnly>> C; + // In C++17, move assignment for allocators are not allowed to throw +#if TEST_STD_VER > 14 + static_assert( std::is_nothrow_move_assignable<C>::value, ""); +#else + static_assert(!std::is_nothrow_move_assignable<C>::value, ""); +#endif + } + +#if TEST_STD_VER > 14 + { // POCMA false, is_always_equal true + typedef std::vector<MoveOnly, some_alloc2<MoveOnly>> C; + static_assert( std::is_nothrow_move_assignable<C>::value, ""); + } + { // POCMA false, is_always_equal false + typedef std::vector<MoveOnly, some_alloc3<MoveOnly>> C; static_assert(!std::is_nothrow_move_assignable<C>::value, ""); } #endif + +#endif } Modified: libcxx/trunk/test/std/strings/basic.string/string.cons/move_assign_noexcept.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/strings/basic.string/string.cons/move_assign_noexcept.pass.cpp?rev=245330&r1=245329&r2=245330&view=diff ============================================================================== --- libcxx/trunk/test/std/strings/basic.string/string.cons/move_assign_noexcept.pass.cpp (original) +++ libcxx/trunk/test/std/strings/basic.string/string.cons/move_assign_noexcept.pass.cpp Tue Aug 18 13:57:00 2015 @@ -11,14 +11,18 @@ // basic_string& operator=(basic_string&& c) // noexcept( -// allocator_type::propagate_on_container_move_assignment::value && -// is_nothrow_move_assignable<allocator_type>::value); - -// This tests a conforming extension +// allocator_traits<allocator_type>::propagate_on_container_move_assignment::value || +// allocator_traits<allocator_type>::is_always_equal::value); // C++17 +// +// before C++17, we use the conforming extension +// noexcept( +// allocator_type::propagate_on_container_move_assignment::value && +// is_nothrow_move_assignable<allocator_type>::value); #include <string> #include <cassert> +#include "test_macros.h" #include "test_allocator.h" template <class T> @@ -28,6 +32,32 @@ struct some_alloc some_alloc(const some_alloc&); }; +template <class T> +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_move_assignment; + typedef std::true_type is_always_equal; +}; + +template <class T> +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_move_assignment; + typedef std::false_type is_always_equal; +}; + int main() { #if __has_feature(cxx_noexcept) @@ -41,7 +71,25 @@ int main() } { typedef std::basic_string<char, std::char_traits<char>, some_alloc<char>> C; +#if TEST_STD_VER > 14 + // if the allocators are always equal, then the move assignment can be noexcept + static_assert( std::is_nothrow_move_assignable<C>::value, ""); +#else static_assert(!std::is_nothrow_move_assignable<C>::value, ""); +#endif + } +#if TEST_STD_VER > 14 + { + // POCMA is false, always equal + typedef std::basic_string<char, std::char_traits<char>, some_alloc2<char>> C; + static_assert( std::is_nothrow_move_assignable<C>::value, ""); } + { + // POCMA is false, not always equal + typedef std::basic_string<char, std::char_traits<char>, some_alloc3<char>> C; + static_assert(!std::is_nothrow_move_assignable<C>::value, ""); + } +#endif + #endif } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits