Skip to content

Commit a6eb7e4

Browse files
committed
AST: Fix weak linking for potentially unavailable accessors in extensions.
In #78454 queries for the platform availability of decl were consolidated into `Decl::getAvailableAttrForPlatformIntroduction()`. In addition to checking the attributes directly attached to the decl, this method also checks whether the decl is a member directly contained inside of an extension and checks for attributes attached to the extension as well. Previously, this logic was only used for availability checking diagnostics, where special casing extension members was a requirement. As a result of the consolidation, though, the logic is now also shared by the query that determines whether to weakly link symbols associated with a decl. That determination already had its own way of handling members of extensions but it seemed like consolidating the logic would stil be a net improvement that would reduce overall complexity. Unfortunately, the existing approach to getting the availability of the enclosing extension had a subtle bug for both AccessorDecl and OpaqueTypeDecl. If an AvailableAttr was not directly attached to the immediate decl, then `Decl::getAvailableAttrForPlatformIntroduction()` would check if the enclosing decl context was an extension and look at its attributes as well. For AccessorDecl and OpaqueTypeDecl, checking the enclosing decl context would accidentally skip over the VarDecl and AbstractFunctionDecl that are formally the parents of those decls for the purposes of attribute inheritance. As a result, the availability of the enclosing property or function could be ignored if the enclosing extension had explicit availability attributes. The fix is to use `AvailabilityInference::parentDeclForInferredAvailability()` instead of `getDeclContext()` when looking for the immediately enclosing extension. Resolves rdar://143139472.
1 parent 9907afa commit a6eb7e4

File tree

5 files changed

+216
-15
lines changed

5 files changed

+216
-15
lines changed

lib/AST/Availability.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -766,10 +766,12 @@ Decl::getAvailableAttrForPlatformIntroduction() const {
766766
// itself. This check relies on the fact that we cannot have nested
767767
// extensions.
768768

769-
DeclContext *DC = getDeclContext();
770-
if (auto *ED = dyn_cast<ExtensionDecl>(DC)) {
771-
if (auto attr = getDeclAvailableAttrForPlatformIntroduction(ED))
772-
return attr;
769+
if (auto parent =
770+
AvailabilityInference::parentDeclForInferredAvailability(this)) {
771+
if (auto *ED = dyn_cast<ExtensionDecl>(parent)) {
772+
if (auto attr = getDeclAvailableAttrForPlatformIntroduction(ED))
773+
return attr;
774+
}
773775
}
774776

775777
return std::nullopt;

test/IRGen/Inputs/weak_import_availability_helper.swift

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ public func conditionallyAvailableFunction() {}
44
@available(macOS, unavailable)
55
public func unavailableFunction() {}
66

7+
@available(macOS 50, *)
8+
public func conditionallyAvailableOpaqueReturnFunction() -> some AlwaysAvailableProtocol {
9+
return AlwaysAvailableStruct()
10+
}
11+
712
@available(macOS 50, *)
813
public var conditionallyAvailableGlobal: Int {
914
get {return 0}
@@ -34,6 +39,53 @@ public protocol AlwaysAvailableProtocol {}
3439

3540
public struct AlwaysAvailableStruct {}
3641

42+
@available(macOS 50, *)
43+
extension AlwaysAvailableStruct {
44+
public func methodInConditionallyAvailableExtension() {}
45+
46+
public func opaqueReturnMethodInConditionallyAvailableExtension() -> some AlwaysAvailableProtocol {
47+
return AlwaysAvailableStruct()
48+
}
49+
50+
public var varInConditionallyAvailableExtension: Int {
51+
get {return 0}
52+
set {}
53+
}
54+
}
55+
56+
extension AlwaysAvailableStruct {
57+
@available(macOS 50, *)
58+
public func conditionallyAvailableMethodInExtension() {}
59+
60+
@available(macOS 50, *)
61+
public func conditionallyAvailableOpaqueReturnMethodInExtension() -> some AlwaysAvailableProtocol {
62+
return AlwaysAvailableStruct()
63+
}
64+
65+
@available(macOS 50, *)
66+
public var conditionallyAvailableVarInExtension: Int {
67+
get {return 0}
68+
set {}
69+
}
70+
}
71+
72+
@available(macOS 10.9, *)
73+
extension AlwaysAvailableStruct {
74+
@available(macOS 50, *)
75+
public func conditionallyAvailableMethodInExplicitlyAvailableExtension() {}
76+
77+
@available(macOS 50, *)
78+
public func conditionallyAvailableOpaqueReturnMethodInExplicitlyAvailableExtension() -> some AlwaysAvailableProtocol {
79+
return AlwaysAvailableStruct()
80+
}
81+
82+
@available(macOS 50, *)
83+
public var conditionallyAvailableVarInExplicitlyAvailablextension: Int {
84+
get {return 0}
85+
set {}
86+
}
87+
}
88+
3789
@available(macOS 50, *)
3890
extension AlwaysAvailableStruct : AlwaysAvailableProtocol {}
3991

test/IRGen/Inputs/weak_import_native_helper.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@ public struct S {
3333
}
3434
}
3535

36+
extension S {
37+
@_weakLinked
38+
public func extensionFn() {}
39+
40+
@_weakLinked
41+
public var extensionProp: Int {
42+
get { return 1 }
43+
set {}
44+
}
45+
}
46+
3647
public enum E {
3748
case strong
3849

test/IRGen/weak_import_availability.swift

Lines changed: 137 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,29 +12,56 @@
1212

1313
import weak_import_availability_helper
1414

15+
// AlwaysAvailableEnum.conditionallyAvailableCase enum case
16+
// CHECK-OLD-LABEL: @"$s31weak_import_availability_helper19AlwaysAvailableEnumO013conditionallyF4CaseyA2CmFWC" = extern_weak constant
17+
// CHECK-NEW-LABEL: @"$s31weak_import_availability_helper19AlwaysAvailableEnumO013conditionallyF4CaseyA2CmFWC" = external constant
18+
19+
20+
// Protocol witness table for AlwaysAvailableStruct: AlwaysAvailableProtocol
21+
// FIXME: We reference the witness table directly -- that's a bug since the
22+
// module is resilient. Should reference the conformance descriptor instead.
23+
// CHECK-OLD-LABEL: @"$s31weak_import_availability_helper21AlwaysAvailableStructVAA0eF8ProtocolAAWP" = extern_weak global ptr
24+
// CHECK-NEW-LABEL: @"$s31weak_import_availability_helper21AlwaysAvailableStructVAA0eF8ProtocolAAWP" = external global ptr
25+
26+
27+
// Protocol witness table for AlwaysAvailableStruct: UnavailableProtocol
28+
// CHECK-LABEL: @"$s31weak_import_availability_helper21AlwaysAvailableStructVAA19UnavailableProtocolAAWP" = extern_weak global ptr
29+
30+
31+
// Opaque type descriptor for conditionallyAvailableOpaqueReturnFunction()
32+
// CHECK-OLD-LABEL: @"$s31weak_import_availability_helper42conditionallyAvailableOpaqueReturnFunctionQryFQOMQ" = extern_weak global %swift.type_descriptor
33+
// CHECK-NEW-LABEL: @"$s31weak_import_availability_helper42conditionallyAvailableOpaqueReturnFunctionQryFQOMQ" = external global %swift.type_descriptor
34+
35+
36+
// Opaque type descriptor for AlwaysAvailableStruct.opaqueReturnMethodInConditionallyAvailableExtension()
37+
// CHECK-OLD-LABEL: @"$s31weak_import_availability_helper21AlwaysAvailableStructV033opaqueReturnMethodInConditionallyF9ExtensionQryFQOMQ" = extern_weak global %swift.type_descriptor
38+
// CHECK-NEW-LABEL: @"$s31weak_import_availability_helper21AlwaysAvailableStructV033opaqueReturnMethodInConditionallyF9ExtensionQryFQOMQ" = external global %swift.type_descriptor
39+
40+
41+
// Opaque type descriptor for AlwaysAvailableStruct.conditionallyAvailableOpaqueReturnMethodInExtension()
42+
// CHECK-OLD-LABEL: @"$s31weak_import_availability_helper21AlwaysAvailableStructV013conditionallyF29OpaqueReturnMethodInExtensionQryFQOMQ" = extern_weak global %swift.type_descriptor
43+
// CHECK-NEW-LABEL: @"$s31weak_import_availability_helper21AlwaysAvailableStructV013conditionallyF29OpaqueReturnMethodInExtensionQryFQOMQ" = external global %swift.type_descriptor
44+
45+
46+
// Opaque type descriptor for AlwaysAvailableStruct.conditionallyAvailableOpaqueReturnMethodInExplicitlyAvailableExtension()
47+
// CHECK-OLD-LABEL: @"$s31weak_import_availability_helper21AlwaysAvailableStructV013conditionallyf30OpaqueReturnMethodInExplicitlyF9ExtensionQryFQOMQ" = extern_weak global %swift.type_descriptor
48+
// CHECK-NEW-LABEL: @"$s31weak_import_availability_helper21AlwaysAvailableStructV013conditionallyf30OpaqueReturnMethodInExplicitlyF9ExtensionQryFQOMQ" = external global %swift.type_descriptor
49+
50+
1551
public func useConditionallyAvailableCase(e: AlwaysAvailableEnum) {
1652
switch e {
1753
case .alwaysAvailableCase: break
1854
case .conditionallyAvailableCase: break
1955
}
2056
}
2157

22-
// CHECK-OLD-LABEL: @"$s31weak_import_availability_helper19AlwaysAvailableEnumO013conditionallyF4CaseyA2CmFWC" = extern_weak constant i32
23-
// CHECK-NEW-LABEL: @"$s31weak_import_availability_helper19AlwaysAvailableEnumO013conditionallyF4CaseyA2CmFWC" = external constant i32
24-
2558
func useConformance<T : AlwaysAvailableProtocol>(_: T.Type) {}
2659

2760
@available(macOS 50, *)
2861
public func useConditionallyAvailableConformance() {
2962
useConformance(AlwaysAvailableStruct.self)
3063
}
3164

32-
// FIXME: We reference the witness table directly -- that's a bug since the module is resilient. Should reference the
33-
// conformance descriptor instead.
34-
35-
// CHECK-OLD-LABEL: @"$s31weak_import_availability_helper21AlwaysAvailableStructVAA0eF8ProtocolAAWP" = extern_weak global ptr
36-
// CHECK-NEW-LABEL: @"$s31weak_import_availability_helper21AlwaysAvailableStructVAA0eF8ProtocolAAWP" = external global ptr
37-
3865
@available(macOS, unavailable)
3966
func useUnavailableConformance<T : UnavailableProtocol>(_: T.Type) {}
4067

@@ -43,8 +70,6 @@ public func useUnavailableConformance() {
4370
useUnavailableConformance(AlwaysAvailableStruct.self)
4471
}
4572

46-
// CHECK-LABEL: @"$s31weak_import_availability_helper21AlwaysAvailableStructVAA19UnavailableProtocolAAWP" = extern_weak global ptr, align 8
47-
4873
@available(macOS 50, *)
4974
public func callConditionallyAvailableFunction() {
5075
conditionallyAvailableFunction()
@@ -60,6 +85,14 @@ public func callUnavailableFunction() {
6085

6186
// CHECK-LABEL: declare extern_weak swiftcc void @"$s31weak_import_availability_helper19unavailableFunctionyyF"()
6287

88+
@available(macOS 50, *)
89+
public func callConditionallyAvailableOpaqueReturnFunction() {
90+
blackHole(conditionallyAvailableOpaqueReturnFunction())
91+
}
92+
93+
// CHECK-OLD-LABEL: declare extern_weak swiftcc void @"$s31weak_import_availability_helper42conditionallyAvailableOpaqueReturnFunctionQryF"
94+
// CHECK-NEW-LABEL: declare swiftcc void @"$s31weak_import_availability_helper42conditionallyAvailableOpaqueReturnFunctionQryF"
95+
6396
@available(macOS 50, *)
6497
public func useConditionallyAvailableGlobal() {
6598
_ = conditionallyAvailableGlobal
@@ -113,6 +146,99 @@ public func useConditionallyAvailableMethod(s: ConditionallyAvailableStruct) {
113146
// CHECK-OLD-LABEL: declare extern_weak swiftcc void @"$s31weak_import_availability_helper28ConditionallyAvailableStructV013conditionallyF6MethodyyF"(ptr noalias swiftself)
114147
// CHECK-NEW-LABEL: declare swiftcc void @"$s31weak_import_availability_helper28ConditionallyAvailableStructV013conditionallyF6MethodyyF"(ptr noalias swiftself)
115148

149+
@available(macOS 50, *)
150+
public func useMethodInConditionallyAvailableExtension(s: AlwaysAvailableStruct) {
151+
s.methodInConditionallyAvailableExtension()
152+
}
153+
154+
// CHECK-OLD-LABEL: declare extern_weak swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV021methodInConditionallyF9ExtensionyyF"
155+
// CHECK-NEW-LABEL: declare swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV021methodInConditionallyF9ExtensionyyF"
156+
157+
@available(macOS 50, *)
158+
public func useOpaqueReturnMethodInConditionallyAvailableExtension(s: AlwaysAvailableStruct) {
159+
blackHole(s.opaqueReturnMethodInConditionallyAvailableExtension())
160+
}
161+
// CHECK-OLD-LABEL: declare extern_weak swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV033opaqueReturnMethodInConditionallyF9ExtensionQryF"
162+
// CHECK-NEW-LABEL: declare swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV033opaqueReturnMethodInConditionallyF9ExtensionQryF"
163+
164+
@available(macOS 50, *)
165+
public func useVarInConditionallyAvailableExtension(s: inout AlwaysAvailableStruct) {
166+
_ = s.varInConditionallyAvailableExtension
167+
s.varInConditionallyAvailableExtension = 0
168+
s.varInConditionallyAvailableExtension += 0
169+
}
170+
171+
// CHECK-OLD-LABEL: declare extern_weak swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV018varInConditionallyF9ExtensionSivg"
172+
// CHECK-OLD-LABEL: declare extern_weak swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV018varInConditionallyF9ExtensionSivs"
173+
// CHECK-OLD-LABEL: declare extern_weak swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV018varInConditionallyF9ExtensionSivM"
174+
175+
// CHECK-NEW-LABEL: declare swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV018varInConditionallyF9ExtensionSivg"
176+
// CHECK-NEW-LABEL: declare swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV018varInConditionallyF9ExtensionSivs"
177+
// CHECK-NEW-LABEL: declare swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV018varInConditionallyF9ExtensionSivM"
178+
179+
@available(macOS 50, *)
180+
public func useConditionallyAvailableMethodInExtension(s: AlwaysAvailableStruct) {
181+
s.conditionallyAvailableMethodInExtension()
182+
}
183+
184+
// CHECK-OLD-LABEL: declare extern_weak swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV013conditionallyF17MethodInExtensionyyF"
185+
// CHECK-NEW-LABEL: declare swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV013conditionallyF17MethodInExtensionyyF"
186+
187+
@available(macOS 50, *)
188+
public func useConditionallyAvailableOpaqueReturnMethodInExtension(s: AlwaysAvailableStruct) {
189+
blackHole(s.conditionallyAvailableOpaqueReturnMethodInExtension())
190+
}
191+
192+
// CHECK-OLD-LABEL: declare extern_weak swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV013conditionallyF29OpaqueReturnMethodInExtensionQryF"
193+
// CHECK-NEW-LABEL: declare swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV013conditionallyF29OpaqueReturnMethodInExtensionQryF"
194+
195+
@available(macOS 50, *)
196+
public func useConditionallyAvailableVarInExtension(s: inout AlwaysAvailableStruct) {
197+
_ = s.conditionallyAvailableVarInExtension
198+
s.conditionallyAvailableVarInExtension = 0
199+
s.conditionallyAvailableVarInExtension += 0
200+
}
201+
202+
// CHECK-OLD-LABEL: declare extern_weak swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV013conditionallyF14VarInExtensionSivg"
203+
// CHECK-OLD-LABEL: declare extern_weak swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV013conditionallyF14VarInExtensionSivs"
204+
// CHECK-OLD-LABEL: declare extern_weak swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV013conditionallyF14VarInExtensionSivM"
205+
206+
// CHECK-NEW-LABEL: declare swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV013conditionallyF14VarInExtensionSivg"
207+
// CHECK-NEW-LABEL: declare swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV013conditionallyF14VarInExtensionSivs"
208+
// CHECK-NEW-LABEL: declare swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV013conditionallyF14VarInExtensionSivM"
209+
210+
@available(macOS 50, *)
211+
public func useConditionallyAvailableMethodInExplicitlyAvailableExtension(s: AlwaysAvailableStruct) {
212+
s.conditionallyAvailableMethodInExplicitlyAvailableExtension()
213+
}
214+
215+
// CHECK-OLD-LABEL: declare extern_weak swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV013conditionallyf18MethodInExplicitlyF9ExtensionyyF"
216+
// CHECK-NEW-LABEL: declare swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV013conditionallyf18MethodInExplicitlyF9ExtensionyyF"
217+
218+
@available(macOS 50, *)
219+
public func useConditionallyAvailableOpaqueReturnMethodInExplicitlyAvailableExtension(s: AlwaysAvailableStruct) {
220+
blackHole(s.conditionallyAvailableOpaqueReturnMethodInExplicitlyAvailableExtension())
221+
}
222+
223+
// CHECK-OLD-LABEL: declare extern_weak swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV013conditionallyf30OpaqueReturnMethodInExplicitlyF9ExtensionQryF"
224+
// CHECK-NEW-LABEL: declare swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV013conditionallyf30OpaqueReturnMethodInExplicitlyF9ExtensionQryF"
225+
226+
227+
@available(macOS 50, *)
228+
public func useConditionallyAvailableVarInExplicitlyAvailableExtension(s: inout AlwaysAvailableStruct) {
229+
_ = s.conditionallyAvailableVarInExplicitlyAvailablextension
230+
s.conditionallyAvailableVarInExplicitlyAvailablextension = 0
231+
s.conditionallyAvailableVarInExplicitlyAvailablextension += 0
232+
}
233+
234+
// CHECK-OLD-LABEL: declare extern_weak swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV013conditionallyF32VarInExplicitlyAvailablextensionSivg"
235+
// CHECK-OLD-LABEL: declare extern_weak swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV013conditionallyF32VarInExplicitlyAvailablextensionSivs"
236+
// CHECK-OLD-LABEL: declare extern_weak swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV013conditionallyF32VarInExplicitlyAvailablextensionSivM"
237+
238+
// CHECK-NEW-LABEL: declare swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV013conditionallyF32VarInExplicitlyAvailablextensionSivg"
239+
// CHECK-NEW-LABEL: declare swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV013conditionallyF32VarInExplicitlyAvailablextensionSivs"
240+
// CHECK-NEW-LABEL: declare swiftcc {{.+}} @"$s31weak_import_availability_helper21AlwaysAvailableStructV013conditionallyF32VarInExplicitlyAvailablextensionSivM"
241+
116242
@available(macOS, unavailable)
117243
public func useUnavailableStruct() {
118244
blackHole(UnavailableStruct.self)

test/IRGen/weak_import_native.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,16 @@ func testStruct() {
5858
s[0] = z
5959
s[0] += 1
6060

61+
// CHECK-DAG: declare extern_weak {{.+}} @"$s25weak_import_native_helper1SV11extensionFnyyF"
62+
s.extensionFn()
63+
64+
// CHECK-DAG: declare extern_weak {{.+}} @"$s25weak_import_native_helper1SV13extensionPropSivg"
65+
// CHECK-DAG: declare extern_weak {{.+}} @"$s25weak_import_native_helper1SV13extensionPropSivs"
66+
// CHECK-DAG: declare extern_weak {{.+}} @"$s25weak_import_native_helper1SV13extensionPropSivM"
67+
let yy = s.extensionProp
68+
s.extensionProp = yy
69+
s.extensionProp += 1
70+
6171
// CHECK-DAG: declare extern_weak {{.+}} @"$s25weak_import_native_helper5WeakSV0A6MemberyyF"
6272
let w = WeakS()
6373
w.weakMember()

0 commit comments

Comments
 (0)