[libcxx-commits] [libcxx] 0d450aa - [libc++] P2401: conditional noexcept for std::exchange

Joe Loser via libcxx-commits libcxx-commits at lists.llvm.org
Mon Oct 11 11:35:36 PDT 2021


Author: Joe Loser
Date: 2021-10-11T14:34:45-04:00
New Revision: 0d450aa641f94ae2e50cc38438ad1b52e3ed900f

URL: https://github.com/llvm/llvm-project/commit/0d450aa641f94ae2e50cc38438ad1b52e3ed900f
DIFF: https://github.com/llvm/llvm-project/commit/0d450aa641f94ae2e50cc38438ad1b52e3ed900f.diff

LOG: [libc++] P2401: conditional noexcept for std::exchange

Implement P2401 which adds a `noexcept` specification to
`std::exchange`. Treated as a defect fix which is the motivation for
applying this change to all standards mode rather than just C++23 or
later as the paper suggests.

Reviewed By: Quuxplusone, Mordante, #libc

Differential Revision: https://reviews.llvm.org/D111481

Added: 
    

Modified: 
    libcxx/docs/Status/Cxx2bPapers.csv
    libcxx/include/__utility/exchange.h
    libcxx/include/utility
    libcxx/test/std/utilities/utility/exchange/exchange.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/Status/Cxx2bPapers.csv b/libcxx/docs/Status/Cxx2bPapers.csv
index a6bc898effd5d..5ebaa89d0dab8 100644
--- a/libcxx/docs/Status/Cxx2bPapers.csv
+++ b/libcxx/docs/Status/Cxx2bPapers.csv
@@ -36,5 +36,5 @@
 "`P2321 <https://wg21.link/P2321>`__","LWG","``zip``","October 2021","",""
 "`P2340 <https://wg21.link/P2340>`__","LWG","Clarifying the status of the 'C headers'","October 2021","",""
 "`P2393 <https://wg21.link/P2393>`__","LWG","Cleaning up ``integer``-class types","October 2021","",""
-"`P2401 <https://wg21.link/P2401>`__","LWG","Add a conditional ``noexcept`` specification to ``std::exchange``","October 2021","",""
+"`P2401 <https://wg21.link/P2401>`__","LWG","Add a conditional ``noexcept`` specification to ``std::exchange``","October 2021","|Complete|","14.0"
 "","","","","",""

diff  --git a/libcxx/include/__utility/exchange.h b/libcxx/include/__utility/exchange.h
index 9e20219ebddf9..f9c92c622f544 100644
--- a/libcxx/include/__utility/exchange.h
+++ b/libcxx/include/__utility/exchange.h
@@ -12,6 +12,7 @@
 #include <__config>
 #include <__utility/forward.h>
 #include <__utility/move.h>
+#include <type_traits>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
@@ -22,7 +23,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 #if _LIBCPP_STD_VER > 11
 template<class _T1, class _T2 = _T1>
 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
-_T1 exchange(_T1& __obj, _T2 && __new_value)
+_T1 exchange(_T1& __obj, _T2&& __new_value)
+    noexcept(is_nothrow_move_constructible<_T1>::value && is_nothrow_assignable<_T1&, _T2>::value)
 {
     _T1 __old_value = _VSTD::move(__obj);
     __obj = _VSTD::forward<_T2>(__new_value);

diff  --git a/libcxx/include/utility b/libcxx/include/utility
index 6c9da84253cf4..7d021d9580299 100644
--- a/libcxx/include/utility
+++ b/libcxx/include/utility
@@ -183,7 +183,8 @@ template<class... T>
   using index_sequence_for = make_index_sequence<sizeof...(T)>;
 
 template<class T, class U=T>
-    T exchange(T& obj, U&& new_value);
+    constexpr T exchange(T& obj, U&& new_value)
+      noexcept(is_nothrow_move_constructible<T>::value && is_nothrow_assignable<T&, U>::value); // constexpr in C++17, noexcept in C++23
 
 // 20.2.7, in-place construction // C++17
 struct in_place_t {

diff  --git a/libcxx/test/std/utilities/utility/exchange/exchange.pass.cpp b/libcxx/test/std/utilities/utility/exchange/exchange.pass.cpp
index c38dd06cc2980..da5bf346826a8 100644
--- a/libcxx/test/std/utilities/utility/exchange/exchange.pass.cpp
+++ b/libcxx/test/std/utilities/utility/exchange/exchange.pass.cpp
@@ -13,7 +13,8 @@
 
 // template<class T, class U=T>
 //    constexpr T            // constexpr after C++17
-//    exchange(T& obj, U&& new_value);
+//    exchange(T& obj, U&& new_value)
+//      noexcept(is_nothrow_move_constructible<T>::value && is_nothrow_assignable<T&, U>::value);
 
 #include <utility>
 #include <cassert>
@@ -37,7 +38,36 @@ TEST_CONSTEXPR bool test_constexpr() {
     }
 #endif
 
-
+template<bool Move, bool Assign>
+struct TestNoexcept {
+    TestNoexcept() = default;
+    TestNoexcept(const TestNoexcept&);
+    TestNoexcept(TestNoexcept&&) noexcept(Move);
+    TestNoexcept& operator=(const TestNoexcept&);
+    TestNoexcept& operator=(TestNoexcept&&) noexcept(Assign);
+};
+
+constexpr bool test_noexcept() {
+  {
+    int x = 42;
+    ASSERT_NOEXCEPT(std::exchange(x, 42));
+  }
+  {
+    TestNoexcept<true, true> x;
+    ASSERT_NOEXCEPT(std::exchange(x, std::move(x)));
+    ASSERT_NOT_NOEXCEPT(std::exchange(x, x)); // copy-assignment is not noexcept
+  }
+  {
+    TestNoexcept<true, false> x;
+    ASSERT_NOT_NOEXCEPT(std::exchange(x, std::move(x)));
+  }
+  {
+    TestNoexcept<false, true> x;
+    ASSERT_NOT_NOEXCEPT(std::exchange(x, std::move(x)));
+  }
+
+  return true;
+}
 
 int main(int, char**)
 {
@@ -81,5 +111,7 @@ int main(int, char**)
     static_assert(test_constexpr());
 #endif
 
+    static_assert(test_noexcept(), "");
+
   return 0;
 }


        


More information about the libcxx-commits mailing list