Files
swift-mirror/test/decl/ext/c_implementation_cf.swift
Doug Gregor f2340ec9af [C interop] Allow an Unmanaged<T> result in a @c @implementation function
A C function returning a foreign reference or CoreFoundation type
unretained cannot be safely implemented, because there is no way to
ensure that the result object lives past the return. However, such C
functions do exist, and we would like to be able to implement them via
`@c @implementation`. Extend the signature-matching logic for
`@implementation` to permit an `Unmanaged<T>` result even when the
signature comes in an `T` to allow the use of `@implementation` here.

Implements rdar://188429740
2026-09-29 07:49:36 -07:00

78 lines
3.2 KiB
Swift

// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -verify %s \
// RUN: -import-objc-header %S/Inputs/c_implementation_cf.h \
// RUN: -target %target-stable-abi-triple
// REQUIRES: objc_interop
import CoreFoundation
// CF class types are representable in C, so they can be used in the signature
// of an '@c @implementation' function.
@implementation @c
func CImplTakesCFArray(_ arr: CFArray?) { }
@implementation @c
func CImplTakesCFTree(_ tree: CFTree?) { }
@implementation @c
func CImplTakesConsumedCFString(_ string: consuming CFString?) { }
@implementation @c
func CImplReturnsRetainedCFString() -> CFString? { fatalError() }
@implementation @c
func CImplReturnsNotRetainedCFString() -> CFString? { fatalError() }
// An unaudited CF-returning function is imported as returning
// 'Unmanaged<CFString>?', which is representable in C too.
@implementation @c
func CImplReturnsUnauditedCFString() -> Unmanaged<CFString>? { fatalError() }
// 'CFTypeRef' is imported as 'AnyObject', but it names the C type
// 'const void *' and so is representable in C.
@implementation @c
func CImplTakesCFTypeRef(_ obj: CFTypeRef?) { }
@implementation @c
func CImplReturnsRetainedCFTypeRef() -> CFTypeRef? { fatalError() }
// 'Unmanaged<CFTypeRef>' composes the two rules, which is what an unaudited
// 'CFTypeRef'-returning C function imports as.
@implementation @c
func CImplReturnsUnauditedCFTypeRef() -> Unmanaged<CFTypeRef>? { fatalError() }
// Writing the same type as 'AnyObject' does not name the C type, so it cannot
// be used to implement the same function.
@implementation @c(CImplTakesCFTypeRef)
// expected-error@-1 {{could not find imported function 'CImplTakesCFTypeRef' matching global function 'CImplTakesAnyObject'; make sure you import the module or header that declares it}}
func CImplTakesAnyObject(_ obj: AnyObject?) { }
// expected-error@-1 {{global function cannot be marked '@c' because the type of the parameter cannot be represented in C}}
// An audited CF result can be implemented as returning 'Unmanaged', which
// gives the implementation manual control over the retain count.
@implementation @c
func CImplReturnsAuditedCFString() -> Unmanaged<CFString> { fatalError() }
@implementation @c
func CImplReturnsAuditedNullableCFString() -> Unmanaged<CFString>? {
fatalError()
}
@implementation @c
func CImplReturnsAuditedCFTypeRef() -> Unmanaged<CFTypeRef> { fatalError() }
@implementation @c
func CImplReturnsAuditedCFStringWrongType() -> Unmanaged<CFArray> { fatalError() }
// expected-error@-1 {{global function 'CImplReturnsAuditedCFStringWrongType()' of type '() -> Unmanaged<CFArray>' does not match type '() -> CFString' declared by the header}}
@implementation @c
func CImplReturnsAuditedCFStringDroppedOptional() -> Unmanaged<CFString>? {
// expected-error@-1 {{global function 'CImplReturnsAuditedCFStringDroppedOptional()' of type '() -> Unmanaged<CFString>?' does not match type '() -> CFString' declared by the header}}
fatalError()
}
// Only results can be written as 'Unmanaged'.
@implementation @c
func CImplTakesAuditedCFString(_ string: Unmanaged<CFString>) { }
// expected-error@-1 {{global function 'CImplTakesAuditedCFString' of type '(Unmanaged<CFString>) -> ()' does not match type '(CFString) -> Void' declared by the header}}