Skip to content

Commit da23bcf

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 51fd394 commit da23bcf

File tree

3 files changed

+46
-18
lines changed

3 files changed

+46
-18
lines changed

include/swift/AST/DiagnosticsClangImporter.def

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -231,10 +231,14 @@ 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,
235-
"specified %select{retain|release}0 function '%1' is invalid; "
236-
"%select{retain|release}0 function must have 'void' return type",
237-
(bool, StringRef))
234+
ERROR(foreign_reference_types_retain_non_void_or_self_return_type, none,
235+
"specified retain function '%0' is invalid; "
236+
"retain function must have 'void' or parameter return type",
237+
(StringRef))
238+
ERROR(foreign_reference_types_release_non_void_return_type, none,
239+
"specified release function '%0' is invalid; "
240+
"release function must have 'void' return type",
241+
(StringRef))
238242
ERROR(foreign_reference_types_retain_release_not_a_function_decl, none,
239243
"specified %select{retain|release}0 function '%1' is not a function",
240244
(bool, StringRef))

lib/ClangImporter/ImportDecl.cpp

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2532,20 +2532,19 @@ namespace {
25322532

25332533
enum class RetainReleaseOperationKind {
25342534
notAfunction,
2535-
doesntReturnVoid,
2535+
doesntReturnVoidOrSelf,
25362536
invalidParameters,
25372537
valid
25382538
};
25392539

25402540
auto getOperationValidity =
2541-
[&](ValueDecl *operation) -> RetainReleaseOperationKind {
2541+
[&](ValueDecl *operation,
2542+
CustomRefCountingOperationKind operationKind)
2543+
-> RetainReleaseOperationKind {
25422544
auto operationFn = dyn_cast<FuncDecl>(operation);
25432545
if (!operationFn)
25442546
return RetainReleaseOperationKind::notAfunction;
25452547

2546-
if (!operationFn->getResultInterfaceType()->isVoid())
2547-
return RetainReleaseOperationKind::doesntReturnVoid;
2548-
25492548
if (operationFn->getParameters()->size() != 1)
25502549
return RetainReleaseOperationKind::invalidParameters;
25512550

@@ -2557,6 +2556,16 @@ namespace {
25572556
}
25582557

25592558
swift::NominalTypeDecl *paramDecl = paramType->getAnyNominal();
2559+
2560+
// The return type should be void (for release functions), or void
2561+
// or the parameter type (for retain functions).
2562+
auto resultInterfaceType = operationFn->getResultInterfaceType();
2563+
if (!resultInterfaceType->isVoid()) {
2564+
if (operationKind == CustomRefCountingOperationKind::release ||
2565+
!resultInterfaceType->lookThroughSingleOptionalType()->isEqual(paramType))
2566+
return RetainReleaseOperationKind::doesntReturnVoidOrSelf;
2567+
}
2568+
25602569
// The parameter of the retain/release function should be pointer to the
25612570
// same FRT or a base FRT.
25622571
if (paramDecl != classDecl) {
@@ -2570,6 +2579,7 @@ namespace {
25702579
}
25712580
return RetainReleaseOperationKind::invalidParameters;
25722581
}
2582+
25732583
return RetainReleaseOperationKind::valid;
25742584
};
25752585

@@ -2608,7 +2618,8 @@ namespace {
26082618
} else if (retainOperation.kind ==
26092619
CustomRefCountingOperationResult::foundOperation) {
26102620
RetainReleaseOperationKind operationKind =
2611-
getOperationValidity(retainOperation.operation);
2621+
getOperationValidity(retainOperation.operation,
2622+
CustomRefCountingOperationKind::retain);
26122623
HeaderLoc loc(decl->getLocation());
26132624
switch (operationKind) {
26142625
case RetainReleaseOperationKind::notAfunction:
@@ -2617,11 +2628,11 @@ namespace {
26172628
diag::foreign_reference_types_retain_release_not_a_function_decl,
26182629
false, retainOperation.name);
26192630
break;
2620-
case RetainReleaseOperationKind::doesntReturnVoid:
2631+
case RetainReleaseOperationKind::doesntReturnVoidOrSelf:
26212632
Impl.diagnose(
26222633
loc,
2623-
diag::foreign_reference_types_retain_release_non_void_return_type,
2624-
false, retainOperation.name);
2634+
diag::foreign_reference_types_retain_non_void_or_self_return_type,
2635+
retainOperation.name);
26252636
break;
26262637
case RetainReleaseOperationKind::invalidParameters:
26272638
Impl.diagnose(loc,
@@ -2672,7 +2683,8 @@ namespace {
26722683
} else if (releaseOperation.kind ==
26732684
CustomRefCountingOperationResult::foundOperation) {
26742685
RetainReleaseOperationKind operationKind =
2675-
getOperationValidity(releaseOperation.operation);
2686+
getOperationValidity(releaseOperation.operation,
2687+
CustomRefCountingOperationKind::release);
26762688
HeaderLoc loc(decl->getLocation());
26772689
switch (operationKind) {
26782690
case RetainReleaseOperationKind::notAfunction:
@@ -2681,11 +2693,11 @@ namespace {
26812693
diag::foreign_reference_types_retain_release_not_a_function_decl,
26822694
true, releaseOperation.name);
26832695
break;
2684-
case RetainReleaseOperationKind::doesntReturnVoid:
2696+
case RetainReleaseOperationKind::doesntReturnVoidOrSelf:
26852697
Impl.diagnose(
26862698
loc,
2687-
diag::foreign_reference_types_retain_release_non_void_return_type,
2688-
true, releaseOperation.name);
2699+
diag::foreign_reference_types_release_non_void_return_type,
2700+
releaseOperation.name);
26892701
break;
26902702
case RetainReleaseOperationKind::invalidParameters:
26912703
Impl.diagnose(loc,

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)