Skip to content

Commit 7b50414

Browse files
committed
AST: Don't optimize decls that are unavailable in extensions.
Unavailable decl optimization is meant to optimize declarations that are unreachable at runtime. A declaration that is marked unavailable in app extensions (e.g. `@available(macOSApplicationExtension, unavailable)`) may be reachable by non-extension processes so it cannot be safely optimized. Resolves rdar://122924862
1 parent 81ffafd commit 7b50414

File tree

4 files changed

+53
-18
lines changed

4 files changed

+53
-18
lines changed

include/swift/AST/PlatformKind.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ StringRef prettyPlatformString(PlatformKind platform);
5757
llvm::Optional<PlatformKind>
5858
basePlatformForExtensionPlatform(PlatformKind Platform);
5959

60+
/// Returns true if \p Platform represents and application extension platform,
61+
/// e.g. `iOSApplicationExtension`.
62+
inline bool isApplicationExtensionPlatform(PlatformKind Platform) {
63+
return basePlatformForExtensionPlatform(Platform).has_value();
64+
}
65+
6066
/// Returns whether the passed-in platform is active, given the language
6167
/// options. A platform is active if either it is the target platform or its
6268
/// AppExtension variant is the target platform. For example, OS X is

lib/AST/Availability.cpp

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -321,11 +321,29 @@ llvm::Optional<AvailableAttrDeclPair> Decl::getSemanticUnavailableAttr() const {
321321
llvm::None);
322322
}
323323

324-
static bool isUnconditionallyUnavailable(const Decl *D) {
325-
if (auto unavailableAttrAndDecl = D->getSemanticUnavailableAttr())
326-
return unavailableAttrAndDecl->first->isUnconditionallyUnavailable();
324+
static bool shouldStubOrSkipUnavailableDecl(const Decl *D) {
325+
// Don't trust unavailability on declarations from clang modules.
326+
if (isa<ClangModuleUnit>(D->getDeclContext()->getModuleScopeContext()))
327+
return false;
327328

328-
return false;
329+
auto unavailableAttrAndDecl = D->getSemanticUnavailableAttr();
330+
if (!unavailableAttrAndDecl)
331+
return false;
332+
333+
// getSemanticUnavailableAttr() can return an @available attribute that makes
334+
// its declaration unavailable conditionally due to deployment target. Only
335+
// stub or skip a declaration that is unavailable regardless of deployment
336+
// target.
337+
auto *unavailableAttr = unavailableAttrAndDecl->first;
338+
if (!unavailableAttr->isUnconditionallyUnavailable())
339+
return false;
340+
341+
// If the decl is only unavailable to app extensions it still may need to be
342+
// present at runtime for non-extension processes.
343+
if (isApplicationExtensionPlatform(unavailableAttr->Platform))
344+
return false;
345+
346+
return true;
329347
}
330348

331349
static UnavailableDeclOptimization
@@ -343,10 +361,7 @@ bool Decl::isAvailableDuringLowering() const {
343361
UnavailableDeclOptimization::Complete)
344362
return true;
345363

346-
if (isa<ClangModuleUnit>(getDeclContext()->getModuleScopeContext()))
347-
return true;
348-
349-
return !isUnconditionallyUnavailable(this);
364+
return !shouldStubOrSkipUnavailableDecl(this);
350365
}
351366

352367
bool Decl::requiresUnavailableDeclABICompatibilityStubs() const {
@@ -356,10 +371,7 @@ bool Decl::requiresUnavailableDeclABICompatibilityStubs() const {
356371
UnavailableDeclOptimization::Stub)
357372
return false;
358373

359-
if (isa<ClangModuleUnit>(getDeclContext()->getModuleScopeContext()))
360-
return false;
361-
362-
return isUnconditionallyUnavailable(this);
374+
return shouldStubOrSkipUnavailableDecl(this);
363375
}
364376

365377
bool UnavailabilityReason::requiresDeploymentTargetOrEarlier(

lib/AST/PlatformKind.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,6 @@ swift::basePlatformForExtensionPlatform(PlatformKind Platform) {
109109
llvm_unreachable("bad PlatformKind");
110110
}
111111

112-
static bool isApplicationExtensionPlatform(PlatformKind Platform) {
113-
return basePlatformForExtensionPlatform(Platform).has_value();
114-
}
115-
116112
static bool isPlatformActiveForTarget(PlatformKind Platform,
117113
const llvm::Triple &Target,
118114
bool EnableAppExtensionRestrictions) {

test/SILGen/unavailable_decl_optimization_stub_macos.swift

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
// RUN: %target-swift-emit-silgen -target %target-swift-abi-5.8-triple -module-name Test -parse-as-library %s -verify -unavailable-decl-optimization=stub | %FileCheck %s --check-prefixes=CHECK-SWIFT5_8
2-
// RUN: %target-swift-emit-silgen -target %target-swift-abi-5.9-triple -module-name Test -parse-as-library %s -verify -unavailable-decl-optimization=stub | %FileCheck %s --check-prefixes=CHECK-SWIFT5_9
1+
// RUN: %target-swift-emit-silgen -target %target-swift-abi-5.8-triple -module-name Test -parse-as-library %s -verify -unavailable-decl-optimization=stub | %FileCheck %s --check-prefixes=CHECK,CHECK-SWIFT5_8
2+
// RUN: %target-swift-emit-silgen -target %target-swift-abi-5.8-triple -module-name Test -parse-as-library %s -verify -unavailable-decl-optimization=stub -application-extension | %FileCheck %s --check-prefixes=CHECK,CHECK-SWIFT5_8
3+
// RUN: %target-swift-emit-silgen -target %target-swift-abi-5.9-triple -module-name Test -parse-as-library %s -verify -unavailable-decl-optimization=stub | %FileCheck %s --check-prefixes=CHECK,CHECK-SWIFT5_9
4+
// RUN: %target-swift-emit-silgen -target %target-swift-abi-5.9-triple -module-name Test -parse-as-library %s -verify -unavailable-decl-optimization=stub -application-extension | %FileCheck %s --check-prefixes=CHECK,CHECK-SWIFT5_9
35

46
// REQUIRES: OS=macosx
57

@@ -19,3 +21,22 @@ public func unavailableFunc() {}
1921
@available(*, unavailable)
2022
@inlinable public func unavailableInlinableFunc() {}
2123

24+
// CHECK-LABEL: sil{{.*}}@$s4Test22unavailableOnMacOSFuncyyF
25+
// CHECK-SWIFT5_8: [[FNREF:%.*]] = function_ref @$ss36_diagnoseUnavailableCodeReached_aeics5NeverOyF : $@convention(thin) () -> Never
26+
// CHECK-SWIFT5_9: [[FNREF:%.*]] = function_ref @$ss31_diagnoseUnavailableCodeReacheds5NeverOyF : $@convention(thin) () -> Never
27+
// CHECK-NEXT: [[APPLY:%.*]] = apply [[FNREF]]()
28+
// CHECK: } // end sil function '$s4Test22unavailableOnMacOSFuncyyF'
29+
@available(macOS, unavailable)
30+
public func unavailableOnMacOSFunc() {}
31+
32+
// CHECK-LABEL: sil{{.*}}@$s4Test31unavailableOnMacOSExtensionFuncyyF
33+
// CHECK-NOT: function_ref @$ss36_diagnoseUnavailableCodeReached{{.*}} : $@convention(thin) () -> Never
34+
// CHECK: } // end sil function '$s4Test31unavailableOnMacOSExtensionFuncyyF'
35+
@available(macOSApplicationExtension, unavailable)
36+
public func unavailableOnMacOSExtensionFunc() {}
37+
38+
// CHECK-LABEL: sil{{.*}}@$s4Test20unavailableOniOSFuncyyF
39+
// CHECK-NOT: function_ref @$ss36_diagnoseUnavailableCodeReached{{.*}} : $@convention(thin) () -> Never
40+
// CHECK: } // end sil function '$s4Test20unavailableOniOSFuncyyF'
41+
@available(iOS, unavailable)
42+
public func unavailableOniOSFunc() {}

0 commit comments

Comments
 (0)