@@ -125,18 +125,12 @@ lookupNestedClangTypeDecl(const clang::CXXRecordDecl *clangDecl,
125
125
126
126
static clang::TypeDecl *
127
127
getIteratorCategoryDecl (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
+ }
138
130
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" );
140
134
}
141
135
142
136
static ValueDecl *lookupOperator (NominalTypeDecl *decl, Identifier id,
@@ -435,55 +429,54 @@ void swift::conformToCxxIteratorIfNeeded(
435
429
if (!iteratorCategory)
436
430
return ;
437
431
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
+
438
447
// If `iterator_category` is a typedef or a using-decl, retrieve the
439
448
// 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);
451
450
if (!underlyingCategoryDecl)
452
451
return ;
453
452
454
- auto isIteratorCategoryDecl = [&](const clang::CXXRecordDecl *base,
455
- StringRef tag) {
453
+ auto isIteratorTagDecl = [&](const clang::CXXRecordDecl *base,
454
+ StringRef tag) {
456
455
return base->isInStdNamespace () && base->getIdentifier () &&
457
456
base->getName () == tag;
458
457
};
459
458
auto isInputIteratorDecl = [&](const clang::CXXRecordDecl *base) {
460
- return isIteratorCategoryDecl (base, " input_iterator_tag" );
459
+ return isIteratorTagDecl (base, " input_iterator_tag" );
461
460
};
462
461
auto isRandomAccessIteratorDecl = [&](const clang::CXXRecordDecl *base) {
463
- return isIteratorCategoryDecl (base, " random_access_iterator_tag" );
462
+ return isIteratorTagDecl (base, " random_access_iterator_tag" );
464
463
};
465
464
auto isContiguousIteratorDecl = [&](const clang::CXXRecordDecl *base) {
466
- return isIteratorCategoryDecl (base, " contiguous_iterator_tag" ); // C++20
465
+ return isIteratorTagDecl (base, " contiguous_iterator_tag" ); // C++20
467
466
};
468
467
469
468
// Traverse all transitive bases of `underlyingDecl` to check if
470
469
// it inherits from `std::input_iterator_tag`.
471
470
bool isInputIterator = isInputIteratorDecl (underlyingCategoryDecl);
472
471
bool isRandomAccessIterator =
473
472
isRandomAccessIteratorDecl (underlyingCategoryDecl);
474
- bool isContiguousIterator = isContiguousIteratorDecl (underlyingCategoryDecl);
475
473
underlyingCategoryDecl->forallBases ([&](const clang::CXXRecordDecl *base) {
476
474
if (isInputIteratorDecl (base)) {
477
475
isInputIterator = true ;
478
476
}
479
477
if (isRandomAccessIteratorDecl (base)) {
480
478
isRandomAccessIterator = true ;
481
479
isInputIterator = true ;
482
- }
483
- if (isContiguousIteratorDecl (base)) {
484
- isContiguousIterator = true ;
485
- isRandomAccessIterator = true ;
486
- isInputIterator = true ;
487
480
return false ;
488
481
}
489
482
return true ;
@@ -492,6 +485,27 @@ void swift::conformToCxxIteratorIfNeeded(
492
485
if (!isInputIterator)
493
486
return ;
494
487
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
+
495
509
// Check if present: `var pointee: Pointee { get }`
496
510
auto pointeeId = ctx.getIdentifier (" pointee" );
497
511
auto pointee = lookupDirectSingleWithoutExtensions<VarDecl>(decl, pointeeId);
0 commit comments