Alternative for D49234.
Details
Diff Detail
- Repository
- rL LLVM
Event Timeline
What's the reason for not specializing std::reverse_iterator? AFAIK, that is officially permitted by the standard.
This way somebody can still construct a std::reverse_iterator<DWARFDie::iterator> (via make_reverse_iterator or whatever) and get UB.
What exactly would you do difference? I can see a solution where we make the current __tmp a class member of the iterator adapter, but maybe you have something more straightforward in mind?
This way somebody can still construct a std::reverse_iterator<DWARFDie::iterator> (via make_reverse_iterator or whatever) and get UB.
That's not entirely true because it's no longer a bidirectional iterator. Regardless of the specialization, both *++iterator and *--iterator will remain UB.
Sorry I wrote the reply without looking at the patch in detail. I did not notice you demoted the iterator back to "forward". In case this is not a bidirectional operator, but a collection of two forward iterators that happen to iterate in the reverse order, the specializing std::reverse_iterator is not the right approach.
I have to admit I haven't thought about the specifics of how the reverse iterator would work until now. However, now that I think about it, I think it could be implemented as a pair of DWARFDie + bool flag. The trick would be that we store the element that we really dereference to, instead of its successor. The bool flag would be used denote the before_begin state, as we cannot represent rend() this way. The implementation would do something like:
operator++() { assert(!AtEnd && "Incrementing rend"); DWARFDie D = Die.getPreviousSibling(); if (D) Die = D; else AtEnd = true; } operator--() { if (AtEnd) { AtEnd = false; return; } Die = Die.getNextSibling(); assert(!Die.isNULL() && "Decrementing rbegin"); }
However, if you don't need that extra complexity now, then I suppose this solution is fine too.
llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp | ||
---|---|---|
1081–1116 ↗ | (On Diff #156820) | This will succeed even if the iterator range returns an empty sequence. Might I suggest a shorter alternative with a more helpful error message? EXPECT_THAT(std::vector<DWARFDie>(A.begin(), A.end()), testing::ElementsAre(B, C, D)); |
I think I'm missing something; what are you implementing here exactly and what problem is it trying to solve?
However, if you don't need that extra complexity now, then I suppose this solution is fine too.
I like this, but that's not surprising, as it was my idea in the first place. :)
I think David should have a pass at this too.
llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h | ||
---|---|---|
373 ↗ | (On Diff #157026) | This will inject all llvm decls into the std namespace. bad idea :) |
389–392 ↗ | (On Diff #157026) | These should be already inherited via std::iterator, shouldn't they? |
410–418 ↗ | (On Diff #157026) | We should also add a test which does a manual reverse iteration (via this function) on the reverse_iterator :), to check that this works too. |
420 ↗ | (On Diff #157026) | This should also take the value of AtEnd into account. Probably something like Die.isValid() && !AtEnd. Maybe you could even assert AtEnd == false when dereferencing. |
Address Pavel's feedback:
- Don't clutter std namespace.
- Don't redefine iterator traits.
- Add test cases that checks bidirectional aspect of both iterators.
- Fix operator bool() to check AtEnd.
llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h | ||
---|---|---|
383–384 ↗ | (On Diff #157035) | Could a null DWARFDie (a default constructed one, rather than a non-default constructed one that points to a null DIE) be used as the 'rend' value - avoiding the need for the bool? |
413–414 ↗ | (On Diff #157035) | Is this used/needed? Might be easier to leave it out & require users to do comparisons with the rend iterator? |
420 ↗ | (On Diff #157035) | Any operator that can be a non-member should be, ideally (so op== and op!= for example), so that any implicit conversions can occur equally on the LHS and RHS of the expression. |
llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h | ||
---|---|---|
383–384 ↗ | (On Diff #157035) | for operator-- you need to be able to go back from the "rend" position, which won't work for a default-constructed DWARFDie. I suppose that would be possible if we dropped operator-- (I don't expect anyone will need it), though then this will not be a conforming reverse_iterator. |
(probably a separate patch) Wonder if we could have a specialization of llvm::reverse that detects whether the underlying range has 'rbegin/rend' functions and use those, rather than making reverse iterators out of end/begin. That way reverse(die) would work correctly.
llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h | ||
---|---|---|
393–394 ↗ | (On Diff #157242) | /looks/ to me like this declaration isn't needed? I don't see any use of it in the specialization/before the op== definition later. |
397–402 ↗ | (On Diff #157242) | Any chance of using llvm's iterator_facade here, might simplify things a bit? |
447–456 ↗ | (On Diff #157242) | I wonder if these should go in the llvm namespace (they'd still be found by ADL, I think) rather than here in the std namespace? |