@@ -618,10 +618,25 @@ static DiagnosticBehavior defaultSendableDiagnosticBehavior(
618618 return DiagnosticBehavior::Unspecified;
619619}
620620
621+ bool SendableCheckContext::isExplicitSendableConformance () const {
622+ if (!conformanceCheck)
623+ return false ;
624+
625+ switch (*conformanceCheck) {
626+ case SendableCheck::Explicit:
627+ return true ;
628+
629+ case SendableCheck::ImpliedByStandardProtocol:
630+ case SendableCheck::Implicit:
631+ return false ;
632+ }
633+ }
634+
621635DiagnosticBehavior SendableCheckContext::defaultDiagnosticBehavior () const {
622636 // If we're not supposed to diagnose existing data races from this context,
623637 // ignore the diagnostic entirely.
624- if (!shouldDiagnoseExistingDataRaces (fromDC))
638+ if (!isExplicitSendableConformance () &&
639+ !shouldDiagnoseExistingDataRaces (fromDC))
625640 return DiagnosticBehavior::Ignore;
626641
627642 return defaultSendableDiagnosticBehavior (fromDC->getASTContext ().LangOpts );
@@ -633,21 +648,8 @@ DiagnosticBehavior SendableCheckContext::diagnosticBehavior(
633648 NominalTypeDecl *nominal) const {
634649 // Determine whether the type was explicitly non-Sendable.
635650 auto nominalModule = nominal->getParentModule ();
636- bool isExplicitlyNonSendable = nominalModule->isConcurrencyChecked ();
637-
638- // If we are performing an explicit conformance check, always consider this
639- // to be an explicitly non-Sendable type.
640- if (conformanceCheck) {
641- switch (*conformanceCheck) {
642- case SendableCheck::Explicit:
643- isExplicitlyNonSendable = true ;
644- break ;
645-
646- case SendableCheck::ImpliedByStandardProtocol:
647- case SendableCheck::Implicit:
648- break ;
649- }
650- }
651+ bool isExplicitlyNonSendable = nominalModule->isConcurrencyChecked () ||
652+ isExplicitSendableConformance ();
651653
652654 // Determine whether this nominal type is visible via a @_predatesConcurrency
653655 // import.
@@ -679,8 +681,7 @@ DiagnosticBehavior SendableCheckContext::diagnosticBehavior(
679681// / a Sendable type is required.
680682static bool diagnoseSingleNonSendableType (
681683 Type type, SendableCheckContext fromContext, SourceLoc loc,
682- llvm::function_ref<
683- std::pair<DiagnosticBehavior, bool >(Type, DiagnosticBehavior)> diagnose) {
684+ llvm::function_ref<bool (Type, DiagnosticBehavior)> diagnose) {
684685
685686 auto behavior = DiagnosticBehavior::Unspecified;
686687
@@ -693,11 +694,9 @@ static bool diagnoseSingleNonSendableType(
693694 behavior = fromContext.defaultDiagnosticBehavior ();
694695 }
695696
696- DiagnosticBehavior actualBehavior;
697- bool wasError;
698- std::tie (actualBehavior, wasError) = diagnose (type, behavior);
697+ bool wasSuppressed = diagnose (type, behavior);
699698
700- if (actualBehavior == DiagnosticBehavior::Ignore) {
699+ if (behavior == DiagnosticBehavior::Ignore || wasSuppressed ) {
701700 // Don't emit any other diagnostics.
702701 } else if (type->is <FunctionType>()) {
703702 ctx.Diags .diagnose (loc, diag::nonsendable_function_type);
@@ -713,13 +712,12 @@ static bool diagnoseSingleNonSendableType(
713712 nominal->getName ());
714713 }
715714
716- return wasError ;
715+ return behavior == DiagnosticBehavior::Unspecified && !wasSuppressed ;
717716}
718717
719718bool swift::diagnoseNonSendableTypes (
720719 Type type, SendableCheckContext fromContext, SourceLoc loc,
721- llvm::function_ref<
722- std::pair<DiagnosticBehavior, bool >(Type, DiagnosticBehavior)> diagnose) {
720+ llvm::function_ref<bool (Type, DiagnosticBehavior)> diagnose) {
723721 auto module = fromContext.fromDC ->getParentModule ();
724722
725723 // If the Sendable protocol is missing, do nothing.
@@ -3640,44 +3638,6 @@ bool swift::contextUsesConcurrencyFeatures(const DeclContext *dc) {
36403638 return false ;
36413639}
36423640
3643- // / Limit the diagnostic behavior used when performing checks for the Sendable
3644- // / instance storage of Sendable types.
3645- // /
3646- // / \returns a pair containing the diagnostic behavior that should be used
3647- // / for this diagnostic, as well as a Boolean value indicating whether to
3648- // / treat this as an error.
3649- static std::pair<DiagnosticBehavior, bool > limitSendableInstanceBehavior (
3650- const LangOptions &langOpts, SendableCheck check,
3651- DiagnosticBehavior suggestedBehavior) {
3652- // Is an error suggested?
3653- bool suggestedError = suggestedBehavior == DiagnosticBehavior::Unspecified ||
3654- suggestedBehavior == DiagnosticBehavior::Error;
3655- switch (check) {
3656- case SendableCheck::Implicit:
3657- // For implicit checks, we always ignore the diagnostic and fail.
3658- return std::make_pair (DiagnosticBehavior::Ignore, true );
3659-
3660- case SendableCheck::Explicit:
3661- // Bump warnings up to errors due to explicit Sendable conformance.
3662- if (suggestedBehavior == DiagnosticBehavior::Warning)
3663- return std::make_pair (DiagnosticBehavior::Unspecified, true );
3664-
3665- return std::make_pair (suggestedBehavior, suggestedError);
3666-
3667- case SendableCheck::ImpliedByStandardProtocol:
3668- // If we aren't in Swift 6, downgrade diagnostics.
3669- if (!langOpts.isSwiftVersionAtLeast (6 )) {
3670- if (langOpts.WarnConcurrency &&
3671- suggestedBehavior != DiagnosticBehavior::Ignore)
3672- return std::make_pair (DiagnosticBehavior::Warning, false );
3673-
3674- return std::make_pair (DiagnosticBehavior::Ignore, false );
3675- }
3676-
3677- return std::make_pair (suggestedBehavior, suggestedError);
3678- }
3679- }
3680-
36813641namespace {
36823642 // / Visit the instance storage of the given nominal type as seen through
36833643 // / the given declaration context.
@@ -3749,38 +3709,36 @@ static bool checkSendableInstanceStorage(
37493709 if (check == SendableCheck::Implicit)
37503710 return true ;
37513711
3752- auto action = limitSendableInstanceBehavior (
3753- langOpts, check, DiagnosticBehavior::Unspecified);
3754-
3755- property->diagnose (diag::concurrent_value_class_mutable_property,
3756- property->getName (), nominal->getDescriptiveKind (),
3757- nominal->getName ())
3758- .limitBehavior (action.first );
3759- invalid = invalid || action.second ;
3712+ auto behavior = SendableCheckContext (
3713+ dc, check).defaultDiagnosticBehavior ();
3714+ if (behavior != DiagnosticBehavior::Ignore) {
3715+ property->diagnose (diag::concurrent_value_class_mutable_property,
3716+ property->getName (), nominal->getDescriptiveKind (),
3717+ nominal->getName ())
3718+ .limitBehavior (behavior);
3719+ }
3720+ invalid = invalid || (behavior == DiagnosticBehavior::Unspecified);
37603721 return true ;
37613722 }
37623723
37633724 // Check that the property type is Sendable.
3764- bool diagnosedProperty = diagnoseNonSendableTypes (
3725+ diagnoseNonSendableTypes (
37653726 propertyType, SendableCheckContext (dc, check), property->getLoc (),
3766- [&](Type type, DiagnosticBehavior suggestedBehavior ) {
3767- auto action = limitSendableInstanceBehavior (
3768- langOpts, check, suggestedBehavior) ;
3769- if (check == SendableCheck::Implicit)
3770- return action;
3727+ [&](Type type, DiagnosticBehavior behavior ) {
3728+ if (check == SendableCheck::Implicit) {
3729+ invalid = true ;
3730+ return true ;
3731+ }
37713732
37723733 property->diagnose (diag::non_concurrent_type_member,
3773- false , property->getName (),
3734+ propertyType, false , property->getName (),
37743735 nominal->getDescriptiveKind (),
3775- nominal->getName (),
3776- propertyType)
3777- .limitBehavior (action.first );
3778- return action;
3736+ nominal->getName ())
3737+ .limitBehavior (behavior);
3738+ return false ;
37793739 });
37803740
3781- if (diagnosedProperty) {
3782- invalid = true ;
3783-
3741+ if (invalid) {
37843742 // For implicit checks, bail out early if anything failed.
37853743 if (check == SendableCheck::Implicit)
37863744 return true ;
@@ -3791,26 +3749,23 @@ static bool checkSendableInstanceStorage(
37913749
37923750 // / Handle an enum associated value.
37933751 bool operator ()(EnumElementDecl *element, Type elementType) {
3794- bool diagnosedElement = diagnoseNonSendableTypes (
3752+ diagnoseNonSendableTypes (
37953753 elementType, SendableCheckContext (dc, check), element->getLoc (),
3796- [&](Type type, DiagnosticBehavior suggestedBehavior ) {
3797- auto action = limitSendableInstanceBehavior (
3798- langOpts, check, suggestedBehavior) ;
3799- if (check == SendableCheck::Implicit)
3800- return action;
3754+ [&](Type type, DiagnosticBehavior behavior ) {
3755+ if (check == SendableCheck::Implicit) {
3756+ invalid = true ;
3757+ return true ;
3758+ }
38013759
3802- element->diagnose (diag::non_concurrent_type_member,
3760+ element->diagnose (diag::non_concurrent_type_member, type,
38033761 true , element->getName (),
38043762 nominal->getDescriptiveKind (),
3805- nominal->getName (),
3806- type)
3807- .limitBehavior (action.first );
3808- return action;
3763+ nominal->getName ())
3764+ .limitBehavior (behavior);
3765+ return false ;
38093766 });
38103767
3811- if (diagnosedElement) {
3812- invalid = true ;
3813-
3768+ if (invalid) {
38143769 // For implicit checks, bail out early if anything failed.
38153770 if (check == SendableCheck::Implicit)
38163771 return true ;
@@ -3859,46 +3814,43 @@ bool swift::checkSendableConformance(
38593814
38603815 // Sendable can only be used in the same source file.
38613816 auto conformanceDecl = conformanceDC->getAsDecl ();
3862- const LangOptions &langOpts = conformanceDC->getASTContext ().LangOpts ;
3863- DiagnosticBehavior behavior;
3864- bool diagnosticCausesFailure;
3865- std::tie (behavior, diagnosticCausesFailure) = limitSendableInstanceBehavior (
3866- langOpts, check, DiagnosticBehavior::Unspecified);
3867- if (!conformanceDC->getParentSourceFile () ||
3817+ auto behavior = SendableCheckContext (conformanceDC)
3818+ .defaultDiagnosticBehavior ();
3819+ if (conformanceDC->getParentSourceFile () &&
3820+ nominal->getParentSourceFile () &&
38683821 conformanceDC->getParentSourceFile () != nominal->getParentSourceFile ()) {
38693822 conformanceDecl->diagnose (diag::concurrent_value_outside_source_file,
38703823 nominal->getDescriptiveKind (),
38713824 nominal->getName ())
3872- .limitBehavior (behavior);
3825+ .limitBehavior (behavior);
38733826
3874- if (diagnosticCausesFailure )
3827+ if (behavior == DiagnosticBehavior::Unspecified )
38753828 return true ;
38763829 }
38773830
3878- if (classDecl) {
3831+ if (classDecl && classDecl->getParentSourceFile ()) {
3832+ bool isInherited = isa<InheritedProtocolConformance>(conformance);
3833+
38793834 // An non-final class cannot conform to `Sendable`.
38803835 if (!classDecl->isSemanticallyFinal ()) {
38813836 classDecl->diagnose (diag::concurrent_value_nonfinal_class,
38823837 classDecl->getName ())
3883- .limitBehavior (behavior);
3838+ .limitBehavior (behavior);
38843839
3885- if (diagnosticCausesFailure )
3840+ if (behavior == DiagnosticBehavior::Unspecified )
38863841 return true ;
38873842 }
38883843
3889- // A 'Sendable' class cannot inherit from another class, although
3890- // we allow `NSObject` for Objective-C interoperability.
3891- if (!isa<InheritedProtocolConformance>(conformance)) {
3844+ if (!isInherited) {
3845+ // A 'Sendable' class cannot inherit from another class, although
3846+ // we allow `NSObject` for Objective-C interoperability.
38923847 if (auto superclassDecl = classDecl->getSuperclassDecl ()) {
38933848 if (!superclassDecl->isNSObject ()) {
38943849 classDecl->diagnose (
38953850 diag::concurrent_value_inherit,
38963851 nominal->getASTContext ().LangOpts .EnableObjCInterop ,
3897- classDecl->getName ())
3898- .limitBehavior (behavior);
3899-
3900- if (diagnosticCausesFailure)
3901- return true ;
3852+ classDecl->getName ());
3853+ return true ;
39023854 }
39033855 }
39043856 }
0 commit comments