Skip to content

Commit df0b81c

Browse files
committed
Lifetime diagnostics: clarify @_lifetime usage for inout parameters
This comes up often when passing a MutableSpan as an 'inout' argument. The vague diagnostic was causing developers to attempt incorrect @_lifetime annotations. Be clear about why the annotation is needed and which annotation should be used.
1 parent 465d6a8 commit df0b81c

File tree

4 files changed

+27
-1
lines changed

4 files changed

+27
-1
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8340,7 +8340,7 @@ ERROR(lifetime_dependence_feature_required_return, none,
83408340
ERROR(lifetime_dependence_feature_required_mutating, none,
83418341
"%0 cannot have a ~Escapable 'self'", (StringRef))
83428342
ERROR(lifetime_dependence_feature_required_inout, none,
8343-
"%0 cannot have a ~Escapable 'inout' parameter '%1'",
8343+
"%0 cannot have a ~Escapable 'inout' parameter '%1' in addition to other ~Escapable parameters",
83448344
// this arg list must be compatible with
83458345
// lifetime_dependence_cannot_infer_inout
83468346
(StringRef, StringRef))
@@ -8374,6 +8374,9 @@ ERROR(lifetime_dependence_cannot_infer_kind, none,
83748374
ERROR(lifetime_dependence_cannot_infer_scope_ownership, none,
83758375
"cannot borrow the lifetime of '%0', which has consuming ownership on %1",
83768376
(StringRef, StringRef))
8377+
NOTE(lifetime_dependence_cannot_infer_inout_suggest, none,
8378+
"use '@_lifetime(%0: copy %0) to forward the inout dependency",
8379+
(StringRef))
83778380

83788381
//------------------------------------------------------------------------------
83798382
// MARK: Lifetime Dependence Experimental Inference

lib/AST/LifetimeDependence.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,12 @@ class LifetimeDependenceChecker {
555555
ctx.Diags.diagnose(param->getLoc(), diagID,
556556
{StringRef(diagnosticQualifier()),
557557
param->getName().str()});
558+
if (diagID == diag::lifetime_dependence_cannot_infer_inout.ID) {
559+
ctx.Diags.diagnose(
560+
param->getLoc(),
561+
diag::lifetime_dependence_cannot_infer_inout_suggest,
562+
param->getName().str());
563+
}
558564
}
559565
}
560566
}

test/Sema/lifetime_attr_nofeature.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,9 @@ struct NE : ~Escapable { // expected-error{{an implicit initializer cannot retur
88
func derive(_ ne: NE) -> NE { // expected-error{{a function cannot return a ~Escapable result}}
99
ne
1010
}
11+
12+
func f_inout_infer(a: inout MutableRawSpan) {}
13+
14+
func f_inout_no_infer(a: inout MutableRawSpan, b: RawSpan) {}
15+
// expected-error @-1{{a function cannot have a ~Escapable 'inout' parameter 'a' in addition to other ~Escapable parameters}}
16+

test/Sema/lifetime_depend_infer.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ struct NEImmortal: ~Escapable {
1515
init() {}
1616
}
1717

18+
struct MutNE: ~Copyable & ~Escapable {}
19+
1820
// =============================================================================
1921
// Handle non-Escapable results with 'self'
2022
// =============================================================================
@@ -577,3 +579,12 @@ struct NonEscapableMutableSelf: ~Escapable {
577579
@_lifetime(&self)
578580
mutating func mutatingMethodOneParamBorrow(_: NE) {}
579581
}
582+
583+
// =============================================================================
584+
// Handle common mistakes with inout parameter annotations
585+
// =============================================================================
586+
587+
// Unable to infer an 'inout' dependency. Provide valid guidance.
588+
//
589+
func f_inout_no_infer(a: inout MutNE, b: NE) {} // expected-error{{a function with a ~Escapable 'inout' parameter requires '@_lifetime(a: ...)'}}
590+
// expected-note @-1{{use '@_lifetime(a: copy a) to forward the inout dependency}}

0 commit comments

Comments
 (0)