Skip to content

[libc++] Implement P2538R1 "ADL-proof std::projected" #65411

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 15, 2023

Conversation

ldionne
Copy link
Member

@ldionne ldionne commented Sep 5, 2023

Notice that because Holder is possible to complete, but unsafe to complete, that means that Holder* is basically not an iterator and it's not even safe to ask if input_iterator<Holder*> because that will necessarily complete the type. So it's totally expected that we still cannot safely ask e.g.

static_assert(std::indirect_unary_predicate<bool(&)(Holder&), Holder*>);

or even

static_assert(!std::indirect_unary_predicate<int, Holder*>);

This was originally uploaded as https://reviews.llvm.org/D119029 and I picked it up here as part of the Github PR transition.

@ldionne ldionne added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Sep 5, 2023
@ldionne ldionne requested a review from a team as a code owner September 5, 2023 20:25
Copy link
Member

@EricWF EricWF left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don' think this builds.

include/c++/v1/__iterator/projected.h:49:8: error: class template partial specialization contains template parameters that cannot be deduced; this partial specialization will never be used [-Wunusable-partial-specialization]
   49 | struct incrementable_traits<projected<_It, _Proj>> {

Copy link
Member

@EricWF EricWF left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

None of the tests included with this change actually work.

They're all missing the include for TEST_STD_VER, which disables the tests.
But after re-enabling the tests and removing the fix, all the tests still passed.

Do you know what's going on there?

@@ -80,3 +80,11 @@ struct BadPredicate6 {
bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete;
};
static_assert(!std::indirect_binary_predicate<BadPredicate6, It1, It2>);

// Test ADL-proofing (P2538R1)
#if TEST_STD_VER >= 26
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we not testing this in older dialectts?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests pass before your change as well.

Also you're missing an include for test_macros.h, so this test was never running.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch with the test_macros.h.

Why are we not testing this in older dialectts?

This is technically a C++26 paper, so I was going to test this only in C++26. The fact that it happens to pass in C++20/23 is just because we will implement projected the same in all standard modes, but we're not technically guaranteeing that projected is ADL-proof in older standards. Does that make sense?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding test_macros.h, -Wundef actually catches those!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This very much feels like a defect report. I would rather we test the behavior in all dialects where we provide the behavior.

Comment on lines 48 to 51
template <weakly_incrementable _It, class _Proj>
struct incrementable_traits<projected<_It, _Proj>> {
using difference_type = iter_difference_t<_It>;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's strange that this (no longer valid) partial specialization is not removed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it should be removed, thanks for the heads up. I basically just took https://reviews.llvm.org/D119029 and did a few changes I could spot, uploaded it here and closed the Phab revision. I'll address this.

@ldionne ldionne force-pushed the review/P2538R1-std-projected branch from f3e9988 to 23567ab Compare September 6, 2023 15:30
Copy link
Member

@EricWF EricWF left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM but I would like to see the tests backported to all the dialects where projected is available.

@EricWF EricWF self-requested a review September 7, 2023 17:18
@ldionne
Copy link
Member Author

ldionne commented Sep 12, 2023

LGTM but I would like to see the tests backported to all the dialects where projected is available.

I'll test our implementation in all standard modes, but I won't make the tests unconditional on the standard version. This is a c++26 paper, so a conforming C++20 or C++23 implementation should be able to pass our test suite without implementing that paper.

@ldionne ldionne force-pushed the review/P2538R1-std-projected branch from 23567ab to 5fb0cf8 Compare September 12, 2023 15:17
Notice that because Holder<Incomplete> is _possible_ to complete,
but _unsafe_ to complete, that means that Holder<Incomplete>*
is basically not an iterator and it's not even safe to ask if
input_iterator<Holder<Incomplete>*> because that _will_ necessarily
complete the type. So it's totally expected that we still cannot
safely ask e.g.

  static_assert(std::indirect_unary_predicate<bool(&)(Holder<Incomplete>&), Holder<Incomplete>*>);

or even

  static_assert(!std::indirect_unary_predicate<int, Holder<Incomplete>*>);

Differential Revision: https://reviews.llvm.org/D119029

Co-authored-by: Louis Dionne <[email protected]>
@ldionne ldionne force-pushed the review/P2538R1-std-projected branch from 5fb0cf8 to a6e632a Compare September 14, 2023 17:20
@ldionne ldionne merged commit 4d08ecc into llvm:main Sep 15, 2023
@ldionne ldionne deleted the review/P2538R1-std-projected branch September 15, 2023 14:09
ZijunZhaoCCK pushed a commit to ZijunZhaoCCK/llvm-project that referenced this pull request Sep 19, 2023
Notice that because Holder<Incomplete> is _possible_ to complete, but
_unsafe_ to complete, that means that Holder<Incomplete>* is basically
not an iterator and it's not even safe to ask if
input_iterator<Holder<Incomplete>*> because that _will_ necessarily
complete the type. So it's totally expected that we still cannot safely
ask e.g.


static_assert(std::indirect_unary_predicate<bool(&)(Holder<Incomplete>&),
Holder<Incomplete>*>);

or even

static_assert(!std::indirect_unary_predicate<int, Holder<Incomplete>*>);

This was originally uploaded as https://reviews.llvm.org/D119029 and I
picked it up here as part of the Github PR transition.

Co-authored-by: Arthur O'Dwyer <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants