Skip to content

Commit 8bb6846

Browse files
authored
Merge pull request #71419 from xedin/rdar-114052705
[ClangImporter] Import NSNotificationName constants as `nonisolated`
2 parents 95beb6c + 5f0a9c4 commit 8bb6846

File tree

4 files changed

+72
-0
lines changed

4 files changed

+72
-0
lines changed

lib/ClangImporter/ClangAdapter.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,13 @@ bool importer::isNSString(clang::QualType qt) {
590590
return qt.getTypePtrOrNull() && isNSString(qt.getTypePtrOrNull());
591591
}
592592

593+
bool importer::isNSNotificationName(clang::QualType type) {
594+
if (auto *typealias = type->getAs<clang::TypedefType>()) {
595+
return typealias->getDecl()->getName() == "NSNotificationName";
596+
}
597+
return false;
598+
}
599+
593600
bool importer::isNSNotificationGlobal(const clang::NamedDecl *decl) {
594601
// Looking for: extern NSString *fooNotification;
595602

lib/ClangImporter/ClangAdapter.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ clang::TypedefNameDecl *findSwiftNewtype(const clang::NamedDecl *decl,
129129
bool isNSString(const clang::Type *);
130130
bool isNSString(clang::QualType);
131131

132+
/// Wehther the passed type is `NSNotificationName` typealias
133+
bool isNSNotificationName(clang::QualType);
134+
132135
/// Whether the given declaration was exported from Swift.
133136
///
134137
/// Note that this only checks the immediate declaration being passed.

lib/ClangImporter/ImportDecl.cpp

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

81398156
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)