Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions include/swift/AST/DiagnosticsClangImporter.def
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
20 changes: 15 additions & 5 deletions lib/ClangImporter/ImportDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2717,7 +2717,7 @@ namespace {

enum class RetainReleaseOperationKind {
notAfunction,
doesntReturnVoidOrSelf,
invalidReturnType,
invalidParameters,
valid
};
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
14 changes: 14 additions & 0 deletions test/Interop/Cxx/foreign-reference/Inputs/reference-counted.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down