diff --git a/include/swift/AST/DiagnosticsClangImporter.def b/include/swift/AST/DiagnosticsClangImporter.def index 8ab826cc04839..f13a7c9dcef91 100644 --- a/include/swift/AST/DiagnosticsClangImporter.def +++ b/include/swift/AST/DiagnosticsClangImporter.def @@ -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", diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index b3c202545e7fd..a1ccefb60d025 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -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, diff --git a/test/Interop/Cxx/foreign-reference/Inputs/reference-counted.h b/test/Interop/Cxx/foreign-reference/Inputs/reference-counted.h index 1ed4c3512d8d5..b0669edfe4c6f 100644 --- a/test/Interop/Cxx/foreign-reference/Inputs/reference-counted.h +++ b/test/Interop/Cxx/foreign-reference/Inputs/reference-counted.h @@ -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 diff --git a/test/Interop/Cxx/foreign-reference/invalid-retain-operation-errors.swift b/test/Interop/Cxx/foreign-reference/invalid-retain-operation-errors.swift index a44068fc5a38a..03b6b4f4a1cfd 100644 --- a/test/Interop/Cxx/foreign-reference/invalid-retain-operation-errors.swift +++ b/test/Interop/Cxx/foreign-reference/invalid-retain-operation-errors.swift @@ -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) { } diff --git a/test/Interop/Cxx/foreign-reference/reference-counted-irgen.swift b/test/Interop/Cxx/foreign-reference/reference-counted-irgen.swift index c5e723c6c86f6..fbef0db69bbba 100644 --- a/test/Interop/Cxx/foreign-reference/reference-counted-irgen.swift +++ b/test/Interop/Cxx/foreign-reference/reference-counted-irgen.swift @@ -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()