Skip to content

Commit 1818c02

Browse files
committed
[libc++] Implement N4258(Cleaning-up noexcept in the Library)
1 parent b07e7b7 commit 1818c02

29 files changed

+772
-705
lines changed

libcxx/docs/ReleaseNotes/20.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ Implemented Papers
4545
- ``std::jthread`` and ``<stop_token>`` are not guarded behind ``-fexperimental-library`` anymore
4646
- P2674R1: A trait for implicit lifetime types (`Github <https://github.com/llvm/llvm-project/issues/105259>`__)
4747
- P0429R9: A Standard ``flat_map`` is partially implemented and ``flat_map`` is provided (`Github <https://github.com/llvm/llvm-project/issues/105190>`__)
48+
- N4258: Cleaning-up noexcept in the Library (`Github <https://github.com/llvm/llvm-project/issues/99937>`__)
4849

4950
Improvements and New Features
5051
-----------------------------

libcxx/docs/Status/Cxx17Papers.csv

Lines changed: 1 addition & 1 deletion
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)","|In Progress|","3.9",""
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|","20",""
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

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -772,9 +772,16 @@ public:
772772

773773
_LIBCPP_HIDE_FROM_ABI __hash_table& operator=(const __hash_table& __u);
774774
_LIBCPP_HIDE_FROM_ABI __hash_table& operator=(__hash_table&& __u)
775-
_NOEXCEPT_(__node_traits::propagate_on_container_move_assignment::value&&
776-
is_nothrow_move_assignable<__node_allocator>::value&& is_nothrow_move_assignable<hasher>::value&&
777-
is_nothrow_move_assignable<key_equal>::value);
775+
#ifndef _LIBCPP_CXX03_LANG
776+
noexcept(is_nothrow_move_assignable<hasher>::value && is_nothrow_move_assignable<key_equal>::value &&
777+
((__node_traits::propagate_on_container_move_assignment::value &&
778+
is_nothrow_move_assignable<__node_allocator>::value)
779+
# if _LIBCPP_STD_VER >= 17
780+
|| allocator_traits<__node_allocator>::is_always_equal::value
781+
# endif
782+
))
783+
#endif
784+
;
778785
template <class _InputIterator>
779786
_LIBCPP_HIDE_FROM_ABI void __assign_unique(_InputIterator __first, _InputIterator __last);
780787
template <class _InputIterator>
@@ -1240,10 +1247,17 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(__hash_table& __u,
12401247
}
12411248

12421249
template <class _Tp, class _Hash, class _Equal, class _Alloc>
1243-
inline __hash_table<_Tp, _Hash, _Equal, _Alloc>&
1244-
__hash_table<_Tp, _Hash, _Equal, _Alloc>::operator=(__hash_table&& __u) _NOEXCEPT_(
1245-
__node_traits::propagate_on_container_move_assignment::value&& is_nothrow_move_assignable<__node_allocator>::value&&
1246-
is_nothrow_move_assignable<hasher>::value&& is_nothrow_move_assignable<key_equal>::value) {
1250+
inline __hash_table<_Tp, _Hash, _Equal, _Alloc>& __hash_table<_Tp, _Hash, _Equal, _Alloc>::operator=(__hash_table&& __u)
1251+
#ifndef _LIBCPP_CXX03_LANG
1252+
noexcept(is_nothrow_move_assignable<hasher>::value && is_nothrow_move_assignable<key_equal>::value &&
1253+
((__node_traits::propagate_on_container_move_assignment::value &&
1254+
is_nothrow_move_assignable<__node_allocator>::value)
1255+
# if _LIBCPP_STD_VER >= 17
1256+
|| allocator_traits<__node_allocator>::is_always_equal::value
1257+
# endif
1258+
))
1259+
#endif
1260+
{
12471261
__move_assign(__u, integral_constant<bool, __node_traits::propagate_on_container_move_assignment::value>());
12481262
return *this;
12491263
}

libcxx/include/__tree

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -989,9 +989,18 @@ public:
989989
_LIBCPP_HIDE_FROM_ABI __tree(__tree&& __t) _NOEXCEPT_(
990990
is_nothrow_move_constructible<__node_allocator>::value&& is_nothrow_move_constructible<value_compare>::value);
991991
_LIBCPP_HIDE_FROM_ABI __tree(__tree&& __t, const allocator_type& __a);
992-
_LIBCPP_HIDE_FROM_ABI __tree& operator=(__tree&& __t) _NOEXCEPT_(
993-
__node_traits::propagate_on_container_move_assignment::value&& is_nothrow_move_assignable<value_compare>::value&&
994-
is_nothrow_move_assignable<__node_allocator>::value);
992+
_LIBCPP_HIDE_FROM_ABI __tree& operator=(__tree&& __t)
993+
#ifndef _LIBCPP_CXX03_LANG
994+
noexcept(is_nothrow_move_assignable<value_compare>::value &&
995+
((__node_traits::propagate_on_container_move_assignment::value &&
996+
is_nothrow_move_assignable<__node_allocator>::value)
997+
# if _LIBCPP_STD_VER >= 17
998+
|| allocator_traits<__node_allocator>::is_always_equal::value)
999+
# endif
1000+
)
1001+
#endif
1002+
;
1003+
9951004
_LIBCPP_HIDE_FROM_ABI ~__tree();
9961005

9971006
_LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return iterator(__begin_node()); }
@@ -1522,10 +1531,16 @@ void __tree<_Tp, _Compare, _Allocator>::__move_assign(__tree& __t, false_type) {
15221531
}
15231532

15241533
template <class _Tp, class _Compare, class _Allocator>
1525-
__tree<_Tp, _Compare, _Allocator>& __tree<_Tp, _Compare, _Allocator>::operator=(__tree&& __t) _NOEXCEPT_(
1526-
__node_traits::propagate_on_container_move_assignment::value&& is_nothrow_move_assignable<value_compare>::value&&
1527-
is_nothrow_move_assignable<__node_allocator>::value)
1528-
1534+
__tree<_Tp, _Compare, _Allocator>& __tree<_Tp, _Compare, _Allocator>::operator=(__tree&& __t)
1535+
#ifndef _LIBCPP_CXX03_LANG
1536+
noexcept(is_nothrow_move_assignable<value_compare>::value &&
1537+
((__node_traits::propagate_on_container_move_assignment::value &&
1538+
is_nothrow_move_assignable<__node_allocator>::value)
1539+
# if _LIBCPP_STD_VER >= 17
1540+
|| allocator_traits<__node_allocator>::is_always_equal::value)
1541+
# endif
1542+
)
1543+
#endif
15291544
{
15301545
__move_assign(__t, integral_constant<bool, __node_traits::propagate_on_container_move_assignment::value>());
15311546
return *this;

libcxx/include/deque

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -672,9 +672,13 @@ public:
672672

673673
_LIBCPP_HIDE_FROM_ABI deque(deque&& __c) noexcept(is_nothrow_move_constructible<allocator_type>::value);
674674
_LIBCPP_HIDE_FROM_ABI deque(deque&& __c, const __type_identity_t<allocator_type>& __a);
675-
_LIBCPP_HIDE_FROM_ABI deque&
676-
operator=(deque&& __c) noexcept(__alloc_traits::propagate_on_container_move_assignment::value &&
677-
is_nothrow_move_assignable<allocator_type>::value);
675+
_LIBCPP_HIDE_FROM_ABI deque& operator=(deque&& __c) noexcept(
676+
(__alloc_traits::propagate_on_container_move_assignment::value &&
677+
is_nothrow_move_assignable<allocator_type>::value)
678+
# if _LIBCPP_STD_VER >= 17
679+
|| allocator_traits<allocator_type>::is_always_equal::value
680+
# endif
681+
);
678682

679683
_LIBCPP_HIDE_FROM_ABI void assign(initializer_list<value_type> __il) { assign(__il.begin(), __il.end()); }
680684
# endif // _LIBCPP_CXX03_LANG
@@ -1377,8 +1381,11 @@ inline deque<_Tp, _Allocator>::deque(deque&& __c, const __type_identity_t<alloca
13771381

13781382
template <class _Tp, class _Allocator>
13791383
inline deque<_Tp, _Allocator>& deque<_Tp, _Allocator>::operator=(deque&& __c) noexcept(
1380-
__alloc_traits::propagate_on_container_move_assignment::value &&
1381-
is_nothrow_move_assignable<allocator_type>::value) {
1384+
(__alloc_traits::propagate_on_container_move_assignment::value && is_nothrow_move_assignable<allocator_type>::value)
1385+
# if _LIBCPP_STD_VER >= 17
1386+
|| allocator_traits<allocator_type>::is_always_equal::value
1387+
# endif
1388+
) {
13821389
__move_assign(__c, integral_constant<bool, __alloc_traits::propagate_on_container_move_assignment::value>());
13831390
return *this;
13841391
}

libcxx/include/forward_list

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -714,8 +714,12 @@ public:
714714
_LIBCPP_HIDE_FROM_ABI forward_list(initializer_list<value_type> __il, const allocator_type& __a);
715715

716716
_LIBCPP_HIDE_FROM_ABI forward_list& operator=(forward_list&& __x) noexcept(
717-
__node_traits::propagate_on_container_move_assignment::value &&
718-
is_nothrow_move_assignable<allocator_type>::value);
717+
(__node_traits::propagate_on_container_move_assignment::value &&
718+
is_nothrow_move_assignable<allocator_type>::value)
719+
# if _LIBCPP_STD_VER >= 17
720+
|| allocator_traits<allocator_type>::is_always_equal::value
721+
# endif
722+
);
719723

720724
_LIBCPP_HIDE_FROM_ABI forward_list& operator=(initializer_list<value_type> __il);
721725

@@ -1000,8 +1004,12 @@ void forward_list<_Tp, _Alloc>::__move_assign(forward_list& __x, false_type) {
10001004
}
10011005

10021006
template <class _Tp, class _Alloc>
1003-
inline forward_list<_Tp, _Alloc>& forward_list<_Tp, _Alloc>::operator=(forward_list&& __x) _NOEXCEPT_(
1004-
__node_traits::propagate_on_container_move_assignment::value&& is_nothrow_move_assignable<allocator_type>::value) {
1007+
inline forward_list<_Tp, _Alloc>& forward_list<_Tp, _Alloc>::operator=(forward_list&& __x) noexcept(
1008+
(__node_traits::propagate_on_container_move_assignment::value && is_nothrow_move_assignable<allocator_type>::value)
1009+
# if _LIBCPP_STD_VER >= 17
1010+
|| allocator_traits<allocator_type>::is_always_equal::value
1011+
# endif
1012+
) {
10051013
__move_assign(__x, integral_constant<bool, __node_traits::propagate_on_container_move_assignment::value>());
10061014
return *this;
10071015
}

libcxx/include/list

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -727,9 +727,13 @@ public:
727727

728728
_LIBCPP_HIDE_FROM_ABI list(list&& __c) _NOEXCEPT_(is_nothrow_move_constructible<__node_allocator>::value);
729729
_LIBCPP_HIDE_FROM_ABI list(list&& __c, const __type_identity_t<allocator_type>& __a);
730-
_LIBCPP_HIDE_FROM_ABI list& operator=(list&& __c)
731-
_NOEXCEPT_(__node_alloc_traits::propagate_on_container_move_assignment::value&&
732-
is_nothrow_move_assignable<__node_allocator>::value);
730+
_LIBCPP_HIDE_FROM_ABI list& operator=(list&& __c) noexcept(
731+
(__node_alloc_traits::propagate_on_container_move_assignment::value &&
732+
is_nothrow_move_assignable<__node_allocator>::value)
733+
# if _LIBCPP_STD_VER >= 17
734+
|| allocator_traits<allocator_type>::is_always_equal::value
735+
# endif
736+
);
733737

734738
_LIBCPP_HIDE_FROM_ABI list& operator=(initializer_list<value_type> __il) {
735739
assign(__il.begin(), __il.end());
@@ -1066,8 +1070,12 @@ inline list<_Tp, _Alloc>::list(list&& __c, const __type_identity_t<allocator_typ
10661070

10671071
template <class _Tp, class _Alloc>
10681072
inline list<_Tp, _Alloc>& list<_Tp, _Alloc>::operator=(list&& __c) noexcept(
1069-
__node_alloc_traits::propagate_on_container_move_assignment::value &&
1070-
is_nothrow_move_assignable<__node_allocator>::value) {
1073+
(__node_alloc_traits::propagate_on_container_move_assignment::value &&
1074+
is_nothrow_move_assignable<__node_allocator>::value)
1075+
# if _LIBCPP_STD_VER >= 17
1076+
|| allocator_traits<allocator_type>::is_always_equal::value
1077+
# endif
1078+
) {
10711079
__move_assign(__c, integral_constant<bool, __node_alloc_traits::propagate_on_container_move_assignment::value>());
10721080
return *this;
10731081
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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 "MoveOnly.h"
24+
#include "test_allocator.h"
25+
26+
template <class T>
27+
struct some_comp {
28+
using value_type = T;
29+
some_comp& operator=(const some_comp&);
30+
bool operator()(const T&, const T&) const { return false; }
31+
};
32+
33+
template <class T>
34+
struct always_equal_alloc {
35+
using value_type = T;
36+
always_equal_alloc(const always_equal_alloc&);
37+
void allocate(std::size_t);
38+
};
39+
40+
template <class T>
41+
struct not_always_equal_alloc {
42+
int i;
43+
using value_type = T;
44+
not_always_equal_alloc(const not_always_equal_alloc&);
45+
void allocate(std::size_t);
46+
};
47+
48+
template <template <class> class Alloc>
49+
using multimap_alloc = std::map<MoveOnly, MoveOnly, std::less<MoveOnly>, Alloc<std::pair<const MoveOnly, MoveOnly>>>;
50+
51+
static_assert(std::is_nothrow_move_assignable<multimap_alloc<std::allocator>>::value, "");
52+
static_assert(!std::is_nothrow_move_assignable<multimap_alloc<test_allocator>>::value, "");
53+
static_assert(std::is_nothrow_move_assignable<multimap_alloc<always_equal_alloc>>::value, "");
54+
static_assert(!std::is_nothrow_move_assignable<multimap_alloc<not_always_equal_alloc>>::value, "");
55+
#if defined(_LIBCPP_VERSION)
56+
static_assert(std::is_nothrow_move_assignable<multimap_alloc<other_allocator>>::value, "");
57+
#endif // _LIBCPP_VERSION
58+
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

Lines changed: 0 additions & 59 deletions
This file was deleted.
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
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 "MoveOnly.h"
24+
#include "test_allocator.h"
25+
26+
template <class T>
27+
struct some_comp {
28+
using value_type = T;
29+
some_comp& operator=(const some_comp&);
30+
bool operator()(const T&, const T&) const { return false; }
31+
};
32+
33+
template <class T>
34+
struct always_equal_alloc {
35+
using value_type = T;
36+
always_equal_alloc(const always_equal_alloc&);
37+
void allocate(std::size_t);
38+
};
39+
40+
template <class T>
41+
struct not_always_equal_alloc {
42+
int i;
43+
using value_type = T;
44+
not_always_equal_alloc(const not_always_equal_alloc&);
45+
void allocate(std::size_t);
46+
};
47+
48+
template <template <class> class Alloc>
49+
using multimap_alloc =
50+
std::multimap<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+
static_assert(std::is_nothrow_move_assignable<multimap_alloc<always_equal_alloc>>::value, "");
55+
static_assert(!std::is_nothrow_move_assignable<multimap_alloc<not_always_equal_alloc>>::value, "");
56+
#if defined(_LIBCPP_VERSION)
57+
static_assert(std::is_nothrow_move_assignable<multimap_alloc<other_allocator>>::value, "");
58+
#endif // _LIBCPP_VERSION
59+
static_assert(!std::is_nothrow_move_assignable<std::multimap<int, int, some_comp<int>>>::value, "");

0 commit comments

Comments
 (0)