Skip to content

Commit 384334e

Browse files
committed
Diagnostic note for invalid @_lifetime annotations on inout params
Users commonly try to write a lifetime dependency on an 'inout' parameters as: @_lifetime(a: &a) func f_inout_useless(a: inout MutableRawSpan) {} This is useless. Guide them toward what they really wanted: @_lifetime(a: copy a) Fixes rdar://151618856 (@Lifetime(..) gives inconsistent error messages) (cherry picked from commit 87f2510)
1 parent 707da68 commit 384334e

File tree

2 files changed

+18
-6
lines changed

2 files changed

+18
-6
lines changed

lib/AST/LifetimeDependence.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -910,17 +910,21 @@ class LifetimeDependenceChecker {
910910
if (!paramDeclAndIndex.has_value()) {
911911
return std::nullopt;
912912
}
913-
auto lifetimeKind =
914-
getDependenceKindFromDescriptor(source, paramDeclAndIndex->first);
913+
auto *param = paramDeclAndIndex->first;
914+
unsigned sourceIndex = paramDeclAndIndex->second;
915+
auto lifetimeKind = getDependenceKindFromDescriptor(source, param);
915916
if (!lifetimeKind.has_value()) {
916917
return std::nullopt;
917918
}
918-
unsigned sourceIndex = paramDeclAndIndex->second;
919919
if (lifetimeKind == LifetimeDependenceKind::Scope
920-
&& paramDeclAndIndex->first->isInOut()
920+
&& param->isInOut()
921921
&& sourceIndex == targetIndex) {
922922
diagnose(source.getLoc(),
923923
diag::lifetime_dependence_cannot_use_parsed_borrow_inout);
924+
ctx.Diags.diagnose(source.getLoc(),
925+
diag::lifetime_dependence_cannot_infer_inout_suggest,
926+
param->getName().str());
927+
924928
return std::nullopt;
925929
}
926930
bool hasError =

test/Sema/lifetime_depend_infer.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,7 @@ struct NonEscapableMutableSelf: ~Escapable {
566566
mutating func mutatingMethodNoParamCopy() {}
567567
568568
@_lifetime(self: &self) // expected-error{{invalid use of inout dependence on the same inout parameter}}
569+
// expected-note @-1{{use '@_lifetime(self: copy self) to forward the inout dependency}}
569570
mutating func mutatingMethodNoParamBorrow() {}
570571
571572
mutating func mutatingMethodOneParam(_: NE) {} // expected-error{{a mutating method with a ~Escapable 'self' requires '@_lifetime(self: ...)'}}
@@ -622,11 +623,18 @@ struct NE_NE_C: ~Escapable { // expected-error{{cannot infer implicit initializa
622623
623624
// Unable to infer an 'inout' dependency. Provide valid guidance.
624625
//
625-
func f_inout_no_infer(a: inout MutNE, b: NE) {} // expected-error{{a function with a ~Escapable 'inout' parameter requires '@_lifetime(a: ...)'}}
626-
// expected-note @-1{{use '@_lifetime(a: copy a) to forward the inout dependency}}
626+
func f_inout_no_infer(a: inout MutNE, b: NE) {}
627+
// expected-error @-1{{a function with a ~Escapable 'inout' parameter requires '@_lifetime(a: ...)'}}
628+
// expected-note @-2{{use '@_lifetime(a: copy a) to forward the inout dependency}}
627629
628630
// Invalid keyword for the dependence kind.
629631
//
630632
@_lifetime(a: inout a) // expected-error{{expected 'copy', 'borrow', or '&' followed by an identifier, index or 'self' in lifetime dependence specifier}}
631633
func f_inout_bad_keyword(a: inout MutableRawSpan) {}
632634

635+
// Don't allow a useless borrow dependency on an inout param--it is misleading.
636+
//
637+
@_lifetime(a: &a) // expected-error{{invalid use of inout dependence on the same inout parameter}}
638+
// expected-note @-1{{use '@_lifetime(a: copy a) to forward the inout dependency}}
639+
func f_inout_useless(a: inout MutableRawSpan) {}
640+

0 commit comments

Comments
 (0)