diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst index 29ecbf3f01c8..82f1de6bad39 100644 --- a/libcxx/docs/ReleaseNotes/21.rst +++ b/libcxx/docs/ReleaseNotes/21.rst @@ -38,8 +38,7 @@ What's New in Libc++ 21.0.0? Implemented Papers ------------------ -- TODO - +- N4258: Cleaning-up noexcept in the Library (`Github `__) Improvements and New Features ----------------------------- diff --git a/libcxx/docs/Status/Cxx17Papers.csv b/libcxx/docs/Status/Cxx17Papers.csv index fbcac452adb8..24fc7f718c36 100644 --- a/libcxx/docs/Status/Cxx17Papers.csv +++ b/libcxx/docs/Status/Cxx17Papers.csv @@ -3,7 +3,7 @@ "`N4089 `__","Safe conversions in ``unique_ptr``\ .","2014-11 (Urbana)","|Complete|","5","" "`N4169 `__","A proposal to add invoke function template","2014-11 (Urbana)","|Complete|","3.7","" "`N4190 `__","Removing auto_ptr, random_shuffle(), And Old Stuff.","2014-11 (Urbana)","|Complete|","15","" -"`N4258 `__","Cleaning-up noexcept in the Library.","2014-11 (Urbana)","|In Progress|","3.7","" +"`N4258 `__","Cleaning-up noexcept in the Library.","2014-11 (Urbana)","|Complete|","21","" "`N4259 `__","Wording for std::uncaught_exceptions","2014-11 (Urbana)","|Complete|","3.7","``std::uncaught_exception`` is deprecated since LLVM 20" "`N4277 `__","TriviallyCopyable ``reference_wrapper``\ .","2014-11 (Urbana)","|Complete|","3.2","" "`N4279 `__","Improved insertion interface for unique-key maps.","2014-11 (Urbana)","|Complete|","3.7","" diff --git a/libcxx/include/__hash_table b/libcxx/include/__hash_table index 9a82ec51daee..d7b312f8774f 100644 --- a/libcxx/include/__hash_table +++ b/libcxx/include/__hash_table @@ -770,9 +770,10 @@ public: _LIBCPP_HIDE_FROM_ABI __hash_table& operator=(const __hash_table& __u); _LIBCPP_HIDE_FROM_ABI __hash_table& operator=(__hash_table&& __u) - _NOEXCEPT_(__node_traits::propagate_on_container_move_assignment::value&& - is_nothrow_move_assignable<__node_allocator>::value&& is_nothrow_move_assignable::value&& - is_nothrow_move_assignable::value); + _NOEXCEPT_(is_nothrow_move_assignable::value&& is_nothrow_move_assignable::value && + ((__node_traits::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable<__node_allocator>::value) || + allocator_traits<__node_allocator>::is_always_equal::value)); template _LIBCPP_HIDE_FROM_ABI void __assign_unique(_InputIterator __first, _InputIterator __last); template @@ -1238,10 +1239,11 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(__hash_table& __u, } template -inline __hash_table<_Tp, _Hash, _Equal, _Alloc>& -__hash_table<_Tp, _Hash, _Equal, _Alloc>::operator=(__hash_table&& __u) _NOEXCEPT_( - __node_traits::propagate_on_container_move_assignment::value&& is_nothrow_move_assignable<__node_allocator>::value&& - is_nothrow_move_assignable::value&& is_nothrow_move_assignable::value) { +inline __hash_table<_Tp, _Hash, _Equal, _Alloc>& __hash_table<_Tp, _Hash, _Equal, _Alloc>::operator=(__hash_table&& __u) + _NOEXCEPT_(is_nothrow_move_assignable::value&& is_nothrow_move_assignable::value && + ((__node_traits::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable<__node_allocator>::value) || + allocator_traits<__node_allocator>::is_always_equal::value)) { __move_assign(__u, integral_constant()); return *this; } diff --git a/libcxx/include/__tree b/libcxx/include/__tree index acad6c33f878..c627641d5d86 100644 --- a/libcxx/include/__tree +++ b/libcxx/include/__tree @@ -987,9 +987,12 @@ public: _LIBCPP_HIDE_FROM_ABI __tree(__tree&& __t) _NOEXCEPT_( is_nothrow_move_constructible<__node_allocator>::value&& is_nothrow_move_constructible::value); _LIBCPP_HIDE_FROM_ABI __tree(__tree&& __t, const allocator_type& __a); - _LIBCPP_HIDE_FROM_ABI __tree& operator=(__tree&& __t) _NOEXCEPT_( - __node_traits::propagate_on_container_move_assignment::value&& is_nothrow_move_assignable::value&& - is_nothrow_move_assignable<__node_allocator>::value); + _LIBCPP_HIDE_FROM_ABI __tree& operator=(__tree&& __t) + _NOEXCEPT_(is_nothrow_move_assignable::value && + ((__node_traits::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable<__node_allocator>::value) || + allocator_traits<__node_allocator>::is_always_equal::value)); + _LIBCPP_HIDE_FROM_ABI ~__tree(); _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return iterator(__begin_node()); } @@ -1520,11 +1523,11 @@ void __tree<_Tp, _Compare, _Allocator>::__move_assign(__tree& __t, false_type) { } template -__tree<_Tp, _Compare, _Allocator>& __tree<_Tp, _Compare, _Allocator>::operator=(__tree&& __t) _NOEXCEPT_( - __node_traits::propagate_on_container_move_assignment::value&& is_nothrow_move_assignable::value&& - is_nothrow_move_assignable<__node_allocator>::value) - -{ +__tree<_Tp, _Compare, _Allocator>& __tree<_Tp, _Compare, _Allocator>::operator=(__tree&& __t) + _NOEXCEPT_(is_nothrow_move_assignable::value && + ((__node_traits::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable<__node_allocator>::value) || + allocator_traits<__node_allocator>::is_always_equal::value)) { __move_assign(__t, integral_constant()); return *this; } diff --git a/libcxx/include/deque b/libcxx/include/deque index df3094cff7f8..95200b4801d7 100644 --- a/libcxx/include/deque +++ b/libcxx/include/deque @@ -59,9 +59,9 @@ public: deque& operator=(const deque& c); deque& operator=(deque&& c) - noexcept( - allocator_type::propagate_on_container_move_assignment::value && - is_nothrow_move_assignable::value); + noexcept((__alloc_traits::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable::value) || + allocator_traits::is_always_equal::value); deque& operator=(initializer_list il); template @@ -674,9 +674,10 @@ public: _LIBCPP_HIDE_FROM_ABI deque(deque&& __c) noexcept(is_nothrow_move_constructible::value); _LIBCPP_HIDE_FROM_ABI deque(deque&& __c, const __type_identity_t& __a); - _LIBCPP_HIDE_FROM_ABI deque& - operator=(deque&& __c) noexcept(__alloc_traits::propagate_on_container_move_assignment::value && - is_nothrow_move_assignable::value); + _LIBCPP_HIDE_FROM_ABI deque& operator=(deque&& __c) noexcept( + (__alloc_traits::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable::value) || + allocator_traits::is_always_equal::value); _LIBCPP_HIDE_FROM_ABI void assign(initializer_list __il) { assign(__il.begin(), __il.end()); } # endif // _LIBCPP_CXX03_LANG @@ -1379,8 +1380,9 @@ inline deque<_Tp, _Allocator>::deque(deque&& __c, const __type_identity_t inline deque<_Tp, _Allocator>& deque<_Tp, _Allocator>::operator=(deque&& __c) noexcept( - __alloc_traits::propagate_on_container_move_assignment::value && - is_nothrow_move_assignable::value) { + (__alloc_traits::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable::value) || + allocator_traits::is_always_equal::value) { __move_assign(__c, integral_constant()); return *this; } diff --git a/libcxx/include/forward_list b/libcxx/include/forward_list index f3b9617ab2e0..4b6ca8ea8587 100644 --- a/libcxx/include/forward_list +++ b/libcxx/include/forward_list @@ -58,9 +58,9 @@ public: forward_list& operator=(const forward_list& x); forward_list& operator=(forward_list&& x) - noexcept( - allocator_type::propagate_on_container_move_assignment::value && - is_nothrow_move_assignable::value); + noexcept((__node_traits::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable::value) || + allocator_traits::is_always_equal::value); forward_list& operator=(initializer_list il); template @@ -717,8 +717,9 @@ public: _LIBCPP_HIDE_FROM_ABI forward_list(initializer_list __il, const allocator_type& __a); _LIBCPP_HIDE_FROM_ABI forward_list& operator=(forward_list&& __x) noexcept( - __node_traits::propagate_on_container_move_assignment::value && - is_nothrow_move_assignable::value); + (__node_traits::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable::value) || + allocator_traits::is_always_equal::value); _LIBCPP_HIDE_FROM_ABI forward_list& operator=(initializer_list __il); @@ -1009,8 +1010,10 @@ void forward_list<_Tp, _Alloc>::__move_assign(forward_list& __x, false_type) { } template -inline forward_list<_Tp, _Alloc>& forward_list<_Tp, _Alloc>::operator=(forward_list&& __x) _NOEXCEPT_( - __node_traits::propagate_on_container_move_assignment::value&& is_nothrow_move_assignable::value) { +inline forward_list<_Tp, _Alloc>& forward_list<_Tp, _Alloc>::operator=(forward_list&& __x) noexcept( + (__node_traits::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable::value) || + allocator_traits::is_always_equal::value) { __move_assign(__x, integral_constant()); return *this; } diff --git a/libcxx/include/list b/libcxx/include/list index 5e2fd40d6ee9..3fcf796ebc03 100644 --- a/libcxx/include/list +++ b/libcxx/include/list @@ -60,9 +60,9 @@ public: list& operator=(const list& x); list& operator=(list&& x) - noexcept( - allocator_type::propagate_on_container_move_assignment::value && - is_nothrow_move_assignable::value); + noexcept((__node_alloc_traits::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable<__node_allocator>::value) || + allocator_traits::is_always_equal::value); list& operator=(initializer_list); template void assign(Iter first, Iter last); @@ -728,9 +728,10 @@ public: _LIBCPP_HIDE_FROM_ABI list(list&& __c) _NOEXCEPT_(is_nothrow_move_constructible<__node_allocator>::value); _LIBCPP_HIDE_FROM_ABI list(list&& __c, const __type_identity_t& __a); - _LIBCPP_HIDE_FROM_ABI list& operator=(list&& __c) - _NOEXCEPT_(__node_alloc_traits::propagate_on_container_move_assignment::value&& - is_nothrow_move_assignable<__node_allocator>::value); + _LIBCPP_HIDE_FROM_ABI list& operator=(list&& __c) noexcept( + (__node_alloc_traits::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable<__node_allocator>::value) || + allocator_traits::is_always_equal::value); _LIBCPP_HIDE_FROM_ABI list& operator=(initializer_list __il) { assign(__il.begin(), __il.end()); @@ -1067,8 +1068,9 @@ inline list<_Tp, _Alloc>::list(list&& __c, const __type_identity_t inline list<_Tp, _Alloc>& list<_Tp, _Alloc>::operator=(list&& __c) noexcept( - __node_alloc_traits::propagate_on_container_move_assignment::value && - is_nothrow_move_assignable<__node_allocator>::value) { + (__node_alloc_traits::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable<__node_allocator>::value) || + allocator_traits::is_always_equal::value) { __move_assign(__c, integral_constant()); return *this; } diff --git a/libcxx/test/std/containers/associative/map/map.cons/move_assign_noexcept.compile.pass.cpp b/libcxx/test/std/containers/associative/map/map.cons/move_assign_noexcept.compile.pass.cpp new file mode 100644 index 000000000000..a4c8ef1c5b42 --- /dev/null +++ b/libcxx/test/std/containers/associative/map/map.cons/move_assign_noexcept.compile.pass.cpp @@ -0,0 +1,61 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// map& operator=(map&& c) +// noexcept( +// allocator_type::propagate_on_container_move_assignment::value && +// is_nothrow_move_assignable::value && +// is_nothrow_move_assignable::value); + +// This tests a conforming extension + +// UNSUPPORTED: c++03 + +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "test_allocator.h" + +template +struct some_comp { + using value_type = T; + some_comp& operator=(const some_comp&); + bool operator()(const T&, const T&) const { return false; } +}; + +template +struct always_equal_alloc { + using value_type = T; + always_equal_alloc(const always_equal_alloc&); + void allocate(std::size_t); +}; + +template +struct not_always_equal_alloc { + int i; + using value_type = T; + not_always_equal_alloc(const not_always_equal_alloc&); + void allocate(std::size_t); +}; + +template