This is an archive of the discontinued LLVM Phabricator instance.

[libc++][ranges] fix errors on passing input iterator to `std::views::take`
ClosedPublic

Authored by huixie90 on Sep 2 2022, 11:26 AM.

Details

Summary

In the implementation of std::views::take, it uses subrange<Iter> as part of the return type. But in case of input iterator, subrange<Iter> can be ill-formed

Diff Detail

Event Timeline

huixie90 created this revision.Sep 2 2022, 11:26 AM
Herald added a project: Restricted Project. · View Herald TranscriptSep 2 2022, 11:26 AM
huixie90 requested review of this revision.Sep 2 2022, 11:26 AM
Herald added a project: Restricted Project. · View Herald TranscriptSep 2 2022, 11:26 AM
Herald added a reviewer: Restricted Project. · View Herald Transcript
philnik accepted this revision.Sep 9 2022, 8:42 AM

Could you add [libc++] to the commit message?
LGTM % nits. Thanks for the quick fix; sorry that I didn't review it earlier.

libcxx/include/__ranges/take_view.h
229

I think you said somewhere that GCC was OK without the requires clause. Could you check whether that's a GCC or Clang bug? (If you didn't, just ignore the comment)

libcxx/test/std/ranges/range.adaptors/range.take/adaptor.pass.cpp
136

clang-format seems to be quite unhappy here. Could you file a bug and fix the formatting for now?

207

Nit: Use CTAD?

208

The [[maybe_unused]] seems to be unnecessary.

This revision is now accepted and ready to land.Sep 9 2022, 8:42 AM
huixie90 retitled this revision from fix errors on passing input iterator to `std::views::take` to [libc++][ranges] fix errors on passing input iterator to `std::views::take`.Sep 11 2022, 8:48 AM
var-const requested changes to this revision.Sep 22 2022, 3:05 PM
var-const added inline comments.
libcxx/include/__ranges/take_view.h
229

The wording is, with simplifications (see https://eel.is/c++draft/range.take#overview-2.2):

...if `T` models [...] `ranges​::​subrange`, then [...] `U` is a type determined as follows:
[...]
* otherwise, `T` is a specialization of `ranges​::​subrange`, and `U` is `ranges​::​subrange<iterator_­t<T>>`;

Is this a defect in the standard, perhaps? The wording doesn't seem to take into account that T modeling subrange doesn't guarantee that iterator_t<T> models subrange. Might be worth asking on the reflector or writing an LWG issue (unless you don't think it's a defect, of course).

I'm also not sure if placing an additional constraint is the best solution here. Wouldn't returning subrange<_Iter, _Sent> reflect the intention of the standard better in this case (which is to avoid creating a take_view where its effect can easily be applied to the original type or a closely related type)?

Additionally, can you please check what other implementations are doing to inform our decision? From a brief glance, it seems like both GCC and MSVC would return subrange<_Iter, _Sent> in this case (though I could easily misread it, a Godbolt would be very helpful).

libcxx/test/std/ranges/range.adaptors/range.take/adaptor.pass.cpp
108

Nit: it's better to commit reformatting in a separate NFC patch, it makes reviewing easier. But feel free to keep in this patch if splitting it would be too much of a hassle.

136

+1.

208

+1.

This revision now requires changes to proceed.Sep 22 2022, 3:05 PM
huixie90 updated this revision to Diff 462439.Sep 23 2022, 4:21 AM
huixie90 marked 6 inline comments as done.

addressed comments

huixie90 added inline comments.Sep 23 2022, 4:21 AM
libcxx/include/__ranges/take_view.h
229

I don't think it is a defect in the standard. That paragraph has a condition "if T models random_­access_­range". In case of random_­access_­range, subrange<Iter> is always valid. But in this particular case of input_iterator, subrange<Iter> is invalid but it should not pass the "if T models random_­access_­range" condition, and should fall through https://eel.is/c++draft/range.take#overview-2.5

The standard is correct, in case of random_access_range, it should return subrange<Iter>, i.e. subrange<Iter, Iter>, because we need to return subrange(it, it + n) (both are iterators not sentinel). In case of input_iterator, it should simply fall under the last paragraph and return take_view (it should never return subrange<Iter, Sent>)

var-const accepted this revision.Sep 23 2022, 9:58 PM
var-const added inline comments.
libcxx/include/__ranges/take_view.h
229

You're right -- sorry, I missed the random_access_range part. In that case, it looks like this is the right fix.

This revision is now accepted and ready to land.Sep 23 2022, 9:58 PM