@@ -1570,42 +1570,68 @@ void Parser::parseAllAvailabilityMacroArguments() {
15701570 AvailabilityMacrosComputed = true ;
15711571}
15721572
1573- static HasAsyncAlternativeAttr *parseAsyncAlternativeAttribute (
1574- Parser &P, StringRef AttrName, SourceLoc AtLoc, DeclAttrKind DK) {
1573+ static CompletionHandlerAsyncAttr *
1574+ parseCompletionHandlerAsyncAttribute (Parser &P, StringRef AttrName,
1575+ SourceLoc AtLoc, DeclAttrKind DK) {
15751576 SourceLoc Loc = P.PreviousLoc ;
15761577
1577- // Unnamed @hasAsyncAlternative attribute
1578- if (P.Tok . isNot (tok::l_paren))
1579- return new (P. Context ) HasAsyncAlternativeAttr (AtLoc, Loc );
1580-
1581- P. consumeToken (tok::l_paren);
1578+ if (!P. consumeIf (tok::l_paren)) {
1579+ P. diagnose (P.getEndOfPreviousLoc (), diag::attr_expected_lparen, AttrName,
1580+ DeclAttribute::isDeclModifier (DK) );
1581+ return nullptr ;
1582+ }
15821583
15831584 if (!P.Tok .is (tok::string_literal)) {
15841585 P.diagnose (Loc, diag::attr_expected_string_literal, AttrName);
15851586 return nullptr ;
15861587 }
15871588
1588- auto Value = P.getStringLiteralIfNotInterpolated (
1589- Loc, (" argument of '" + AttrName + " '" ).str ());
1589+ SourceLoc nameLoc = P.Tok .getLoc ();
1590+ Optional<StringRef> asyncFunctionName = P.getStringLiteralIfNotInterpolated (
1591+ nameLoc, (" argument of '" + AttrName + " '" ).str ());
15901592 P.consumeToken (tok::string_literal);
1591- if (!Value)
1593+
1594+ if (!asyncFunctionName)
15921595 return nullptr ;
15931596
1594- ParsedDeclName parsedName = parseDeclName (Value.getValue ());
1595- if (!parsedName || !parsedName.ContextName .empty ()) {
1596- P.diagnose (AtLoc, diag::has_async_alternative_invalid_name, AttrName);;
1597+ ParsedDeclName parsedAsyncName = parseDeclName (*asyncFunctionName);
1598+ if (!parsedAsyncName || !parsedAsyncName.ContextName .empty ()) {
1599+ P.diagnose (nameLoc, diag::attr_completion_handler_async_invalid_name,
1600+ AttrName);
15971601 return nullptr ;
15981602 }
15991603
1604+ size_t handlerIndex = 0 ;
1605+ SourceLoc handlerIndexLoc = SourceLoc ();
1606+ if (P.consumeIf (tok::comma)) {
1607+ // The completion handler is explicitly specified, parse it
1608+ if (P.parseSpecificIdentifier (" completionHandlerIndex" ,
1609+ diag::attr_missing_label,
1610+ " completionHandlerIndex" , AttrName) ||
1611+ P.parseToken (tok::colon, diag::expected_colon_after_label,
1612+ " completionHandlerIndex" )) {
1613+ return nullptr ;
1614+ }
1615+
1616+ if (P.Tok .getText ().getAsInteger (0 , handlerIndex)) {
1617+ P.diagnose (P.Tok .getLoc (), diag::attr_expected_integer_literal, AttrName);
1618+ return nullptr ;
1619+ }
1620+
1621+ handlerIndexLoc = P.consumeToken (tok::integer_literal);
1622+ }
1623+
16001624 SourceRange AttrRange = SourceRange (Loc, P.Tok .getRange ().getStart ());
16011625 if (!P.consumeIf (tok::r_paren)) {
1602- P.diagnose (Loc , diag::attr_expected_rparen, AttrName,
1626+ P.diagnose (P. getEndOfPreviousLoc () , diag::attr_expected_rparen, AttrName,
16031627 DeclAttribute::isDeclModifier (DK));
16041628 return nullptr ;
16051629 }
16061630
1607- return new (P.Context ) HasAsyncAlternativeAttr (
1608- parsedName.formDeclNameRef (P.Context ), AtLoc, AttrRange);
1631+ return new (P.Context ) CompletionHandlerAsyncAttr (
1632+ parsedAsyncName.formDeclNameRef (P.Context ), nameLoc,
1633+ handlerIndex, handlerIndexLoc, AtLoc,
1634+ AttrRange);
16091635}
16101636
16111637bool Parser::parseNewDeclAttribute (DeclAttributes &Attributes, SourceLoc AtLoc,
@@ -2686,8 +2712,9 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
26862712 name, AtLoc, range, /* implicit*/ false ));
26872713 break ;
26882714 }
2689- case DAK_HasAsyncAlternative: {
2690- auto *attr = parseAsyncAlternativeAttribute (*this , AttrName, AtLoc, DK);
2715+ case DAK_CompletionHandlerAsync: {
2716+ auto *attr =
2717+ parseCompletionHandlerAsyncAttribute (*this , AttrName, AtLoc, DK);
26912718 if (!attr) {
26922719 skipUntilDeclStmtRBrace (tok::r_paren);
26932720 consumeIf (tok::r_paren);
0 commit comments