This is an archive of the discontinued LLVM Phabricator instance.

[libc++] [test] Add "robust_re_difference_type.compile.pass.cpp" for all the algorithms.
ClosedPublic

Authored by Quuxplusone on Nov 15 2021, 8:44 AM.

Details

Summary

This is my suggested regression test for D113868, plus some matching improvements to my existing "robust_against_adl" test.

Also, mark these tests as compile-only. They actually are safe to run — notice that the code "runs" at constexpr-time in C++20, without error — because both of the input ranges are entirely filled with nullptr, so no matter how you shuffle the elements, they remain sorted and partitioned and heapified and everything. But there's no real reason to run them at runtime, so let's just avoid the distraction.

Test cases that fail in trunk right now are commented out with TODO FIXME. D113868 currently fixes some-but-not-all of them.

Diff Detail

Event Timeline

Quuxplusone requested review of this revision.Nov 15 2021, 8:44 AM
Herald added 1 blocking reviewer(s): Restricted Project. · View Herald TranscriptNov 15 2021, 8:44 AM

In general looks good, but some questions.

libcxx/test/std/algorithms/robust_against_adl.compile.pass.cpp
8

My concern with this test is a bit, how can we keep it up-to-date when newer versions of the Standard add new algorithms.
I don't see this as a blocker, but if you have any suggestions I'd like to hear them.

58

Is there a reason to change from our usual pattern of #if TEST_STD_VER > 14?
IIRC this question was raised in a review not that long ago, but I don't recall that we wanted to move to this style.

libcxx/test/std/algorithms/robust_re_difference_type.compile.pass.cpp
88

Any idea why this one fails?

philnik added inline comments.Nov 15 2021, 9:20 AM
libcxx/test/std/algorithms/robust_against_adl.compile.pass.cpp
3

Since these are new tests maybe clang-format them to LLVM style?

23

I think a better name would be ConvertibleToInt.

libcxx/test/std/algorithms/robust_re_difference_type.compile.pass.cpp
29

In D110598 I define a TEST_IS_CONSTANT_EVALUATED. The TEST_IS_CONSTANT_EVALUATED is more verbose but I think it is the more general approach. And maybe feature test with __cpp_lib_is_constant_evaluated instead of assuming it in C++20 if you still want to go with NOT_CONSTEVAL.

libcxx/test/std/algorithms/robust_against_adl.compile.pass.cpp
8

The ideal is, whenever someone implements a new algorithm (like shift_left), they do a quick git grep shift_left for all the places in the codebase that mention it, and fix up the places that need fixing up. Also, they do a quick git grep inplace_merge or whatever, on an algorithm that's similar to the one they're adding, and again fix up the places that need fixing up.
Obviously this ideal was not followed in practice even for shift_left, because there were still TODO comments left in this code. But I can't think of any protocol that would be better than the existing ideal. Just have to work on communicating the best practices and reminding people in code reviews.

23

Veto; sure it's only used once in the whole file, but still I see no reason to make the name longer and more technical.

58

Well, this isn't a "change" for this particular piece of code; I did it with >= in D92776 for some reason.
I don't object to changing it from >= to > in this same PR, as long as we're confusing Phab anyway. :)

libcxx/test/std/algorithms/robust_re_difference_type.compile.pass.cpp
29

I remembered something like that, but was unable to find it via git grep. Apparently because it wasn't checked in yet. :)

I'll merge that "test_macros.h" diff in here and start using it.

Btw, a problem I foresee, both here and (probably) there, is that very soon we'll need a macro that expresses "Test this only if !is_constant_evaluated(), or if the surrounding function isn't constexpr, or if TEST_STD_VER > 20," because some algorithms will be "non-constexpr-friendly in C++20 but constexpr-friendly in C++23". We're going to need something like if (TEST_IS_RUNTIME_OR_CXX20), if (TEST_IS_RUNTIME_OR_CXX23), etc. We don't need to solve that yet, but it's worth seeing that the problem is coming.

88

Yes: we fail to cast count to the difference_type. (The spec of the _n algorithms is quite weird; they don't accept something of difference_type right off the bat, they accept an arbitrary type and then convert it to "an" integral type.)

Switch >= 20 to > 17.
Use TEST_IS_CONSTANT_EVALUATED.

var-const added inline comments.Nov 15 2021, 4:03 PM
libcxx/test/std/algorithms/robust_against_adl.compile.pass.cpp
10

Question: why doesn't this test apply to C++03?

34

Optional nit: maybe initialize data inside the struct instead?

45

Optional nit: functors are repeated a lot across the test, maybe create variables for them as well? It would also be consistent with how the test uses named variables like first and last instead of t.data, t.data + 10, etc.:

(void)std::all_of(first, last, pred);
(void)std::for_each(first, last, apply);
(void)std::generate(first, last, generator);
(void)std::is_sorted(first, last, less);
// ...
46

Do these tests not apply to any of the algorithms in <numeric>?

61

Ultranit: omit the empty parentheses?

83

Just checking: random_shuffle is omitted deliberately, right?

147

Optional: having "with comparators" and "without comparators" as two separate lists makes it harder to notice if the lists happen to go out of sync. I'd prefer having the both versions right next to each other, so that it's easier to spot if one version is accidentally omitted (because the overloads are always next to each other, rather than arbitrarily far away):

(void)std::adjacent_find(first, last);
(void)std::adjacent_find(first, last, std::equal_to<void*>());
(void)std::binary_search(first, last, value, std::less<void*>());
(void)std::equal(first, last, first2);
(void)std::equal(first, last, first2, std::equal_to<void*>());

This is purely a matter of taste, though -- feel free to ignore.

libcxx/test/std/algorithms/robust_re_difference_type.compile.pass.cpp
21

Question: is <utillity> used?

26

Can you please add a comment with a brief explanation of what is special about this iterator class?

29

Nit: include <iterator>?

ldionne accepted this revision as: ldionne.Nov 16 2021, 8:07 AM

LGTM despite some suggestions.

libcxx/test/std/algorithms/robust_against_adl.compile.pass.cpp
23

Honestly, Intable is a poor name IMO. I would actually do:

template <class T>
struct ConvertibleTo { TEST_CONSTEXPR operator T() const { return T(); } };
Quuxplusone marked 17 inline comments as done.Nov 16 2021, 8:55 AM
Quuxplusone added inline comments.
libcxx/test/std/algorithms/robust_against_adl.compile.pass.cpp
10

Lambdas and braced-initializer-lists (for std::min/max), but really probably just I didn't originally feel like going through and ifdeffing all the algos that were "new in C++11." It was easier just to unsupport the test pre-C++11.

23

Well, I definitely wouldn't make it a template. Tell you what, I'll change it to ConvertibleToIntegral. (That's the phrase in https://eel.is/c++draft/alg.copy#11 )

46

I suppose they could apply to all of the algorithms in <numeric>. I'll do that as a separate PR, since it opens a new can of worms (namely, whether it should be a new test or part of this test).

61

Definitely not. :)

83

I don't remember my original logic, but yeah, since it's deprecated/removed, I think it's fine to omit.
std::shuffle is also omitted, and I think my logic in that case was just that it was too awkward to define a URBG just for that one call.

147

My original logic was that separate lists made it easier to detect when one of the calls was accidentally omitting (or accidentally including) the comparator.
However, when updating these lists in this PR, I did find it pretty awkward to figure out which algos belonged in which list(s); so yeah, I think I'll combine the lists.

libcxx/test/std/algorithms/robust_re_difference_type.compile.pass.cpp
21

I'd thought so, but I guess not. Added <iterator>, removed <utility>.

Quuxplusone marked 7 inline comments as done.

Review comments. Merged the three lists of algorithms into one. (Turned out I was even missing at least one: std::find!)

Oops, reupload with git diff -U999 context.

philnik accepted this revision.Nov 16 2021, 9:16 AM
ldionne requested changes to this revision.Nov 16 2021, 10:56 AM
ldionne added inline comments.
libcxx/test/std/algorithms/robust_against_adl.compile.pass.cpp
10

I know this is annoying, but we don't go the easy way "just because". If this can reasonably be tested in C++03, we should.

This revision now requires changes to proceed.Nov 16 2021, 10:56 AM
ldionne added inline comments.Nov 16 2021, 10:56 AM
libcxx/test/std/algorithms/robust_against_adl.compile.pass.cpp
10

(When I did my review for some reason I thought this test didn't apply to C++03, but I looked too quickly.)

Enable the "robust_xxx" tests in C++03 too.
(This means switching from lambdas to named class types, and ifdef'ing out a surprisingly low number of lines.)

var-const added inline comments.Nov 16 2021, 11:18 AM
libcxx/test/std/algorithms/robust_against_adl.compile.pass.cpp
61

Just curious, what's your rationale? I've always seen them as unnecessary boilerplate, so I'm interested to know why you prefer to keep them. To be clear, I'm absolutely fine with keeping them, just interested in your perspective.

83

Can you please add a brief comment to that effect?

libcxx/test/std/algorithms/robust_against_adl.compile.pass.cpp
61

I've always seen the extra parser codepath that says "Lambdas look like this, except that if the function parameter list is empty, you can omit it" (specially for lambdas — ordinary functions' parameter lists can't be omitted) as unnecessary complication added to an otherwise relatively clean design.
I don't teach people that the special case exists, and my impression is that nobody ever discovers it on their own. (Because why would anyone ever try omitting a function's parameter-list? nobody should expect that to work!)

(The other lambda snafu of which I'm aware is that [x, y, &]() { } is ill-formed — the correct syntax places the default first, not last: [&, x, y]() { }. That's marginally more discoverable by newbies, but still a relative corner case, because 99% of the time, you want [&], and if the compiler stops you from writing [x,&] or [&x,=] with a cryptic error message, well, strewing the road with nails is one way to discourage people from going down it. ;)

One nit for me left.

libcxx/test/std/algorithms/robust_against_adl.compile.pass.cpp
58

There are still some >='s left.

Quuxplusone marked an inline comment as done.Nov 16 2021, 12:11 PM
Quuxplusone added inline comments.
libcxx/test/std/algorithms/robust_against_adl.compile.pass.cpp
58

My intent is that the only >=s left are for >= 11, where that seems to be our style:

$ git grep -ho 'TEST_STD_VER >[=]* [0-9]*' ../libcxx/test/ | sort | uniq -c | sort -n
  15 TEST_STD_VER > 3
  20 TEST_STD_VER > 03
  37 TEST_STD_VER >= 17
  92 TEST_STD_VER >= 20
 110 TEST_STD_VER > 20
 181 TEST_STD_VER >= 14
 309 TEST_STD_VER > 11
 381 TEST_STD_VER > 14
 474 TEST_STD_VER > 17
1259 TEST_STD_VER >= 11
ldionne accepted this revision.Nov 16 2021, 12:39 PM
This revision is now accepted and ready to land.Nov 16 2021, 12:39 PM
var-const accepted this revision.Nov 16 2021, 12:43 PM

LGTM (with one optional comment re. random_shuffle).

philnik added inline comments.Nov 16 2021, 12:55 PM
libcxx/test/std/algorithms/robust_re_difference_type.compile.pass.cpp
75

You didn't format this file

Mordante accepted this revision.Nov 17 2021, 9:22 AM

LGTM when the CI is green.

Quuxplusone marked an inline comment as done.

Add missing TEST_CONSTEXPRs to the new callable struct types. This should make CI happy.

libcxx/test/std/algorithms/robust_against_adl.compile.pass.cpp