This is an archive of the discontinued LLVM Phabricator instance.

[libc++] Do not enable P1951 before C++23, since it's a breaking change
ClosedPublic

Authored by ldionne on Sep 23 2021, 10:06 AM.

Details

Summary

In reaction to the issues raised by Richard in https://llvm.org/D109066,
this commit does not apply P1951 as a DR in previous standard modes,
since it breaks valid code.

I do believe it should be applied as a DR, however ideally we'd get some
sort of statement from the Committee to this effect (and all implementations
would behave consistently). In the meantime, only implement P1951 starting
with C++23 -- we can always come back and apply it as a DR if that's what
the Committee says.

Diff Detail

Event Timeline

ldionne requested review of this revision.Sep 23 2021, 10:06 AM
ldionne created this revision.
Herald added a project: Restricted Project. · View Herald TranscriptSep 23 2021, 10:06 AM
Herald added a reviewer: Restricted Project. · View Herald Transcript
Quuxplusone requested changes to this revision.Sep 23 2021, 10:20 AM
Quuxplusone added a subscriber: Quuxplusone.
Quuxplusone added inline comments.
libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.brace-init.P1951.pass.cpp
21–29

Well, this compiles either way, right? So to actually test the situation, it would be better to actually use the string's contents inside f. Or write a contrived toy version like

struct A {
    int *p_;
    A(int *p) : p_(p) { *p_ += 1; }
    A(const A& a) : p_(a.p_) { *p_ += 1; }
    ~A() { *p_ -= 1; }
};
int i = 0;
auto f = [&](std::pair<int, const A&>) { assert(i >= 1); };
f({42, &i});

https://godbolt.org/z/39q13bx41
Looks like libstdc++ did it as a DR (or has some other bug), and MSVC hasn't implemented it at all yet?

35–38

This test seems fine, since the symptom is "fail to compile."
Weirdly, libstdc++ is OK with this test; which is why I wondered above if they had some other bug causing the first test to fail.

This revision now requires changes to proceed.Sep 23 2021, 10:20 AM
ldionne updated this revision to Diff 374620.Sep 23 2021, 10:51 AM
ldionne marked an inline comment as done.

Address review comments.

libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.brace-init.P1951.pass.cpp
21–29

No, it doesn't compile:

In file included from <..>/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.brace-init.P1951.pass.cpp:15:
In file included from <..>/build/default/include/c++/v1/string:520:
In file included from <..>/build/default/include/c++/v1/__functional_base:26:
In file included from <..>/build/default/include/c++/v1/utility:225:
<..>/build/default/include/c++/v1/__utility/pair.h:189:17: error: reference member 'first' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object
        : first(_VSTD::forward<_U1>(__u1)), second(_VSTD::forward<_U2>(__u2)) {}
                ^~~~~~~~~~~~~~~~~~~~~~~~~
<..>/build/default/include/c++/v1/__config:755:15: note: expanded from macro '_VSTD'
#define _VSTD std::_LIBCPP_ABI_NAMESPACE
              ^
<..>/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.brace-init.P1951.pass.cpp:27:11: note: in instantiation of function template specialization 'std::pair<const std::string &, std::vector<int>>::pair<char const (&)[4], std::vector<int>, nullptr>' requested here
        f({"foo", {1, 2}});
          ^
<..>/build/default/include/c++/v1/__utility/pair.h:48:9: note: reference member declared here
    _T1 first;
        ^

I guess it might just be Clang being helpful, though, so I agree we could make the test more robust (also GCC doesn't produce a build failure AFAICT).

libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.brace-init.P1951.pass.cpp
21–29

FWIW, yeah, I noticed Clang giving that error on Godbolt. Making it a hard error, instead of a warning, is... aggressive... if the error message is not mandated by the Standard; so a priori I'd guess it must be mandated by the Standard.
But no other compiler gives that error message, and the code is certainly reasonable in practice (as long as the caller never tries to use the reference that is now dangling). So maybe this is Clang being helpful in a slightly extralegal, "vigilante" sense.

ldionne updated this revision to Diff 375304.Sep 27 2021, 9:38 AM

Re-upload -- I accidentally removed the fix before uploading last revision. This should be good to go, @Quuxplusone can you please have a look?

I'm happy if buildkite is happy. My comment about lines 116+117 is worth addressing one way or the other (either complicate the ctors, or remove the redundant assertions), but I don't really care which way.

libcxx/test/std/utilities/utility/pairs/pairs.pair/U_V.pass.cpp
105–109

FWIW, the paired assertions (e.g. lines 116+117) seem like overkill, since right now obviously it's impossible ever to have wasCopyInit && wasMoveInit. I wonder if you meant to do, like,

constexpr TrackInit(TrackInit const& rhs) : wasCopyInit(true), wasMoveInit(rhs.wasMoveInit) { }
constexpr TrackInit(TrackInit&& rhs) : wasCopyInit(rhs.wasCopyInit), wasMoveInit(true) { }
libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.brace-init.P1951.pass.cpp
35–36

LGTM, although of course you could replace vector<int> with int and/or {42,43} with {} if you wanted to simplify it a bit.

ldionne updated this revision to Diff 375325.Sep 27 2021, 10:18 AM
ldionne marked 4 inline comments as done.

Address comments.

ldionne added inline comments.Sep 27 2021, 10:18 AM
libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.brace-init.P1951.pass.cpp
35–36

(I think this comment does not appear on the right line).

Actually, if you do that, Clang starts diagnosing that we're binding a temporary beyond its lifetime. That *sounds* like a false-positive to me.

ldionne accepted this revision.Sep 27 2021, 10:18 AM

Will ship once BuildKite is happy.

This revision is now accepted and ready to land.Sep 27 2021, 10:18 AM
This revision was landed with ongoing or failed builds.Sep 27 2021, 2:07 PM
This revision was automatically updated to reflect the committed changes.