[Swiftify] Emit @availability when expansions contain Span (#81320)

This prevents errors when compiling for older targets using a newer
compiler.

rdar://150740330
This commit is contained in:
Henrik G. Olsson
2025-05-08 16:13:24 -07:00
committed by GitHub
parent 23f0fb5941
commit 59d7d3160f
8 changed files with 169 additions and 19 deletions

View File

@@ -9031,10 +9031,11 @@ public:
static const ssize_t SELF_PARAM_INDEX = -2;
static const ssize_t RETURN_VALUE_INDEX = -1;
clang::ASTContext &ctx;
ASTContext &SwiftContext;
llvm::raw_ostream &out;
bool firstParam = true;
SwiftifyInfoPrinter(clang::ASTContext &ctx, llvm::raw_ostream &out)
: ctx(ctx), out(out) {
SwiftifyInfoPrinter(clang::ASTContext &ctx, ASTContext &SwiftContext, llvm::raw_ostream &out)
: ctx(ctx), SwiftContext(SwiftContext), out(out) {
out << "@_SwiftifyImport(";
}
~SwiftifyInfoPrinter() { out << ")"; }
@@ -9091,7 +9092,34 @@ public:
out << "]";
}
void printAvailability() {
printSeparator();
out << "spanAvailability: ";
printAvailabilityOfType("Span");
}
private:
ValueDecl *getDecl(StringRef DeclName) {
SmallVector<ValueDecl *, 1> decls;
SwiftContext.lookupInSwiftModule(DeclName, decls);
assert(decls.size() == 1);
if (decls.size() != 1) return nullptr;
return decls[0];
}
void printAvailabilityOfType(StringRef Name) {
ValueDecl *D = getDecl(Name);
out << "\"";
llvm::SaveAndRestore<bool> hasAvailbilitySeparatorRestore(firstParam, true);
for (auto attr : D->getSemanticAvailableAttrs(/*includingInactive=*/true)) {
auto introducedOpt = attr.getIntroduced();
if (!introducedOpt.has_value()) continue;
printSeparator();
out << prettyPlatformString(attr.getPlatform()) << " " << introducedOpt.value();
}
out << "\"";
}
void printSeparator() {
if (!firstParam) {
out << ", ";
@@ -9143,7 +9171,7 @@ void ClangImporter::Implementation::swiftify(FuncDecl *MappedDecl) {
}
return false;
};
SwiftifyInfoPrinter printer(getClangASTContext(), out);
SwiftifyInfoPrinter printer(getClangASTContext(), SwiftContext, out);
bool returnIsStdSpan = registerStdSpanTypeMapping(
MappedDecl->getResultInterfaceType(), ClangDecl->getReturnType());
if (auto CAT =
@@ -9187,6 +9215,7 @@ void ClangImporter::Implementation::swiftify(FuncDecl *MappedDecl) {
}
if (returnIsStdSpan && returnHasLifetimeInfo)
attachMacro = true;
printer.printAvailability();
printer.printTypeMapping(typeMapping);
}

View File

@@ -1069,14 +1069,7 @@ func parseLifetimeDependence(_ enumConstructorExpr: FunctionCallExprSyntax) thro
return (pointer, dependence)
}
func parseTypeMappingParam(_ paramAST: LabeledExprSyntax?) throws -> [String: String]? {
guard let unwrappedParamAST = paramAST else {
return nil
}
let paramExpr = unwrappedParamAST.expression
guard let dictExpr = paramExpr.as(DictionaryExprSyntax.self) else {
return nil
}
func parseStringLiteralDict(_ dictExpr: DictionaryExprSyntax) throws -> [String: String] {
var dict: [String: String] = [:]
switch dictExpr.content {
case .colon(_):
@@ -1098,6 +1091,45 @@ func parseTypeMappingParam(_ paramAST: LabeledExprSyntax?) throws -> [String: St
return dict
}
func parseStringMappingParam(_ paramAST: LabeledExprSyntax?, paramName: String) throws -> [String: String]? {
guard let unwrappedParamAST = paramAST else {
return nil
}
guard let label = unwrappedParamAST.label else {
return nil
}
if label.trimmed.text != paramName {
return nil
}
let paramExpr = unwrappedParamAST.expression
guard let dictExpr = paramExpr.as(DictionaryExprSyntax.self) else {
return nil
}
return try parseStringLiteralDict(dictExpr)
}
func parseTypeMappingParam(_ paramAST: LabeledExprSyntax?) throws -> [String: String]? {
return try parseStringMappingParam(paramAST, paramName: "typeMappings")
}
func parseSpanAvailabilityParam(_ paramAST: LabeledExprSyntax?) throws -> String? {
guard let unwrappedParamAST = paramAST else {
return nil
}
guard let label = unwrappedParamAST.label else {
return nil
}
if label.trimmed.text != "spanAvailability" {
return nil
}
let paramExpr = unwrappedParamAST.expression
guard let stringLitExpr = paramExpr.as(StringLiteralExprSyntax.self) else {
throw DiagnosticError(
"expected a string literal, got '\(paramExpr)'", node: paramExpr)
}
return stringLitExpr.representedLiteralValue
}
func parseCxxSpansInSignature(
_ signature: FunctionSignatureSyntax,
_ typeMappings: [String: String]?
@@ -1316,6 +1348,35 @@ func isMutableSpan(_ type: TypeSyntax) -> Bool {
return name == "MutableSpan" || name == "MutableRawSpan"
}
func isAnySpan(_ type: TypeSyntax) -> Bool {
if let optType = type.as(OptionalTypeSyntax.self) {
return isAnySpan(optType.wrappedType)
}
if let impOptType = type.as(ImplicitlyUnwrappedOptionalTypeSyntax.self) {
return isAnySpan(impOptType.wrappedType)
}
if let attrType = type.as(AttributedTypeSyntax.self) {
return isAnySpan(attrType.baseType)
}
guard let identifierType = type.as(IdentifierTypeSyntax.self) else {
return false
}
let name = identifierType.name.text
return name == "Span" || name == "RawSpan" || name == "MutableSpan" || name == "MutableRawSpan"
}
func getAvailability(_ newSignature: FunctionSignatureSyntax, _ spanAvailability: String?)
throws -> [AttributeListSyntax.Element] {
guard let spanAvailability else {
return []
}
let returnIsSpan = newSignature.returnClause != nil && isAnySpan(newSignature.returnClause!.type)
if !returnIsSpan && !newSignature.parameterClause.parameters.contains(where: { isAnySpan($0.type) }) {
return []
}
return [.attribute(AttributeSyntax("@available(\(raw: spanAvailability), *)"))]
}
func containsLifetimeAttr(_ attrs: AttributeListSyntax, for paramName: TokenSyntax) -> Bool {
for elem in attrs {
guard let attr = elem.as(AttributeSyntax.self) else {
@@ -1386,6 +1447,10 @@ public struct SwiftifyImportMacro: PeerMacro {
if typeMappings != nil {
arguments = arguments.dropLast()
}
let spanAvailability = try parseSpanAvailabilityParam(arguments.last)
if spanAvailability != nil {
arguments = arguments.dropLast()
}
var nonescapingPointers = Set<Int>()
var lifetimeDependencies: [SwiftifyExpr: [LifetimeDependence]] = [:]
var parsedArgs = try arguments.compactMap {
@@ -1441,6 +1506,7 @@ public struct SwiftifyImportMacro: PeerMacro {
let returnLifetimeAttribute = getReturnLifetimeAttribute(funcDecl, lifetimeDependencies)
let lifetimeAttrs =
returnLifetimeAttribute + paramLifetimeAttributes(newSignature, funcDecl.attributes)
let availabilityAttr = try getAvailability(newSignature, spanAvailability)
let disfavoredOverload: [AttributeListSyntax.Element] =
(onlyReturnTypeChanged
? [
@@ -1469,6 +1535,7 @@ public struct SwiftifyImportMacro: PeerMacro {
atSign: .atSignToken(),
attributeName: IdentifierTypeSyntax(name: "_alwaysEmitIntoClient")))
]
+ availabilityAttr
+ lifetimeAttrs
+ disfavoredOverload)
return [DeclSyntax(newFunc)]

View File

@@ -54,13 +54,15 @@ public enum _SwiftifyInfo {
/// It will replace some std::span arguments with Swift's Span type when sufficient information is
/// available.
///
/// Currently not supported: return pointers, nested pointers, pointee "count" parameters, endedBy.
/// Currently not supported: nested pointers, pointee "count" parameters, endedBy.
///
/// Parameter paramInfo: information about how the function uses the pointer passed to it. The
/// safety of the generated wrapper function depends on this info being extensive and accurate.
#if hasFeature(Macros)
@attached(peer, names: overloaded)
public macro _SwiftifyImport(_ paramInfo: _SwiftifyInfo..., typeMappings: [String: String] = [:]) =
public macro _SwiftifyImport(_ paramInfo: _SwiftifyInfo...,
spanAvailability: String? = nil,
typeMappings: [String: String] = [:]) =
#externalMacro(module: "SwiftMacros", type: "SwiftifyImportMacro")
#endif

View File

@@ -7,7 +7,7 @@
void simple(int len, int * __counted_by(len) __noescape p);
void swiftAttr(int len, int *p) __attribute__((
swift_attr("@_SwiftifyImport(.countedBy(pointer: .param(2), count: \"len\"), .nonescaping(pointer: .param(2)))")));
swift_attr("@_SwiftifyImport(.countedBy(pointer: .param(2), count: \"len\"), .nonescaping(pointer: .param(2)), spanAvailability: \"visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4\")")));
void shared(int len, int * __counted_by(len) __noescape p1, int * __counted_by(len) __noescape p2);

View File

@@ -6,7 +6,7 @@
void simple(int len, const void * __sized_by(len) __noescape p);
void swiftAttr(int len, const void *p) __attribute__((swift_attr(
"@_SwiftifyImport(.sizedBy(pointer: .param(2), size: \"len\"), .nonescaping(pointer: .param(2)))")));
"@_SwiftifyImport(.sizedBy(pointer: .param(2), size: \"len\"), .nonescaping(pointer: .param(2)), spanAvailability: \"visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4\")")));
void shared(int len, const void * __sized_by(len) __noescape p1, const void * __sized_by(len) __noescape p2);

View File

@@ -11,62 +11,77 @@
import CountedByNoEscapeClang
// CHECK: @lifetime(p: copy p)
// CHECK: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(p: copy p)
// CHECK-NEXT: @_alwaysEmitIntoClient public func complexExpr(_ len: Int32, _ offset: Int32, _ p: inout MutableSpan<Int32>)
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(p: copy p)
// CHECK-NEXT: @_alwaysEmitIntoClient public func nonnull(_ p: inout MutableSpan<Int32>)
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(p: copy p)
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullUnspecified(_ p: inout MutableSpan<Int32>)
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(p: copy p)
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullable(_ p: inout MutableSpan<Int32>?)
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(copy p)
// CHECK-NEXT: @lifetime(p: copy p)
// CHECK-NEXT: @_alwaysEmitIntoClient public func returnLifetimeBound(_ len1: Int32, _ p: inout MutableSpan<Int32>) -> MutableSpan<Int32>
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func returnPointer(_ len: Int32) -> UnsafeMutableBufferPointer<Int32>
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(p1: copy p1)
// CHECK-NEXT: @lifetime(p2: copy p2)
// CHECK-NEXT: @_alwaysEmitIntoClient public func shared(_ len: Int32, _ p1: inout MutableSpan<Int32>, _ p2: inout MutableSpan<Int32>)
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(p: copy p)
// CHECK-NEXT: @_alwaysEmitIntoClient public func simple(_ p: inout MutableSpan<Int32>)
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(p: copy p)
// CHECK-NEXT: @_alwaysEmitIntoClient public func swiftAttr(_ p: inout MutableSpan<Int32>)
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@lifetime(p: copy p)
@inlinable
public func callComplexExpr(_ p: inout MutableSpan<CInt>) {
complexExpr(CInt(p.count), 1, &p)
}
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@lifetime(p: copy p)
@inlinable
public func callNonnull(_ p: inout MutableSpan<CInt>) {
nonnull(&p)
}
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@lifetime(p: copy p)
@inlinable
public func callNullUnspecified(_ p: inout MutableSpan<CInt>) {
nullUnspecified(&p)
}
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@lifetime(p: copy p)
@inlinable
public func callNullable(_ p: inout MutableSpan<CInt>?) {
nullable(&p)
}
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@lifetime(p: copy p)
@inlinable
public func callReturnLifetimeBound(_ p: inout MutableSpan<CInt>) {
let a: MutableSpan<CInt> = returnLifetimeBound(2, &p)
}
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@inlinable
public func callReturnPointer() {
let a: UnsafeMutableBufferPointer<CInt>? = returnPointer(4) // call wrapper
let b: UnsafeMutablePointer<CInt>? = returnPointer(4) // call unsafe interop
}
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@lifetime(p: copy p)
@lifetime(p2: copy p2)
@inlinable
@@ -74,12 +89,14 @@ public func callShared(_ p: inout MutableSpan<CInt>, _ p2: inout MutableSpan<CIn
shared(CInt(p.count), &p, &p2)
}
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@lifetime(p: copy p)
@inlinable
public func callSimple(_ p: inout MutableSpan<CInt>) {
simple(&p)
}
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@lifetime(p: copy p)
@inlinable
public func callSwiftAttr(_ p: inout MutableSpan<CInt>) {

View File

@@ -9,52 +9,68 @@
// Check that ClangImporter correctly infers and expands @_SwiftifyImport macros for functions with __sized_by __noescape parameters.
import SizedByNoEscapeClang
// CHECK: @_alwaysEmitIntoClient public func complexExpr(_ len: Int{{.*}}, _ offset: Int{{.*}}, _ p: RawSpan)
// CHECK: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @_alwaysEmitIntoClient public func complexExpr(_ len: Int{{.*}}, _ offset: Int{{.*}}, _ p: RawSpan)
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @_alwaysEmitIntoClient public func nonnull(_ p: RawSpan)
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullUnspecified(_ p: RawSpan)
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullable(_ p: RawSpan?)
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @_alwaysEmitIntoClient public func opaque(_ p: RawSpan)
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func returnPointer(_ len: Int{{.*}}) -> UnsafeRawBufferPointer
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @_alwaysEmitIntoClient public func shared(_ len: Int{{.*}}, _ p1: RawSpan, _ p2: RawSpan)
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @_alwaysEmitIntoClient public func simple(_ p: RawSpan)
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @_alwaysEmitIntoClient public func swiftAttr(_ p: RawSpan)
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@inlinable
public func callComplexExpr(_ p: RawSpan) {
complexExpr(CInt(p.byteCount), 1, p)
}
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@inlinable
public func callNonnull(_ p: RawSpan) {
nonnull(p)
}
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@inlinable
public func callNullUnspecified(_ p: RawSpan) {
nullUnspecified(p)
}
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@inlinable
public func callNullable(_ p: RawSpan?) {
nullable(p)
}
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@inlinable
public func callReturnPointer() {
let a: UnsafeRawBufferPointer? = returnPointer(4) // call wrapper
let b: UnsafeRawPointer? = returnPointer(4) // call unsafe interop
}
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@inlinable
public func callShared(_ p: RawSpan, _ p2: RawSpan) {
shared(CInt(p.byteCount), p, p2)
}
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@inlinable
public func callSimple(_ p: RawSpan) {
simple(p)
}
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@inlinable
public func callSwiftAttr(_ p: RawSpan) {
swiftAttr(p)

View File

@@ -23,51 +23,70 @@ import CxxStdlib
// CHECK-NEXT: func funcWithSafeWrapper3(_ v: borrowing VecOfInt) -> ConstSpanOfInt
// CHECK: struct X {
// CHECK-NEXT: init()
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @_alwaysEmitIntoClient public mutating func methodWithSafeWrapper(_ s: Span<CInt>)
// CHECK-NEXT: mutating func methodWithSafeWrapper(_ s: ConstSpanOfInt)
// CHECK-NEXT: }
// CHECK: struct SpanWithoutTypeAlias {
// CHECK-NEXT: init()
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(borrow self)
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public mutating func bar() -> Span<CInt>
// CHECK-NEXT: mutating func bar() -> std.{{.*}}span<__cxxConst<CInt>, _C{{.*}}_{{.*}}>
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @_alwaysEmitIntoClient public mutating func foo(_ s: Span<CInt>)
// CHECK-NEXT: mutating func foo(_ s: std.{{.*}}span<__cxxConst<CInt>, _C{{.*}}_{{.*}}>)
// CHECK-NEXT: }
// CHECK: @lifetime(s: copy s)
// CHECK: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(s: copy s)
// CHECK-NEXT: @_alwaysEmitIntoClient public func FuncWithMutableSafeWrapper(_ s: inout MutableSpan<CInt>)
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(copy s)
// CHECK-NEXT: @lifetime(s: copy s)
// CHECK-NEXT: @_alwaysEmitIntoClient public func FuncWithMutableSafeWrapper2(_ s: inout MutableSpan<CInt>) -> MutableSpan<CInt>
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(borrow v)
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func FuncWithMutableSafeWrapper3(_ v: inout VecOfInt) -> MutableSpan<CInt>
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(copy p)
// CHECK-NEXT: @lifetime(p: copy p)
// CHECK-NEXT: @_alwaysEmitIntoClient public func MixedFuncWithMutableSafeWrapper1(_ p: inout MutableSpan<Int32>) -> MutableSpan<CInt>
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(borrow v)
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func MixedFuncWithMutableSafeWrapper2(_ v: inout VecOfInt, _ len: Int32) -> MutableSpan<Int32>
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(s: copy s)
// CHECK-NEXT: @_alwaysEmitIntoClient public func MixedFuncWithMutableSafeWrapper3(_ s: inout MutableSpan<CInt>, _ p: UnsafeMutableBufferPointer<Int32>)
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(s: copy s)
// CHECK-NEXT: @lifetime(p: copy p)
// CHECK-NEXT: @_alwaysEmitIntoClient public func MixedFuncWithMutableSafeWrapper4(_ s: inout MutableSpan<CInt>, _ p: inout MutableSpan<Int32>)
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(p: copy p)
// CHECK-NEXT: @_alwaysEmitIntoClient public func MixedFuncWithMutableSafeWrapper5(_ s: SpanOfInt, _ p: inout MutableSpan<Int32>)
// CHECK-NEXT: @_alwaysEmitIntoClient public func MixedFuncWithMutableSafeWrapper6(_ s: SpanOfInt, _ p: UnsafeMutableBufferPointer<Int32>)
// CHECK-NEXT: @_alwaysEmitIntoClient public func MixedFuncWithMutableSafeWrapper7(_ p: UnsafeMutableBufferPointer<Int32>) -> SpanOfInt
// CHECK: @_alwaysEmitIntoClient public func funcWithSafeWrapper(_ s: Span<CInt>)
// CHECK: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @_alwaysEmitIntoClient public func funcWithSafeWrapper(_ s: Span<CInt>)
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(copy s)
// CHECK-NEXT: @_alwaysEmitIntoClient public func funcWithSafeWrapper2(_ s: Span<CInt>) -> Span<CInt>
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(borrow v)
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func funcWithSafeWrapper3(_ v: borrowing VecOfInt) -> Span<CInt>
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(copy p)
// CHECK-NEXT: @_alwaysEmitIntoClient public func mixedFuncWithSafeWrapper1(_ p: Span<Int32>) -> Span<CInt>
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(borrow v)
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func mixedFuncWithSafeWrapper2(_ v: borrowing VecOfInt, _ len: Int32) -> Span<Int32>
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @_alwaysEmitIntoClient public func mixedFuncWithSafeWrapper3(_ s: Span<CInt>, _ p: UnsafeMutableBufferPointer<Int32>)
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @_alwaysEmitIntoClient public func mixedFuncWithSafeWrapper4(_ s: Span<CInt>, _ p: Span<Int32>)
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @_alwaysEmitIntoClient public func mixedFuncWithSafeWrapper5(_ s: ConstSpanOfInt, _ p: Span<Int32>)
// CHECK-NEXT: @_alwaysEmitIntoClient public func mixedFuncWithSafeWrapper6(_ s: ConstSpanOfInt, _ p: UnsafeMutableBufferPointer<Int32>)
// CHECK-NEXT: @_alwaysEmitIntoClient public func mixedFuncWithSafeWrapper7(_ p: UnsafeBufferPointer<Int32>) -> ConstSpanOfInt