Fix a compiler crash with '@'_lifetime(inout x), add diagnostic

This is a common mistake made more common be suggestions of existing diagnostic
that tell users not to use a 'copy' dependency.

Report a diagnostic error rather than crashing the compiler. Fix the diagnostic
output to make sense relative to the source location.

Fixes rdar://154136015 ([nonescapable] compiler assertion with @_lifetime(x: inout x))
This commit is contained in:
Andrew Trick
2025-06-25 12:26:51 -07:00
parent 05fa82b7a7
commit 080b68292d
4 changed files with 13 additions and 2 deletions

View File

@@ -2147,7 +2147,7 @@ ERROR(expected_lparen_after_lifetime_dependence, PointsToFirstBadToken,
ERROR(expected_identifier_or_index_or_self_after_lifetime_dependence,
PointsToFirstBadToken,
"expected identifier, index or self in lifetime dependence specifier",
"expected 'copy', 'borrow', or '&' followed by an identifier, index or 'self' in lifetime dependence specifier",
())
ERROR(expected_rparen_after_lifetime_dependence, PointsToFirstBadToken,

View File

@@ -5014,6 +5014,7 @@ ParserResult<LifetimeEntry> Parser::parseLifetimeEntry(SourceLoc loc) {
SmallVector<LifetimeDescriptor> sources;
SourceLoc rParenLoc;
bool foundParamId = false;
bool invalidSourceDescriptor = false;
status = parseList(
tok::r_paren, lParenLoc, rParenLoc, /*AllowSepAfterLast=*/false,
diag::expected_rparen_after_lifetime_dependence, [&]() -> ParserStatus {
@@ -5030,6 +5031,7 @@ ParserResult<LifetimeEntry> Parser::parseLifetimeEntry(SourceLoc loc) {
auto sourceDescriptor =
parseLifetimeDescriptor(*this, lifetimeDependenceKind);
if (!sourceDescriptor) {
invalidSourceDescriptor = true;
listStatus.setIsParseError();
return listStatus;
}
@@ -5037,6 +5039,10 @@ ParserResult<LifetimeEntry> Parser::parseLifetimeEntry(SourceLoc loc) {
return listStatus;
});
if (invalidSourceDescriptor) {
status.setIsParseError();
return status;
}
if (!foundParamId) {
diagnose(
Tok,

View File

@@ -24,7 +24,7 @@ func testMissingLParenError(_ ne: NE) -> NE { // expected-error{{cannot infer th
ne
}
@_lifetime() // expected-error{{expected identifier, index or self in lifetime dependence specifier}}
@_lifetime() // expected-error{{expected 'copy', 'borrow', or '&' followed by an identifier, index or 'self' in lifetime dependence specifier}}
func testMissingDependence(_ ne: NE) -> NE { // expected-error{{cannot infer the lifetime dependence scope on a function with a ~Escapable parameter, specify '@_lifetime(borrow ne)' or '@_lifetime(copy ne)'}}
ne
}

View File

@@ -588,3 +588,8 @@ struct NonEscapableMutableSelf: ~Escapable {
//
func f_inout_no_infer(a: inout MutNE, b: NE) {} // expected-error{{a function with a ~Escapable 'inout' parameter requires '@_lifetime(a: ...)'}}
// expected-note @-1{{use '@_lifetime(a: copy a) to forward the inout dependency}}
// Invalid keyword for the dependence kind.
//
@_lifetime(a: inout a) // expected-error{{expected 'copy', 'borrow', or '&' followed by an identifier, index or 'self' in lifetime dependence specifier}}
func f_inout_bad_keyword(a: inout MutableRawSpan) {}