From e2155412ddbf8eb16597533484fbcf87cec1a574 Mon Sep 17 00:00:00 2001 From: Andrew Trick Date: Mon, 7 Jul 2025 00:10:54 -0700 Subject: [PATCH] Fix LifetimeDependenceDiagnostics: allow inout assignment to Void. Bypess lifetime dependence diagnostics completely for immortal values. We did not do this initially because we wanted to potentially consider a value with a missing dependency to mean that it could not escape the current function. But now we use `Void` as a stand-in for immortal values. This is needed for reassigning a Span/MutableSpan to an empty, immortal Span: func inoutToImmortal(_ s: inout RawSpan) { let tmp = RawSpan(_unsafeBytes: UnsafeRawBufferPointer(start: nil, count: 0)) s = _overrideLifetime(tmp, borrowing: ()) } Fixes rdar://152572002 ([GH:#81976] Cannot reinitialize inout parameter of type `MutableSpan?`) (cherry picked from commit ac94d7df1d99bdf83bee152185822410d6a9a442) --- .../LifetimeDependenceDiagnostics.swift | 17 +++++++++++++++++ .../verify_diagnostics.swift | 10 ++++++++++ 2 files changed, 27 insertions(+) diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceDiagnostics.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceDiagnostics.swift index 9983ee125e933..6e78e373aa250 100644 --- a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceDiagnostics.swift +++ b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceDiagnostics.swift @@ -110,6 +110,20 @@ private func analyze(dependence: LifetimeDependence, _ context: FunctionPassCont } } + // Check for immortal dependence. + switch dependence.scope { + case .global: + log("Immortal global dependence.") + return true + case let .unknown(value): + if value.type.isVoid { + log("Immortal void dependence.") + return true + } + default: + break + } + // Compute this dependence scope. var range = dependence.computeRange(context) defer { range?.deinitialize() } @@ -200,6 +214,9 @@ private struct DiagnoseDependence { return .continueWalk } // Check for immortal lifetime. + // + // FIXME: remove this immortal check. It should be redundant with the earlier check that bypasses dependence + // diagnostics. switch dependence.scope { case .global: return .continueWalk diff --git a/test/SILOptimizer/lifetime_dependence/verify_diagnostics.swift b/test/SILOptimizer/lifetime_dependence/verify_diagnostics.swift index 659e7f4d66d3b..6976d33dc80fc 100644 --- a/test/SILOptimizer/lifetime_dependence/verify_diagnostics.swift +++ b/test/SILOptimizer/lifetime_dependence/verify_diagnostics.swift @@ -287,3 +287,13 @@ func testSpanMayThrow(buffer: inout [Int]) { let bufferSpan = buffer.mutableSpan try! mutableSpanMayThrow(bufferSpan) } + +// ============================================================================= +// inout +// ============================================================================= + +@available(Span 0.1, *) +func inoutToImmortal(_ s: inout RawSpan) { + let tmp = RawSpan(_unsafeBytes: UnsafeRawBufferPointer(start: nil, count: 0)) + s = _overrideLifetime(tmp, borrowing: ()) +}