diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index bb75f58ee9879..7bc1a2e8592ac 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -2178,8 +2178,8 @@ ERROR(expected_lparen_after_lifetime_dependence, PointsToFirstBadToken, ERROR(expected_identifier_or_index_or_self_after_lifetime_dependence, PointsToFirstBadToken, - "expected 'copy', 'borrow', or '&' followed by an identifier, index or 'self' in lifetime dependence specifier", - ()) + "expected 'copy', 'borrow', or '&' followed by an identifier%select{|, index}0 or 'self' in lifetime dependence specifier", + (bool)) ERROR(expected_rparen_after_lifetime_dependence, PointsToFirstBadToken, "expected ')' after parameter list in lifetime dependence specifier", ()) diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index c06cdc402a9e8..9cacd167cfd9e 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -1158,7 +1158,8 @@ class Parser { /// Common utility to parse swift @lifetime decl attribute and SIL @lifetime /// type modifier. - ParserResult parseLifetimeEntry(SourceLoc loc); + ParserResult parseLifetimeEntry(SourceLoc loc, + bool allowIndices); /// Parse a specific attribute. ParserStatus parseDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc, diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index e5f629231bf9b..e6a1991809778 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2545,7 +2545,7 @@ static std::optional parseSingleAttrOptionImpl( } static std::optional -parseLifetimeDescriptor(Parser &P, +parseLifetimeDescriptor(Parser &P, bool allowIndices, ParsedLifetimeDependenceKind lifetimeDependenceKind = ParsedLifetimeDependenceKind::Default) { auto token = P.Tok; @@ -2577,6 +2577,13 @@ parseLifetimeDescriptor(Parser &P, case tok::integer_literal: { SourceLoc loc; unsigned index; + if (!allowIndices) { + P.diagnose( + token, + diag::expected_identifier_or_index_or_self_after_lifetime_dependence, + /* allow indices */ false); + return std::nullopt; + } if (P.parseUnsignedInteger( index, loc, diag::expected_param_index_lifetime_dependence)) { return std::nullopt; @@ -2590,7 +2597,8 @@ parseLifetimeDescriptor(Parser &P, default: { P.diagnose( token, - diag::expected_identifier_or_index_or_self_after_lifetime_dependence); + diag::expected_identifier_or_index_or_self_after_lifetime_dependence, + allowIndices); return std::nullopt; } } @@ -2601,7 +2609,7 @@ ParserResult Parser::parseLifetimeAttribute(StringRef attrName, SourceLoc loc) { ParserStatus status; - auto lifetimeEntry = parseLifetimeEntry(loc); + auto lifetimeEntry = parseLifetimeEntry(loc, /*allowIndices=*/false); if (lifetimeEntry.isNull()) { status.setIsParseError(); return status; @@ -5077,7 +5085,7 @@ ParserStatus Parser::parseTypeAttribute(TypeOrCustomAttr &result, } case TypeAttrKind::Lifetime: { - const auto entryResult = parseLifetimeEntry(AtLoc); + const auto entryResult = parseLifetimeEntry(AtLoc, /*allowIndices=*/false); if (entryResult.isNull()) { return makeParserError(); } @@ -5164,7 +5172,8 @@ ParserStatus Parser::parseTypeAttribute(TypeOrCustomAttr &result, llvm_unreachable("bad attribute kind"); } -ParserResult Parser::parseLifetimeEntry(SourceLoc loc) { +ParserResult Parser::parseLifetimeEntry(SourceLoc loc, + bool allowIndices) { ParserStatus status; auto getLifetimeDependenceKind = @@ -5198,7 +5207,7 @@ ParserResult Parser::parseLifetimeEntry(SourceLoc loc) { std::optional targetDescriptor; if (Tok.isAny(tok::identifier, tok::integer_literal, tok::kw_self) && peekToken().is(tok::colon)) { - targetDescriptor = parseLifetimeDescriptor(*this); + targetDescriptor = parseLifetimeDescriptor(*this, allowIndices); if (!targetDescriptor) { status.setIsParseError(); return status; @@ -5223,8 +5232,8 @@ ParserResult Parser::parseLifetimeEntry(SourceLoc loc) { consumeToken(); } - auto sourceDescriptor = - parseLifetimeDescriptor(*this, lifetimeDependenceKind); + auto sourceDescriptor = parseLifetimeDescriptor(*this, allowIndices, + lifetimeDependenceKind); if (!sourceDescriptor) { invalidSourceDescriptor = true; listStatus.setIsParseError(); @@ -5241,7 +5250,8 @@ ParserResult Parser::parseLifetimeEntry(SourceLoc loc) { if (!foundParamId) { diagnose( Tok, - diag::expected_identifier_or_index_or_self_after_lifetime_dependence); + diag::expected_identifier_or_index_or_self_after_lifetime_dependence, + /* allow indices */ isInSILMode()); status.setIsParseError(); return status; } @@ -5583,7 +5593,7 @@ ParserStatus Parser::ParsedTypeAttributeList::slowParse(Parser &P) { } P.consumeToken(); // consume '@' auto loc = P.consumeToken(); // consume 'lifetime' - auto result = P.parseLifetimeEntry(loc); + auto result = P.parseLifetimeEntry(loc, /*allowIndices=*/true); if (result.isNull()) { status |= result; continue; diff --git a/test/Parse/lifetime_attr.swift b/test/Parse/lifetime_attr.swift index 218dc8b5bbe70..53349171731a7 100644 --- a/test/Parse/lifetime_attr.swift +++ b/test/Parse/lifetime_attr.swift @@ -24,7 +24,7 @@ func testMissingLParenError(_ ne: NE) -> NE { ne } -@_lifetime() // expected-error{{expected 'copy', 'borrow', or '&' followed by an identifier, index or 'self' in lifetime dependence specifier}} +@_lifetime() // expected-error{{expected 'copy', 'borrow', or '&' followed by an identifier or 'self' in lifetime dependence specifier}} func testMissingDependence(_ ne: NE) -> NE { ne } diff --git a/test/Sema/lifetime_attr.swift b/test/Sema/lifetime_attr.swift index 9c1cb4016c664..dc90e4f5ffddd 100644 --- a/test/Sema/lifetime_attr.swift +++ b/test/Sema/lifetime_attr.swift @@ -17,7 +17,12 @@ func invalidAttrOnNonExistingSelf(_ ne: NE) -> NE { ne } -@_lifetime(2) // expected-error{{invalid parameter index specified '2'}} +@_lifetime(copy 0) // expected-error{{expected 'copy', 'borrow', or '&' followed by an identifier or 'self' in lifetime dependence specifier}} +func invalidAttrOnExistingParamIndex(_ ne: NE) -> NE { + ne +} + +@_lifetime(2) // expected-error{{expected 'copy', 'borrow', or '&' followed by an identifier or 'self' in lifetime dependence specifier}} func invalidAttrOnNonExistingParamIndex(_ ne: NE) -> NE { ne } diff --git a/test/Sema/lifetime_depend_infer.swift b/test/Sema/lifetime_depend_infer.swift index e87b6e43fc95b..71c7998920639 100644 --- a/test/Sema/lifetime_depend_infer.swift +++ b/test/Sema/lifetime_depend_infer.swift @@ -849,7 +849,7 @@ struct NoncopyableSelfAccessors: ~Copyable & ~Escapable { // 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}} +@_lifetime(a: inout a) // expected-error{{expected 'copy', 'borrow', or '&' followed by an identifier or 'self' in lifetime dependence specifier}} func f_inout_bad_keyword(a: inout MutableRawSpan) {} // Don't allow a useless borrow dependency on an inout param--it is misleading. diff --git a/test/Sema/lifetime_dependence_functype.swift b/test/Sema/lifetime_dependence_functype.swift index 871af3d61b9c7..d7ce9a85d514e 100644 --- a/test/Sema/lifetime_dependence_functype.swift +++ b/test/Sema/lifetime_dependence_functype.swift @@ -19,7 +19,7 @@ func transfer(_ ne: NE) -> NE { } @_lifetime(copy ne) -func applyAnnotatedTransfer(ne: NE, @_lifetime(0) transfer: (NE) -> NE) -> NE { // expected-error{{'@_lifetime' attribute cannot be applied to this declaration}} +func applyAnnotatedTransfer(ne: NE, @_lifetime(copy ne) transfer: (_ ne: NE) -> NE) -> NE { // expected-error{{'@_lifetime' attribute cannot be applied to this declaration}} transfer(ne) } @@ -61,7 +61,9 @@ typealias InvalidAttrOnNonExistingParamType = @_lifetime(copy nonexisting) (_ ne typealias InvalidAttrOnNonExistingSelfType = @_lifetime(copy self) (_ ne: NE) -> NE // expected-error{{invalid lifetime dependence specifier on non-existent self}} -typealias InvalidAttrOnNonExistingParamIndexType = @_lifetime(2) (_ ne: NE) -> NE // expected-error{{invalid parameter index specified '2'}} +typealias InvalidAttrOnExistingParamIndexType = @_lifetime(0) (_ ne: NE) -> NE // expected-error{{expected 'copy', 'borrow', or '&' followed by an identifier or 'self' in lifetime dependence specifier}} + +typealias InvalidAttrOnNonExistingParamIndexType = @_lifetime(2) (_ ne: NE) -> NE // expected-error{{expected 'copy', 'borrow', or '&' followed by an identifier or 'self' in lifetime dependence specifier}} typealias InvalidDuplicateLifetimeDependenceType = @_lifetime(copy ne, borrow ne) (_ ne: borrowing NE) -> NE // expected-error{{duplicate lifetime dependence specifier}}