@@ -3597,35 +3597,60 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
3597
3597
case DeclAttrKind::UnavailableFromAsync: {
3598
3598
StringRef message;
3599
3599
if (consumeIfAttributeLParen ()) {
3600
- if (!Tok.is (tok::identifier)) {
3601
- llvm_unreachable (" Flag must start with an identifier" );
3602
- }
3603
-
3604
- StringRef flag = Tok.getText ();
3600
+ auto tokMayBeArgument = [&]() -> bool {
3601
+ return Tok.isNot (tok::r_paren, tok::comma) &&
3602
+ !isKeywordPossibleDeclStart (Context.LangOpts , Tok);
3603
+ };
3605
3604
3606
- if (flag != " message" ) {
3607
- diagnose (Tok.getLoc (), diag::attr_unknown_option, flag, AttrName);
3608
- return makeParserError ();
3609
- }
3610
- consumeToken ();
3611
- if (!consumeIf (tok::colon)) {
3612
- if (!Tok.is (tok::equal)) {
3613
- diagnose (Tok.getLoc (), diag::attr_expected_colon_after_label, flag);
3614
- return makeParserSuccess ();
3605
+ Identifier label;
3606
+ SourceLoc labelLoc;
3607
+ parseOptionalArgumentLabel (label, labelLoc, /* isAttr=*/ true );
3608
+
3609
+ if (label.empty ()) {
3610
+ // If we have the identifier 'message', assume the user forgot the
3611
+ // colon.
3612
+ if (Tok.isContextualKeyword (" message" )) {
3613
+ labelLoc = consumeToken ();
3614
+ auto diag = diagnose (Tok, diag::attr_expected_colon_after_label,
3615
+ " message" );
3616
+ if (Tok.is (tok::string_literal))
3617
+ diag.fixItInsertAfter (labelLoc, " :" );
3618
+ else
3619
+ return makeParserError ();
3615
3620
}
3616
- diagnose (Tok.getLoc (), diag::replace_equal_with_colon_for_value)
3617
- .fixItReplace (Tok.getLoc (), " : " );
3618
- consumeToken ();
3621
+ // If the argument list just abruptly cuts off, handle that as a
3622
+ // missing argument (below). Otherwise, diagnose the missing label.
3623
+ else if (tokMayBeArgument ()) {
3624
+ if (labelLoc.isValid ())
3625
+ // The user wrote an explicitly omitted label (`_:`).
3626
+ diagnose (labelLoc, diag::attr_expected_label, " message" , AttrName)
3627
+ .fixItReplace (labelLoc, " message" );
3628
+ else
3629
+ diagnose (Tok, diag::attr_expected_label, " message" , AttrName)
3630
+ .fixItInsert (Tok.getLoc (), " message: " );
3631
+ }
3632
+ // Fall through to parse the argument.
3633
+ } else if (label != Context.Id_message ) {
3634
+ diagnose (labelLoc, diag::attr_unknown_option, label.str (), AttrName)
3635
+ .fixItReplace (labelLoc, " message" );
3636
+ return makeParserError ();
3619
3637
}
3638
+
3620
3639
if (!Tok.is (tok::string_literal)) {
3621
- diagnose (Tok.getLoc (), diag::attr_expected_string_literal, AttrName);
3622
- return makeParserSuccess ();
3640
+ // If this token looks like an argument, replace it; otherwise insert
3641
+ // before it.
3642
+ auto endLoc = tokMayBeArgument () ? peekToken ().getLoc () : Tok.getLoc ();
3643
+
3644
+ diagnose (Tok, diag::attr_expected_string_literal, AttrName)
3645
+ .fixItReplaceChars (Tok.getLoc (), endLoc, " \" <#error message#>\" " );
3646
+
3647
+ return makeParserError ();
3623
3648
}
3624
3649
3625
3650
std::optional<StringRef> value =
3626
- getStringLiteralIfNotInterpolated (Tok.getLoc (), flag );
3651
+ getStringLiteralIfNotInterpolated (Tok.getLoc (), " message " );
3627
3652
if (!value)
3628
- return makeParserSuccess ();
3653
+ return makeParserError ();
3629
3654
Token stringTok = Tok;
3630
3655
consumeToken ();
3631
3656
message = *value;
0 commit comments