Skip to content

Commit 5f71e52

Browse files
committed
[Clang import] Apply main-thread annotations from parameters to types.
Import a main-thread annotation on a function/method parameter in (Objective-)C as a `@MainActor` function type.
1 parent ea60a2b commit 5f71e52

File tree

6 files changed

+75
-15
lines changed

6 files changed

+75
-15
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8010,6 +8010,19 @@ SourceFile &ClangImporter::Implementation::getClangSwiftAttrSourceFile(
80108010
return *sourceFile;
80118011
}
80128012

8013+
Optional<bool> swift::importer::isMainActorAttr(
8014+
ASTContext &ctx, const clang::SwiftAttrAttr *swiftAttr) {
8015+
if (swiftAttr->getAttribute() == "@MainActor" ||
8016+
swiftAttr->getAttribute() == "@MainActor(unsafe)" ||
8017+
swiftAttr->getAttribute() == "@UIActor") {
8018+
bool isUnsafe = swiftAttr->getAttribute() == "@MainActor(unsafe)" ||
8019+
!ctx.LangOpts.isSwiftVersionAtLeast(6);
8020+
return isUnsafe;
8021+
}
8022+
8023+
return None;
8024+
}
8025+
80138026
/// Import Clang attributes as Swift attributes.
80148027
void ClangImporter::Implementation::importAttributes(
80158028
const clang::NamedDecl *ClangDecl,
@@ -8180,11 +8193,8 @@ void ClangImporter::Implementation::importAttributes(
81808193
if (auto swiftAttr = dyn_cast<clang::SwiftAttrAttr>(*AI)) {
81818194
// FIXME: Hard-core @MainActor and @UIActor, because we don't have a
81828195
// point at which to do name lookup for imported entities.
8183-
if (swiftAttr->getAttribute() == "@MainActor" ||
8184-
swiftAttr->getAttribute() == "@MainActor(unsafe)" ||
8185-
swiftAttr->getAttribute() == "@UIActor") {
8186-
bool isUnsafe = swiftAttr->getAttribute() == "@MainActor(unsafe)" ||
8187-
!C.LangOpts.isSwiftVersionAtLeast(6);
8196+
if (auto isMainActor = isMainActorAttr(SwiftContext, swiftAttr)) {
8197+
bool isUnsafe = *isMainActor;
81888198
if (Type mainActorType = getMainActorType()) {
81898199
auto typeExpr = TypeExpr::createImplicit(mainActorType, SwiftContext);
81908200
auto attr = CustomAttr::create(SwiftContext, SourceLoc(), typeExpr);

lib/ClangImporter/ImportType.cpp

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1695,26 +1695,50 @@ ImportedType ClangImporter::Implementation::importPropertyType(
16951695

16961696
/// Apply an attribute to a function type.
16971697
static Type applyToFunctionType(
1698-
Type type, llvm::function_ref<Type(FunctionType *)> transform) {
1698+
Type type, llvm::function_ref<ASTExtInfo(ASTExtInfo)> transform) {
16991699
// Recurse into optional types.
17001700
if (Type objectType = type->getOptionalObjectType()) {
17011701
return OptionalType::get(applyToFunctionType(objectType, transform));
17021702
}
17031703

17041704
// Apply @noescape to function types.
1705-
if (auto funcType = type->getAs<FunctionType>())
1706-
return transform(funcType);
1705+
if (auto funcType = type->getAs<FunctionType>()) {
1706+
return FunctionType::get(funcType->getParams(), funcType->getResult(),
1707+
transform(funcType->getExtInfo()));
1708+
}
17071709

17081710
return type;
17091711
}
17101712

1711-
static Type applyParamAttributes(const clang::ParmVarDecl *param, Type type) {
1712-
// Map __attribute__((noescape)) to @noescape.
1713-
if (param->hasAttr<clang::NoEscapeAttr>()) {
1714-
type = applyToFunctionType(type, [](FunctionType *funcType) {
1715-
return FunctionType::get(funcType->getParams(), funcType->getResult(),
1716-
funcType->getExtInfo().withNoEscape());
1717-
});
1713+
Type ClangImporter::Implementation::applyParamAttributes(
1714+
const clang::ParmVarDecl *param, Type type) {
1715+
if (!param->hasAttrs())
1716+
return type;
1717+
1718+
for (auto attr : param->getAttrs()) {
1719+
// Map __attribute__((noescape)) to @noescape.
1720+
if (isa<clang::NoEscapeAttr>(attr)) {
1721+
type = applyToFunctionType(type, [](ASTExtInfo extInfo) {
1722+
return extInfo.withNoEscape();
1723+
});
1724+
1725+
continue;
1726+
}
1727+
1728+
auto swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr);
1729+
if (!swiftAttr)
1730+
continue;
1731+
1732+
// Map the main-actor attribute.
1733+
if (isMainActorAttr(SwiftContext, swiftAttr)) {
1734+
if (Type mainActor = getMainActorType()) {
1735+
type = applyToFunctionType(type, [&](ASTExtInfo extInfo) {
1736+
return extInfo.withGlobalActor(mainActor);
1737+
});
1738+
}
1739+
1740+
continue;
1741+
}
17181742
}
17191743

17201744
return type;

lib/ClangImporter/ImporterImpl.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,8 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
830830
void importAttributes(const clang::NamedDecl *ClangDecl, Decl *MappedDecl,
831831
const clang::ObjCContainerDecl *NewContext = nullptr);
832832

833+
Type applyParamAttributes(const clang::ParmVarDecl *param, Type type);
834+
833835
/// If we already imported a given decl, return the corresponding Swift decl.
834836
/// Otherwise, return nullptr.
835837
Decl *importDeclCached(const clang::NamedDecl *ClangDecl, Version version,
@@ -1562,6 +1564,14 @@ class SwiftNameLookupExtension : public clang::ModuleFileExtension {
15621564
const llvm::BitstreamCursor &stream) override;
15631565
};
15641566

1567+
/// Determines whether the given swift_attr attribute describes the main
1568+
/// actor.
1569+
///
1570+
/// \returns None if this is not a main-actor attribute, and a Boolean
1571+
/// indicating whether (unsafe) was provided in the attribute otherwise.
1572+
Optional<bool> isMainActorAttr(
1573+
ASTContext &ctx, const clang::SwiftAttrAttr *swiftAttr);
1574+
15651575
}
15661576
}
15671577

test/ClangImporter/objc_async.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import Foundation
66
import ObjCConcurrency
77

8+
@MainActor func onlyOnMainActor() { }
9+
810
func testSlowServer(slowServer: SlowServer) async throws {
911
let _: Int = await slowServer.doSomethingSlow("mail")
1012
let _: Bool = await slowServer.checkAvailability()
@@ -49,6 +51,8 @@ func testSlowServer(slowServer: SlowServer) async throws {
4951

5052

5153
_ = await slowServer.operations()
54+
55+
_ = await slowServer.runOnMainThread()
5256
}
5357

5458
func testSlowServerSynchronous(slowServer: SlowServer) {
@@ -63,6 +67,11 @@ func testSlowServerSynchronous(slowServer: SlowServer) {
6367

6468
let s = slowServer.operations
6569
_ = s + []
70+
71+
slowServer.runOnMainThread { s in
72+
print(s)
73+
onlyOnMainActor() // okay because runOnMainThread has a @MainActor closure
74+
}
6675
}
6776

6877
func testSlowServerOldSchool(slowServer: SlowServer) {

test/IDE/print_clang_objc_async.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import _Concurrency
2626
// CHECK-DAG: func doSomethingFun(_ operation: String) async
2727
// CHECK-DAG: func dance(_ step: String) async -> String
2828
// CHECK-DAG: func __leap(_ height: Int) async -> String
29+
// CHECK-DAG: func runOnMainThread(completionHandler completion: (@MainActor (String) -> Void)? = nil)
30+
// CHECK-DAG: func runOnMainThread() async -> String
2931
// CHECK: {{^[}]$}}
3032

3133
// CHECK-LABEL: protocol RefrigeratorDelegate

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
#pragma clang assume_nonnull begin
55

6+
#define MAIN_ACTOR __attribute__((__swift_attr__("@MainActor")))
7+
68
@protocol ServiceProvider
79
@property(readonly) NSArray<NSString *> *allOperations;
810
-(void)allOperationsWithCompletionHandler:(void (^)(NSArray<NSString *> *))completion;
@@ -66,6 +68,9 @@ typedef void (^CompletionHandler)(NSString * _Nullable, NSString * _Nullable_res
6668
-(void)doSomethingFlaggyWithCompletionHandler:(void (^)(BOOL, NSString *_Nullable, NSError *_Nullable))completionHandler __attribute__((swift_async_error(nonzero_argument, 1)));
6769
-(void)doSomethingZeroFlaggyWithCompletionHandler:(void (^)(NSString *_Nullable, BOOL, NSError *_Nullable))completionHandler __attribute__((swift_async_error(zero_argument, 2)));
6870
-(void)doSomethingMultiResultFlaggyWithCompletionHandler:(void (^)(BOOL, NSString *_Nullable, NSError *_Nullable, NSString *_Nullable))completionHandler __attribute__((swift_async_error(zero_argument, 1)));
71+
72+
73+
-(void)runOnMainThreadWithCompletionHandler:(MAIN_ACTOR void (^ _Nullable)(NSString *))completion;
6974
@end
7075

7176
@protocol RefrigeratorDelegate<NSObject>

0 commit comments

Comments
 (0)