Merge pull request #83815 from egorzhdan/egorzhdan/6.2-retain-release-unsigned

🍒[cxx-interop] Allow retain/release operations to return an unsigned integer
This commit is contained in:
Egor Zhdan
2025-08-20 02:58:41 +01:00
committed by GitHub
5 changed files with 46 additions and 9 deletions

View File

@@ -256,11 +256,11 @@ ERROR(foreign_reference_types_invalid_retain_release, none,
ERROR(foreign_reference_types_retain_non_void_or_self_return_type, none,
"specified retain function '%0' is invalid; "
"retain function must have 'void' or parameter return type",
"retain function must either return have 'void', the reference count as an integer, or the parameter type",
(StringRef))
ERROR(foreign_reference_types_release_non_void_return_type, none,
"specified release function '%0' is invalid; "
"release function must have 'void' return type",
"release function must either return 'void' or the reference count as an integer",
(StringRef))
ERROR(foreign_reference_types_retain_release_not_a_function_decl, none,
"specified %select{retain|release}0 function '%1' is not a function",

View File

@@ -2717,7 +2717,7 @@ namespace {
enum class RetainReleaseOperationKind {
notAfunction,
doesntReturnVoidOrSelf,
invalidReturnType,
invalidParameters,
valid
};
@@ -2745,10 +2745,20 @@ namespace {
// The return type should be void (for release functions), or void
// or the parameter type (for retain functions).
auto resultInterfaceType = operationFn->getResultInterfaceType();
if (!resultInterfaceType->isVoid()) {
if (!resultInterfaceType->isVoid() &&
!resultInterfaceType->isUInt() &&
!resultInterfaceType->isUInt8() &&
!resultInterfaceType->isUInt16() &&
!resultInterfaceType->isUInt32() &&
!resultInterfaceType->isUInt64() &&
!resultInterfaceType->isInt() &&
!resultInterfaceType->isInt8() &&
!resultInterfaceType->isInt16() &&
!resultInterfaceType->isInt32() &&
!resultInterfaceType->isInt64()) {
if (operationKind == CustomRefCountingOperationKind::release ||
!resultInterfaceType->lookThroughSingleOptionalType()->isEqual(paramType))
return RetainReleaseOperationKind::doesntReturnVoidOrSelf;
return RetainReleaseOperationKind::invalidReturnType;
}
// The parameter of the retain/release function should be pointer to the
@@ -2813,7 +2823,7 @@ namespace {
diag::foreign_reference_types_retain_release_not_a_function_decl,
false, retainOperation.name);
break;
case RetainReleaseOperationKind::doesntReturnVoidOrSelf:
case RetainReleaseOperationKind::invalidReturnType:
Impl.diagnose(
loc,
diag::foreign_reference_types_retain_non_void_or_self_return_type,
@@ -2878,7 +2888,7 @@ namespace {
diag::foreign_reference_types_retain_release_not_a_function_decl,
true, releaseOperation.name);
break;
case RetainReleaseOperationKind::doesntReturnVoidOrSelf:
case RetainReleaseOperationKind::invalidReturnType:
Impl.diagnose(
loc,
diag::foreign_reference_types_release_non_void_return_type,

View File

@@ -64,6 +64,20 @@ GlobalCountNullableInit {
inline void GCRetainNullableInit(GlobalCountNullableInit *x) { globalCount++; }
inline void GCReleaseNullableInit(GlobalCountNullableInit *x) { globalCount--; }
struct __attribute__((swift_attr("import_as_ref")))
__attribute__((swift_attr("retain:RCRetain")))
__attribute__((swift_attr("release:RCRelease"))) HasOpsReturningRefCount final {
int refCount = 0;
static HasOpsReturningRefCount *create() {
return new (malloc(sizeof(HasOpsReturningRefCount)))
HasOpsReturningRefCount();
}
};
inline unsigned RCRetain(HasOpsReturningRefCount *x) { return ++x->refCount; }
inline unsigned RCRelease(HasOpsReturningRefCount *x) { return --x->refCount; }
SWIFT_END_NULLABILITY_ANNOTATIONS
#endif // TEST_INTEROP_CXX_FOREIGN_REFERENCE_INPUTS_REFERENCE_COUNTED_H

View File

@@ -25,7 +25,7 @@ struct
__attribute__((swift_attr("release:badRelease")))
BadRetainRelease {};
int badRetain(BadRetainRelease *v);
float badRetain(BadRetainRelease *v);
void badRelease(BadRetainRelease *v, int i);
struct
@@ -235,7 +235,7 @@ public func test(x: NonExistent) { }
@available(macOS 13.3, *)
public func test(x: NoRetainRelease) { }
// CHECK: error: specified retain function 'badRetain' is invalid; retain function must have 'void' or parameter return type
// CHECK: error: specified retain function 'badRetain' is invalid; retain function must either return have 'void', the reference count as an integer, or the parameter type
// CHECK: error: specified release function 'badRelease' is invalid; release function must have exactly one argument of type 'BadRetainRelease'
@available(macOS 13.3, *)
public func test(x: BadRetainRelease) { }

View File

@@ -17,6 +17,19 @@ public func getLocalCount() -> NS.LocalCount {
// CHECK-NEXT: }
public func useRetainReleaseOpsReturningRefCount() -> HasOpsReturningRefCount {
let result = HasOpsReturningRefCount.create()
return result
}
// CHECK: define {{.*}}swiftcc ptr @"$s4main36useRetainReleaseOpsReturningRefCountSo03HasefgH0VyF"()
// CHECK-NEXT: entry:
// CHECK: %0 = call ptr @{{_ZN23HasOpsReturningRefCount6createEv|"\?create\@HasOpsReturningRefCount\@\@SAPEAU1\@XZ"}}()
// CHECK: %1 = call i32 @{{_Z8RCRetainP23HasOpsReturningRefCount|"\?RCRetain\@\@YAIPEAUHasOpsReturningRefCount\@\@\@Z"}}(ptr %0)
// CHECK: ret ptr %0
// CHECK-NEXT: }
public func get42() -> Int32 {
let result = NS.LocalCount.create()
return result.returns42()