diff --git a/libcxx/docs/Status/Cxx2bPapers.csv b/libcxx/docs/Status/Cxx2bPapers.csv --- a/libcxx/docs/Status/Cxx2bPapers.csv +++ b/libcxx/docs/Status/Cxx2bPapers.csv @@ -36,5 +36,5 @@ "`P2321 `__","LWG","``zip``","October 2021","","" "`P2340 `__","LWG","Clarifying the status of the 'C headers'","October 2021","","" "`P2393 `__","LWG","Cleaning up ``integer``-class types","October 2021","","" -"`P2401 `__","LWG","Add a conditional ``noexcept`` specification to ``std::exchange``","October 2021","","" +"`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 --- 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 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header @@ -22,7 +23,7 @@ #if _LIBCPP_STD_VER > 11 template 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_v<_T1> && is_nothrow_assignable_v<_T1&, _T2>) { _T1 __old_value = _VSTD::move(__obj); __obj = _VSTD::forward<_T2>(__new_value); diff --git a/libcxx/test/std/utilities/utility/exchange/exchange.pass.cpp b/libcxx/test/std/utilities/utility/exchange/exchange.pass.cpp --- a/libcxx/test/std/utilities/utility/exchange/exchange.pass.cpp +++ b/libcxx/test/std/utilities/utility/exchange/exchange.pass.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include "test_macros.h" @@ -37,6 +38,31 @@ } #endif +template +struct TestExchangeNoexcept{ + TestExchangeNoexcept() = default; + TestExchangeNoexcept(TestExchangeNoexcept&&) noexcept(Move); + void operator=(const TestExchangeNoexcept&) noexcept(Assign); +}; + +constexpr bool test_noexcept() { + int v = 42; + static_assert(std::is_nothrow_move_constructible_v); + static_assert(std::is_nothrow_assignable_v); + ASSERT_NOEXCEPT(std::exchange(v, {})); + + TestExchangeNoexcept nothrow_move_constructible{}; + static_assert(std::is_nothrow_move_constructible_v); + static_assert(!std::is_nothrow_assignable_v); + ASSERT_NOT_NOEXCEPT(std::exchange(nothrow_move_constructible, {})); + + TestExchangeNoexcept nothrow_assignable{}; + static_assert(!std::is_nothrow_move_constructible_v); + static_assert(std::is_nothrow_assignable_v); + ASSERT_NOT_NOEXCEPT(std::exchange(nothrow_assignable, {})); + + return true; +} int main(int, char**) @@ -81,5 +107,8 @@ static_assert(test_constexpr()); #endif + test_noexcept(); + static_assert(test_noexcept()); + return 0; }