Skip to content

Commit 8b8aafb

Browse files
committed
Sema: Don't complain about implied Sendable conformance of imported type being retroactive
- Fixes rdar://145184871.
1 parent a232a2d commit 8b8aafb

File tree

5 files changed

+46
-11
lines changed

5 files changed

+46
-11
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6816,6 +6816,9 @@ static bool checkSendableInstanceStorage(
68166816

68176817
bool swift::checkSendableConformance(
68186818
ProtocolConformance *conformance, SendableCheck check) {
6819+
ASSERT(conformance->getProtocol()->isSpecificProtocol(
6820+
KnownProtocolKind::Sendable));
6821+
68196822
auto conformanceDC = conformance->getDeclContext();
68206823
auto nominal = conformance->getType()->getAnyNominal();
68216824
if (!nominal)
@@ -6905,13 +6908,16 @@ bool swift::checkSendableConformance(
69056908
return false;
69066909
}
69076910

6911+
// An implied conformance is generated when you state a conformance to
6912+
// a protocol P that inherits from Sendable.
6913+
bool wasImplied = (conformance->getSourceKind() ==
6914+
ConformanceEntryKind::Implied);
6915+
69086916
// Sendable can only be used in the same source file.
69096917
auto conformanceDecl = conformanceDC->getAsDecl();
69106918
SendableCheckContext checkContext(conformanceDC, check);
69116919
DiagnosticBehavior behavior = checkContext.defaultDiagnosticBehavior();
6912-
if (conformance->getSourceKind() == ConformanceEntryKind::Implied &&
6913-
conformance->getProtocol()->isSpecificProtocol(
6914-
KnownProtocolKind::Sendable)) {
6920+
if (wasImplied) {
69156921
if (auto optBehavior = checkContext.preconcurrencyBehavior(
69166922
nominal, /*ignoreExplicitConformance=*/true))
69176923
behavior = *optBehavior;
@@ -6920,12 +6926,14 @@ bool swift::checkSendableConformance(
69206926
if (conformanceDC->getOutermostParentSourceFile() &&
69216927
conformanceDC->getOutermostParentSourceFile() !=
69226928
nominal->getOutermostParentSourceFile()) {
6923-
conformanceDecl->diagnose(diag::concurrent_value_outside_source_file,
6924-
nominal)
6925-
.limitBehaviorUntilSwiftVersion(behavior, 6);
6929+
if (!(nominal->hasClangNode() && wasImplied)) {
6930+
conformanceDecl->diagnose(diag::concurrent_value_outside_source_file,
6931+
nominal)
6932+
.limitBehaviorUntilSwiftVersion(behavior, 6);
69266933

6927-
if (behavior == DiagnosticBehavior::Unspecified)
6928-
return true;
6934+
if (behavior == DiagnosticBehavior::Unspecified)
6935+
return true;
6936+
}
69296937
}
69306938

69316939
if (classDecl && classDecl->getParentSourceFile()) {
@@ -6963,7 +6971,7 @@ bool swift::checkSendableConformance(
69636971
// a Sendable conformance. The implied conformance is unconditional, so check
69646972
// the storage for sendability as if the conformance was declared on the nominal,
69656973
// and not some (possibly constrained) extension.
6966-
if (conformance->getSourceKind() == ConformanceEntryKind::Implied)
6974+
if (wasImplied)
69676975
conformanceDC = nominal;
69686976
return checkSendableInstanceStorage(nominal, conformanceDC, check);
69696977
}

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1843,6 +1843,18 @@ static void diagnoseRetroactiveConformances(
18431843
bool inserted = protocols.insert(std::make_pair(
18441844
proto, conformance->isRetroactive())).second;
18451845
ASSERT(inserted);
1846+
1847+
if (proto->isSpecificProtocol(KnownProtocolKind::SendableMetatype)) {
1848+
protocolsWithRetroactiveAttr.insert(proto);
1849+
}
1850+
1851+
// Implied conformance to Sendable is a special case that should not be
1852+
// diagnosed. Pretend it's always @retroactive.
1853+
if (conformance->getSourceKind() == ConformanceEntryKind::Implied &&
1854+
proto->isSpecificProtocol(KnownProtocolKind::Sendable) &&
1855+
extendedNominalDecl->hasClangNode()) {
1856+
protocolsWithRetroactiveAttr.insert(proto);
1857+
}
18461858
}
18471859

18481860
for (const InheritedEntry &entry : ext->getInherited().getEntries()) {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-sil -o /dev/null -I %S/Inputs/custom-modules %s -verify -parse-as-library -swift-version 6
2+
3+
// REQUIRES: objc_interop
4+
// REQUIRES: concurrency
5+
6+
import Foundation
7+
8+
extension CGRect: Sendable {}
9+
// expected-warning@-1 {{extension declares a conformance of imported type 'CGRect' to imported protocol 'Sendable'; this will not behave correctly if the owners of 'CoreGraphics' introduce this conformance in the future}}
10+
// expected-note@-2 {{add '@retroactive' to silence this warning}}
11+
// expected-error@-3 {{conformance to 'Sendable' must occur in the same source file as struct 'CGRect'; use '@unchecked Sendable' for retroactive conformance}}
12+
protocol P: Sendable {}
13+
14+
extension CGPoint: P {}
15+

test/Inputs/clang-importer-sdk/swift-modules/CoreFoundation.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
protocol _CFObject: Hashable {}
44

55
#if CGFLOAT_IN_COREFOUNDATION
6-
public struct CGFloat {
6+
public struct CGFloat: @unchecked Sendable {
77
#if _pointerBitWidth(_32)
88
public typealias UnderlyingType = Float
99
#elseif _pointerBitWidth(_64)

test/Inputs/clang-importer-sdk/swift-modules/CoreGraphics.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ public func == (lhs: CGPoint, rhs: CGPoint) -> Bool {
66
}
77

88
#if !CGFLOAT_IN_COREFOUNDATION
9-
public struct CGFloat {
9+
public struct CGFloat: Sendable {
1010
#if _pointerBitWidth(_32)
1111
public typealias UnderlyingType = Float
1212
#elseif _pointerBitWidth(_64)

0 commit comments

Comments
 (0)