This is an archive of the discontinued LLVM Phabricator instance.

[llvm][ADT] Fix invalid `reference` type of depth-first, breadth-first and post order iterators
ClosedPublic

Authored by zero9178 on May 23 2023, 3:49 AM.

Details

Summary

C++s iterator concept requires operator* to return the same type as is specified by the iterators reference type. This functionality is especially important for older generic code that did not yet make use of auto.
An example from within LLVM is iterator_adaptor_base which uses the reference type of the iterator it is wrapping as its return type for operator* (this class is used as base for a lot of other functionality like filter iterators and so on).
Using any of the graph traversal iterators listed above with it would previously fail to compile due to reference being non-const while operator* returned a const reference.

This patch fixes that by correctly specifying reference and using it as the return type of operator* explicitly to prevent further issues in the future.

Diff Detail

Event Timeline

zero9178 created this revision.May 23 2023, 3:49 AM
Herald added a project: Restricted Project. · View Herald TranscriptMay 23 2023, 3:49 AM
zero9178 requested review of this revision.May 23 2023, 3:49 AM
Herald added a project: Restricted Project. · View Herald TranscriptMay 23 2023, 3:49 AM
zero9178 retitled this revision from [llvm][ADT] Fix invlid `reference` type of depth-first, breadth-first and post order iterators to [llvm][ADT] Fix invalid `reference` type of depth-first, breadth-first and post order iterators.May 23 2023, 5:56 AM
kuhar added inline comments.May 23 2023, 7:27 AM
llvm/include/llvm/ADT/BreadthFirstIterator.h
53

Could we add const conditionally, either with some type traits or define reference in terms of decltype(*declval<pointer>())?

Do you know if it there's any existing use of non-const references with these iterators?

zero9178 added inline comments.May 23 2023, 7:51 AM
llvm/include/llvm/ADT/BreadthFirstIterator.h
53

The result of operator* has always been a const-reference so there couldn't have been (or at the very least can't currently be) any real properly compiling code that relies on reference being non-const while operator* isn't.

Defining it to decltype(*declval<pointer>()) would just be equal to value_type& no? That would at the very least not be possible in a non-const operator* and I think is intentionally not the case, since a NodeRef& would allow breaking the invariants of the iterators (would modify the NodeRef within VisitQueue)

Hope I understood your comment correctly.

kuhar accepted this revision.May 23 2023, 8:26 AM
kuhar added inline comments.
llvm/include/llvm/ADT/BreadthFirstIterator.h
53

Oh I see what you mean: the runtime usage used to depend on the definition of operator*() const and what this PR does is aligning the definition of the reference typedef to that usage.

I'd expect to see this operator return const_reference perhaps, but since there's no non-const version then this change seems fine to me.

This revision is now accepted and ready to land.May 23 2023, 8:26 AM
This revision was landed with ongoing or failed builds.May 23 2023, 10:30 AM
This revision was automatically updated to reflect the committed changes.