Files
swift-mirror/test/SILOptimizer/dead_function_elimination_distributed.swift
T
Konrad `ktoso` Malawski 791f0796e2 [Distributed] Prevent dead code elimination of distributed funcs, thunks, witnesses (#87901)
Dead code elimination is not aware of the fact that distributed function
accessors and witnesses are actually used by the runtime, and therefore
may remove them. 🧟

This seems to have flown under the radar however when whole module
optimization is enabled in release mode this can trigger reliably and
result in pointing at deleted witnesses.

This PR mades a few cleanups in the way we mark and handle distributed
accessors so they don't get optimized away.

This is an additional fix on top of
https://github.com/swiftlang/swift/pull/87453

Resolves rdar://168881945
2026-03-18 22:20:24 +09:00

45 lines
2.7 KiB
Swift

// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -target %target-swift-5.7-abi-triple %S/../Distributed/Inputs/FakeDistributedActorSystems.swift
// RUN: %target-swift-frontend %s -O -emit-sil -target %target-swift-5.7-abi-triple -I %t | %FileCheck %s --dump-input=always
// REQUIRES: concurrency
// REQUIRES: distributed
// Verify that dead function elimination does NOT remove distributed thunks,
// distributed method bodies, or their witness table entries. These are invoked
// at runtime via function pointer from the IRGen-generated distributed accessor,
// so they have no direct SIL callers. DFE must treat them as alive.
//
// rdar://168881945
import Distributed
import FakeDistributedActorSystems
protocol MyService: DistributedActor where ActorSystem == FakeActorSystem {
distributed func distributedMethod() async throws -> String
func nonDistributedMethod()
}
distributed actor MyServiceImpl: MyService {
typealias ActorSystem = FakeActorSystem
distributed func distributedMethod() async throws -> String { "hello" }
func nonDistributedMethod() {}
}
// The distributed thunk (TE suffix) must survive DFE:
// CHECK: sil hidden [thunk] [distributed] [ref_adhoc_requirement_witness "$s27FakeDistributedActorSystems0A17InvocationDecoderC18decodeNextArgumentxyKSeRzSERzlF"] @$s37dead_function_elimination_distributed13MyServiceImplC0D6MethodSSyYaKFTE : $@convention(method) @async (@guaranteed MyServiceImpl) -> (@owned String, @error any Error) {
// The distributed method body must survive DFE:
// CHECK: sil hidden [distributed] @$s37dead_function_elimination_distributed13MyServiceImplC0D6MethodSSyYaKF : $@convention(method) @async (@sil_isolated @guaranteed MyServiceImpl) -> (@owned String, @error any Error) {
// The witness table must still contain entries for the distributed func and thunk:
// CHECK-LABEL: sil_witness_table hidden MyServiceImpl: MyService module dead_function_elimination_distributed {
// protocol witness (TW):
// CHECK: method #MyService.distributedMethod!distributed({{.*}}): <Self where Self : MyService> (isolated Self) -> () async throws -> String : @$s37dead_function_elimination_distributed13MyServiceImplCAA0eF0A2aDP0D6MethodSSyYaKFTW
// protocol thunk witness (TWTE):
// CHECK: method #MyService.distributedMethod!distributed_thunk({{.*}}): <Self where Self : MyService> (Self) -> () async throws -> String : @$s37dead_function_elimination_distributed13MyServiceImplCAA0eF0A2aDP0D6MethodSSyYaKFTWTE
// The not used not-distributed method witness was dead eliminated:
// CHECK: method #MyService.nonDistributedMethod: <Self where Self : MyService> (isolated Self) -> () -> () : nil