@@ -7932,15 +7932,17 @@ bool Parser::parseAccessorAfterIntroducer(
79327932 if (requiresFeatureCoroutineAccessors (Kind) &&
79337933 !Context.LangOpts .hasFeature (Feature::CoroutineAccessors)) {
79347934 diagnose (Tok, diag::accessor_requires_coroutine_accessors,
7935- getAccessorNameForDiagnostic (Kind, /* article*/ false ));
7935+ getAccessorNameForDiagnostic (Kind, /* article*/ false ,
7936+ /* underscored*/ false ));
79367937 }
79377938
79387939 // There should be no body in the limited syntax; diagnose unexpected
79397940 // accessor implementations.
79407941 if (parsingLimitedSyntax) {
79417942 if (Tok.is (tok::l_brace))
79427943 diagnose (Tok, diag::unexpected_getset_implementation_in_protocol,
7943- getAccessorNameForDiagnostic (Kind, /* article*/ false ));
7944+ getAccessorNameForDiagnostic (Kind, /* article*/ false ,
7945+ /* underscored*/ false ));
79447946 return false ;
79457947 }
79467948
@@ -8352,16 +8354,45 @@ void Parser::ParsedAccessors::record(Parser &P, AbstractStorageDecl *storage,
83528354 storage->setAccessors (LBLoc, Accessors, RBLoc);
83538355}
83548356
8357+ static std::optional<AccessorKind>
8358+ getCorrespondingUnderscoredAccessorKind (AccessorKind kind) {
8359+ switch (kind) {
8360+ case AccessorKind::Read2:
8361+ return {AccessorKind::Read};
8362+ case AccessorKind::Modify2:
8363+ return {AccessorKind::Modify};
8364+ case AccessorKind::Get:
8365+ case AccessorKind::DistributedGet:
8366+ case AccessorKind::Set:
8367+ case AccessorKind::Read:
8368+ case AccessorKind::Modify:
8369+ case AccessorKind::WillSet:
8370+ case AccessorKind::DidSet:
8371+ case AccessorKind::Address:
8372+ case AccessorKind::MutableAddress:
8373+ case AccessorKind::Init:
8374+ return std::nullopt ;
8375+ }
8376+ }
8377+
83558378static void diagnoseConflictingAccessors (Parser &P, AccessorDecl *first,
83568379 AccessorDecl *&second) {
83578380 if (!second) return ;
8358- P.diagnose (second->getLoc (), diag::conflicting_accessor,
8359- isa<SubscriptDecl>(first->getStorage ()),
8360- getAccessorNameForDiagnostic (second, /* article*/ true ),
8361- getAccessorNameForDiagnostic (first, /* article*/ true ));
8362- P.diagnose (first->getLoc (), diag::previous_accessor,
8363- getAccessorNameForDiagnostic (first, /* article*/ false ),
8364- /* already*/ false );
8381+ bool underscored =
8382+ (getCorrespondingUnderscoredAccessorKind (first->getAccessorKind ()) ==
8383+ second->getAccessorKind ()) ||
8384+ (getCorrespondingUnderscoredAccessorKind (second->getAccessorKind ()) ==
8385+ first->getAccessorKind ()) ||
8386+ first->getASTContext ().LangOpts .hasFeature (Feature::CoroutineAccessors);
8387+ P.diagnose (
8388+ second->getLoc (), diag::conflicting_accessor,
8389+ isa<SubscriptDecl>(first->getStorage ()),
8390+ getAccessorNameForDiagnostic (second, /* article*/ true , underscored),
8391+ getAccessorNameForDiagnostic (first, /* article*/ true , underscored));
8392+ P.diagnose (
8393+ first->getLoc (), diag::previous_accessor,
8394+ getAccessorNameForDiagnostic (first, /* article*/ false , underscored),
8395+ /* already*/ false );
83658396 second->setInvalid ();
83668397}
83678398
@@ -8404,12 +8435,13 @@ void Parser::ParsedAccessors::classify(Parser &P, AbstractStorageDecl *storage,
84048435
84058436 // Okay, observers are out of the way.
84068437
8407- // 'get', 'read', and a non-mutable addressor are all exclusive.
8438+ // 'get', '_read', 'read' and a non-mutable addressor are all exclusive.
84088439 if (Get) {
84098440 diagnoseConflictingAccessors (P, Get, Read);
84108441 diagnoseConflictingAccessors (P, Get, Read2);
84118442 diagnoseConflictingAccessors (P, Get, Address);
84128443 } else if (Read) {
8444+ diagnoseConflictingAccessors (P, Read, Read2);
84138445 diagnoseConflictingAccessors (P, Read, Address);
84148446 } else if (Read2) {
84158447 diagnoseConflictingAccessors (P, Read2, Address);
@@ -8438,11 +8470,13 @@ void Parser::ParsedAccessors::classify(Parser &P, AbstractStorageDecl *storage,
84388470 }
84398471 }
84408472
8441- // A mutable addressor is exclusive with 'set' and 'modify', but
8442- // 'set' and 'modify' can appear together.
8473+ // '_modify', 'modify' and 'unsafeMutableAddress' are all mutually exclusive.
8474+ // 'unsafeMutableAddress' and 'set' are mutually exclusive, but 'set' and
8475+ // 'modify' can appear together.
84438476 if (Set) {
84448477 diagnoseConflictingAccessors (P, Set, MutableAddress);
84458478 } else if (Modify) {
8479+ diagnoseConflictingAccessors (P, Modify, Modify2);
84468480 diagnoseConflictingAccessors (P, Modify, MutableAddress);
84478481 }
84488482
0 commit comments