This is an archive of the discontinued LLVM Phabricator instance.

[libcxx][test] {move,reverse}_iterator cannot be instantiated for a type with no `operator*` in C++20
ClosedPublic

Authored by CaseyCarter on Jan 14 2022, 4:55 PM.

Details

Summary

Since their nested reference types are defined in terms of iter_reference_t<T>, which examines decltype(*declval<T>()).

Diff Detail

Event Timeline

CaseyCarter requested review of this revision.Jan 14 2022, 4:55 PM
CaseyCarter created this revision.
Herald added 1 blocking reviewer(s): Restricted Project. · View Herald TranscriptJan 14 2022, 4:55 PM

I'd like @ldionne to make an executive decision about whether libc++ should continue to compile move_iterator<ToIter>, as an extension, in pre-C++20 modes. (class ToIter does not have an operator*: dereferencing such a move_iterator wouldn't compile, but merely forming the type is currently legal in libc++ pre-C++20.)
If we think our "extension" is important, then this PR is removing test coverage. If we think no sane user would ever make a move_iterator of a non-iterator type, then this PR is a great simplification.

Scope creep: Same question but in re the fact that ToIter doesn't have an operator++ either. If we discover we also need to add an operator++ to ToIter, would that be removing test coverage?

I'd like @ldionne to make an executive decision about whether libc++ should continue to compile move_iterator<ToIter>, as an extension, in pre-C++20 modes. (class ToIter does not have an operator*: dereferencing such a move_iterator wouldn't compile, but merely forming the type is currently legal in libc++ pre-C++20.)
If we think our "extension" is important, then this PR is removing test coverage. If we think no sane user would ever make a move_iterator of a non-iterator type, then this PR is a great simplification.

I'm happy to make the presence of operator* depend on the language mode under test if we do want to preserve this extension, although it seems very low-value to me.

Scope creep: Same question but in re the fact that ToIter doesn't have an operator++ either. If we discover we also need to add an operator++ to ToIter, would that be removing test coverage?

There are a ton of types named "MeowIterator" in the test suite that conform to neither the old iterator requirements nor the new iterator concepts. It's not my goal to fix them all, merely to correct test failures for stdlib=msvc.

ldionne accepted this revision.Jan 24 2022, 7:55 AM

IMO this is a low value extension that we probably never intended to provide, and I think it would be 100% OK to remove that extension. I doubt it would create any downstream breakage too, because nobody should be instantiating move_iterator<It> where It isn't an iterator.

Just curious, why does it not work with MSVC? The most naive implementation of move_iterator would allow instantiating it without an operator* as long as you don't try to instantiate operator*. Does MSVC do it differently?

This revision is now accepted and ready to land.Jan 24 2022, 7:55 AM

Just curious, why does it not work with MSVC? The most naive implementation of move_iterator would allow instantiating it without an operator* as long as you don't try to instantiate operator*. Does MSVC do it differently?

Casey explains this in the commit summary:

their nested reference types are defined in terms of iter_reference_t<T>, which examines decltype(*declval<T>()).

This is new in C++20; we haven't done it yet (but I'm working on it).

Just curious, why does it not work with MSVC? The most naive implementation of move_iterator would allow instantiating it without an operator* as long as you don't try to instantiate operator*. Does MSVC do it differently?

Casey explains this in the commit summary:

their nested reference types are defined in terms of iter_reference_t<T>, which examines decltype(*declval<T>()).

This is new in C++20; we haven't done it yet (but I'm working on it).

Oh thanks for pointing this out and sorry for the noise.

Oh thanks for pointing this out and sorry for the noise.

Technically the description is incorrect for move_iterator, whose reference is iter_rvalue_reference_t<Iter> which also examines decltype(*declval<Iter>()) indirectly (pun intended) via ranges::iter_move. It is a convenient approximation.

And don't sweat it: I'm renowned for ignoring commit messages, or at least forgetting them at some point during a review.