Skip to content

Commit ed7c2b9

Browse files
committed
LifetimeDependenceDiagnostics: note for unsupported closure capture
Add a note explaining that dependence on closure captures is not supported. Otherwise, the diagnostics are very confusing: "it depends on a closure capture; this is not yet supported"
1 parent 8857989 commit ed7c2b9

File tree

6 files changed

+51
-3
lines changed

6 files changed

+51
-3
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceDiagnostics.swift

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,9 @@ private struct DiagnoseDependence {
274274
// function's source location is sufficient for argument diagnostics, but if the function has no location, don't
275275
// report any scope.
276276
if parentVar.isArgument, let argLoc = parentVar.sourceLoc ?? function.location.sourceLoc {
277-
if let parentName = parentVar.name {
277+
if parentVar.isClosureCapture {
278+
diagnose(argLoc, .lifetime_outside_scope_capture)
279+
} else if let parentName = parentVar.name {
278280
diagnose(argLoc, .lifetime_outside_scope_argument, parentName)
279281
} else {
280282
diagnose(argLoc, .lifetime_outside_scope_synthesized_argument, parentVar.accessorKind ?? function.name)
@@ -298,8 +300,9 @@ private struct DiagnoseDependence {
298300
private struct LifetimeVariable {
299301
var varDecl: VarDecl? = nil
300302
var sourceLoc: SourceLoc? = nil
301-
var isArgument: Bool = false
302303
var isAccessScope: Bool = false
304+
var isArgument: Bool = false
305+
var isClosureCapture: Bool = false
303306
var accessorKind: String?
304307
var thunkKind: Function.ThunkKind = .noThunk
305308

@@ -338,10 +341,11 @@ private struct LifetimeVariable {
338341
}
339342

340343
private init(introducer: Value, _ context: some Context) {
341-
if let arg = introducer as? Argument {
344+
if let arg = introducer as? FunctionArgument {
342345
self.varDecl = arg.varDecl
343346
self.sourceLoc = arg.sourceLoc
344347
self.isArgument = true
348+
self.isClosureCapture = arg.isClosureCapture
345349
return
346350
}
347351
if let varDecl = introducer.definingInstruction?.findVarDecl() {

SwiftCompilerSources/Sources/SIL/Argument.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ final public class FunctionArgument : Argument {
6161
bridged.FunctionArgument_isLexical()
6262
}
6363

64+
public var isClosureCapture: Bool {
65+
bridged.FunctionArgument_isClosureCapture()
66+
}
67+
6468
public var isSelf: Bool {
6569
parentFunction.argumentConventions.selfIndex == index
6670
}

include/swift/AST/DiagnosticsSIL.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,6 +1183,8 @@ NOTE(lifetime_outside_scope_variable, none,
11831183
"it depends on the lifetime of variable '%0'", (Identifier))
11841184
NOTE(lifetime_outside_scope_value, none,
11851185
"it depends on the lifetime of this parent value", ())
1186+
NOTE(lifetime_outside_scope_capture, none,
1187+
"it depends on a closure capture; this is not yet supported", ())
11861188
NOTE(lifetime_outside_scope_use, none,
11871189
"this use of the lifetime-dependent value is out of scope", ())
11881190
NOTE(lifetime_outside_scope_escape, none,

include/swift/SIL/SILBridging.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -897,6 +897,7 @@ struct BridgedArgument {
897897
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedBasicBlock getParent() const;
898898
BRIDGED_INLINE bool isReborrow() const;
899899
BRIDGED_INLINE bool FunctionArgument_isLexical() const;
900+
BRIDGED_INLINE bool FunctionArgument_isClosureCapture() const;
900901
BRIDGED_INLINE void setReborrow(bool reborrow) const;
901902
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE OptionalBridgedDeclObj getVarDecl() const;
902903
BRIDGED_INLINE void copyFlags(BridgedArgument fromArgument) const;

include/swift/SIL/SILBridgingImpl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,11 @@ bool BridgedArgument::FunctionArgument_isLexical() const {
588588
return llvm::cast<swift::SILFunctionArgument>(getArgument())->getLifetime().isLexical();
589589
}
590590

591+
bool BridgedArgument::FunctionArgument_isClosureCapture() const {
592+
return llvm::cast<swift::SILFunctionArgument>(
593+
getArgument())->isClosureCapture();
594+
}
595+
591596
OptionalBridgedDeclObj BridgedArgument::getVarDecl() const {
592597
return {llvm::dyn_cast_or_null<swift::VarDecl>(getArgument()->getDecl())};
593598
}

test/SILOptimizer/lifetime_dependence/verify_diagnostics.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,35 @@ public struct NoncopyableImplicitAccessors : ~Copyable & ~Escapable {
124124
}
125125
}
126126
}
127+
128+
struct HasMethods {
129+
@lifetime(borrow self)
130+
func data(index: Int) -> NEImmortal {
131+
NEImmortal()
132+
}
133+
}
134+
135+
func testClosureCapture1(_ a: HasMethods) {
136+
let fn = a.data
137+
// expected-error @-1{{lifetime-dependent value escapes its scope}}
138+
// expected-note @-2{{it depends on a closure capture; this is not yet supported}}
139+
// expected-note @-3{{this use causes the lifetime-dependent value to escape}}
140+
_ = consume fn
141+
142+
let fn2 = a.data(index:)
143+
// expected-error @-1{{lifetime-dependent value escapes its scope}}
144+
// expected-note @-2{{it depends on a closure capture; this is not yet supported}}
145+
// expected-note @-3{{this use causes the lifetime-dependent value to escape}}
146+
_ = consume fn2
147+
148+
// FIXME: rdar://150073405 ([SILGen] support synthesized _modify on top of borrowed getters with library evolution)
149+
//
150+
// withUnsafePointer is disabled because it generates a reabstraction thunk, which is impossible to diagenose.
151+
/*
152+
withUnsafePointer(to: a.data) { fptr in
153+
// future-error @-1{{lifetime-dependent value escapes its scope}}
154+
// future-note @-2{{it depends on a closure capture; this is not yet supported}}
155+
// future-note @-3{{this use causes the lifetime-dependent value to escape}}
156+
}
157+
*/
158+
}

0 commit comments

Comments
 (0)