This is an archive of the discontinued LLVM Phabricator instance.

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

Authored by jloser on Oct 8 2021, 8:28 PM.

Details

Summary

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.

Diff Detail

Event Timeline

jloser requested review of this revision.Oct 8 2021, 8:28 PM
jloser created this revision.
Herald added a project: Restricted Project. · View Herald TranscriptOct 8 2021, 8:28 PM
Herald added a reviewer: Restricted Project. · View Herald Transcript
Mordante requested changes to this revision.Oct 9 2021, 6:37 AM

Thanks for working on this! It seems you use C++17 only code in C++14 mode.

libcxx/include/__utility/exchange.h
26–27

is_nothrow_move_constructible_v requires C++17.

libcxx/test/std/utilities/utility/exchange/exchange.pass.cpp
16–17

Please update the synopsis. Here and in the <utility> header.

54

Can you make a typedef for this type so the decltypes below aren't required.

114

Maybe move this to line 105, so the static_assert test can be guarded by the TEST_STD_VER at line 106.

This revision now requires changes to proceed.Oct 9 2021, 6:37 AM
jloser updated this revision to Diff 378477.Oct 9 2021, 2:13 PM

Address review comments

jloser marked 4 inline comments as done.Oct 9 2021, 2:14 PM
jloser added inline comments.
libcxx/include/__utility/exchange.h
26–27

Fixed, thanks!

libcxx/test/std/utilities/utility/exchange/exchange.pass.cpp
16–17

Updated the synopsis, including the note about constexpr after C++17 in the <utility> header.

54

Added type aliases to clean things up.

114

The above TEST_STD_VER is > 17 but since this noexcept goes back to C++14 (when std::exchange was introduced), I think it's best to leave it here.

Quuxplusone requested changes to this revision.Oct 9 2021, 2:45 PM

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

libcxx/docs/Status/Cxx2bPapers.csv
39

s/Complete/|Complete|/

libcxx/include/__utility/exchange.h
26–27

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.

libcxx/test/std/utilities/utility/exchange/exchange.pass.cpp
45

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.)

49–64

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)));
}
This revision now requires changes to proceed.Oct 9 2021, 2:45 PM
jloser updated this revision to Diff 378479.Oct 9 2021, 3:12 PM
jloser marked 4 inline comments as done.

Address Arthur's feedback

jloser marked 4 inline comments as done.Oct 9 2021, 3:14 PM
jloser added inline comments.
libcxx/test/std/utilities/utility/exchange/exchange.pass.cpp
45

Agree with the mildly weird, but they weren't strictly needed. In any case, I took your suggestion along with the rename.

49–64

I'm good with those tests. I like the explicit use of moving x. Just adopted your tests.

jloser marked 2 inline comments as done.Oct 9 2021, 3:15 PM
jloser updated this revision to Diff 378480.Oct 9 2021, 3:44 PM

Empty message for static_assert so test works in C++14 mode

A few small remarks remaining.

libcxx/include/utility
187

Please add the constexpr in the signature.

Please add noexcept in C++23. This only is required in C++23. Since it's allowed to strengthen noexcept I don't mind it available in earlier versions.

libcxx/test/std/utilities/utility/exchange/exchange.pass.cpp
49–64

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));
}

I'm fine with this version without typedefs, my main issue was the amount of decltypes in the original version.

114

I see the test executes no code, otherwise it couldn't execute the test in constexpr until C++20. ASSERT_NOEXCEPT is just a static_assert. So there's no real need to test this function twice.

jloser updated this revision to Diff 378512.Oct 10 2021, 8:26 AM

Add constexpr noexcept to synopsis
Remove runtime call of test_noexcept() in test

jloser marked 2 inline comments as done.Oct 10 2021, 8:27 AM
jloser added inline comments.
libcxx/include/utility
187

Added both constexpr and noexcept.

libcxx/test/std/utilities/utility/exchange/exchange.pass.cpp
114

Valid point -- just removed the runtime function call.

Mordante accepted this revision as: Mordante.Oct 10 2021, 9:51 AM

LGTM provided the CI passes. (Some of our builders are currently offline, I already notified the maintainer of these nodes.)

jloser marked 2 inline comments as done.Oct 11 2021, 11:30 AM

ping @Quuxplusone. The test is as you proposed, but wanted your approval before I land this.

This revision is now accepted and ready to land.Oct 11 2021, 11:32 AM