Skip to content

[cxx-interop] Conform to UnsafeCxxContiguousIterator based on iterator_concept nested type #77049

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 17, 2024

Conversation

egorzhdan
Copy link
Contributor

3a200de has a logic bug where we tried to conform C++ iterator types to UnsafeCxxContiguousIterator protocol based on their nested type called iterator_category. The C++20 standard says we should rely on iterator_concept instead.

https://en.cppreference.com/w/cpp/iterator/iterator_tags#Iterator_concept

Despite what the name suggests, we are not actually using C++ concepts in this change.

rdar://137877849

@egorzhdan egorzhdan added the c++ interop Feature: Interoperability with C++ label Oct 16, 2024
@egorzhdan
Copy link
Contributor Author

@swift-ci please smoke test

Copy link
Contributor

@Xazax-hun Xazax-hun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We never really look at the std::iterator_traits<It>::iterator_concept specialization, do we? I think it is OK to not support it now, but I wonder if we want to have a FIXME in the code.

Have some questions inline.

// `iterator_concept`. It is not possible to detect a contiguous iterator
// based on its `iterator_category`. The type might not have an
// `iterator_concept` defined.
auto iteratorConcept = getIteratorConceptDecl(clangDecl);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to move this down, closer to its use?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, done!

auto unwrapUnderlyingTypeDecl =
[](clang::TypeDecl *typeDecl) -> clang::CXXRecordDecl * {
clang::CXXRecordDecl *underlyingDecl = nullptr;
if (auto typedefDecl = dyn_cast<clang::TypedefNameDecl>(typeDecl)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we have multiple layers of TypedefNameDecls? Would that be a problem?
E.g.:

struct MyIterator {
  using iterator_concept =  std::vector<int>::iterator::iterator_concept;
// ...
private:
  std::vector<int>::iterator it;
};

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! Let's make sure this works. I'll add a test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually this already works fine, I'll add a test in a separate PR.

};

// Traverse all transitive bases of `underlyingDecl` to check if
// it inherits from `std::input_iterator_tag`.
bool isInputIterator = isInputIteratorDecl(underlyingCategoryDecl);
bool isRandomAccessIterator =
isRandomAccessIteratorDecl(underlyingCategoryDecl);
bool isContiguousIterator = isContiguousIteratorDecl(underlyingCategoryDecl);
underlyingCategoryDecl->forallBases([&](const clang::CXXRecordDecl *base) {
if (isInputIteratorDecl(base)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not shortcut the search if we only found an input iterator but we do when we found a random access one. Is this intended?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeap, this is intended. If we found an input_iterator_tag, we might still find a random_access_iterator_tag later during traversal, which gives us stronger guarantees. This isn't very likely to happen in practice, but it's valid to have a complex inheritance tree of the tags.

…ator_concept` nested type

3a200de has a logic bug where we tried to conform C++ iterator types to `UnsafeCxxContiguousIterator` protocol based on their nested type called `iterator_category`. The C++20 standard says we should rely on `iterator_concept` instead.

https://en.cppreference.com/w/cpp/iterator/iterator_tags#Iterator_concept

Despite what the name suggests, we are not actually using C++ concepts in this change.

rdar://137877849
@egorzhdan egorzhdan force-pushed the egorzhdan/cxx-contiguous-fix branch from 42b3db7 to 34f6cd3 Compare October 16, 2024 18:48
@egorzhdan
Copy link
Contributor Author

@swift-ci please smoke test

@egorzhdan
Copy link
Contributor Author

@swift-ci please build toolchain Amazon Linux 2

Copy link
Contributor

@Xazax-hun Xazax-hun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@egorzhdan egorzhdan merged commit 04d055a into main Oct 17, 2024
3 of 4 checks passed
@egorzhdan egorzhdan deleted the egorzhdan/cxx-contiguous-fix branch October 17, 2024 11:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ interop Feature: Interoperability with C++
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants