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, ERROR(foreign_reference_types_retain_non_void_or_self_return_type, none,
"specified retain function '%0' is invalid; " "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)) (StringRef))
ERROR(foreign_reference_types_release_non_void_return_type, none, ERROR(foreign_reference_types_release_non_void_return_type, none,
"specified release function '%0' is invalid; " "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)) (StringRef))
ERROR(foreign_reference_types_retain_release_not_a_function_decl, none, ERROR(foreign_reference_types_retain_release_not_a_function_decl, none,
"specified %select{retain|release}0 function '%1' is not a function", "specified %select{retain|release}0 function '%1' is not a function",

View File

@@ -2717,7 +2717,7 @@ namespace {
enum class RetainReleaseOperationKind { enum class RetainReleaseOperationKind {
notAfunction, notAfunction,
doesntReturnVoidOrSelf, invalidReturnType,
invalidParameters, invalidParameters,
valid valid
}; };
@@ -2745,10 +2745,20 @@ namespace {
// The return type should be void (for release functions), or void // The return type should be void (for release functions), or void
// or the parameter type (for retain functions). // or the parameter type (for retain functions).
auto resultInterfaceType = operationFn->getResultInterfaceType(); 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 || if (operationKind == CustomRefCountingOperationKind::release ||
!resultInterfaceType->lookThroughSingleOptionalType()->isEqual(paramType)) !resultInterfaceType->lookThroughSingleOptionalType()->isEqual(paramType))
return RetainReleaseOperationKind::doesntReturnVoidOrSelf; return RetainReleaseOperationKind::invalidReturnType;
} }
// The parameter of the retain/release function should be pointer to the // 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, diag::foreign_reference_types_retain_release_not_a_function_decl,
false, retainOperation.name); false, retainOperation.name);
break; break;
case RetainReleaseOperationKind::doesntReturnVoidOrSelf: case RetainReleaseOperationKind::invalidReturnType:
Impl.diagnose( Impl.diagnose(
loc, loc,
diag::foreign_reference_types_retain_non_void_or_self_return_type, 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, diag::foreign_reference_types_retain_release_not_a_function_decl,
true, releaseOperation.name); true, releaseOperation.name);
break; break;
case RetainReleaseOperationKind::doesntReturnVoidOrSelf: case RetainReleaseOperationKind::invalidReturnType:
Impl.diagnose( Impl.diagnose(
loc, loc,
diag::foreign_reference_types_release_non_void_return_type, diag::foreign_reference_types_release_non_void_return_type,

View File

@@ -64,6 +64,20 @@ GlobalCountNullableInit {
inline void GCRetainNullableInit(GlobalCountNullableInit *x) { globalCount++; } inline void GCRetainNullableInit(GlobalCountNullableInit *x) { globalCount++; }
inline void GCReleaseNullableInit(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 SWIFT_END_NULLABILITY_ANNOTATIONS
#endif // TEST_INTEROP_CXX_FOREIGN_REFERENCE_INPUTS_REFERENCE_COUNTED_H #endif // TEST_INTEROP_CXX_FOREIGN_REFERENCE_INPUTS_REFERENCE_COUNTED_H

View File

@@ -25,7 +25,7 @@ struct
__attribute__((swift_attr("release:badRelease"))) __attribute__((swift_attr("release:badRelease")))
BadRetainRelease {}; BadRetainRelease {};
int badRetain(BadRetainRelease *v); float badRetain(BadRetainRelease *v);
void badRelease(BadRetainRelease *v, int i); void badRelease(BadRetainRelease *v, int i);
struct struct
@@ -235,7 +235,7 @@ public func test(x: NonExistent) { }
@available(macOS 13.3, *) @available(macOS 13.3, *)
public func test(x: NoRetainRelease) { } 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' // CHECK: error: specified release function 'badRelease' is invalid; release function must have exactly one argument of type 'BadRetainRelease'
@available(macOS 13.3, *) @available(macOS 13.3, *)
public func test(x: BadRetainRelease) { } public func test(x: BadRetainRelease) { }

View File

@@ -17,6 +17,19 @@ public func getLocalCount() -> NS.LocalCount {
// CHECK-NEXT: } // 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 { public func get42() -> Int32 {
let result = NS.LocalCount.create() let result = NS.LocalCount.create()
return result.returns42() return result.returns42()