Skip to content

Commit a57aff0

Browse files
author
Gabor Horvath
committed
[cxx-interop] Avoid generating ambiguous wrapper functions
When we generate a safe wrapper that only differs in the return type we might introduce ambiguities as some callers might not have enough information to disambiguate between the overloads. This PR makes sure the newly generated declarations are marked as @_disfavoredOverload so the compiler can keep calling the old functions without a source break when the feature is turned on. rdar://139074571
1 parent 415fe04 commit a57aff0

File tree

8 files changed

+29
-19
lines changed

8 files changed

+29
-19
lines changed

lib/Macros/Sources/SwiftMacros/SwiftifyImportMacro.swift

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -289,8 +289,10 @@ func transformType(_ prev: TypeSyntax, _ generateSpan: Bool, _ isSizedBy: Bool)
289289
protocol BoundsCheckedThunkBuilder {
290290
func buildFunctionCall(_ pointerArgs: [Int: ExprSyntax]) throws -> ExprSyntax
291291
func buildBoundsChecks() throws -> [CodeBlockItemSyntax.Item]
292+
// The second component of the return value is true when only the return type of the
293+
// function signature was changed.
292294
func buildFunctionSignature(_ argTypes: [Int: TypeSyntax?], _ returnType: TypeSyntax?) throws
293-
-> FunctionSignatureSyntax
295+
-> (FunctionSignatureSyntax, Bool)
294296
}
295297

296298
func getParam(_ signature: FunctionSignatureSyntax, _ paramIndex: Int) -> FunctionParameterSyntax {
@@ -308,6 +310,7 @@ func getParam(_ funcDecl: FunctionDeclSyntax, _ paramIndex: Int) -> FunctionPara
308310

309311
struct FunctionCallBuilder: BoundsCheckedThunkBuilder {
310312
let base: FunctionDeclSyntax
313+
311314
init(_ function: FunctionDeclSyntax) {
312315
base = function
313316
}
@@ -317,7 +320,7 @@ struct FunctionCallBuilder: BoundsCheckedThunkBuilder {
317320
}
318321

319322
func buildFunctionSignature(_ argTypes: [Int: TypeSyntax?], _ returnType: TypeSyntax?) throws
320-
-> FunctionSignatureSyntax {
323+
-> (FunctionSignatureSyntax, Bool) {
321324
var newParams = base.signature.parameterClause.parameters.enumerated().filter {
322325
let type = argTypes[$0.offset]
323326
// filter out deleted parameters, i.e. ones where argTypes[i] _contains_ nil
@@ -333,7 +336,7 @@ struct FunctionCallBuilder: BoundsCheckedThunkBuilder {
333336
if returnType != nil {
334337
sig = sig.with(\.returnClause!.type, returnType!)
335338
}
336-
return sig
339+
return (sig, (argTypes.count == 0 && returnType != nil))
337340
}
338341

339342
func buildFunctionCall(_ pointerArgs: [Int: ExprSyntax]) throws -> ExprSyntax {
@@ -381,7 +384,7 @@ struct CxxSpanThunkBuilder: ParamPointerBoundsThunkBuilder {
381384
}
382385

383386
func buildFunctionSignature(_ argTypes: [Int: TypeSyntax?], _ returnType: TypeSyntax?) throws
384-
-> FunctionSignatureSyntax {
387+
-> (FunctionSignatureSyntax, Bool) {
385388
var types = argTypes
386389
let typeName = try getTypeName(oldType).text
387390
guard let desugaredType = typeMappings[typeName] else {
@@ -417,7 +420,7 @@ struct CxxSpanReturnThunkBuilder: BoundsCheckedThunkBuilder {
417420
}
418421

419422
func buildFunctionSignature(_ argTypes: [Int: TypeSyntax?], _ returnType: TypeSyntax?) throws
420-
-> FunctionSignatureSyntax {
423+
-> (FunctionSignatureSyntax, Bool) {
421424
assert(returnType == nil)
422425
let typeName = try getTypeName(signature.returnClause!.type).text
423426
guard let desugaredType = typeMappings[typeName] else {
@@ -490,7 +493,7 @@ struct CountedOrSizedReturnPointerThunkBuilder: PointerBoundsThunkBuilder {
490493
}
491494

492495
func buildFunctionSignature(_ argTypes: [Int: TypeSyntax?], _ returnType: TypeSyntax?) throws
493-
-> FunctionSignatureSyntax {
496+
-> (FunctionSignatureSyntax, Bool) {
494497
assert(returnType == nil)
495498
return try base.buildFunctionSignature(argTypes, newType)
496499
}
@@ -518,7 +521,7 @@ struct CountedOrSizedPointerThunkBuilder: ParamPointerBoundsThunkBuilder {
518521
public let skipTrivialCount: Bool
519522

520523
func buildFunctionSignature(_ argTypes: [Int: TypeSyntax?], _ returnType: TypeSyntax?) throws
521-
-> FunctionSignatureSyntax {
524+
-> (FunctionSignatureSyntax, Bool) {
522525
var types = argTypes
523526
types[index] = try newType
524527
if skipTrivialCount {
@@ -1104,7 +1107,7 @@ public struct SwiftifyImportMacro: PeerMacro {
11041107
{ (prev, parsedArg) in
11051108
parsedArg.getBoundsCheckedThunkBuilder(prev, funcDecl, skipTrivialCount)
11061109
})
1107-
let newSignature = try builder.buildFunctionSignature([:], nil)
1110+
let (newSignature, onlyReturnTypeChanged) = try builder.buildFunctionSignature([:], nil)
11081111
let checks =
11091112
skipTrivialCount
11101113
? [] as [CodeBlockItemSyntax]
@@ -1118,6 +1121,12 @@ public struct SwiftifyImportMacro: PeerMacro {
11181121
expression: try builder.buildFunctionCall([:]))))
11191122
let body = CodeBlockSyntax(statements: CodeBlockItemListSyntax(checks + [call]))
11201123
let lifetimeAttrs = lifetimeAttributes(funcDecl, lifetimeDependencies)
1124+
let disfavoredOverload : [AttributeListSyntax.Element] = (onlyReturnTypeChanged ? [
1125+
.attribute(
1126+
AttributeSyntax(
1127+
atSign: .atSignToken(),
1128+
attributeName: IdentifierTypeSyntax(name: "_disfavoredOverload")))
1129+
] : [])
11211130
let newFunc =
11221131
funcDecl
11231132
.with(\.signature, newSignature)
@@ -1138,7 +1147,8 @@ public struct SwiftifyImportMacro: PeerMacro {
11381147
atSign: .atSignToken(),
11391148
attributeName: IdentifierTypeSyntax(name: "_alwaysEmitIntoClient")))
11401149
]
1141-
+ lifetimeAttrs)
1150+
+ lifetimeAttrs
1151+
+ disfavoredOverload)
11421152
return [DeclSyntax(newFunc)]
11431153
} catch let error as DiagnosticError {
11441154
context.diagnose(

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import CountedByNoEscapeClang
1414
// CHECK: @_alwaysEmitIntoClient public func complexExpr(_ len: Int{{.*}}, _ offset: Int{{.*}}, _ p: MutableSpan<Int{{.*}}>)
1515
// CHECK-NEXT: @_alwaysEmitIntoClient public func nonnull(_ p: MutableSpan<Int{{.*}}>)
1616
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullUnspecified(_ p: MutableSpan<Int{{.*}}>)
17-
// CHECK-NEXT: @_alwaysEmitIntoClient public func returnPointer(_ len: Int{{.*}}) -> UnsafeMutableBufferPointer<Int{{.*}}>
17+
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func returnPointer(_ len: Int{{.*}}) -> UnsafeMutableBufferPointer<Int{{.*}}>
1818
// CHECK-NEXT: @_alwaysEmitIntoClient public func shared(_ len: Int{{.*}}, _ p1: MutableSpan<Int{{.*}}>, _ p2: MutableSpan<Int{{.*}}>)
1919
// CHECK-NEXT: @_alwaysEmitIntoClient public func simple(_ p: MutableSpan<Int{{.*}}>)
2020
// CHECK-NEXT: @_alwaysEmitIntoClient public func swiftAttr(_ p: MutableSpan<Int{{.*}}>)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import CountedByClang
1414
// CHECK-NEXT: @_alwaysEmitIntoClient public func nonnull(_ p: UnsafeMutableBufferPointer<Int{{.*}}>)
1515
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullUnspecified(_ p: UnsafeMutableBufferPointer<Int{{.*}}>)
1616
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullable(_ p: UnsafeMutableBufferPointer<Int{{.*}}>?)
17-
// CHECK-NEXT: @_alwaysEmitIntoClient public func returnPointer(_ len: Int{{.*}}) -> UnsafeMutableBufferPointer<Int{{.*}}>
17+
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func returnPointer(_ len: Int{{.*}}) -> UnsafeMutableBufferPointer<Int{{.*}}>
1818
// CHECK-NEXT: @_alwaysEmitIntoClient public func shared(_ len: Int{{.*}}, _ p1: UnsafeMutableBufferPointer<Int{{.*}}>, _ p2: UnsafeMutableBufferPointer<Int{{.*}}>)
1919
// CHECK-NEXT: @_alwaysEmitIntoClient public func simple(_ p: UnsafeMutableBufferPointer<Int{{.*}}>)
2020
// CHECK-NEXT: @_alwaysEmitIntoClient public func swiftAttr(_ p: UnsafeMutableBufferPointer<Int{{.*}}>)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import SizedByNoEscapeClang
1414
// CHECK-NEXT: @_alwaysEmitIntoClient public func nonnull(_ p: RawSpan)
1515
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullUnspecified(_ p: RawSpan)
1616
// CHECK-NEXT: @_alwaysEmitIntoClient public func opaque(_ p: RawSpan)
17-
// CHECK-NEXT: @_alwaysEmitIntoClient public func returnPointer(_ len: Int{{.*}}) -> UnsafeRawBufferPointer
17+
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func returnPointer(_ len: Int{{.*}}) -> UnsafeRawBufferPointer
1818
// CHECK-NEXT: @_alwaysEmitIntoClient public func shared(_ len: Int{{.*}}, _ p1: RawSpan, _ p2: RawSpan)
1919
// CHECK-NEXT: @_alwaysEmitIntoClient public func simple(_ p: RawSpan)
2020
// CHECK-NEXT: @_alwaysEmitIntoClient public func swiftAttr(_ p: RawSpan)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import SizedByClang
1414
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullUnspecified(_ p: UnsafeMutableRawBufferPointer)
1515
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullable(_ p: UnsafeMutableRawBufferPointer?)
1616
// CHECK-NEXT: @_alwaysEmitIntoClient public func opaque(_ p: UnsafeRawBufferPointer)
17-
// CHECK-NEXT: @_alwaysEmitIntoClient public func returnPointer(_ len: Int{{.*}}) -> UnsafeMutableRawBufferPointer
17+
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func returnPointer(_ len: Int{{.*}}) -> UnsafeMutableRawBufferPointer
1818
// CHECK-NEXT: @_alwaysEmitIntoClient public func shared(_ len: Int{{.*}}, _ p1: UnsafeMutableRawBufferPointer, _ p2: UnsafeMutableRawBufferPointer)
1919
// CHECK-NEXT: @_alwaysEmitIntoClient public func simple(_ p: UnsafeMutableRawBufferPointer)
2020
// CHECK-NEXT: @_alwaysEmitIntoClient public func swiftAttr(_ p: UnsafeMutableRawBufferPointer)

test/Interop/Cxx/stdlib/std-span-interface.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import CxxStdlib
1616

1717
// CHECK: struct DependsOnSelf {
1818
// CHECK: @lifetime(borrow self)
19-
// CHECK-NEXT: @_alwaysEmitIntoClient public mutating func get() -> Span<CInt>
19+
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public mutating func get() -> Span<CInt>
2020
// CHECK-NEXT: mutating func get() -> ConstSpanOfInt
2121

2222
// CHECK: func funcWithSafeWrapper(_ s: ConstSpanOfInt)
@@ -31,4 +31,4 @@ import CxxStdlib
3131
// CHECK-NEXT: @lifetime(s)
3232
// CHECK-NEXT: @_alwaysEmitIntoClient public func funcWithSafeWrapper2(_ s: borrowing Span<CInt>) -> Span<CInt>
3333
// CHECK-NEXT: @lifetime(borrow v)
34-
// CHECK-NEXT: @_alwaysEmitIntoClient public func funcWithSafeWrapper3(_ v: borrowing VecOfInt) -> Span<CInt>
34+
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func funcWithSafeWrapper3(_ v: borrowing VecOfInt) -> Span<CInt>

test/Macros/SwiftifyImport/CountedBy/PointerReturn.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ func myFunc(_ len: CInt) -> UnsafeMutablePointer<CInt> {
1010
func nonEscaping(_ len: CInt) -> UnsafePointer<CInt> {
1111
}
1212

13-
// CHECK: @_alwaysEmitIntoClient
13+
// CHECK: @_alwaysEmitIntoClient @_disfavoredOverload
1414
// CHECK-NEXT: func myFunc(_ len: CInt) -> UnsafeMutableBufferPointer<CInt> {
1515
// CHECK-NEXT: return UnsafeMutableBufferPointer<CInt> (start: myFunc(len), count: Int(len))
1616
// CHECK-NEXT: }
1717

18-
// CHECK: @_alwaysEmitIntoClient
18+
// CHECK: @_alwaysEmitIntoClient @_disfavoredOverload
1919
// CHECK-NEXT: func nonEscaping(_ len: CInt) -> UnsafeBufferPointer<CInt> {
2020
// CHECK-NEXT: return UnsafeBufferPointer<CInt> (start: nonEscaping(len), count: Int(len))
2121
// CHECK-NEXT: }

test/Macros/SwiftifyImport/CxxSpan/LifetimeboundSpan.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ struct X {
3939
// CHECK-NEXT: return Span(_unsafeCxxSpan: myFunc(SpanOfInt(span)))
4040
// CHECK-NEXT: }
4141

42-
// CHECK: @_alwaysEmitIntoClient @lifetime(borrow vec)
42+
// CHECK: @_alwaysEmitIntoClient @lifetime(borrow vec) @_disfavoredOverload
4343
// CHECK-NEXT: func myFunc2(_ vec: borrowing VecOfInt) -> Span<CInt> {
4444
// CHECK-NEXT: return Span(_unsafeCxxSpan: myFunc2(vec))
4545
// CHECK-NEXT: }
@@ -54,7 +54,7 @@ struct X {
5454
// CHECK-NEXT: return Span(_unsafeCxxSpan: myFunc4(vec, SpanOfInt(span)))
5555
// CHECK-NEXT: }
5656

57-
// CHECK: @_alwaysEmitIntoClient @lifetime(borrow self)
57+
// CHECK: @_alwaysEmitIntoClient @lifetime(borrow self) @_disfavoredOverload
5858
// CHECK-NEXT: func myFunc5() -> Span<CInt> {
5959
// CHECK-NEXT: return Span(_unsafeCxxSpan: myFunc5())
6060
// CHECK-NEXT: }

0 commit comments

Comments
 (0)