Skip to content

Commit ab0f7c1

Browse files
committed
IRGen: Weakly link symbols for unavailable declarations.
When computing linkage, the compiler would treat unavailable declarations as if they were "always available" when they lack an `introduced:` version: ``` // Library @available(macOS, unavailable) public func foo() { // … } // Client import Library @available(macOS, unavailable) func bar() { // Even though foo() and bar() are unavalable on macOS the compiler still // strongly links foo(). foo() } ``` This created an unnecessary dependency between libraries and their clients and also can interfere with back deployment, since unavailable declarations may not be present in a library on all OS versions. Developers could work around these issues by conditionally compiling the code that references an unavailable declaration, but they shouldn't have to given that unavailable code is meant to be provably unreachable at runtime. Additionally, it could improve library code size if we allowed the compiler to strip unavailable declarations from a binary completely. Resolves rdar://106673713
1 parent 5aa4b2f commit ab0f7c1

File tree

4 files changed

+86
-8
lines changed

4 files changed

+86
-8
lines changed

lib/AST/Decl.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -1126,6 +1126,9 @@ bool Decl::isAlwaysWeakImported() const {
11261126
if (getAttrs().hasAttribute<WeakLinkedAttr>())
11271127
return true;
11281128

1129+
if (getSemanticUnavailableAttr())
1130+
return true;
1131+
11291132
if (auto *accessor = dyn_cast<AccessorDecl>(this))
11301133
return accessor->getStorage()->isAlwaysWeakImported();
11311134

Original file line numberDiff line numberDiff line change
@@ -1,27 +1,51 @@
11
@available(macOS 10.50, *)
22
public func conditionallyAvailableFunction() {}
33

4+
@available(macOS, unavailable)
5+
public func unavailableFunction() {}
6+
47
@available(macOS 10.50, *)
58
public var conditionallyAvailableGlobal: Int {
69
get {return 0}
710
set {}
811
}
912

13+
@available(macOS, unavailable)
14+
public var unavailableGlobal: Int {
15+
get {return 0}
16+
set {}
17+
}
18+
1019
@available(macOS 10.50, *)
1120
public struct ConditionallyAvailableStruct {
1221
public func conditionallyAvailableMethod() {}
1322
}
1423

24+
extension ConditionallyAvailableStruct {
25+
public struct NestedStruct {}
26+
}
27+
28+
@available(macOS, unavailable)
29+
public struct UnvailableStruct {
30+
public func unavailableMethod() {}
31+
}
32+
1533
public protocol AlwaysAvailableProtocol {}
1634

1735
public struct AlwaysAvailableStruct {}
1836

1937
@available(macOS 10.50, *)
2038
extension AlwaysAvailableStruct : AlwaysAvailableProtocol {}
2139

40+
@available(macOS, unavailable)
41+
public protocol UnavailableProtocol {}
42+
43+
@available(macOS, unavailable)
44+
extension AlwaysAvailableStruct : UnavailableProtocol {}
45+
2246
public enum AlwaysAvailableEnum {
2347
case alwaysAvailableCase
2448

2549
@available(macOS 10.50, *)
2650
case conditionallyAvailableCase
27-
}
51+
}

test/IRGen/weak_import_availability.swift

+56-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// RUN: %empty-directory(%t)
2-
// RUN: %target-swift-frontend -emit-module -emit-module-path %t/weak_import_availability_helper.swiftmodule -parse-as-library %S/Inputs/weak_import_availability_helper.swift -enable-library-evolution
2+
// RUN: %target-swift-frontend -target %target-cpu-apple-macosx10.50 -emit-module -emit-module-path %t/weak_import_availability_helper.swiftmodule -parse-as-library %S/Inputs/weak_import_availability_helper.swift -enable-library-evolution
33
//
4-
// RUN: %target-swift-frontend -primary-file %s -I %t -emit-ir | %FileCheck %s --check-prefix=CHECK-OLD
5-
// RUN: %target-swift-frontend -primary-file %s -I %t -emit-ir -target %target-cpu-apple-macosx10.50 | %FileCheck %s --check-prefix=CHECK-NEW
6-
// RUN: %target-swift-frontend -primary-file %s -I %t -emit-ir -target %target-cpu-apple-macosx10.60 | %FileCheck %s --check-prefix=CHECK-NEW
4+
// RUN: %target-swift-frontend -primary-file %s -I %t -emit-ir | %FileCheck %s --check-prefixes=CHECK,CHECK-OLD
5+
// RUN: %target-swift-frontend -primary-file %s -I %t -emit-ir -target %target-cpu-apple-macosx10.50 | %FileCheck %s --check-prefixes=CHECK,CHECK-NEW
6+
// RUN: %target-swift-frontend -primary-file %s -I %t -emit-ir -target %target-cpu-apple-macosx10.60 | %FileCheck %s --check-prefixes=CHECK,CHECK-NEW
77

8-
// RUN: %target-swift-frontend -primary-file %s -I %t -emit-ir -target %target-cpu-apple-macosx10.50 -weak-link-at-target | %FileCheck %s --check-prefix=CHECK-OLD
9-
// RUN: %target-swift-frontend -primary-file %s -I %t -emit-ir -target %target-cpu-apple-macosx10.60 -weak-link-at-target | %FileCheck %s --check-prefix=CHECK-NEW
8+
// RUN: %target-swift-frontend -primary-file %s -I %t -emit-ir -target %target-cpu-apple-macosx10.50 -weak-link-at-target | %FileCheck %s --check-prefixes=CHECK,CHECK-OLD
9+
// RUN: %target-swift-frontend -primary-file %s -I %t -emit-ir -target %target-cpu-apple-macosx10.60 -weak-link-at-target | %FileCheck %s --check-prefixes=CHECK,CHECK-NEW
1010

1111
// REQUIRES: OS=macosx
1212

@@ -35,6 +35,16 @@ public func useConditionallyAvailableConformance() {
3535
// CHECK-OLD-LABEL: @"$s31weak_import_availability_helper21AlwaysAvailableStructVAA0eF8ProtocolAAWP" = extern_weak global i8*
3636
// CHECK-NEW-LABEL: @"$s31weak_import_availability_helper21AlwaysAvailableStructVAA0eF8ProtocolAAWP" = external global i8*
3737

38+
@available(macOS, unavailable)
39+
func useUnavailableConformance<T : UnavailableProtocol>(_: T.Type) {}
40+
41+
@available(macOS, unavailable)
42+
public func useUnavailableConformance() {
43+
useUnavailableConformance(AlwaysAvailableStruct.self)
44+
}
45+
46+
// CHECK-LABEL: @"$s31weak_import_availability_helper21AlwaysAvailableStructVAA19UnavailableProtocolAAWP" = extern_weak global i8*, align 8
47+
3848
@available(macOS 10.50, *)
3949
public func callConditionallyAvailableFunction() {
4050
conditionallyAvailableFunction()
@@ -43,6 +53,13 @@ public func callConditionallyAvailableFunction() {
4353
// CHECK-OLD-LABEL: declare extern_weak swiftcc void @"$s31weak_import_availability_helper30conditionallyAvailableFunctionyyF"()
4454
// CHECK-NEW-LABEL: declare swiftcc void @"$s31weak_import_availability_helper30conditionallyAvailableFunctionyyF"()
4555

56+
@available(macOS, unavailable)
57+
public func callUnavailableFunction() {
58+
unavailableFunction()
59+
}
60+
61+
// CHECK-LABEL: declare extern_weak swiftcc void @"$s31weak_import_availability_helper19unavailableFunctionyyF"()
62+
4663
@available(macOS 10.50, *)
4764
public func useConditionallyAvailableGlobal() {
4865
_ = conditionallyAvailableGlobal
@@ -59,6 +76,17 @@ public func useConditionallyAvailableGlobal() {
5976
// CHECK-OLD-LABEL: declare extern_weak swiftcc { i8*, %TSi* } @"$s31weak_import_availability_helper28conditionallyAvailableGlobalSivM"(i8* noalias dereferenceable(32))
6077
// CHECK-NEW-LABEL: declare swiftcc { i8*, %TSi* } @"$s31weak_import_availability_helper28conditionallyAvailableGlobalSivM"(i8* noalias dereferenceable(32))
6178

79+
@available(macOS, unavailable)
80+
public func useUnavailableGlobal() {
81+
_ = unavailableGlobal
82+
unavailableGlobal = 0
83+
unavailableGlobal += 1
84+
}
85+
86+
// CHECK-LABEL: declare extern_weak swiftcc i64 @"$s31weak_import_availability_helper17unavailableGlobalSivg"()
87+
// CHECK-LABEL: declare extern_weak swiftcc void @"$s31weak_import_availability_helper17unavailableGlobalSivs"(i64)
88+
// CHECK-LABEL: declare extern_weak swiftcc { i8*, %TSi* } @"$s31weak_import_availability_helper17unavailableGlobalSivM"(i8* noalias dereferenceable(32))
89+
6290
func blackHole<T>(_: T) {}
6391

6492
@available(macOS 10.50, *)
@@ -69,10 +97,32 @@ public func useConditionallyAvailableStruct() {
6997
// CHECK-OLD-LABEL: declare extern_weak swiftcc %swift.metadata_response @"$s31weak_import_availability_helper28ConditionallyAvailableStructVMa"(i64)
7098
// CHECK-NEW-LABEL: declare swiftcc %swift.metadata_response @"$s31weak_import_availability_helper28ConditionallyAvailableStructVMa"(i64)
7199

100+
@available(macOS 10.50, *)
101+
public func useNestedConditionallyAvailableStruct() {
102+
blackHole(ConditionallyAvailableStruct.NestedStruct.self)
103+
}
104+
105+
// CHECK-OLD-LABEL: declare extern_weak swiftcc %swift.metadata_response @"$s31weak_import_availability_helper28ConditionallyAvailableStructV06NestedG0VMa"(i64)
106+
// CHECK-NEW-LABEL: declare swiftcc %swift.metadata_response @"$s31weak_import_availability_helper28ConditionallyAvailableStructV06NestedG0VMa"(i64)
107+
72108
@available(macOS 10.50, *)
73109
public func useConditionallyAvailableMethod(s: ConditionallyAvailableStruct) {
74110
s.conditionallyAvailableMethod()
75111
}
76112

77113
// CHECK-OLD-LABEL: declare extern_weak swiftcc void @"$s31weak_import_availability_helper28ConditionallyAvailableStructV013conditionallyF6MethodyyF"(%swift.opaque* noalias nocapture swiftself)
78114
// CHECK-NEW-LABEL: declare swiftcc void @"$s31weak_import_availability_helper28ConditionallyAvailableStructV013conditionallyF6MethodyyF"(%swift.opaque* noalias nocapture swiftself)
115+
116+
@available(macOS, unavailable)
117+
public func useUnavailableStruct() {
118+
blackHole(UnvailableStruct.self)
119+
}
120+
121+
// CHECK-LABEL: declare extern_weak swiftcc %swift.metadata_response @"$s31weak_import_availability_helper16UnvailableStructVMa"(i64)
122+
123+
@available(macOS, unavailable)
124+
public func useUnavailableMethod(s: UnvailableStruct) {
125+
s.unavailableMethod()
126+
}
127+
128+
// CHECK-LABEL: declare extern_weak swiftcc void @"$s31weak_import_availability_helper16UnvailableStructV17unavailableMethodyyF"(%swift.opaque* noalias nocapture swiftself)

test/SILGen/objc_init_unavailable.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
// RUN: %target-swift-emit-silgen(mock-sdk: %clang-importer-sdk) -enable-objc-interop -import-objc-header %S/Inputs/objc_init_unavailable.h %s | %FileCheck %s
22
// REQUIRES: objc_interop
3+
// REQUIRES: OS=macosx
34

45
@available(macOS, unavailable)
56
public func callUnavailableInit(name: String) -> ClassWithUnavailableInit {
67
return ClassWithUnavailableInit(bundleID: name)
78
}
89

9-
// CHECK-LABEL: sil [ossa] @$s21objc_init_unavailable19callUnavailableInit4nameSo09ClassWitheF0CSS_tF : $@convention(thin) (@guaranteed String) -> @owned ClassWithUnavailableInit {
10+
// CHECK-LABEL: sil [weak_imported] [ossa] @$s21objc_init_unavailable19callUnavailableInit4nameSo09ClassWitheF0CSS_tF : $@convention(thin) (@guaranteed String) -> @owned ClassWithUnavailableInit {
1011
// CHECK: function_ref @$sSo24ClassWithUnavailableInitC8bundleIDABSgSSSg_tcfC : $@convention(method) (@owned Optional<String>, @thick ClassWithUnavailableInit.Type) -> @owned Optional<ClassWithUnavailableInit>
1112
// CHECK: return
1213

0 commit comments

Comments
 (0)