Skip to content

Translate iterator categories - #540

Open
lucic71 wants to merge 33 commits into
Cpp2Rust:masterfrom
lucic71:iteratory-category
Open

lucic71 wants to merge 33 commits into
Cpp2Rust:masterfrom
lucic71:iteratory-category

Conversation

@lucic71

@lucic71 lucic71 commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Closes #539.

A rule for a container iterator such as std::vector<T, A>::iterator cannot match a usage, because T and A cannot be deduced from the iterator type (see #539).

This PR matches iterator types by their iterator category instead. The category is read from std::iterator_traits<It>, which every standard iterator provides, so the rules do not depend on how a particular standard library implements its iterators.

This also removes duplicate rules. One rule for random access iterators replaces one rule per container that has a random access iterator.


  • rules/iterator_category/shim.rs defines the Rust types for the iterator categories used in translated code: iterator, input, output, bidirectional, and random ac
    cess.
  • rules/iterator_category/src.cpp defines a type rule for each category plus rules for its operations.

For example, this is the rule for an iterator that is bidirectional but not random access:

template <
    typename It, typename T1 = typename std::iterator_traits<It>::value_type,
    typename = typename std::enable_if<
        std::is_base_of<
            std::bidirectional_iterator_tag,
            typename std::iterator_traits<It>::iterator_category>::value &&
        !std::is_base_of<
            std::random_access_iterator_tag,
            typename std::iterator_traits<It>::iterator_category>::value &&
        !std::is_pointer<It>::value>::type>
using t4 = It;

It is deduced directly from the usage, and T1 and the enable_if condition are computed from it using only standard names. This rule matches std::map<K, V>::iterator, std::set<T>::iterator, std::list<T>::iterator, and so on, without naming any of them.


The existing vector and map iterator rules are rewritten in terms of RandomAccessIterator and BidirectionalIterator.

  • vector: RandomAccessIterator<T> is a Ptr<T>, which is what vector iterators already translated to, so the change is small.
  • map: RefcountMapIter and UnsafeMapIterator were MapIter<K, MapRef>, which has two type parameters. A category rule only knows T, the iterator's value_type, which for a map is std::pair<const K, V>. The Rust iterator type therefore has to depend on T alone. The new map iterator is built on MapNode<T>. The map itself still owns a BTreeMap.

The converter special cases for map iterators (GetStrongestIteratorCategory, PushSuppressIteratorClone, and the Vec</BTreeMap< checks in RecordHasCopyableFields) are removed, since the rules now handle these types.


Function rules that take the container as an argument already work, even when they also spell a container member type. For example std::map::erase:

template <typename T1, typename T2>
typename std::map<T1, T2>::iterator
f27(std::map<T1, T2> &o, typename std::map<T1, T2>::const_iterator it) {
  return o.erase(it);
}

template <typename T1, typename T2>
std::size_t f28(std::map<T1, T2> &o,
                const typename std::map<T1, T2>::key_type &key) {
  return o.erase(key);
}

std::map<T1, T2>::const_iterator is still a non-deduced context, but that does not matter here: T1 and T2 are deduced from the first parameter o, and Clang then substitutes them into the second parameter. Deduction only fails when the iterator is the only place the template parameters appear, as in the type rule using t = typename std::map<T1, T2>::iterator;. Those are the rules this PR replaces.

@lucic71
lucic71 marked this pull request as draft October 16, 2026 14:19
@lucic71
lucic71 marked this pull request as ready for review October 16, 2026 18:37

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rules with un-deducible template arguments are not scalable

1 participant