Avoid relying on iterator_traits and instead deduce the return type of
dereferencing the iterator. Additionally, add a static check to reject
iterators with incorrect iterator_traits at compile time.
Details
- Reviewers
ldionne huixie90 - Group Reviewers
Restricted Project - Commits
- rGb3afea1ce0bd: [libc++] Make `_IterOps::__iter_move` more similar to `std::ranges::iter_move`.
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
I don't personally love changing the code here for a regression that caught user code UB, but I understand.
In any case, can we add a test for the "invalid proxy iterator" case to bind this support to avoid future regressions in this area, please?
Are you absolutely certain that this won't break anything else? I'm definitely not, so I'd say rather break invalid code than valid code.
I like this new approach regardless of the issues raised in D129823 because it is closer to decltype(auto), and that's what we're trying to achieve at the end of the day.
However, the truth is that any iterator that lies about its iterator_traits::reference is a potential issue just waiting to explode, and since we can easily diagnose it, I think we should. That's why I've suggested adding a static_assert as a QOI thing.
Is it going to break some code? Probably, but that will actually point out potential bugs in people's code, which is a nice property to have.
libcxx/include/__algorithm/iterator_operations.h | ||
---|---|---|
68 | This way, we'll match the definition of iter_reference_t. | |
71 | IMO that's easier to read, since I don't have to substitute __deref_t in my head and work through the additional declval<T>() layer. | |
77–80 | ||
84–85 | (suggested message, feel free to change) The full link is http://eel.is/c++draft/input.iterators#tab:inputiterator. Also, please add a libc++ specific test to ensure that we do trigger the static_assert at least when we call std::sort with a mis-behaving iterator. |
I'm not absolutely certain, but the same can be said of any change of non-trivial complexity. Even completely ignoring the MySQL issue, this change is arguably an improvement because it brings this implementation closer to how the actual C++20 iter_move is specified, and at the end of the day we are trying to emulate that. I believe we would have used decltype here from the start, but we had the (incorrect) assumption that it's not supported in C++03. If you have a specific concern, I'm of course happy to address it.
libcxx/include/__algorithm/iterator_operations.h | ||
---|---|---|
84–85 | Done (with a slight tweak to the wording). I created a helper function and added this assertion to both specializations of __iter_move. |
For future context, the issue of incorrect iterator_traits came up from a breakage in MySQL; more context here: https://reviews.llvm.org/D129823#3677969.
For future context, the issue of incorrect iterator_traits came up from a breakage in MySQL; more context here: https://reviews.llvm.org/D129823#3677969.
libcxx/include/__algorithm/iterator_operations.h | ||
---|---|---|
76–77 | Rephrased the comment to make it clearer that we can't use decltype(auto) or auto as the return type, regardless of the SFINAE. | |
93 | Discussed offline -- this makes it closer to how iter_reference_t and iter_move are defined in C++20, and there doesn't seem to be an observable difference. |
This way, we'll match the definition of iter_reference_t.