Skip to content

Commit 546accb

Browse files
committed
[cxx-interop] Allow conforming C++ APIs that return IUO to Swift protocols
If a C++ method returns a pointer and is not annotated with `returns_nonnull`, ClangImporter imports its return type as implicitly unwrapped optional `UnsafePointer<T>!`. This happens, for example, for `begin()`/`end()` methods of C++ collection types. We would like to be able to conform C++ collections to `Swift.Sequence`/`Swift.Collection`/... To make this work, we create Swift protocols that require `func begin() -> RawIterator` and `func end() -> RawIterator` where `RawIterator` is an associated type. The problem is that currently if `RawIterator` is `UnsafePointer<T>?`, `begin()`/`end()` methods that return an implicitly unwrapped optional `UnsafePointer<T>!` won't satisfy the requirements. This change fixes that.
1 parent 9af8376 commit 546accb

File tree

3 files changed

+28
-1
lines changed

3 files changed

+28
-1
lines changed

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,9 @@ swift::matchWitness(
754754
OptionalAdjustment(std::get<2>(types)));
755755
}
756756

757-
if (!req->isObjC() && reqTypeIsIUO != witnessTypeIsIUO)
757+
if (!req->isObjC() &&
758+
!isa_and_nonnull<clang::CXXMethodDecl>(witness->getClangDecl()) &&
759+
reqTypeIsIUO != witnessTypeIsIUO)
758760
return RequirementMatch(witness, MatchKind::TypeConflict, witnessType);
759761

760762
if (auto result = matchTypes(std::get<0>(types), std::get<1>(types))) {

test/Interop/Cxx/class/Inputs/protocol-conformance.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,14 @@ struct Trivial {
2828
char test3(int, unsigned) { return 42; }
2929
};
3030

31+
struct ReturnsNullableValue {
32+
const int *returnPointer() { return nullptr; }
33+
};
34+
35+
struct ReturnsNonNullValue {
36+
const int *returnPointer() __attribute__((returns_nonnull)) {
37+
return (int *)this;
38+
}
39+
};
40+
3141
#endif // TEST_INTEROP_CXX_CLASS_INPUTS_PROTOCOL_CONFORMANCE_H

test/Interop/Cxx/class/protocol-conformance-typechecker.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,18 @@ protocol HasReturn42 {
1111
extension ConformsToProtocol : HasReturn42 {}
1212

1313
extension DoesNotConformToProtocol : HasReturn42 {} // expected-error {{'DoesNotConformToProtocol' does not conform to protocol}}
14+
15+
16+
protocol HasReturnNullable {
17+
mutating func returnPointer() -> UnsafePointer<Int32>?
18+
}
19+
20+
// HasReturnNullable's returnNullable returns an implicitly unwrapped optional:
21+
// mutating func returnPointer() -> UnsafePointer<Int32>!
22+
extension ReturnsNullableValue: HasReturnNullable {}
23+
24+
protocol HasReturnNonNull {
25+
mutating func returnPointer() -> UnsafePointer<Int32>
26+
}
27+
28+
extension ReturnsNonNullValue: HasReturnNonNull {}

0 commit comments

Comments
 (0)