This is an archive of the discontinued LLVM Phabricator instance.

[libc++][ranges] Implement LWG-3865 Sorting a range of pairs
ClosedPublic

Authored by fsb4000 on Feb 17 2023, 6:05 AM.

Diff Detail

Event Timeline

fsb4000 created this revision.Feb 17 2023, 6:05 AM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 17 2023, 6:05 AM
fsb4000 requested review of this revision.Feb 17 2023, 6:05 AM
fsb4000 added a reviewer: Restricted Project.
fsb4000 set the repository for this revision to rG LLVM Github Monorepo.
fsb4000 added a subscriber: Restricted Project.
Herald added a project: Restricted Project. · View Herald TranscriptFeb 17 2023, 6:06 AM
Herald added 1 blocking reviewer(s): Restricted Project. · View Herald Transcript

Thanks for your patch! I haven't looked in detail, since I first like to agree to which language versions we want to backport this fix.

libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp
68

We typically back-port LWG issues to older language versions.
However I'm a bit wary of retroactively applying this LWG issue, since it may affect existing code.
Looking at MSVC STL it seems @strega-nil has the same concerns.
https://github.com/microsoft/STL/pull/3476/files/4f2ec495a6b5e6ab61d504663b0ad7d3db9db547#r1110452521

Since operator== and operator<=> are added/changed in C++20, I feel less wary to change it there.
Doing this back to C++03 feels a bit scary.

@ldionne What's your opinion?

libcxx/test/std/utilities/utility/pairs/pairs.spec/comparison.pass.cpp
11

Can you also update libcxx/test/std/utilities/utility/pairs/pairs.spec/three_way_comparison.pass.cpp.

fsb4000 updated this revision to Diff 498643.Feb 18 2023, 4:03 PM
fsb4000 marked an inline comment as done.
frederick-vs-ja added inline comments.
libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp
68

The changes do break such not-so-reasonable code:

struct BadPairs : std::pair<int, int>, std::pair<long, long> {};
std::pair<int, int>{} == BadPairs{};

And some uses of (IMO, unreasonable) explicit usage of operartor@(p, x) or operator@<T, U>(p, x).

I think if we provide both old and new overloads, almost nothing is broken (except some code expecting incomparability).

strega-nil added a comment.EditedFeb 21 2023, 11:07 AM

Given that the MSVC-STL team is planning on backporting this fix to C++14 (the earliest supported version), I think it's reasonable to backport this to at least C++11 (see the comment thread).

I think it's good if MSVC-STL and libc++ are aligned on this.

fsb4000 added a reviewer: philnik.
philnik added inline comments.Feb 25 2023, 1:50 AM
libcxx/test/std/utilities/tuple/tuple.tuple/tuple.apply/make_from_tuple.pass.cpp
68

Given that you aren't allowed to explicitly specify template parameters unless the standard explicitly allows it, I think we can break at least that part. I don't really expect a lot of code to be broken in the wild, so I think it should be OK to back-port to C++03. Since we are early in the release cycle we can also just land it for now; if enough people complain we can revert.

I think we should implement this as a DR in all supported modes, like any normal LWG issue. I would only change this stance if we find actual breakage in the wild of crazy incompatibilities with older standard modes.

libcxx/test/std/utilities/utility/pairs/pairs.spec/three_way_comparison.pass.cpp
13–15

Do you not need actual changes to the tests below?

I think we should implement this as a DR in all supported modes, like any normal LWG issue. I would only change this stance if we find actual breakage in the wild of crazy incompatibilities with older standard modes.

Thanks for the confirmation.

fsb4000 updated this revision to Diff 500927.Feb 27 2023, 2:54 PM

I rebased and added tests to pair's spaceship operator.

fsb4000 marked an inline comment as done.Feb 27 2023, 2:55 PM
fsb4000 added inline comments.
libcxx/test/std/utilities/utility/pairs/pairs.spec/three_way_comparison.pass.cpp
13–15

Yes, thanks, I added tests.

fsb4000 updated this revision to Diff 500934.Feb 27 2023, 3:23 PM
fsb4000 marked an inline comment as done.

fix formatting conflicts in libcxx/include/utility

Mordante accepted this revision.Mar 4 2023, 5:12 AM

In general LGTM, but one comment.

libcxx/test/std/utilities/utility/pairs/pairs.spec/three_way_comparison.pass.cpp
43

I would like to see a few more tests int <=> double, int <=> string.

This revision is now accepted and ready to land.Mar 4 2023, 5:12 AM
fsb4000 updated this revision to Diff 503275.Mar 8 2023, 2:13 AM
fsb4000 added inline comments.
libcxx/test/std/utilities/utility/pairs/pairs.spec/three_way_comparison.pass.cpp
43

I added int <=> double

But what test do you want with int <=> string ?

fsb4000 updated this revision to Diff 503279.Mar 8 2023, 2:34 AM
Mordante added inline comments.Mar 8 2023, 10:42 AM
libcxx/test/std/utilities/utility/pairs/pairs.spec/three_way_comparison.pass.cpp
43

Making sure it does not work, so this needs to be some static_assert.

fsb4000 updated this revision to Diff 503613.Mar 8 2023, 9:09 PM

add static_assert(!HasSpaceship<std::pair<int, int>, std::pair<std::string, int>>);

fsb4000 marked 2 inline comments as done.Mar 8 2023, 9:10 PM
This revision was landed with ongoing or failed builds.Mar 9 2023, 6:04 PM
This revision was automatically updated to reflect the committed changes.
alexfh added a subscriber: alexfh.Mar 16 2023, 9:40 AM

The following snippet (reduced from a version of mysql) compiles well before this commit and fails to compile after it (https://gcc.godbolt.org/z/zrGbbbWb5):

#include <utility>

struct X {};
struct Y {};

bool operator==(const std::pair<const X, const X> &a, const std::pair<Y, Y> &b);

bool f(std::pair<const X, X> x, std::pair<Y, Y> y) {
  return x == y;
}

The error is:

In file included from bin/../include/c++/v1/utility:259:
bin/../include/c++/v1/__utility/pair.h:432:22: error: invalid operands to binary expression ('const X' and 'const Y')
    return __x.first == __y.first && __x.second == __y.second;
           ~~~~~~~~~ ^  ~~~~~~~~~
<source>:9:12: note: in instantiation of function template specialization 'std::operator==<const X, X, Y, Y>' requested here
  return x == y;
           ^
<source>:6:6: note: candidate function not viable: no known conversion from 'const X' to 'const std::pair<const X, const X>' for 1st argument
bool operator==(const std::pair<const X, const X> &a, const std::pair<Y, Y> &b);
     ^
bin/../include/c++/v1/__utility/pair.h:430:1: note: candidate template ignored: could not match 'const pair<_T1, _T2>' against 'const X'
operator==(const pair<_T1,_T2>& __x, const pair<_U1,_U2>& __y)
^

I can fix this by changing the custom operator== declaration to bool operator==(const std::pair<const X, X> &a, const std::pair<Y, Y> &b); (removing the second const), but I wonder if this sort of a breakage is intended.

The following snippet (reduced from a version of mysql) compiles well before this commit and fails to compile after it (https://gcc.godbolt.org/z/zrGbbbWb5):

#include <utility>

struct X {};
struct Y {};

bool operator==(const std::pair<const X, const X> &a, const std::pair<Y, Y> &b);

bool f(std::pair<const X, X> x, std::pair<Y, Y> y) {
  return x == y;
}

The error is:

In file included from bin/../include/c++/v1/utility:259:
bin/../include/c++/v1/__utility/pair.h:432:22: error: invalid operands to binary expression ('const X' and 'const Y')
    return __x.first == __y.first && __x.second == __y.second;
           ~~~~~~~~~ ^  ~~~~~~~~~
<source>:9:12: note: in instantiation of function template specialization 'std::operator==<const X, X, Y, Y>' requested here
  return x == y;
           ^
<source>:6:6: note: candidate function not viable: no known conversion from 'const X' to 'const std::pair<const X, const X>' for 1st argument
bool operator==(const std::pair<const X, const X> &a, const std::pair<Y, Y> &b);
     ^
bin/../include/c++/v1/__utility/pair.h:430:1: note: candidate template ignored: could not match 'const pair<_T1, _T2>' against 'const X'
operator==(const pair<_T1,_T2>& __x, const pair<_U1,_U2>& __y)
^

I can fix this by changing the custom operator== declaration to bool operator==(const std::pair<const X, X> &a, const std::pair<Y, Y> &b); (removing the second const), but I wonder if this sort of a breakage is intended.

This is a known issue, see this bug report https://bugs.mysql.com/bug.php?id=110254

This is a known issue, see this bug report https://bugs.mysql.com/bug.php?id=110254

Thanks for the pointer!