mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
This is needed in Embedded Swift because the `witness_method` convention requires passing the witness table to the callee.
However, the witness table is not necessarily available.
A witness table is only generated if an existential value of a protocol is created.
This is a rare situation because only witness thunks have `witness_method` convention and those thunks are created as "transparent" functions, which means they are always inlined (after de-virtualization of a witness method call).
However, inlining - even of transparent functions - can fail for some reasons.
This change adds a new EmbeddedWitnessCallSpecialization pass:
If a function with `witness_method` convention is directly called, the function is specialized by changing the convention to `method` and the call is replaced by a call to the specialized function:
```
%1 = function_ref @callee : $@convention(witness_method: P) (@guaranteed C) -> ()
%2 = apply %1(%0) : $@convention(witness_method: P) (@guaranteed C) -> ()
...
sil [ossa] @callee : $@convention(witness_method: P) (@guaranteed C) -> () {
...
}
```
->
```
%1 = function_ref @$e6calleeTfr9 : $@convention(method) (@guaranteed C) -> ()
%2 = apply %1(%0) : $@convention(method) (@guaranteed C) -> ()
...
// specialized callee
sil shared [ossa] @$e6calleeTfr9 : $@convention(method) (@guaranteed C) -> () {
...
}
```
Fixes a compiler crash
rdar://165184147
66 lines
1.3 KiB
Swift
66 lines
1.3 KiB
Swift
// RUN: %empty-directory(%t)
|
|
// RUN: %target-swift-frontend %s -Onone -parse-as-library -enable-experimental-feature Embedded -c -o %t/main.o
|
|
// RUN: %target-clang %target-clang-resource-dir-opt %t/main.o -o %t/a.out -dead_strip
|
|
// RUN: %target-run %t/a.out | %FileCheck %s
|
|
|
|
// REQUIRES: swift_in_compiler
|
|
// REQUIRES: executable_test
|
|
// REQUIRES: optimized_stdlib
|
|
// REQUIRES: swift_feature_Embedded
|
|
|
|
// For some reason integer hashing results in an undefined symbol "arc4random_buf" linker error on linux
|
|
// REQUIRES: OS=macosx
|
|
|
|
public class C {
|
|
public var x: Int {
|
|
_read {
|
|
yield(y)
|
|
}
|
|
_modify {
|
|
yield(&y)
|
|
}
|
|
}
|
|
|
|
var y: Int = 27
|
|
}
|
|
|
|
public protocol P {
|
|
var d: [Int : WrappedBool] { get set }
|
|
}
|
|
|
|
extension P {
|
|
mutating func set(key: Int) {
|
|
d[key]?.b = true
|
|
}
|
|
}
|
|
|
|
public struct WrappedBool {
|
|
public var b: Bool = true
|
|
}
|
|
|
|
public class S: P {
|
|
public var d: [Int : WrappedBool] = [:]
|
|
public func foo() {}
|
|
}
|
|
|
|
@main
|
|
struct Main {
|
|
static func main() {
|
|
print("1") // CHECK: 1
|
|
let c = C() // CHECK: 27
|
|
print(c.y)
|
|
c.y = 28
|
|
print(c.y) // CHECK: 28
|
|
print("")
|
|
|
|
print("2") // CHECK: 2
|
|
print("")
|
|
|
|
var handler = S()
|
|
handler.d[27] = WrappedBool(b: false)
|
|
handler.set(key: 27)
|
|
// CHECK: true
|
|
print(handler.d[27]!.b ? "true" : "false")
|
|
}
|
|
}
|