Skip to content

Commit fcc4ceb

Browse files
authored
[libc++] Implement N4258(Cleaning-up noexcept in the Library) (#120312)
Fixes #99937
1 parent 4f358d7 commit fcc4ceb

29 files changed

+747
-747
lines changed

libcxx/docs/ReleaseNotes/21.rst

+1-2
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@ What's New in Libc++ 21.0.0?
3838
Implemented Papers
3939
------------------
4040

41-
- TODO
42-
41+
- N4258: Cleaning-up noexcept in the Library (`Github <https://github.com/llvm/llvm-project/issues/99937>`__)
4342

4443
Improvements and New Features
4544
-----------------------------

libcxx/docs/Status/Cxx17Papers.csv

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"`N4089 <https://wg21.link/N4089>`__","Safe conversions in ``unique_ptr<T[]>``\ .","2014-11 (Urbana)","|Complete|","5",""
44
"`N4169 <https://wg21.link/N4169>`__","A proposal to add invoke function template","2014-11 (Urbana)","|Complete|","3.7",""
55
"`N4190 <https://wg21.link/N4190>`__","Removing auto_ptr, random_shuffle(), And Old <functional> Stuff.","2014-11 (Urbana)","|Complete|","15",""
6-
"`N4258 <https://wg21.link/N4258>`__","Cleaning-up noexcept in the Library.","2014-11 (Urbana)","|In Progress|","3.7",""
6+
"`N4258 <https://wg21.link/N4258>`__","Cleaning-up noexcept in the Library.","2014-11 (Urbana)","|Complete|","21",""
77
"`N4259 <https://wg21.link/N4259>`__","Wording for std::uncaught_exceptions","2014-11 (Urbana)","|Complete|","3.7","``std::uncaught_exception`` is deprecated since LLVM 20"
88
"`N4277 <https://wg21.link/N4277>`__","TriviallyCopyable ``reference_wrapper``\ .","2014-11 (Urbana)","|Complete|","3.2",""
99
"`N4279 <https://wg21.link/N4279>`__","Improved insertion interface for unique-key maps.","2014-11 (Urbana)","|Complete|","3.7",""

libcxx/include/__hash_table

+9-7
Original file line numberDiff line numberDiff line change
@@ -770,9 +770,10 @@ public:
770770

771771
_LIBCPP_HIDE_FROM_ABI __hash_table& operator=(const __hash_table& __u);
772772
_LIBCPP_HIDE_FROM_ABI __hash_table& operator=(__hash_table&& __u)
773-
_NOEXCEPT_(__node_traits::propagate_on_container_move_assignment::value&&
774-
is_nothrow_move_assignable<__node_allocator>::value&& is_nothrow_move_assignable<hasher>::value&&
775-
is_nothrow_move_assignable<key_equal>::value);
773+
_NOEXCEPT_(is_nothrow_move_assignable<hasher>::value&& is_nothrow_move_assignable<key_equal>::value &&
774+
((__node_traits::propagate_on_container_move_assignment::value &&
775+
is_nothrow_move_assignable<__node_allocator>::value) ||
776+
allocator_traits<__node_allocator>::is_always_equal::value));
776777
template <class _InputIterator>
777778
_LIBCPP_HIDE_FROM_ABI void __assign_unique(_InputIterator __first, _InputIterator __last);
778779
template <class _InputIterator>
@@ -1238,10 +1239,11 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(__hash_table& __u,
12381239
}
12391240

12401241
template <class _Tp, class _Hash, class _Equal, class _Alloc>
1241-
inline __hash_table<_Tp, _Hash, _Equal, _Alloc>&
1242-
__hash_table<_Tp, _Hash, _Equal, _Alloc>::operator=(__hash_table&& __u) _NOEXCEPT_(
1243-
__node_traits::propagate_on_container_move_assignment::value&& is_nothrow_move_assignable<__node_allocator>::value&&
1244-
is_nothrow_move_assignable<hasher>::value&& is_nothrow_move_assignable<key_equal>::value) {
1242+
inline __hash_table<_Tp, _Hash, _Equal, _Alloc>& __hash_table<_Tp, _Hash, _Equal, _Alloc>::operator=(__hash_table&& __u)
1243+
_NOEXCEPT_(is_nothrow_move_assignable<hasher>::value&& is_nothrow_move_assignable<key_equal>::value &&
1244+
((__node_traits::propagate_on_container_move_assignment::value &&
1245+
is_nothrow_move_assignable<__node_allocator>::value) ||
1246+
allocator_traits<__node_allocator>::is_always_equal::value)) {
12451247
__move_assign(__u, integral_constant<bool, __node_traits::propagate_on_container_move_assignment::value>());
12461248
return *this;
12471249
}

libcxx/include/__tree

+11-8
Original file line numberDiff line numberDiff line change
@@ -987,9 +987,12 @@ public:
987987
_LIBCPP_HIDE_FROM_ABI __tree(__tree&& __t) _NOEXCEPT_(
988988
is_nothrow_move_constructible<__node_allocator>::value&& is_nothrow_move_constructible<value_compare>::value);
989989
_LIBCPP_HIDE_FROM_ABI __tree(__tree&& __t, const allocator_type& __a);
990-
_LIBCPP_HIDE_FROM_ABI __tree& operator=(__tree&& __t) _NOEXCEPT_(
991-
__node_traits::propagate_on_container_move_assignment::value&& is_nothrow_move_assignable<value_compare>::value&&
992-
is_nothrow_move_assignable<__node_allocator>::value);
990+
_LIBCPP_HIDE_FROM_ABI __tree& operator=(__tree&& __t)
991+
_NOEXCEPT_(is_nothrow_move_assignable<value_compare>::value &&
992+
((__node_traits::propagate_on_container_move_assignment::value &&
993+
is_nothrow_move_assignable<__node_allocator>::value) ||
994+
allocator_traits<__node_allocator>::is_always_equal::value));
995+
993996
_LIBCPP_HIDE_FROM_ABI ~__tree();
994997

995998
_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) {
15201523
}
15211524

15221525
template <class _Tp, class _Compare, class _Allocator>
1523-
__tree<_Tp, _Compare, _Allocator>& __tree<_Tp, _Compare, _Allocator>::operator=(__tree&& __t) _NOEXCEPT_(
1524-
__node_traits::propagate_on_container_move_assignment::value&& is_nothrow_move_assignable<value_compare>::value&&
1525-
is_nothrow_move_assignable<__node_allocator>::value)
1526-
1527-
{
1526+
__tree<_Tp, _Compare, _Allocator>& __tree<_Tp, _Compare, _Allocator>::operator=(__tree&& __t)
1527+
_NOEXCEPT_(is_nothrow_move_assignable<value_compare>::value &&
1528+
((__node_traits::propagate_on_container_move_assignment::value &&
1529+
is_nothrow_move_assignable<__node_allocator>::value) ||
1530+
allocator_traits<__node_allocator>::is_always_equal::value)) {
15281531
__move_assign(__t, integral_constant<bool, __node_traits::propagate_on_container_move_assignment::value>());
15291532
return *this;
15301533
}

libcxx/include/deque

+10-8
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,9 @@ public:
5959
6060
deque& operator=(const deque& c);
6161
deque& operator=(deque&& c)
62-
noexcept(
63-
allocator_type::propagate_on_container_move_assignment::value &&
64-
is_nothrow_move_assignable<allocator_type>::value);
62+
noexcept((__alloc_traits::propagate_on_container_move_assignment::value &&
63+
is_nothrow_move_assignable<allocator_type>::value) ||
64+
allocator_traits<allocator_type>::is_always_equal::value);
6565
deque& operator=(initializer_list<value_type> il);
6666
6767
template <class InputIterator>
@@ -674,9 +674,10 @@ public:
674674

675675
_LIBCPP_HIDE_FROM_ABI deque(deque&& __c) noexcept(is_nothrow_move_constructible<allocator_type>::value);
676676
_LIBCPP_HIDE_FROM_ABI deque(deque&& __c, const __type_identity_t<allocator_type>& __a);
677-
_LIBCPP_HIDE_FROM_ABI deque&
678-
operator=(deque&& __c) noexcept(__alloc_traits::propagate_on_container_move_assignment::value &&
679-
is_nothrow_move_assignable<allocator_type>::value);
677+
_LIBCPP_HIDE_FROM_ABI deque& operator=(deque&& __c) noexcept(
678+
(__alloc_traits::propagate_on_container_move_assignment::value &&
679+
is_nothrow_move_assignable<allocator_type>::value) ||
680+
allocator_traits<allocator_type>::is_always_equal::value);
680681

681682
_LIBCPP_HIDE_FROM_ABI void assign(initializer_list<value_type> __il) { assign(__il.begin(), __il.end()); }
682683
# endif // _LIBCPP_CXX03_LANG
@@ -1379,8 +1380,9 @@ inline deque<_Tp, _Allocator>::deque(deque&& __c, const __type_identity_t<alloca
13791380

13801381
template <class _Tp, class _Allocator>
13811382
inline deque<_Tp, _Allocator>& deque<_Tp, _Allocator>::operator=(deque&& __c) noexcept(
1382-
__alloc_traits::propagate_on_container_move_assignment::value &&
1383-
is_nothrow_move_assignable<allocator_type>::value) {
1383+
(__alloc_traits::propagate_on_container_move_assignment::value &&
1384+
is_nothrow_move_assignable<allocator_type>::value) ||
1385+
allocator_traits<allocator_type>::is_always_equal::value) {
13841386
__move_assign(__c, integral_constant<bool, __alloc_traits::propagate_on_container_move_assignment::value>());
13851387
return *this;
13861388
}

libcxx/include/forward_list

+10-7
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ public:
5858
5959
forward_list& operator=(const forward_list& x);
6060
forward_list& operator=(forward_list&& x)
61-
noexcept(
62-
allocator_type::propagate_on_container_move_assignment::value &&
63-
is_nothrow_move_assignable<allocator_type>::value);
61+
noexcept((__node_traits::propagate_on_container_move_assignment::value &&
62+
is_nothrow_move_assignable<allocator_type>::value) ||
63+
allocator_traits<allocator_type>::is_always_equal::value);
6464
forward_list& operator=(initializer_list<value_type> il);
6565
6666
template <class InputIterator>
@@ -717,8 +717,9 @@ public:
717717
_LIBCPP_HIDE_FROM_ABI forward_list(initializer_list<value_type> __il, const allocator_type& __a);
718718

719719
_LIBCPP_HIDE_FROM_ABI forward_list& operator=(forward_list&& __x) noexcept(
720-
__node_traits::propagate_on_container_move_assignment::value &&
721-
is_nothrow_move_assignable<allocator_type>::value);
720+
(__node_traits::propagate_on_container_move_assignment::value &&
721+
is_nothrow_move_assignable<allocator_type>::value) ||
722+
allocator_traits<allocator_type>::is_always_equal::value);
722723

723724
_LIBCPP_HIDE_FROM_ABI forward_list& operator=(initializer_list<value_type> __il);
724725

@@ -1009,8 +1010,10 @@ void forward_list<_Tp, _Alloc>::__move_assign(forward_list& __x, false_type) {
10091010
}
10101011

10111012
template <class _Tp, class _Alloc>
1012-
inline forward_list<_Tp, _Alloc>& forward_list<_Tp, _Alloc>::operator=(forward_list&& __x) _NOEXCEPT_(
1013-
__node_traits::propagate_on_container_move_assignment::value&& is_nothrow_move_assignable<allocator_type>::value) {
1013+
inline forward_list<_Tp, _Alloc>& forward_list<_Tp, _Alloc>::operator=(forward_list&& __x) noexcept(
1014+
(__node_traits::propagate_on_container_move_assignment::value &&
1015+
is_nothrow_move_assignable<allocator_type>::value) ||
1016+
allocator_traits<allocator_type>::is_always_equal::value) {
10141017
__move_assign(__x, integral_constant<bool, __node_traits::propagate_on_container_move_assignment::value>());
10151018
return *this;
10161019
}

libcxx/include/list

+10-8
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,9 @@ public:
6060
6161
list& operator=(const list& x);
6262
list& operator=(list&& x)
63-
noexcept(
64-
allocator_type::propagate_on_container_move_assignment::value &&
65-
is_nothrow_move_assignable<allocator_type>::value);
63+
noexcept((__node_alloc_traits::propagate_on_container_move_assignment::value &&
64+
is_nothrow_move_assignable<__node_allocator>::value) ||
65+
allocator_traits<allocator_type>::is_always_equal::value);
6666
list& operator=(initializer_list<value_type>);
6767
template <class Iter>
6868
void assign(Iter first, Iter last);
@@ -728,9 +728,10 @@ public:
728728

729729
_LIBCPP_HIDE_FROM_ABI list(list&& __c) _NOEXCEPT_(is_nothrow_move_constructible<__node_allocator>::value);
730730
_LIBCPP_HIDE_FROM_ABI list(list&& __c, const __type_identity_t<allocator_type>& __a);
731-
_LIBCPP_HIDE_FROM_ABI list& operator=(list&& __c)
732-
_NOEXCEPT_(__node_alloc_traits::propagate_on_container_move_assignment::value&&
733-
is_nothrow_move_assignable<__node_allocator>::value);
731+
_LIBCPP_HIDE_FROM_ABI list& operator=(list&& __c) noexcept(
732+
(__node_alloc_traits::propagate_on_container_move_assignment::value &&
733+
is_nothrow_move_assignable<__node_allocator>::value) ||
734+
allocator_traits<allocator_type>::is_always_equal::value);
734735

735736
_LIBCPP_HIDE_FROM_ABI list& operator=(initializer_list<value_type> __il) {
736737
assign(__il.begin(), __il.end());
@@ -1067,8 +1068,9 @@ inline list<_Tp, _Alloc>::list(list&& __c, const __type_identity_t<allocator_typ
10671068

10681069
template <class _Tp, class _Alloc>
10691070
inline list<_Tp, _Alloc>& list<_Tp, _Alloc>::operator=(list&& __c) noexcept(
1070-
__node_alloc_traits::propagate_on_container_move_assignment::value &&
1071-
is_nothrow_move_assignable<__node_allocator>::value) {
1071+
(__node_alloc_traits::propagate_on_container_move_assignment::value &&
1072+
is_nothrow_move_assignable<__node_allocator>::value) ||
1073+
allocator_traits<allocator_type>::is_always_equal::value) {
10721074
__move_assign(__c, integral_constant<bool, __node_alloc_traits::propagate_on_container_move_assignment::value>());
10731075
return *this;
10741076
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// <map>
10+
11+
// map& operator=(map&& c)
12+
// noexcept(
13+
// allocator_type::propagate_on_container_move_assignment::value &&
14+
// is_nothrow_move_assignable<allocator_type>::value &&
15+
// is_nothrow_move_assignable<key_compare>::value);
16+
17+
// This tests a conforming extension
18+
19+
// UNSUPPORTED: c++03
20+
21+
#include <map>
22+
23+
#include "test_macros.h"
24+
#include "MoveOnly.h"
25+
#include "test_allocator.h"
26+
27+
template <class T>
28+
struct some_comp {
29+
using value_type = T;
30+
some_comp& operator=(const some_comp&);
31+
bool operator()(const T&, const T&) const { return false; }
32+
};
33+
34+
template <class T>
35+
struct always_equal_alloc {
36+
using value_type = T;
37+
always_equal_alloc(const always_equal_alloc&);
38+
void allocate(std::size_t);
39+
};
40+
41+
template <class T>
42+
struct not_always_equal_alloc {
43+
int i;
44+
using value_type = T;
45+
not_always_equal_alloc(const not_always_equal_alloc&);
46+
void allocate(std::size_t);
47+
};
48+
49+
template <template <class> class Alloc>
50+
using multimap_alloc = std::map<MoveOnly, MoveOnly, std::less<MoveOnly>, Alloc<std::pair<const MoveOnly, MoveOnly>>>;
51+
52+
static_assert(std::is_nothrow_move_assignable<multimap_alloc<std::allocator>>::value, "");
53+
static_assert(!std::is_nothrow_move_assignable<multimap_alloc<test_allocator>>::value, "");
54+
#if TEST_STD_VER >= 17
55+
static_assert(std::is_nothrow_move_assignable<multimap_alloc<always_equal_alloc>>::value, "");
56+
#endif
57+
static_assert(!std::is_nothrow_move_assignable<multimap_alloc<not_always_equal_alloc>>::value, "");
58+
#if defined(_LIBCPP_VERSION)
59+
static_assert(std::is_nothrow_move_assignable<multimap_alloc<other_allocator>>::value, "");
60+
#endif // _LIBCPP_VERSION
61+
static_assert(!std::is_nothrow_move_assignable<std::map<int, int, some_comp<int>>>::value, "");

libcxx/test/std/containers/associative/map/map.cons/move_assign_noexcept.pass.cpp

-59
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// <map>
10+
11+
// multimap& operator=(multimap&& c)
12+
// noexcept(
13+
// allocator_type::propagate_on_container_move_assignment::value &&
14+
// is_nothrow_move_assignable<allocator_type>::value &&
15+
// is_nothrow_move_assignable<key_compare>::value);
16+
17+
// This tests a conforming extension
18+
19+
// UNSUPPORTED: c++03
20+
21+
#include <map>
22+
23+
#include "test_macros.h"
24+
#include "MoveOnly.h"
25+
#include "test_allocator.h"
26+
27+
template <class T>
28+
struct some_comp {
29+
using value_type = T;
30+
some_comp& operator=(const some_comp&);
31+
bool operator()(const T&, const T&) const { return false; }
32+
};
33+
34+
template <class T>
35+
struct always_equal_alloc {
36+
using value_type = T;
37+
always_equal_alloc(const always_equal_alloc&);
38+
void allocate(std::size_t);
39+
};
40+
41+
template <class T>
42+
struct not_always_equal_alloc {
43+
int i;
44+
using value_type = T;
45+
not_always_equal_alloc(const not_always_equal_alloc&);
46+
void allocate(std::size_t);
47+
};
48+
49+
template <template <class> class Alloc>
50+
using multimap_alloc =
51+
std::multimap<MoveOnly, MoveOnly, std::less<MoveOnly>, Alloc<std::pair<const MoveOnly, MoveOnly>>>;
52+
53+
static_assert(std::is_nothrow_move_assignable<multimap_alloc<std::allocator>>::value, "");
54+
static_assert(!std::is_nothrow_move_assignable<multimap_alloc<test_allocator>>::value, "");
55+
#if TEST_STD_VER >= 17
56+
static_assert(std::is_nothrow_move_assignable<multimap_alloc<always_equal_alloc>>::value, "");
57+
#endif
58+
static_assert(!std::is_nothrow_move_assignable<multimap_alloc<not_always_equal_alloc>>::value, "");
59+
#if defined(_LIBCPP_VERSION)
60+
static_assert(std::is_nothrow_move_assignable<multimap_alloc<other_allocator>>::value, "");
61+
#endif // _LIBCPP_VERSION
62+
static_assert(!std::is_nothrow_move_assignable<std::multimap<int, int, some_comp<int>>>::value, "");

0 commit comments

Comments
 (0)