[libcxx-commits] [PATCH] D111481: [libc++] P2401: conditional noexcept for std::exchange

Arthur O'Dwyer via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Sat Oct 9 14:45:06 PDT 2021


Quuxplusone requested changes to this revision.
Quuxplusone added a comment.
This revision now requires changes to proceed.

Requesting changes, but pretty minor ones. The idea LGTM in general.



================
Comment at: libcxx/docs/Status/Cxx2bPapers.csv:39
 "`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"
 "","","","","",""
----------------
`s/Complete/|Complete|/`


================
Comment at: libcxx/include/__utility/exchange.h:26
 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)
 {
----------------
I'd prefer to see the `noexcept`-clause broken onto the next line (and indented), for readability:
```
_T1 exchange(_T1& __obj, _T2&& __new_value)
    noexcept(is_nothrow_move_constructible<_T1>::value && is_nothrow_assignable<_T1&, _T2>::value)
```
There's also a pre-existing bogus extra space in `_T2 && __new_value`.


================
Comment at: libcxx/test/std/utilities/utility/exchange/exchange.pass.cpp:45
+  TestExchangeNoexcept(TestExchangeNoexcept&&) noexcept(Move);
+  void operator=(const TestExchangeNoexcept&) noexcept(Assign);
+};
----------------
Mildly weird that you're using move-construction but copy-assignment. (It'd be less weird if you were testing all 4-or-whatever permutations of move and copy operations, but you're not.)
I suggest more like
```
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);
};
```
(No need for `Exchange` in the name of the class, because this whole file is about `std::exchange`.)


================
Comment at: libcxx/test/std/utilities/utility/exchange/exchange.pass.cpp:49-64
+  int v = 42;
+  static_assert(std::is_nothrow_move_constructible_v<int>);
+  static_assert(std::is_nothrow_assignable_v<int&, int>);
+  ASSERT_NOEXCEPT(std::exchange(v, {}));
+
+  using NothrowMoveConstructible = TestExchangeNoexcept<true, false>;
+  NothrowMoveConstructible nothrow_move_constructible{};
----------------
Contrary to @mordante's request, I'd prefer to simplify this code until no typedef is needed. I'd write the whole function's body as simply
```
{
    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)));
}
```


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D111481/new/

https://reviews.llvm.org/D111481



More information about the libcxx-commits mailing list