Skip to content

Commit e11f7f1

Browse files
committed
LifetimeDependenceDiagnostics: diagnostic error on unknown uses
The common def-use walkers should not return .abortWalk without making a diagnostic callback.
1 parent 82d66e3 commit e11f7f1

File tree

2 files changed

+27
-14
lines changed

2 files changed

+27
-14
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceDiagnostics.swift

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -128,27 +128,36 @@ private func analyze(dependence: LifetimeDependence, _ context: FunctionPassCont
128128
var range = dependence.computeRange(context)
129129
defer { range?.deinitialize() }
130130

131-
var error = false
132-
let diagnostics =
133-
DiagnoseDependence(dependence: dependence, range: range,
134-
onError: { error = true }, context: context)
131+
let diagnostics = DiagnoseDependence(dependence: dependence, range: range, context: context)
135132

136133
// Check each lifetime-dependent use via a def-use visitor
137134
var walker = DiagnoseDependenceWalker(diagnostics, context)
138135
defer { walker.deinitialize() }
139136
let result = walker.walkDown(dependence: dependence)
140-
// The walk may abort without a diagnostic error.
141-
assert(!error || result == .abortWalk)
137+
assert(result == .continueWalk || diagnostics.errorStatus != nil,
138+
"Lifetime diagnostics failed without raising an error")
142139
return result == .continueWalk
143140
}
144141

145142
/// Analyze and diagnose a single LifetimeDependence.
146-
private struct DiagnoseDependence {
143+
private class DiagnoseDependence {
144+
enum ErrorStatus {
145+
case diagnostic
146+
case unresolvedDependence
147+
}
148+
147149
let dependence: LifetimeDependence
148150
let range: InstructionRange?
149-
let onError: ()->()
150151
let context: FunctionPassContext
151152

153+
init(dependence: LifetimeDependence, range: InstructionRange?, context: FunctionPassContext) {
154+
self.dependence = dependence
155+
self.range = range
156+
self.context = context
157+
}
158+
159+
var errorStatus: ErrorStatus? = nil
160+
152161
var function: Function { dependence.function }
153162

154163
func diagnose(_ position: SourceLoc?, _ id: DiagID,
@@ -266,9 +275,10 @@ private struct DiagnoseDependence {
266275
func reportError(escapingValue: Value, user: Instruction, diagID: DiagID) {
267276
// If the dependent value is Escapable, then mark_dependence resolution fails, but this is not a diagnostic error.
268277
if dependence.dependentValue.isEscapable {
278+
errorStatus = .unresolvedDependence
269279
return
270280
}
271-
onError()
281+
errorStatus = .diagnostic
272282

273283
// Identify the escaping variable.
274284
let escapingVar = LifetimeVariable(definedBy: escapingValue, user: user, context)
@@ -598,10 +608,10 @@ extension DiagnoseDependenceWalker : LifetimeDependenceDefUseWalker {
598608
return .continueWalk
599609
}
600610

601-
// Override AddressUseVisitor here because LifetimeDependenceDefUseWalker
602-
// returns .abortWalk, and we want a more useful crash report.
611+
// Override AddressUseVisitor here because LifetimeDependenceDefUseWalker returns .abortWalk and
612+
// DiagnoseDependenceWalker requires a diagnostic error for all aborts.
603613
mutating func unknownAddressUse(of operand: Operand) -> WalkResult {
604614
diagnostics.reportUnknown(operand: operand)
605-
return .continueWalk
615+
return .abortWalk
606616
}
607617
}

SwiftCompilerSources/Sources/Optimizer/Utilities/LifetimeDependenceUtils.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,9 @@ extension LifetimeDependence.Scope {
622622
/// walkDown(dependence: LifetimeDependence)
623623
///
624624
/// Note: this may visit values that are not dominated by `dependence` because of dependent phi operands.
625+
///
626+
/// WARNING: Do not return .abortWalk at this level or below. .abortWalk may only be returned by an overridden callback
627+
/// or the default implementation of unknownAddressUse().
625628
protocol LifetimeDependenceDefUseWalker : ForwardingDefUseWalker,
626629
OwnershipUseVisitor,
627630
AddressUseVisitor {
@@ -1074,7 +1077,7 @@ extension LifetimeDependenceDefUseWalker {
10741077
// directly use the original address.
10751078
return .continueWalk
10761079
default:
1077-
return .abortWalk
1080+
return unknownAddressUse(of: localAccess.operand!)
10781081
}
10791082
case .dependenceSource:
10801083
switch localAccess.instruction! {
@@ -1086,7 +1089,7 @@ extension LifetimeDependenceDefUseWalker {
10861089
case let md as MarkDependenceAddrInst:
10871090
return loadedAddressUse(of: localAccess.operand!, intoAddress: md.addressOperand)
10881091
default:
1089-
return .abortWalk
1092+
return unknownAddressUse(of: localAccess.operand!)
10901093
}
10911094
case .dependenceDest:
10921095
// Simply a marker that indicates the start of an in-memory dependent value. If this was a mark_dependence, uses

0 commit comments

Comments
 (0)