I'm having a weird issue that looks like a compiler bug. When my noncopyable struct is consumed under some circumstances, its deinit is never called.
I've created a minimal reproduction case :
import Foundation
struct SpinnerHandle: ~Copyable {
init() {
print("* Showing spinner *")
}
deinit {
print("* Dismissing spinner *")
}
consuming func dismiss() {
print("SpinnerHandle.dismiss()")
// why is deinit() not called ???
}
}
final class SpinnerHandleBoxed {
private var handle: SpinnerHandle?
private init(handle: consuming SpinnerHandle) {
self.handle = consume handle
}
static func displayBoxed() -> SpinnerHandleBoxed {
SpinnerHandleBoxed(handle: SpinnerHandle())
}
func dismiss() {
if let handle = self.handle.take() {
handle.dismiss()
} else {
print("Spinner was already dismissed")
}
}
}
func testHandle() {
print("\nTesting handle\n")
let handle = SpinnerHandle()
// some time later...
handle.dismiss()
}
func testBoxed() {
print("\nTesting boxed\n")
let boxed = SpinnerHandleBoxed.displayBoxed()
// some time later...
boxed.dismiss()
boxed.dismiss()
}
testHandle()
testBoxed()
The testHandle()
case works as expected when compiled with -Onone
and -O
. The testBoxed()
case works as expected only with -Onone
. When compiling with -O
, the deinit
is seemingly never called.
You can run the complete case with this script :
#!/bin/zsh
swiftc -v
echo "\nCompiling without optimisations"
swiftc -Onone main.swift -o main_onone
./main_onone
echo "\nCompiling with optimisations"
swiftc -O main.swift -o main_o
./main_o
echo "\n ISSUE: there no '* Dismissing spinner *' below 'Testing boxed' when using -O"
Output on my machine
Apple Swift version 6.0.3 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)
Target: x86_64-apple-macosx15.0
Compiling without optimisations
Testing handle
* Showing spinner *
SpinnerHandle.dismiss()
* Dismissing spinner *
Testing boxed
* Showing spinner *
SpinnerHandle.dismiss()
* Dismissing spinner *
Spinner was already dismissed
Compiling with optimisations
Testing handle
* Showing spinner *
SpinnerHandle.dismiss()
* Dismissing spinner *
Testing boxed
* Showing spinner *
SpinnerHandle.dismiss()
Spinner was already dismissed
ISSUE: there no '* Dismissing spinner *' below 'Testing boxed' when using -O
Am I doing something incorrect in the code or is this behavior not expected?