Skip to content

Commit a57e71c

Browse files
committed
Import swift_attr(“@sendable”) for result types
If `__attribute__((swift_attr(“@sendable”)))` is applied to an ObjC method, ObjC property, C field, C variable, or C function, we will now make its result type `Sendable`. For some entities, this technically had a different behavior previously, because `@Sendable` can be applied to `func`s to indicate that their interface type should be `@Sendable`. We don’t really want people to use this functionality on non-local functions, so we can safely remove it. This isn’t quite interacting with `Unmanaged` the way we’d want, but I’ve included test cases for the current behavior with FIXME comments. Fixes rdar://90491024.
1 parent 192c52f commit a57e71c

File tree

5 files changed

+87
-41
lines changed

5 files changed

+87
-41
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3993,7 +3993,7 @@ namespace {
39933993
Impl.importType(decl->getType(), ImportTypeKind::Variable,
39943994
ImportDiagnosticAdder(Impl, decl, decl->getLocation()),
39953995
isInSystemModule(dc), Bridgeability::None,
3996-
ImportTypeAttrs());
3996+
getImportTypeAttrs(decl));
39973997
if (!importedType)
39983998
return nullptr;
39993999

@@ -4517,7 +4517,7 @@ namespace {
45174517
Impl.importType(decl->getType(), ImportTypeKind::RecordField,
45184518
ImportDiagnosticAdder(Impl, decl, decl->getLocation()),
45194519
isInSystemModule(dc), Bridgeability::None,
4520-
ImportTypeAttrs());
4520+
getImportTypeAttrs(decl));
45214521
if (!importedType) {
45224522
Impl.addImportDiagnostic(
45234523
decl, Diagnostic(diag::record_field_not_imported, decl),
@@ -4645,7 +4645,7 @@ namespace {
46454645
: ImportTypeKind::Variable),
46464646
ImportDiagnosticAdder(Impl, decl, decl->getLocation()),
46474647
isInSystemModule(dc), Bridgeability::None,
4648-
ImportTypeAttrs());
4648+
getImportTypeAttrs(decl));
46494649

46504650
if (!importedType)
46514651
return nullptr;
@@ -6948,7 +6948,8 @@ SwiftDeclConverter::getImplicitProperty(ImportedName importedName,
69486948
propertyType, ImportTypeKind::Property,
69496949
ImportDiagnosticAdder(Impl, getter, getter->getLocation()),
69506950
Impl.shouldAllowNSUIntegerAsInt(isFromSystemModule, getter),
6951-
Bridgeability::Full, ImportTypeAttrs(), OTK_ImplicitlyUnwrappedOptional);
6951+
Bridgeability::Full, getImportTypeAttrs(accessor),
6952+
OTK_ImplicitlyUnwrappedOptional);
69526953
if (!importedType)
69536954
return nullptr;
69546955

@@ -8131,6 +8132,8 @@ Optional<GenericParamList *> SwiftDeclConverter::importObjCGenericParams(
81318132
if (clangBound->getInterfaceDecl()) {
81328133
auto unqualifiedClangBound =
81338134
clangBound->stripObjCKindOfTypeAndQuals(Impl.getClangASTContext());
8135+
assert(!objcGenericParam->hasAttrs()
8136+
&& "ObjC generics can have attributes now--we should use 'em");
81348137
Type superclassType = Impl.importTypeIgnoreIUO(
81358138
clang::QualType(unqualifiedClangBound, 0), ImportTypeKind::Abstract,
81368139
ImportDiagnosticAdder(Impl, decl, decl->getLocation()),
@@ -8854,6 +8857,15 @@ ClangImporter::Implementation::importSwiftAttrAttributes(Decl *MappedDecl) {
88548857
if (isa<TypeAliasDecl>(MappedDecl))
88558858
return;
88568859

8860+
// `@Sendable` on non-types is treated as an `ImportTypeAttr` and shouldn't
8861+
// be treated as an attribute on the declaration. (Particularly, @Sendable on
8862+
// a function or method should be treated as making the return value Sendable,
8863+
// *not* as making the function/method itself Sendable, because
8864+
// `@Sendable func` is primarily meant for local functions.)
8865+
if (!isa<TypeDecl>(MappedDecl))
8866+
while (auto attr = MappedDecl->getAttrs().getEffectiveSendableAttr())
8867+
MappedDecl->getAttrs().removeAttribute(attr);
8868+
88578869
// Some types have an implicit '@Sendable' attribute.
88588870
if (ClangDecl->hasAttr<clang::SwiftNewTypeAttr>() ||
88598871
ClangDecl->hasAttr<clang::EnumExtensibilityAttr>() ||

lib/ClangImporter/ImportType.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1762,7 +1762,7 @@ ImportedType ClangImporter::Implementation::importPropertyType(
17621762
return importType(decl->getType(), importKind,
17631763
ImportDiagnosticAdder(*this, decl, decl->getLocation()),
17641764
shouldAllowNSUIntegerAsInt(isFromSystemModule, decl),
1765-
Bridgeability::Full, ImportTypeAttrs(),
1765+
Bridgeability::Full, getImportTypeAttrs(decl),
17661766
optionality);
17671767
}
17681768

@@ -1885,6 +1885,9 @@ class GetSendableType :
18851885
// These types are produced during bridging and have conditional
18861886
// conformances to Sendable depending on their generic parameters, so we
18871887
// want to make their generic parameters `Sendable`.
1888+
// FIXME: `Unmanaged` ought to be here too, but `AnyObject & Sendable`
1889+
// doesn't satisfy the generic parameter's `AnyObject` requirement.
1890+
// (rdar://90946615)
18881891
if (ty->isOptional() || ty->isArray() || ty->isSet() ||
18891892
ty->isDictionary())
18901893
return recurse(ty);
@@ -2081,7 +2084,7 @@ ImportedType ClangImporter::Implementation::importFunctionReturnType(
20812084
ImportDiagnosticAdder(*this, clangDecl,
20822085
clangDecl->getLocation()),
20832086
allowNSUIntegerAsInt, Bridgeability::Full,
2084-
ImportTypeAttrs(), OptionalityOfReturn);
2087+
getImportTypeAttrs(clangDecl), OptionalityOfReturn);
20852088
}
20862089

20872090
static Type
@@ -2126,7 +2129,7 @@ ImportedType ClangImporter::Implementation::importFunctionParamsAndReturnType(
21262129
dyn_cast<clang::TemplateTypeParmType>(clangDecl->getReturnType())) {
21272130
importedType = {findGenericTypeInGenericDecls(
21282131
*this, templateType, genericParams,
2129-
ImportTypeAttrs(), addDiag),
2132+
getImportTypeAttrs(clangDecl), addDiag),
21302133
false};
21312134
} else if ((isa<clang::PointerType>(clangDecl->getReturnType()) ||
21322135
isa<clang::ReferenceType>(clangDecl->getReturnType())) &&
@@ -2138,7 +2141,7 @@ ImportedType ClangImporter::Implementation::importFunctionParamsAndReturnType(
21382141
: PTK_UnsafeMutablePointer;
21392142
auto genericType =
21402143
findGenericTypeInGenericDecls(*this, templateParamType, genericParams,
2141-
ImportTypeAttrs(), addDiag);
2144+
getImportTypeAttrs(clangDecl), addDiag);
21422145
importedType = {genericType->wrapInPointer(pointerKind), false};
21432146
} else if (!(isa<clang::RecordType>(clangDecl->getReturnType()) ||
21442147
isa<clang::TemplateSpecializationType>(clangDecl->getReturnType())) ||
@@ -2196,7 +2199,8 @@ ParameterList *ClangImporter::Implementation::importFunctionParameterList(
21962199
auto parentType = importType(
21972200
parent->getASTContext().getRecordType(parent),
21982201
ImportTypeKind::Parameter, ImportDiagnosticAdder(*this, clangDecl),
2199-
allowNSUIntegerAsInt, Bridgeability::None, ImportTypeAttrs());
2202+
allowNSUIntegerAsInt, Bridgeability::None,
2203+
getImportTypeAttrs(clangDecl));
22002204

22012205
param->setInterfaceType(parentType.getType());
22022206

@@ -2691,7 +2695,7 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType(
26912695
auto importedType =
26922696
importType(resultType, resultKind, addImportDiag,
26932697
allowNSUIntegerAsIntInResult, Bridgeability::Full,
2694-
ImportTypeAttrs(), OptionalityOfReturn);
2698+
getImportTypeAttrs(clangDecl), OptionalityOfReturn);
26952699

26962700
// Adjust the result type for a throwing function.
26972701
if (importedType.getType() && errorInfo) {
@@ -2700,7 +2704,7 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType(
27002704
auto origImportedType =
27012705
importType(resultType, resultKind, addImportDiag,
27022706
allowNSUIntegerAsIntInResult, Bridgeability::None,
2703-
ImportTypeAttrs(), OptionalityOfReturn);
2707+
getImportTypeAttrs(clangDecl), OptionalityOfReturn);
27042708
origSwiftResultTy = origImportedType.getType()->getCanonicalType();
27052709

27062710
importedType =

test/IDE/print_clang_objc_async.swift

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -126,18 +126,30 @@ import _Concurrency
126126
// CHECK: @MainActor @objc protocol TripleMainActor {
127127

128128
// CHECK-LABEL: class NXSender :
129-
// CHECK-NEXT: func sendAny(_ obj: Sendable)
130-
// CHECK-NEXT: func sendOptionalAny(_ obj: Sendable?)
131-
// CHECK-NEXT: func sendSendable(_ sendable: SendableClass & Sendable)
132-
// CHECK-NEXT: func sendSendableSubclasses(_ sendableSubclass: NonSendableClass & Sendable)
133-
// CHECK-NEXT: func sendProto(_ obj: LabellyProtocol & Sendable)
134-
// CHECK-NEXT: func sendProtos(_ obj: LabellyProtocol & ObjCClub & Sendable)
135-
// CHECK-NEXT: func sendAnyArray(_ array: [Sendable])
136-
// CHECK-NEXT: func sendGeneric(_ generic: GenericObject<SendableClass> & Sendable)
137-
// CHECK-NEXT: func sendPtr(_ val: UnsafeMutableRawPointer)
138-
// CHECK-NEXT: func sendStringArray(_ obj: [String])
139-
// CHECK-NEXT: func sendAnyTypedef(_ obj: Sendable)
140-
// CHECK-NEXT: func sendAnyTypedefs(_ objs: [Sendable])
141-
// CHECK-NEXT: func sendBlockTypedef(_ block: @escaping @Sendable (Any) -> Void)
142-
// CHECK-NEXT: func sendBlockTypedefs(_ blocks: [@Sendable @convention(block) (Any) -> Void])
143-
// CHECK-NEXT: func sendUnbound(_ array: [Sendable])
129+
// CHECK: func sendAny(_ obj: Sendable) -> Sendable
130+
// CHECK: func sendOptionalAny(_ obj: Sendable?) -> Sendable?
131+
// CHECK: func sendSendable(_ sendable: SendableClass & Sendable) -> SendableClass & Sendable
132+
// CHECK: func sendSendableSubclasses(_ sendableSubclass: NonSendableClass & Sendable) -> NonSendableClass & Sendable
133+
// CHECK: func sendProto(_ obj: LabellyProtocol & Sendable) -> LabellyProtocol & Sendable
134+
// CHECK: func sendProtos(_ obj: LabellyProtocol & ObjCClub & Sendable) -> LabellyProtocol & ObjCClub & Sendable
135+
// CHECK: func sendAnyArray(_ array: [Sendable]) -> [Sendable]
136+
// CHECK: func sendGeneric(_ generic: GenericObject<SendableClass> & Sendable) -> GenericObject<SendableClass> & Sendable
137+
// CHECK: func sendPtr(_ val: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer
138+
// CHECK: func sendStringArray(_ obj: [String]) -> [String]
139+
// CHECK: func sendAnyTypedef(_ obj: Sendable) -> Sendable
140+
// CHECK: func sendAnyTypedefs(_ objs: [Sendable]) -> [Sendable]
141+
// CHECK: func sendBlockTypedef(_ block: @escaping @Sendable (Any) -> Void) -> @Sendable (Any) -> Void
142+
// CHECK: func sendBlockTypedefs(_ blocks: [@Sendable @convention(block) (Any) -> Void]) -> [@Sendable @convention(block) (Any) -> Void]
143+
// CHECK: func sendUnbound(_ array: [Sendable]) -> [Sendable]
144+
// CHECK: var sendableProp: Sendable
145+
// CHECK: }
146+
147+
// CHECK: func NXSendFunc(_ arg: Sendable) -> Sendable
148+
// CHECK: var NXSendGlobal: Sendable
149+
150+
// CHECK-LABEL: struct StructWithSendableContents
151+
// FIXME: `Unmanaged` should support `AnyObject & Sendable`.
152+
// CHECK: var sendableField: Unmanaged<AnyObject>
153+
// FIXME: Should be imported as Unmanaged!
154+
// CHECK: var sendableIndirectField: Sendable & AnyObject
155+
// CHECK: var sendableComputed: Sendable { get }

test/IDE/print_objc_concurrency_interface.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import _Concurrency
1818

1919
// NEGATIVE-NOT: @Sendable{{.+}}class
2020
// NEGATIVE-NOT: @_nonSendable{{.+}}class
21+
// NEGATIVE-NOT: @Sendable{{.+}}func
22+
// NEGATIVE-NOT: @Sendable{{.+}}var
2123

2224
// CHECK-LABEL: class SendableClass :
2325
// CHECK-SAME: @unchecked Sendable

test/Inputs/clang-importer-sdk/usr/include/ObjCConcurrency.h

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -272,21 +272,37 @@ typedef void(^BlockTypedef)(id);
272272

273273
@interface NXSender : NSObject
274274

275-
- (void)sendAny:(SENDABLE id)obj;
276-
- (void)sendOptionalAny:(nullable SENDABLE id)obj;
277-
- (void)sendSendable:(SENDABLE SendableClass *)sendable;
278-
- (void)sendSendableSubclasses:(SENDABLE NonSendableClass *)sendableSubclass;
279-
- (void)sendProto:(SENDABLE id <LabellyProtocol>)obj;
280-
- (void)sendProtos:(SENDABLE id <LabellyProtocol, ObjCClub>)obj;
281-
- (void)sendAnyArray:(SENDABLE NSArray<id> *)array;
282-
- (void)sendGeneric:(SENDABLE GenericObject<SendableClass *> *)generic;
283-
- (void)sendPtr:(SENDABLE void *)val; // bad
284-
- (void)sendStringArray:(SENDABLE NSArray<NSString *> *)obj; // bad
285-
- (void)sendAnyTypedef:(SENDABLE ObjectTypedef)obj;
286-
- (void)sendAnyTypedefs:(SENDABLE NSArray<ObjectTypedef> *)objs;
287-
- (void)sendBlockTypedef:(SENDABLE BlockTypedef)block;
288-
- (void)sendBlockTypedefs:(SENDABLE NSArray<BlockTypedef> *)blocks;
289-
- (void)sendUnbound:(SENDABLE NSArray *)array;
275+
- (id)sendAny:(SENDABLE id)obj SENDABLE;
276+
- (nullable id)sendOptionalAny:(nullable SENDABLE id)obj SENDABLE;
277+
- (SendableClass *)sendSendable:(SENDABLE SendableClass *)sendable SENDABLE;
278+
- (NonSendableClass *)sendSendableSubclasses:(SENDABLE NonSendableClass *)sendableSubclass SENDABLE;
279+
- (id <LabellyProtocol>)sendProto:(SENDABLE id <LabellyProtocol>)obj SENDABLE;
280+
- (id <LabellyProtocol, ObjCClub>)sendProtos:(SENDABLE id <LabellyProtocol, ObjCClub>)obj SENDABLE;
281+
- (NSArray<id> *)sendAnyArray:(SENDABLE NSArray<id> *)array SENDABLE;
282+
- (GenericObject<SendableClass *> *)sendGeneric:(SENDABLE GenericObject<SendableClass *> *)generic SENDABLE;
283+
- (void *)sendPtr:(SENDABLE void *)val SENDABLE; // bad
284+
- (NSArray<NSString *> *)sendStringArray:(SENDABLE NSArray<NSString *> *)obj SENDABLE; // bad
285+
- (ObjectTypedef)sendAnyTypedef:(SENDABLE ObjectTypedef)obj SENDABLE;
286+
- (NSArray<ObjectTypedef> *)sendAnyTypedefs:(SENDABLE NSArray<ObjectTypedef> *)objs SENDABLE;
287+
- (BlockTypedef)sendBlockTypedef:(SENDABLE BlockTypedef)block SENDABLE;
288+
- (NSArray<BlockTypedef> *)sendBlockTypedefs:(SENDABLE NSArray<BlockTypedef> *)blocks SENDABLE;
289+
- (NSArray *)sendUnbound:(SENDABLE NSArray *)array SENDABLE;
290+
291+
@property (strong) SENDABLE id sendableProp;
292+
290293
@end
291294

295+
SENDABLE id NXSendFunc(SENDABLE id arg);
296+
SENDABLE id NXSendGlobal;
297+
298+
struct StructWithSendableContents {
299+
__unsafe_unretained SENDABLE id sendableField;
300+
union {
301+
__unsafe_unretained SENDABLE id sendableIndirectField;
302+
};
303+
};
304+
305+
SENDABLE id StructWithSendableContentsGetSendableComputed(struct StructWithSendableContents contents)
306+
__attribute__((swift_name("getter:StructWithSendableContents.sendableComputed(self:)")));
307+
292308
#pragma clang assume_nonnull end

0 commit comments

Comments
 (0)