Skip to content

Commit 59d7d31

Browse files
authored
[Swiftify] Emit @Availability when expansions contain Span (#81320)
This prevents errors when compiling for older targets using a newer compiler. rdar://150740330
1 parent 23f0fb5 commit 59d7d31

File tree

8 files changed

+169
-19
lines changed

8 files changed

+169
-19
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9031,10 +9031,11 @@ class SwiftifyInfoPrinter {
90319031
static const ssize_t SELF_PARAM_INDEX = -2;
90329032
static const ssize_t RETURN_VALUE_INDEX = -1;
90339033
clang::ASTContext &ctx;
9034+
ASTContext &SwiftContext;
90349035
llvm::raw_ostream &out;
90359036
bool firstParam = true;
9036-
SwiftifyInfoPrinter(clang::ASTContext &ctx, llvm::raw_ostream &out)
9037-
: ctx(ctx), out(out) {
9037+
SwiftifyInfoPrinter(clang::ASTContext &ctx, ASTContext &SwiftContext, llvm::raw_ostream &out)
9038+
: ctx(ctx), SwiftContext(SwiftContext), out(out) {
90389039
out << "@_SwiftifyImport(";
90399040
}
90409041
~SwiftifyInfoPrinter() { out << ")"; }
@@ -9091,7 +9092,34 @@ class SwiftifyInfoPrinter {
90919092
out << "]";
90929093
}
90939094

9095+
void printAvailability() {
9096+
printSeparator();
9097+
out << "spanAvailability: ";
9098+
printAvailabilityOfType("Span");
9099+
}
9100+
90949101
private:
9102+
ValueDecl *getDecl(StringRef DeclName) {
9103+
SmallVector<ValueDecl *, 1> decls;
9104+
SwiftContext.lookupInSwiftModule(DeclName, decls);
9105+
assert(decls.size() == 1);
9106+
if (decls.size() != 1) return nullptr;
9107+
return decls[0];
9108+
}
9109+
9110+
void printAvailabilityOfType(StringRef Name) {
9111+
ValueDecl *D = getDecl(Name);
9112+
out << "\"";
9113+
llvm::SaveAndRestore<bool> hasAvailbilitySeparatorRestore(firstParam, true);
9114+
for (auto attr : D->getSemanticAvailableAttrs(/*includingInactive=*/true)) {
9115+
auto introducedOpt = attr.getIntroduced();
9116+
if (!introducedOpt.has_value()) continue;
9117+
printSeparator();
9118+
out << prettyPlatformString(attr.getPlatform()) << " " << introducedOpt.value();
9119+
}
9120+
out << "\"";
9121+
}
9122+
90959123
void printSeparator() {
90969124
if (!firstParam) {
90979125
out << ", ";
@@ -9143,7 +9171,7 @@ void ClangImporter::Implementation::swiftify(FuncDecl *MappedDecl) {
91439171
}
91449172
return false;
91459173
};
9146-
SwiftifyInfoPrinter printer(getClangASTContext(), out);
9174+
SwiftifyInfoPrinter printer(getClangASTContext(), SwiftContext, out);
91479175
bool returnIsStdSpan = registerStdSpanTypeMapping(
91489176
MappedDecl->getResultInterfaceType(), ClangDecl->getReturnType());
91499177
if (auto CAT =
@@ -9187,6 +9215,7 @@ void ClangImporter::Implementation::swiftify(FuncDecl *MappedDecl) {
91879215
}
91889216
if (returnIsStdSpan && returnHasLifetimeInfo)
91899217
attachMacro = true;
9218+
printer.printAvailability();
91909219
printer.printTypeMapping(typeMapping);
91919220
}
91929221

lib/Macros/Sources/SwiftMacros/SwiftifyImportMacro.swift

Lines changed: 75 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,14 +1069,7 @@ func parseLifetimeDependence(_ enumConstructorExpr: FunctionCallExprSyntax) thro
10691069
return (pointer, dependence)
10701070
}
10711071

1072-
func parseTypeMappingParam(_ paramAST: LabeledExprSyntax?) throws -> [String: String]? {
1073-
guard let unwrappedParamAST = paramAST else {
1074-
return nil
1075-
}
1076-
let paramExpr = unwrappedParamAST.expression
1077-
guard let dictExpr = paramExpr.as(DictionaryExprSyntax.self) else {
1078-
return nil
1079-
}
1072+
func parseStringLiteralDict(_ dictExpr: DictionaryExprSyntax) throws -> [String: String] {
10801073
var dict: [String: String] = [:]
10811074
switch dictExpr.content {
10821075
case .colon(_):
@@ -1098,6 +1091,45 @@ func parseTypeMappingParam(_ paramAST: LabeledExprSyntax?) throws -> [String: St
10981091
return dict
10991092
}
11001093

1094+
func parseStringMappingParam(_ paramAST: LabeledExprSyntax?, paramName: String) throws -> [String: String]? {
1095+
guard let unwrappedParamAST = paramAST else {
1096+
return nil
1097+
}
1098+
guard let label = unwrappedParamAST.label else {
1099+
return nil
1100+
}
1101+
if label.trimmed.text != paramName {
1102+
return nil
1103+
}
1104+
let paramExpr = unwrappedParamAST.expression
1105+
guard let dictExpr = paramExpr.as(DictionaryExprSyntax.self) else {
1106+
return nil
1107+
}
1108+
return try parseStringLiteralDict(dictExpr)
1109+
}
1110+
1111+
func parseTypeMappingParam(_ paramAST: LabeledExprSyntax?) throws -> [String: String]? {
1112+
return try parseStringMappingParam(paramAST, paramName: "typeMappings")
1113+
}
1114+
1115+
func parseSpanAvailabilityParam(_ paramAST: LabeledExprSyntax?) throws -> String? {
1116+
guard let unwrappedParamAST = paramAST else {
1117+
return nil
1118+
}
1119+
guard let label = unwrappedParamAST.label else {
1120+
return nil
1121+
}
1122+
if label.trimmed.text != "spanAvailability" {
1123+
return nil
1124+
}
1125+
let paramExpr = unwrappedParamAST.expression
1126+
guard let stringLitExpr = paramExpr.as(StringLiteralExprSyntax.self) else {
1127+
throw DiagnosticError(
1128+
"expected a string literal, got '\(paramExpr)'", node: paramExpr)
1129+
}
1130+
return stringLitExpr.representedLiteralValue
1131+
}
1132+
11011133
func parseCxxSpansInSignature(
11021134
_ signature: FunctionSignatureSyntax,
11031135
_ typeMappings: [String: String]?
@@ -1316,6 +1348,35 @@ func isMutableSpan(_ type: TypeSyntax) -> Bool {
13161348
return name == "MutableSpan" || name == "MutableRawSpan"
13171349
}
13181350

1351+
func isAnySpan(_ type: TypeSyntax) -> Bool {
1352+
if let optType = type.as(OptionalTypeSyntax.self) {
1353+
return isAnySpan(optType.wrappedType)
1354+
}
1355+
if let impOptType = type.as(ImplicitlyUnwrappedOptionalTypeSyntax.self) {
1356+
return isAnySpan(impOptType.wrappedType)
1357+
}
1358+
if let attrType = type.as(AttributedTypeSyntax.self) {
1359+
return isAnySpan(attrType.baseType)
1360+
}
1361+
guard let identifierType = type.as(IdentifierTypeSyntax.self) else {
1362+
return false
1363+
}
1364+
let name = identifierType.name.text
1365+
return name == "Span" || name == "RawSpan" || name == "MutableSpan" || name == "MutableRawSpan"
1366+
}
1367+
1368+
func getAvailability(_ newSignature: FunctionSignatureSyntax, _ spanAvailability: String?)
1369+
throws -> [AttributeListSyntax.Element] {
1370+
guard let spanAvailability else {
1371+
return []
1372+
}
1373+
let returnIsSpan = newSignature.returnClause != nil && isAnySpan(newSignature.returnClause!.type)
1374+
if !returnIsSpan && !newSignature.parameterClause.parameters.contains(where: { isAnySpan($0.type) }) {
1375+
return []
1376+
}
1377+
return [.attribute(AttributeSyntax("@available(\(raw: spanAvailability), *)"))]
1378+
}
1379+
13191380
func containsLifetimeAttr(_ attrs: AttributeListSyntax, for paramName: TokenSyntax) -> Bool {
13201381
for elem in attrs {
13211382
guard let attr = elem.as(AttributeSyntax.self) else {
@@ -1386,6 +1447,10 @@ public struct SwiftifyImportMacro: PeerMacro {
13861447
if typeMappings != nil {
13871448
arguments = arguments.dropLast()
13881449
}
1450+
let spanAvailability = try parseSpanAvailabilityParam(arguments.last)
1451+
if spanAvailability != nil {
1452+
arguments = arguments.dropLast()
1453+
}
13891454
var nonescapingPointers = Set<Int>()
13901455
var lifetimeDependencies: [SwiftifyExpr: [LifetimeDependence]] = [:]
13911456
var parsedArgs = try arguments.compactMap {
@@ -1441,6 +1506,7 @@ public struct SwiftifyImportMacro: PeerMacro {
14411506
let returnLifetimeAttribute = getReturnLifetimeAttribute(funcDecl, lifetimeDependencies)
14421507
let lifetimeAttrs =
14431508
returnLifetimeAttribute + paramLifetimeAttributes(newSignature, funcDecl.attributes)
1509+
let availabilityAttr = try getAvailability(newSignature, spanAvailability)
14441510
let disfavoredOverload: [AttributeListSyntax.Element] =
14451511
(onlyReturnTypeChanged
14461512
? [
@@ -1469,6 +1535,7 @@ public struct SwiftifyImportMacro: PeerMacro {
14691535
atSign: .atSignToken(),
14701536
attributeName: IdentifierTypeSyntax(name: "_alwaysEmitIntoClient")))
14711537
]
1538+
+ availabilityAttr
14721539
+ lifetimeAttrs
14731540
+ disfavoredOverload)
14741541
return [DeclSyntax(newFunc)]

stdlib/public/core/SwiftifyImport.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,15 @@ public enum _SwiftifyInfo {
5454
/// It will replace some std::span arguments with Swift's Span type when sufficient information is
5555
/// available.
5656
///
57-
/// Currently not supported: return pointers, nested pointers, pointee "count" parameters, endedBy.
57+
/// Currently not supported: nested pointers, pointee "count" parameters, endedBy.
5858
///
5959
/// Parameter paramInfo: information about how the function uses the pointer passed to it. The
6060
/// safety of the generated wrapper function depends on this info being extensive and accurate.
6161
#if hasFeature(Macros)
6262
@attached(peer, names: overloaded)
63-
public macro _SwiftifyImport(_ paramInfo: _SwiftifyInfo..., typeMappings: [String: String] = [:]) =
63+
public macro _SwiftifyImport(_ paramInfo: _SwiftifyInfo...,
64+
spanAvailability: String? = nil,
65+
typeMappings: [String: String] = [:]) =
6466
#externalMacro(module: "SwiftMacros", type: "SwiftifyImportMacro")
6567
#endif
6668

test/Interop/C/swiftify-import/Inputs/counted-by-noescape.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
void simple(int len, int * __counted_by(len) __noescape p);
88

99
void swiftAttr(int len, int *p) __attribute__((
10-
swift_attr("@_SwiftifyImport(.countedBy(pointer: .param(2), count: \"len\"), .nonescaping(pointer: .param(2)))")));
10+
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\")")));
1111

1212
void shared(int len, int * __counted_by(len) __noescape p1, int * __counted_by(len) __noescape p2);
1313

test/Interop/C/swiftify-import/Inputs/sized-by-noescape.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
void simple(int len, const void * __sized_by(len) __noescape p);
77

88
void swiftAttr(int len, const void *p) __attribute__((swift_attr(
9-
"@_SwiftifyImport(.sizedBy(pointer: .param(2), size: \"len\"), .nonescaping(pointer: .param(2)))")));
9+
"@_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\")")));
1010

1111
void shared(int len, const void * __sized_by(len) __noescape p1, const void * __sized_by(len) __noescape p2);
1212

test/Interop/C/swiftify-import/counted-by-noescape.swift

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,75 +11,92 @@
1111

1212
import CountedByNoEscapeClang
1313

14-
// CHECK: @lifetime(p: copy p)
14+
// CHECK: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
15+
// CHECK-NEXT: @lifetime(p: copy p)
1516
// CHECK-NEXT: @_alwaysEmitIntoClient public func complexExpr(_ len: Int32, _ offset: Int32, _ p: inout MutableSpan<Int32>)
17+
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
1618
// CHECK-NEXT: @lifetime(p: copy p)
1719
// CHECK-NEXT: @_alwaysEmitIntoClient public func nonnull(_ p: inout MutableSpan<Int32>)
20+
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
1821
// CHECK-NEXT: @lifetime(p: copy p)
1922
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullUnspecified(_ p: inout MutableSpan<Int32>)
23+
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
2024
// CHECK-NEXT: @lifetime(p: copy p)
2125
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullable(_ p: inout MutableSpan<Int32>?)
26+
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
2227
// CHECK-NEXT: @lifetime(copy p)
2328
// CHECK-NEXT: @lifetime(p: copy p)
2429
// CHECK-NEXT: @_alwaysEmitIntoClient public func returnLifetimeBound(_ len1: Int32, _ p: inout MutableSpan<Int32>) -> MutableSpan<Int32>
2530
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func returnPointer(_ len: Int32) -> UnsafeMutableBufferPointer<Int32>
31+
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
2632
// CHECK-NEXT: @lifetime(p1: copy p1)
2733
// CHECK-NEXT: @lifetime(p2: copy p2)
2834
// CHECK-NEXT: @_alwaysEmitIntoClient public func shared(_ len: Int32, _ p1: inout MutableSpan<Int32>, _ p2: inout MutableSpan<Int32>)
35+
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
2936
// CHECK-NEXT: @lifetime(p: copy p)
3037
// CHECK-NEXT: @_alwaysEmitIntoClient public func simple(_ p: inout MutableSpan<Int32>)
38+
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
3139
// CHECK-NEXT: @lifetime(p: copy p)
3240
// CHECK-NEXT: @_alwaysEmitIntoClient public func swiftAttr(_ p: inout MutableSpan<Int32>)
3341

42+
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
3443
@lifetime(p: copy p)
3544
@inlinable
3645
public func callComplexExpr(_ p: inout MutableSpan<CInt>) {
3746
complexExpr(CInt(p.count), 1, &p)
3847
}
3948

49+
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
4050
@lifetime(p: copy p)
4151
@inlinable
4252
public func callNonnull(_ p: inout MutableSpan<CInt>) {
4353
nonnull(&p)
4454
}
4555

56+
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
4657
@lifetime(p: copy p)
4758
@inlinable
4859
public func callNullUnspecified(_ p: inout MutableSpan<CInt>) {
4960
nullUnspecified(&p)
5061
}
5162

63+
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
5264
@lifetime(p: copy p)
5365
@inlinable
5466
public func callNullable(_ p: inout MutableSpan<CInt>?) {
5567
nullable(&p)
5668
}
5769

70+
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
5871
@lifetime(p: copy p)
5972
@inlinable
6073
public func callReturnLifetimeBound(_ p: inout MutableSpan<CInt>) {
6174
let a: MutableSpan<CInt> = returnLifetimeBound(2, &p)
6275
}
6376

77+
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
6478
@inlinable
6579
public func callReturnPointer() {
6680
let a: UnsafeMutableBufferPointer<CInt>? = returnPointer(4) // call wrapper
6781
let b: UnsafeMutablePointer<CInt>? = returnPointer(4) // call unsafe interop
6882
}
6983

84+
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
7085
@lifetime(p: copy p)
7186
@lifetime(p2: copy p2)
7287
@inlinable
7388
public func callShared(_ p: inout MutableSpan<CInt>, _ p2: inout MutableSpan<CInt>) {
7489
shared(CInt(p.count), &p, &p2)
7590
}
7691

92+
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
7793
@lifetime(p: copy p)
7894
@inlinable
7995
public func callSimple(_ p: inout MutableSpan<CInt>) {
8096
simple(&p)
8197
}
8298

99+
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
83100
@lifetime(p: copy p)
84101
@inlinable
85102
public func callSwiftAttr(_ p: inout MutableSpan<CInt>) {

test/Interop/C/swiftify-import/sized-by-noescape.swift

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,52 +9,68 @@
99
// Check that ClangImporter correctly infers and expands @_SwiftifyImport macros for functions with __sized_by __noescape parameters.
1010
import SizedByNoEscapeClang
1111

12-
// CHECK: @_alwaysEmitIntoClient public func complexExpr(_ len: Int{{.*}}, _ offset: Int{{.*}}, _ p: RawSpan)
12+
// CHECK: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
13+
// CHECK-NEXT: @_alwaysEmitIntoClient public func complexExpr(_ len: Int{{.*}}, _ offset: Int{{.*}}, _ p: RawSpan)
14+
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
1315
// CHECK-NEXT: @_alwaysEmitIntoClient public func nonnull(_ p: RawSpan)
16+
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
1417
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullUnspecified(_ p: RawSpan)
18+
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
1519
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullable(_ p: RawSpan?)
20+
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
1621
// CHECK-NEXT: @_alwaysEmitIntoClient public func opaque(_ p: RawSpan)
1722
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func returnPointer(_ len: Int{{.*}}) -> UnsafeRawBufferPointer
23+
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
1824
// CHECK-NEXT: @_alwaysEmitIntoClient public func shared(_ len: Int{{.*}}, _ p1: RawSpan, _ p2: RawSpan)
25+
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
1926
// CHECK-NEXT: @_alwaysEmitIntoClient public func simple(_ p: RawSpan)
27+
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
2028
// CHECK-NEXT: @_alwaysEmitIntoClient public func swiftAttr(_ p: RawSpan)
2129

30+
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
2231
@inlinable
2332
public func callComplexExpr(_ p: RawSpan) {
2433
complexExpr(CInt(p.byteCount), 1, p)
2534
}
2635

36+
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
2737
@inlinable
2838
public func callNonnull(_ p: RawSpan) {
2939
nonnull(p)
3040
}
3141

42+
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
3243
@inlinable
3344
public func callNullUnspecified(_ p: RawSpan) {
3445
nullUnspecified(p)
3546
}
3647

48+
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
3749
@inlinable
3850
public func callNullable(_ p: RawSpan?) {
3951
nullable(p)
4052
}
4153

54+
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
4255
@inlinable
4356
public func callReturnPointer() {
4457
let a: UnsafeRawBufferPointer? = returnPointer(4) // call wrapper
4558
let b: UnsafeRawPointer? = returnPointer(4) // call unsafe interop
4659
}
4760

61+
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
4862
@inlinable
4963
public func callShared(_ p: RawSpan, _ p2: RawSpan) {
5064
shared(CInt(p.byteCount), p, p2)
5165
}
5266

67+
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
5368
@inlinable
5469
public func callSimple(_ p: RawSpan) {
5570
simple(p)
5671
}
5772

73+
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
5874
@inlinable
5975
public func callSwiftAttr(_ p: RawSpan) {
6076
swiftAttr(p)

0 commit comments

Comments
 (0)