Skip to content

Commit 0c7621d

Browse files
authored
Merge pull request #74541 from hyp/eng/lookup-imported-member-operator-cxx
[cxx-interop][serialization] resolve x-refs to instantiated/synthesiz…
2 parents 67e4f11 + 983fb80 commit 0c7621d

File tree

5 files changed

+95
-0
lines changed

5 files changed

+95
-0
lines changed

include/swift/ClangImporter/ClangImporter.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,13 @@ bool isCFTypeDecl(const clang::TypedefNameDecl *Decl);
684684
/// Determine the imported CF type for the given typedef-name, or the empty
685685
/// string if this is not an imported CF type name.
686686
llvm::StringRef getCFTypeName(const clang::TypedefNameDecl *decl);
687+
688+
/// Lookup and return the synthesized conformance operator like '==' '-' or '+='
689+
/// for the given type.
690+
ValueDecl *getImportedMemberOperator(const DeclBaseName &name,
691+
NominalTypeDecl *selfType,
692+
std::optional<Type> parameterType);
693+
687694
} // namespace importer
688695

689696
struct ClangInvocationFileMapping {

lib/ClangImporter/ClangDerivedConformances.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,28 @@ bool swift::isIterator(const clang::CXXRecordDecl *clangDecl) {
395395
return getIteratorCategoryDecl(clangDecl);
396396
}
397397

398+
ValueDecl *
399+
swift::importer::getImportedMemberOperator(const DeclBaseName &name,
400+
NominalTypeDecl *selfType,
401+
std::optional<Type> parameterType) {
402+
assert(name.isOperator());
403+
// Handle ==, -, and += operators, that are required operators for C++
404+
// iterator types to conform to the corresponding Cxx iterator protocols.
405+
// These operators can be instantiated and synthesized by clang importer below,
406+
// and thus require additional lookup logic when they're being deserialized.
407+
if (name.getIdentifier() == selfType->getASTContext().Id_EqualsOperator) {
408+
return getEqualEqualOperator(selfType);
409+
}
410+
if (name.getIdentifier() == selfType->getASTContext().getIdentifier("-")) {
411+
return getMinusOperator(selfType);
412+
}
413+
if (name.getIdentifier() == selfType->getASTContext().getIdentifier("+=") &&
414+
parameterType) {
415+
return getPlusEqualOperator(selfType, *parameterType);
416+
}
417+
return nullptr;
418+
}
419+
398420
void swift::conformToCxxIteratorIfNeeded(
399421
ClangImporter::Implementation &impl, NominalTypeDecl *decl,
400422
const clang::CXXRecordDecl *clangDecl) {

lib/Serialization/Deserialization.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2040,6 +2040,26 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
20402040
}
20412041
filterValues(filterTy, nullptr, nullptr, isType, inProtocolExt,
20422042
importedFromClang, isStatic, std::nullopt, values);
2043+
if (values.empty() && importedFromClang && name.isOperator() && filterTy) {
2044+
// This could be a Clang-importer instantiated/synthesized conformance
2045+
// operator, like '==', '-' or '+=', that are required for conformances to
2046+
// one of the Cxx iterator protocols. Attempt to resolve it using clang importer
2047+
// lookup logic for the given type instead of looking for it in the module.
2048+
if (auto *fty = dyn_cast<AnyFunctionType>(filterTy.getPointer())) {
2049+
if (fty->getNumParams()) {
2050+
assert(fty->getNumParams() <= 2);
2051+
auto p = fty->getParams()[0].getParameterType();
2052+
if (auto sty = dyn_cast<NominalType>(p.getPointer())) {
2053+
if (auto *op = importer::getImportedMemberOperator(
2054+
name, sty->getDecl(),
2055+
fty->getNumParams() > 1
2056+
? fty->getParams()[1].getParameterType()
2057+
: std::optional<Type>{}))
2058+
values.push_back(op);
2059+
}
2060+
}
2061+
}
2062+
}
20432063
break;
20442064
}
20452065

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,20 @@ struct InheritedTemplatedConstRACIterator : BaseTemplatedRACIterator<T> {
743743

744744
typedef InheritedTemplatedConstRACIterator<int> InheritedTemplatedConstRACIteratorInt;
745745

746+
struct InheritedTypedConstRACIterator: InheritedTemplatedConstRACIterator<int> {
747+
using _super = InheritedTemplatedConstRACIterator<int>;
748+
using iterator_category = std::random_access_iterator_tag;
749+
using pointer = int *;
750+
751+
InheritedTypedConstRACIterator(int x)
752+
: InheritedTemplatedConstRACIterator<int>(value) {}
753+
754+
int operator-(const InheritedTypedConstRACIterator &other) const {
755+
return _super::value - other.value;
756+
}
757+
void operator+=(typename _super::difference_type v) { _super::value += v; }
758+
};
759+
746760
template <typename T>
747761
struct BaseTemplatedRACIteratorOutOfLineOps {
748762
using value_type = T;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swiftxx-frontend -emit-module %s -module-name TestA -I %S/Inputs -o %t/test-part.swiftmodule
3+
// RUN: %target-swiftxx-frontend -merge-modules -emit-module %t/test-part.swiftmodule -module-name TestA -I %S/Inputs -o %t/TestA.swiftmodule -sil-verify-none
4+
// RUN: %target-typecheck-verify-swift -I %S/Inputs -cxx-interoperability-mode=default -I %t
5+
6+
#if USE
7+
8+
import TestA
9+
10+
public func test() {
11+
print(testEqualEqual())
12+
print(testPlusEqualMinus())
13+
}
14+
15+
#else
16+
17+
import CustomSequence
18+
19+
@inlinable
20+
public func testEqualEqual() -> Bool {
21+
let m = HasInheritedConstIterator()
22+
return m.__beginUnsafe() == m.__endUnsafe()
23+
}
24+
25+
@inlinable
26+
public func testPlusEqualOrMinus() -> Bool {
27+
var b = InheritedTypedConstRACIterator(0)
28+
b += 1
29+
return (b - b) == 0
30+
}
31+
32+
#endif

0 commit comments

Comments
 (0)