Skip to content

Commit ed1308d

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 93275ca commit ed1308d

File tree

6 files changed

+122
-12
lines changed

6 files changed

+122
-12
lines changed

lib/AST/Decl.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,6 +1126,12 @@ bool Decl::isAlwaysWeakImported() const {
11261126
if (getAttrs().hasAttribute<WeakLinkedAttr>())
11271127
return true;
11281128

1129+
// FIXME: Weak linking on Windows is not yet supported
1130+
// https://github.com/apple/swift/issues/53303
1131+
if (getSemanticUnavailableAttr() &&
1132+
!getASTContext().LangOpts.Target.isOSWindows())
1133+
return true;
1134+
11291135
if (auto *accessor = dyn_cast<AccessorDecl>(this))
11301136
return accessor->getStorage()->isAlwaysWeakImported();
11311137

Lines changed: 25 additions & 1 deletion
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/float16_macos.swift

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// RUN: %target-swift-frontend -emit-ir %s -target x86_64-apple-macos10.15 | %FileCheck %s --check-prefix=CHECK10
2-
// RUN: %target-swift-frontend -emit-ir %s -target x86_64-apple-macos11 | %FileCheck %s --check-prefix=CHECK11
1+
// RUN: %target-swift-frontend -emit-ir %s -target x86_64-apple-macos10.15 | %FileCheck %s
2+
// RUN: %target-swift-frontend -emit-ir %s -target x86_64-apple-macos11 | %FileCheck %s
33

44
// REQUIRES: OS=macosx
55
// REQUIRES: CPU=x86_64
@@ -11,5 +11,4 @@ public struct Float16Wrapper {
1111
var x: Float16
1212
}
1313

14-
// CHECK10-LABEL: @"$ss7Float16VMn" = extern_weak global %swift.type_descriptor
15-
// CHECK11-LABEL: @"$ss7Float16VMn" = external global %swift.type_descriptor
14+
// CHECK-LABEL: @"$ss7Float16VMn" = extern_weak global %swift.type_descriptor

test/IRGen/weak_import_availability.swift

Lines changed: 56 additions & 6 deletions
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

Lines changed: 2 additions & 1 deletion
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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
// RUN: %target-build-swift-dylib(%t/%target-library-name(Library)) -emit-module -emit-module-path %t/Library.swiftmodule -module-name Library -parse-as-library %t/Library.swift -swift-version 5 -enable-library-evolution
4+
// RUN: %target-build-swift-dylib(%t/%target-library-name(ClientLibrary)) %t/ClientA.swift %t/ClientB.swift -I%t -L%t -swift-version 5 -lLibrary
5+
6+
//--- Library.swift
7+
8+
@available(*, unavailable)
9+
public struct UnavailableStruct {}
10+
11+
//--- ClientA.swift
12+
13+
import Library
14+
15+
@inline(never)
16+
func blackHole<T>(_ t: T) {}
17+
18+
@available(*, unavailable)
19+
public func foo() {
20+
blackHole(UnavailableStruct.self)
21+
}
22+
23+
//--- ClientB.swift
24+
25+
import Library
26+
27+
@available(*, unavailable)
28+
public func bar() {
29+
blackHole(UnavailableStruct.self)
30+
}

0 commit comments

Comments
 (0)