@@ -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,64 @@ void swift::conformToCxxIteratorIfNeeded(
435
429
if (!iteratorCategory)
436
430
return ;
437
431
432
+ // In C++20, `std::contiguous_iterator_tag` is specified as a type called
433
+ // `iterator_concept`. It is not possible to detect a contiguous iterator
434
+ // based on its `iterator_category`. The type might not have an
435
+ // `iterator_concept` defined.
436
+ auto iteratorConcept = getIteratorConceptDecl (clangDecl);
437
+
438
+ auto unwrapUnderlyingTypeDecl =
439
+ [](clang::TypeDecl *typeDecl) -> clang::CXXRecordDecl * {
440
+ clang::CXXRecordDecl *underlyingDecl = nullptr ;
441
+ if (auto typedefDecl = dyn_cast<clang::TypedefNameDecl>(typeDecl)) {
442
+ auto type = typedefDecl->getUnderlyingType ();
443
+ underlyingDecl = type->getAsCXXRecordDecl ();
444
+ } else {
445
+ underlyingDecl = dyn_cast<clang::CXXRecordDecl>(typeDecl);
446
+ }
447
+ if (underlyingDecl) {
448
+ underlyingDecl = underlyingDecl->getDefinition ();
449
+ }
450
+ return underlyingDecl;
451
+ };
452
+
438
453
// If `iterator_category` is a typedef or a using-decl, retrieve the
439
454
// 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
-
455
+ auto underlyingCategoryDecl = unwrapUnderlyingTypeDecl (iteratorCategory);
451
456
if (!underlyingCategoryDecl)
452
457
return ;
453
458
454
- auto isIteratorCategoryDecl = [&](const clang::CXXRecordDecl *base,
455
- StringRef tag) {
459
+ // Same for `iterator_concept`.
460
+ auto underlyingConceptDecl =
461
+ iteratorConcept ? unwrapUnderlyingTypeDecl (iteratorConcept) : nullptr ;
462
+
463
+ auto isIteratorTagDecl = [&](const clang::CXXRecordDecl *base,
464
+ StringRef tag) {
456
465
return base->isInStdNamespace () && base->getIdentifier () &&
457
466
base->getName () == tag;
458
467
};
459
468
auto isInputIteratorDecl = [&](const clang::CXXRecordDecl *base) {
460
- return isIteratorCategoryDecl (base, " input_iterator_tag" );
469
+ return isIteratorTagDecl (base, " input_iterator_tag" );
461
470
};
462
471
auto isRandomAccessIteratorDecl = [&](const clang::CXXRecordDecl *base) {
463
- return isIteratorCategoryDecl (base, " random_access_iterator_tag" );
472
+ return isIteratorTagDecl (base, " random_access_iterator_tag" );
464
473
};
465
474
auto isContiguousIteratorDecl = [&](const clang::CXXRecordDecl *base) {
466
- return isIteratorCategoryDecl (base, " contiguous_iterator_tag" ); // C++20
475
+ return isIteratorTagDecl (base, " contiguous_iterator_tag" ); // C++20
467
476
};
468
477
469
478
// Traverse all transitive bases of `underlyingDecl` to check if
470
479
// it inherits from `std::input_iterator_tag`.
471
480
bool isInputIterator = isInputIteratorDecl (underlyingCategoryDecl);
472
481
bool isRandomAccessIterator =
473
482
isRandomAccessIteratorDecl (underlyingCategoryDecl);
474
- bool isContiguousIterator = isContiguousIteratorDecl (underlyingCategoryDecl);
475
483
underlyingCategoryDecl->forallBases ([&](const clang::CXXRecordDecl *base) {
476
484
if (isInputIteratorDecl (base)) {
477
485
isInputIterator = true ;
478
486
}
479
487
if (isRandomAccessIteratorDecl (base)) {
480
488
isRandomAccessIterator = true ;
481
489
isInputIterator = true ;
482
- }
483
- if (isContiguousIteratorDecl (base)) {
484
- isContiguousIterator = true ;
485
- isRandomAccessIterator = true ;
486
- isInputIterator = true ;
487
490
return false ;
488
491
}
489
492
return true ;
@@ -492,6 +495,19 @@ void swift::conformToCxxIteratorIfNeeded(
492
495
if (!isInputIterator)
493
496
return ;
494
497
498
+ bool isContiguousIterator = false ;
499
+ if (underlyingConceptDecl) {
500
+ isContiguousIterator = isContiguousIteratorDecl (underlyingConceptDecl);
501
+ if (!isContiguousIterator)
502
+ underlyingConceptDecl->forallBases ([&](const clang::CXXRecordDecl *base) {
503
+ if (isContiguousIteratorDecl (base)) {
504
+ isContiguousIterator = true ;
505
+ return false ;
506
+ }
507
+ return true ;
508
+ });
509
+ }
510
+
495
511
// Check if present: `var pointee: Pointee { get }`
496
512
auto pointeeId = ctx.getIdentifier (" pointee" );
497
513
auto pointee = lookupDirectSingleWithoutExtensions<VarDecl>(decl, pointeeId);
0 commit comments