Skip to content

Commit 5f0a9c4

Browse files
committed
[ClangImporter] Import NSNotificationName constants as nonisolated
These constants could be used with observer APIs from a different isolation context, so it's more convenient to import them as `nonisolated` unless they are explicitly isolated to a MainActor. Resolves: rdar://114052705
1 parent 269f30f commit 5f0a9c4

File tree

2 files changed

+62
-0
lines changed

2 files changed

+62
-0
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8138,6 +8138,23 @@ ClangImporter::Implementation::importSwiftAttrAttributes(Decl *MappedDecl) {
81388138
/*isUnchecked=*/true);
81398139
}
81408140
}
8141+
8142+
// Special handling of `NSNotificationName` static immutable properties.
8143+
//
8144+
// These constants could be used with observer APIs from a different isolation
8145+
// context, so it's more convenient to import them as `nonisolated` unless
8146+
// they are explicitly isolated to a MainActor.
8147+
if (!seenMainActorAttr) {
8148+
auto *DC = MappedDecl->getDeclContext();
8149+
if (DC->isTypeContext() && isa<VarDecl>(MappedDecl)) {
8150+
auto *mappedVar = cast<VarDecl>(MappedDecl);
8151+
if (mappedVar->isStatic() && mappedVar->isLet() &&
8152+
isNSNotificationName(cast<clang::ValueDecl>(ClangDecl)->getType())) {
8153+
MappedDecl->getAttrs().add(new (SwiftContext) NonisolatedAttr(
8154+
/*unsafe=*/false, /*implicit=*/true));
8155+
}
8156+
}
8157+
}
81418158
}
81428159

81438160
static bool isUsingMacroName(clang::SourceManager &SM,
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// RUN: %empty-directory(%t/src)
2+
// RUN: %empty-directory(%t/sdk)
3+
// RUN: split-file %s %t/src
4+
5+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck %t/src/main.swift \
6+
// RUN: -import-objc-header %t/src/Test.h \
7+
// RUN: -strict-concurrency=complete \
8+
// RUN: -disable-availability-checking \
9+
// RUN: -module-name main -I %t -verify
10+
11+
// REQUIRES: objc_interop
12+
// REQUIRES: concurrency
13+
14+
//--- Test.h
15+
#define SWIFT_MAIN_ACTOR __attribute__((swift_attr("@MainActor")))
16+
17+
#pragma clang assume_nonnull begin
18+
19+
@import Foundation;
20+
21+
SWIFT_MAIN_ACTOR
22+
@interface Test : NSObject
23+
@end
24+
25+
extern NSNotificationName const TestDidTrigger __attribute__((swift_name("Test.didTrigger")));
26+
27+
SWIFT_MAIN_ACTOR
28+
extern NSNotificationName const TestIsolatedTrigger __attribute__((swift_name("Test.isolatedTrigger")));
29+
30+
#pragma clang assume_nonnull end
31+
32+
//--- main.swift
33+
34+
func testAsync() async {
35+
print(Test.didTrigger) // Ok (property is nonisolated)
36+
print(Test.isolatedTrigger)
37+
// expected-warning@-1 {{expression is 'async' but is not marked with 'await'; this is an error in Swift 6}}
38+
// expected-note@-2 {{property access is 'async'}}
39+
}
40+
41+
@MainActor
42+
func testMainActor() {
43+
print(Test.didTrigger) // Ok
44+
print(Test.isolatedTrigger) // Ok
45+
}

0 commit comments

Comments
 (0)