Skip to content

Commit 85ea760

Browse files
committed
[cxx-interop] allow shared ref retain function to return self
Many existing C APIs for retaining references, including Apple's own, return the reference. Support this pattern, along with the existing void return signature, with when importing reference types from C++.
1 parent a667b22 commit 85ea760

File tree

3 files changed

+41
-13
lines changed

3 files changed

+41
-13
lines changed

include/swift/AST/DiagnosticsClangImporter.def

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,11 @@ ERROR(foreign_reference_types_invalid_retain_release, none,
231231
"type '%2'",
232232
(bool, StringRef, StringRef))
233233

234-
ERROR(foreign_reference_types_retain_release_non_void_return_type, none,
234+
ERROR(foreign_reference_types_retain_non_void_or_self_return_type, none,
235+
"specified %select{retain|release}0 function '%1' is invalid; "
236+
"%select{retain|release}0 function must have 'void' or parameter return type",
237+
(bool, StringRef))
238+
ERROR(foreign_reference_types_release_non_void_return_type, none,
235239
"specified %select{retain|release}0 function '%1' is invalid; "
236240
"%select{retain|release}0 function must have 'void' return type",
237241
(bool, StringRef))

lib/ClangImporter/ImportDecl.cpp

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2536,20 +2536,19 @@ namespace {
25362536

25372537
enum class RetainReleaseOperationKind {
25382538
notAfunction,
2539-
doesntReturnVoid,
2539+
doesntReturnVoidOrSelf,
25402540
invalidParameters,
25412541
valid
25422542
};
25432543

25442544
auto getOperationValidity =
2545-
[&](ValueDecl *operation) -> RetainReleaseOperationKind {
2545+
[&](ValueDecl *operation,
2546+
CustomRefCountingOperationKind operationKind)
2547+
-> RetainReleaseOperationKind {
25462548
auto operationFn = dyn_cast<FuncDecl>(operation);
25472549
if (!operationFn)
25482550
return RetainReleaseOperationKind::notAfunction;
25492551

2550-
if (!operationFn->getResultInterfaceType()->isVoid())
2551-
return RetainReleaseOperationKind::doesntReturnVoid;
2552-
25532552
if (operationFn->getParameters()->size() != 1)
25542553
return RetainReleaseOperationKind::invalidParameters;
25552554

@@ -2561,6 +2560,16 @@ namespace {
25612560
}
25622561

25632562
swift::NominalTypeDecl *paramDecl = paramType->getAnyNominal();
2563+
2564+
// The return type should be void (for release functions), or void
2565+
// or the parameter type (for retain functions).
2566+
auto resultInterfaceType = operationFn->getResultInterfaceType();
2567+
if (!resultInterfaceType->isVoid()) {
2568+
if (operationKind == CustomRefCountingOperationKind::release ||
2569+
resultInterfaceType->getAnyNominal() != paramDecl)
2570+
return RetainReleaseOperationKind::doesntReturnVoidOrSelf;
2571+
}
2572+
25642573
// The parameter of the retain/release function should be pointer to the
25652574
// same FRT or a base FRT.
25662575
if (paramDecl != classDecl) {
@@ -2574,6 +2583,7 @@ namespace {
25742583
}
25752584
return RetainReleaseOperationKind::invalidParameters;
25762585
}
2586+
25772587
return RetainReleaseOperationKind::valid;
25782588
};
25792589

@@ -2612,7 +2622,8 @@ namespace {
26122622
} else if (retainOperation.kind ==
26132623
CustomRefCountingOperationResult::foundOperation) {
26142624
RetainReleaseOperationKind operationKind =
2615-
getOperationValidity(retainOperation.operation);
2625+
getOperationValidity(retainOperation.operation,
2626+
CustomRefCountingOperationKind::retain);
26162627
HeaderLoc loc(decl->getLocation());
26172628
switch (operationKind) {
26182629
case RetainReleaseOperationKind::notAfunction:
@@ -2621,10 +2632,10 @@ namespace {
26212632
diag::foreign_reference_types_retain_release_not_a_function_decl,
26222633
false, retainOperation.name);
26232634
break;
2624-
case RetainReleaseOperationKind::doesntReturnVoid:
2635+
case RetainReleaseOperationKind::doesntReturnVoidOrSelf:
26252636
Impl.diagnose(
26262637
loc,
2627-
diag::foreign_reference_types_retain_release_non_void_return_type,
2638+
diag::foreign_reference_types_retain_non_void_or_self_return_type,
26282639
false, retainOperation.name);
26292640
break;
26302641
case RetainReleaseOperationKind::invalidParameters:
@@ -2676,7 +2687,8 @@ namespace {
26762687
} else if (releaseOperation.kind ==
26772688
CustomRefCountingOperationResult::foundOperation) {
26782689
RetainReleaseOperationKind operationKind =
2679-
getOperationValidity(releaseOperation.operation);
2690+
getOperationValidity(releaseOperation.operation,
2691+
CustomRefCountingOperationKind::release);
26802692
HeaderLoc loc(decl->getLocation());
26812693
switch (operationKind) {
26822694
case RetainReleaseOperationKind::notAfunction:
@@ -2685,10 +2697,10 @@ namespace {
26852697
diag::foreign_reference_types_retain_release_not_a_function_decl,
26862698
true, releaseOperation.name);
26872699
break;
2688-
case RetainReleaseOperationKind::doesntReturnVoid:
2700+
case RetainReleaseOperationKind::doesntReturnVoidOrSelf:
26892701
Impl.diagnose(
26902702
loc,
2691-
diag::foreign_reference_types_retain_release_non_void_return_type,
2703+
diag::foreign_reference_types_release_non_void_return_type,
26922704
true, releaseOperation.name);
26932705
break;
26942706
case RetainReleaseOperationKind::invalidParameters:

test/Interop/Cxx/foreign-reference/invalid-retain-operation-errors.swift

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,15 @@ GoodRetainRelease {};
4646
void goodRetain(GoodRetainRelease *v);
4747
void goodRelease(GoodRetainRelease *v);
4848

49+
struct
50+
__attribute__((swift_attr("import_reference")))
51+
__attribute__((swift_attr("retain:goodRetainWithRetainReturningSelf")))
52+
__attribute__((swift_attr("release:goodReleaseWithRetainReturningSelf")))
53+
GoodRetainReleaseWithRetainReturningSelf {};
54+
55+
GoodRetainReleaseWithRetainReturningSelf *goodRetainWithRetainReturningSelf(GoodRetainReleaseWithRetainReturningSelf *v);
56+
void goodReleaseWithRetainReturningSelf(GoodRetainReleaseWithRetainReturningSelf *v);
57+
4958
struct
5059
__attribute__((swift_attr("import_reference")))
5160
__attribute__((swift_attr("retain:goodRetainWithNullabilityAnnotations")))
@@ -226,7 +235,7 @@ public func test(x: NonExistent) { }
226235
@available(macOS 13.3, *)
227236
public func test(x: NoRetainRelease) { }
228237

229-
// CHECK: error: specified retain function 'badRetain' is invalid; retain function must have 'void' return type
238+
// CHECK: error: specified retain function 'badRetain' is invalid; retain function must have 'void' or parameter return type
230239
// CHECK: error: specified release function 'badRelease' is invalid; release function must have exactly one argument of type 'BadRetainRelease'
231240
@available(macOS 13.3, *)
232241
public func test(x: BadRetainRelease) { }
@@ -239,6 +248,9 @@ public func test(x: BadRetainReleaseWithNullabilityAnnotations) { }
239248
@available(macOS 13.3, *)
240249
public func test(x: GoodRetainRelease) { }
241250

251+
@available(macOS 13.3, *)
252+
public func test(x: GoodRetainReleaseRetainReturningSelf) { }
253+
242254
@available(macOS 13.3, *)
243255
public func test(x: GoodRetainReleaseWithNullabilityAnnotations) { }
244256

0 commit comments

Comments
 (0)