@@ -125,18 +125,12 @@ lookupNestedClangTypeDecl(const clang::CXXRecordDecl *clangDecl,
125125
126126static clang::TypeDecl *
127127getIteratorCategoryDecl (const clang::CXXRecordDecl *clangDecl) {
128- clang::IdentifierInfo *iteratorCategoryDeclName =
129- &clangDecl->getASTContext ().Idents .get (" iterator_category" );
130- auto iteratorCategories = clangDecl->lookup (iteratorCategoryDeclName);
131- // If this is a templated typedef, Clang might have instantiated several
132- // equivalent typedef decls. If they aren't equivalent, Clang has already
133- // complained about this. Let's assume that they are equivalent. (see
134- // filterNonConflictingPreviousTypedefDecls in clang/Sema/SemaDecl.cpp)
135- if (iteratorCategories.empty ())
136- return nullptr ;
137- auto iteratorCategory = iteratorCategories.front ();
128+ return lookupNestedClangTypeDecl (clangDecl, " iterator_category" );
129+ }
138130
139- return dyn_cast_or_null<clang::TypeDecl>(iteratorCategory);
131+ static clang::TypeDecl *
132+ getIteratorConceptDecl (const clang::CXXRecordDecl *clangDecl) {
133+ return lookupNestedClangTypeDecl (clangDecl, " iterator_concept" );
140134}
141135
142136static ValueDecl *lookupOperator (NominalTypeDecl *decl, Identifier id,
@@ -435,55 +429,54 @@ void swift::conformToCxxIteratorIfNeeded(
435429 if (!iteratorCategory)
436430 return ;
437431
432+ auto unwrapUnderlyingTypeDecl =
433+ [](clang::TypeDecl *typeDecl) -> clang::CXXRecordDecl * {
434+ clang::CXXRecordDecl *underlyingDecl = nullptr ;
435+ if (auto typedefDecl = dyn_cast<clang::TypedefNameDecl>(typeDecl)) {
436+ auto type = typedefDecl->getUnderlyingType ();
437+ underlyingDecl = type->getAsCXXRecordDecl ();
438+ } else {
439+ underlyingDecl = dyn_cast<clang::CXXRecordDecl>(typeDecl);
440+ }
441+ if (underlyingDecl) {
442+ underlyingDecl = underlyingDecl->getDefinition ();
443+ }
444+ return underlyingDecl;
445+ };
446+
438447 // If `iterator_category` is a typedef or a using-decl, retrieve the
439448 // underlying struct decl.
440- clang::CXXRecordDecl *underlyingCategoryDecl = nullptr ;
441- if (auto typedefDecl = dyn_cast<clang::TypedefNameDecl>(iteratorCategory)) {
442- auto type = typedefDecl->getUnderlyingType ();
443- underlyingCategoryDecl = type->getAsCXXRecordDecl ();
444- } else {
445- underlyingCategoryDecl = dyn_cast<clang::CXXRecordDecl>(iteratorCategory);
446- }
447- if (underlyingCategoryDecl) {
448- underlyingCategoryDecl = underlyingCategoryDecl->getDefinition ();
449- }
450-
449+ auto underlyingCategoryDecl = unwrapUnderlyingTypeDecl (iteratorCategory);
451450 if (!underlyingCategoryDecl)
452451 return ;
453452
454- auto isIteratorCategoryDecl = [&](const clang::CXXRecordDecl *base,
455- StringRef tag) {
453+ auto isIteratorTagDecl = [&](const clang::CXXRecordDecl *base,
454+ StringRef tag) {
456455 return base->isInStdNamespace () && base->getIdentifier () &&
457456 base->getName () == tag;
458457 };
459458 auto isInputIteratorDecl = [&](const clang::CXXRecordDecl *base) {
460- return isIteratorCategoryDecl (base, " input_iterator_tag" );
459+ return isIteratorTagDecl (base, " input_iterator_tag" );
461460 };
462461 auto isRandomAccessIteratorDecl = [&](const clang::CXXRecordDecl *base) {
463- return isIteratorCategoryDecl (base, " random_access_iterator_tag" );
462+ return isIteratorTagDecl (base, " random_access_iterator_tag" );
464463 };
465464 auto isContiguousIteratorDecl = [&](const clang::CXXRecordDecl *base) {
466- return isIteratorCategoryDecl (base, " contiguous_iterator_tag" ); // C++20
465+ return isIteratorTagDecl (base, " contiguous_iterator_tag" ); // C++20
467466 };
468467
469468 // Traverse all transitive bases of `underlyingDecl` to check if
470469 // it inherits from `std::input_iterator_tag`.
471470 bool isInputIterator = isInputIteratorDecl (underlyingCategoryDecl);
472471 bool isRandomAccessIterator =
473472 isRandomAccessIteratorDecl (underlyingCategoryDecl);
474- bool isContiguousIterator = isContiguousIteratorDecl (underlyingCategoryDecl);
475473 underlyingCategoryDecl->forallBases ([&](const clang::CXXRecordDecl *base) {
476474 if (isInputIteratorDecl (base)) {
477475 isInputIterator = true ;
478476 }
479477 if (isRandomAccessIteratorDecl (base)) {
480478 isRandomAccessIterator = true ;
481479 isInputIterator = true ;
482- }
483- if (isContiguousIteratorDecl (base)) {
484- isContiguousIterator = true ;
485- isRandomAccessIterator = true ;
486- isInputIterator = true ;
487480 return false ;
488481 }
489482 return true ;
@@ -492,6 +485,27 @@ void swift::conformToCxxIteratorIfNeeded(
492485 if (!isInputIterator)
493486 return ;
494487
488+ bool isContiguousIterator = false ;
489+ // In C++20, `std::contiguous_iterator_tag` is specified as a type called
490+ // `iterator_concept`. It is not possible to detect a contiguous iterator
491+ // based on its `iterator_category`. The type might not have an
492+ // `iterator_concept` defined.
493+ if (auto iteratorConcept = getIteratorConceptDecl (clangDecl)) {
494+ if (auto underlyingConceptDecl =
495+ unwrapUnderlyingTypeDecl (iteratorConcept)) {
496+ isContiguousIterator = isContiguousIteratorDecl (underlyingConceptDecl);
497+ if (!isContiguousIterator)
498+ underlyingConceptDecl->forallBases (
499+ [&](const clang::CXXRecordDecl *base) {
500+ if (isContiguousIteratorDecl (base)) {
501+ isContiguousIterator = true ;
502+ return false ;
503+ }
504+ return true ;
505+ });
506+ }
507+ }
508+
495509 // Check if present: `var pointee: Pointee { get }`
496510 auto pointeeId = ctx.getIdentifier (" pointee" );
497511 auto pointee = lookupDirectSingleWithoutExtensions<VarDecl>(decl, pointeeId);
0 commit comments