Skip to content

Commit 41073a8

Browse files
authored
Merge pull request #77837 from lhoward/lhoward/retain-return-self
[cxx-interop] allow shared ref retain function to return self
2 parents 1b2a901 + da23bcf commit 41073a8

File tree

3 files changed

+60
-32
lines changed

3 files changed

+60
-32
lines changed

include/swift/AST/DiagnosticsClangImporter.def

+8-4
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

+39-27
Original file line numberDiff line numberDiff line change
@@ -2542,24 +2542,23 @@ namespace {
25422542
void validateForeignReferenceType(const clang::CXXRecordDecl *decl,
25432543
ClassDecl *classDecl) {
25442544

2545-
enum class RetainReleaseOperatonKind {
2545+
enum class RetainReleaseOperationKind {
25462546
notAfunction,
2547-
doesntReturnVoid,
2547+
doesntReturnVoidOrSelf,
25482548
invalidParameters,
25492549
valid
25502550
};
25512551

25522552
auto getOperationValidity =
2553-
[&](ValueDecl *operation) -> RetainReleaseOperatonKind {
2553+
[&](ValueDecl *operation,
2554+
CustomRefCountingOperationKind operationKind)
2555+
-> RetainReleaseOperationKind {
25542556
auto operationFn = dyn_cast<FuncDecl>(operation);
25552557
if (!operationFn)
2556-
return RetainReleaseOperatonKind::notAfunction;
2557-
2558-
if (!operationFn->getResultInterfaceType()->isVoid())
2559-
return RetainReleaseOperatonKind::doesntReturnVoid;
2558+
return RetainReleaseOperationKind::notAfunction;
25602559

25612560
if (operationFn->getParameters()->size() != 1)
2562-
return RetainReleaseOperatonKind::invalidParameters;
2561+
return RetainReleaseOperationKind::invalidParameters;
25632562

25642563
Type paramType =
25652564
operationFn->getParameters()->get(0)->getInterfaceType();
@@ -2569,20 +2568,31 @@ namespace {
25692568
}
25702569

25712570
swift::NominalTypeDecl *paramDecl = paramType->getAnyNominal();
2571+
2572+
// The return type should be void (for release functions), or void
2573+
// or the parameter type (for retain functions).
2574+
auto resultInterfaceType = operationFn->getResultInterfaceType();
2575+
if (!resultInterfaceType->isVoid()) {
2576+
if (operationKind == CustomRefCountingOperationKind::release ||
2577+
!resultInterfaceType->lookThroughSingleOptionalType()->isEqual(paramType))
2578+
return RetainReleaseOperationKind::doesntReturnVoidOrSelf;
2579+
}
2580+
25722581
// The parameter of the retain/release function should be pointer to the
25732582
// same FRT or a base FRT.
25742583
if (paramDecl != classDecl) {
25752584
if (const clang::Decl *paramClangDecl = paramDecl->getClangDecl()) {
25762585
if (const auto *paramTypeDecl =
25772586
dyn_cast<clang::CXXRecordDecl>(paramClangDecl)) {
25782587
if (decl->isDerivedFrom(paramTypeDecl)) {
2579-
return RetainReleaseOperatonKind::valid;
2588+
return RetainReleaseOperationKind::valid;
25802589
}
25812590
}
25822591
}
2583-
return RetainReleaseOperatonKind::invalidParameters;
2592+
return RetainReleaseOperationKind::invalidParameters;
25842593
}
2585-
return RetainReleaseOperatonKind::valid;
2594+
2595+
return RetainReleaseOperationKind::valid;
25862596
};
25872597

25882598
auto retainOperation = evaluateOrDefault(
@@ -2619,28 +2629,29 @@ namespace {
26192629
false, retainOperation.name, decl->getNameAsString());
26202630
} else if (retainOperation.kind ==
26212631
CustomRefCountingOperationResult::foundOperation) {
2622-
RetainReleaseOperatonKind operationKind =
2623-
getOperationValidity(retainOperation.operation);
2632+
RetainReleaseOperationKind operationKind =
2633+
getOperationValidity(retainOperation.operation,
2634+
CustomRefCountingOperationKind::retain);
26242635
HeaderLoc loc(decl->getLocation());
26252636
switch (operationKind) {
2626-
case RetainReleaseOperatonKind::notAfunction:
2637+
case RetainReleaseOperationKind::notAfunction:
26272638
Impl.diagnose(
26282639
loc,
26292640
diag::foreign_reference_types_retain_release_not_a_function_decl,
26302641
false, retainOperation.name);
26312642
break;
2632-
case RetainReleaseOperatonKind::doesntReturnVoid:
2643+
case RetainReleaseOperationKind::doesntReturnVoidOrSelf:
26332644
Impl.diagnose(
26342645
loc,
2635-
diag::foreign_reference_types_retain_release_non_void_return_type,
2636-
false, retainOperation.name);
2646+
diag::foreign_reference_types_retain_non_void_or_self_return_type,
2647+
retainOperation.name);
26372648
break;
2638-
case RetainReleaseOperatonKind::invalidParameters:
2649+
case RetainReleaseOperationKind::invalidParameters:
26392650
Impl.diagnose(loc,
26402651
diag::foreign_reference_types_invalid_retain_release,
26412652
false, retainOperation.name, classDecl->getNameStr());
26422653
break;
2643-
case RetainReleaseOperatonKind::valid:
2654+
case RetainReleaseOperationKind::valid:
26442655
break;
26452656
}
26462657
} else {
@@ -2683,28 +2694,29 @@ namespace {
26832694
true, releaseOperation.name, decl->getNameAsString());
26842695
} else if (releaseOperation.kind ==
26852696
CustomRefCountingOperationResult::foundOperation) {
2686-
RetainReleaseOperatonKind operationKind =
2687-
getOperationValidity(releaseOperation.operation);
2697+
RetainReleaseOperationKind operationKind =
2698+
getOperationValidity(releaseOperation.operation,
2699+
CustomRefCountingOperationKind::release);
26882700
HeaderLoc loc(decl->getLocation());
26892701
switch (operationKind) {
2690-
case RetainReleaseOperatonKind::notAfunction:
2702+
case RetainReleaseOperationKind::notAfunction:
26912703
Impl.diagnose(
26922704
loc,
26932705
diag::foreign_reference_types_retain_release_not_a_function_decl,
26942706
true, releaseOperation.name);
26952707
break;
2696-
case RetainReleaseOperatonKind::doesntReturnVoid:
2708+
case RetainReleaseOperationKind::doesntReturnVoidOrSelf:
26972709
Impl.diagnose(
26982710
loc,
2699-
diag::foreign_reference_types_retain_release_non_void_return_type,
2700-
true, releaseOperation.name);
2711+
diag::foreign_reference_types_release_non_void_return_type,
2712+
releaseOperation.name);
27012713
break;
2702-
case RetainReleaseOperatonKind::invalidParameters:
2714+
case RetainReleaseOperationKind::invalidParameters:
27032715
Impl.diagnose(loc,
27042716
diag::foreign_reference_types_invalid_retain_release,
27052717
true, releaseOperation.name, classDecl->getNameStr());
27062718
break;
2707-
case RetainReleaseOperatonKind::valid:
2719+
case RetainReleaseOperationKind::valid:
27082720
break;
27092721
}
27102722
} else {

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

+13-1
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)