Skip to content

Commit 3366b47

Browse files
committed
[cxx-interop] Correctly check iterator conformances
To determine whether to conform a C++ type to `CxxSequence` protocol automatically, ClangImporter checks if the corresponding iterator type conforms to `UnsafeCxxInputIterator`. This logic had false-positives, e.g. `Optional<OpaquePointer>` was treated as if it conforms to `UnsafeCxxInputIterator` while it actually doesn't. This happened because `lookupConformance` returned a conformance with a conditional requirement (`Wrapped : UnsafeCxxInputIterator`) that is not satisfied for `OpaquePointer`. rdar://100265664
1 parent e51f1ff commit 3366b47

File tree

3 files changed

+37
-4
lines changed

3 files changed

+37
-4
lines changed

lib/ClangImporter/ClangDerivedConformances.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,20 @@ lookupDirectWithoutExtensions(NominalTypeDecl *decl, Identifier id) {
4141
return result;
4242
}
4343

44+
static bool isConcreteAndValid(ProtocolConformanceRef conformanceRef,
45+
ModuleDecl *module) {
46+
if (conformanceRef.isInvalid())
47+
return false;
48+
if (!conformanceRef.isConcrete())
49+
return false;
50+
auto conformance = conformanceRef.getConcrete();
51+
auto subMap = conformance->getSubstitutions(module);
52+
return llvm::all_of(subMap.getConformances(),
53+
[&](ProtocolConformanceRef each) -> bool {
54+
return isConcreteAndValid(each, module);
55+
});
56+
}
57+
4458
static clang::TypeDecl *
4559
getIteratorCategoryDecl(const clang::CXXRecordDecl *clangDecl) {
4660
clang::IdentifierInfo *iteratorCategoryDeclName =
@@ -228,9 +242,10 @@ void swift::conformToCxxSequenceIfNeeded(
228242
return;
229243

230244
// Check if RawIterator conforms to UnsafeCxxInputIterator.
231-
auto rawIteratorConformanceRef = decl->getModuleContext()->lookupConformance(
232-
rawIteratorTy, cxxIteratorProto);
233-
if (!rawIteratorConformanceRef.isConcrete())
245+
ModuleDecl *module = decl->getModuleContext();
246+
auto rawIteratorConformanceRef =
247+
module->lookupConformance(rawIteratorTy, cxxIteratorProto);
248+
if (!isConcreteAndValid(rawIteratorConformanceRef, module))
234249
return;
235250
auto rawIteratorConformance = rawIteratorConformanceRef.getConcrete();
236251
auto pointeeDecl =
@@ -253,7 +268,7 @@ void swift::conformToCxxSequenceIfNeeded(
253268
return declSelfTy;
254269
return Type(dependentType);
255270
},
256-
LookUpConformanceInModule(decl->getModuleContext()));
271+
LookUpConformanceInModule(module));
257272

258273
impl.addSynthesizedTypealias(decl, ctx.Id_Element, pointeeTy);
259274
impl.addSynthesizedTypealias(decl, ctx.Id_Iterator, iteratorTy);

test/Interop/Cxx/stdlib/overlay/Inputs/custom-sequence.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,16 @@ struct HasBeginEndReturnRef {
8686
const ConstIterator &end() const { return e; }
8787
};
8888

89+
template <typename A> struct NoDefinition;
90+
91+
template <typename A, typename NoDef = NoDefinition<A>>
92+
struct HasTemplatedIterator {
93+
typedef NoDef* iterator; // OpaquePointer
94+
95+
iterator begin() const;
96+
iterator end() const;
97+
};
98+
99+
typedef HasTemplatedIterator<int> HasUninstantiatableIterator;
100+
89101
#endif // TEST_INTEROP_CXX_STDLIB_INPUTS_CUSTOM_SEQUENCE_H

test/Interop/Cxx/stdlib/overlay/custom-sequence-module-interface.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,9 @@
5858
// CHECK-NOT: typealias Iterator
5959
// CHECK-NOT: typealias RawIterator
6060
// CHECK: }
61+
// CHECK: struct __CxxTemplateInst20HasTemplatedIteratorIi12NoDefinitionIiEE {
62+
// CHECK-NOT: typealias Element
63+
// CHECK-NOT: typealias Iterator
64+
// CHECK-NOT: typealias RawIterator
65+
// CHECK: }
66+
// CHECK: typealias HasUninstantiatableIterator = __CxxTemplateInst20HasTemplatedIteratorIi12NoDefinitionIiEE

0 commit comments

Comments
 (0)