Skip to content

Commit eedd0dd

Browse files
committed
When package optimization is enabled, treat public decls as non-resilient
as well besides package decls if in the same package boundary. Resolves rdar://123344579
1 parent ea7d077 commit eedd0dd

File tree

4 files changed

+63
-25
lines changed

4 files changed

+63
-25
lines changed

include/swift/AST/Decl.h

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4099,20 +4099,36 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
40994099

41004100
void setBraces(SourceRange braces) { Braces = braces; }
41014101

4102-
/// Should this declaration behave as if it must be accessed
4103-
/// resiliently, even when we're building a non-resilient module?
4102+
/// Returns whether this declaration is resilient at the definition site, i.e.
4103+
/// must be accessed resiliently even when its defining module is built
4104+
/// non-resiliently.
41044105
///
41054106
/// This is used for diagnostics, because we do not want a behavior
41064107
/// change between builds with resilience enabled and disabled.
41074108
bool isFormallyResilient() const;
41084109

4109-
/// Do we need to use resilient access patterns outside of this type's
4110-
/// resilience domain?
4110+
/// Returns whether this decl is resilient at the definition site
4111+
/// \c isFormallyResilient or whether its defining module
4112+
/// is built resiliently.
41114113
bool isResilient() const;
41124114

4113-
/// Do we need to use resilient access patterns when accessing this
4114-
/// type from the given module?
4115-
bool isResilient(ModuleDecl *M, ResilienceExpansion expansion) const;
4115+
/// Returns whether this decl is accessed non/resiliently at the _use_ site
4116+
/// in \p accessingModule, depending on \p expansion.
4117+
///
4118+
/// If \p expansion is maximal, the decl could be treated as non-resilient
4119+
/// even though the decl is resilient by definition or its defining module is built
4120+
/// resiliently. For example, if accessing a decl defined in the same module or
4121+
/// another module in the same package as the \p accessingModule, the
4122+
/// decl could be treated as non-resilient (with package optimization enabled in
4123+
/// case of different modules); this enables bypassing resilience checks at the
4124+
/// use site so the decl can be accessed directly.
4125+
///
4126+
/// \p accessingModule The module from which this decl is accessed. Might
4127+
/// be the same module as its defining module.
4128+
/// \p expansion Used to determine whether non-resilience / direct access
4129+
/// to this decl is possible.
4130+
bool isResilient(ModuleDecl *accessingModule,
4131+
ResilienceExpansion expansion) const;
41164132

41174133
/// Determine whether we have already attempted to add any
41184134
/// implicitly-defined initializers to this declaration.

lib/AST/Decl.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4206,10 +4206,8 @@ bool ValueDecl::hasOpenAccess(const DeclContext *useDC) const {
42064206

42074207
bool ValueDecl::bypassResilienceInPackage(ModuleDecl *accessingModule) const {
42084208
return getASTContext().LangOpts.EnableBypassResilienceInPackage &&
4209-
getModuleContext()->inSamePackage(accessingModule) &&
4210-
!getModuleContext()->isBuiltFromInterface() &&
4211-
getFormalAccessScope(/*useDC=*/nullptr,
4212-
/*treatUsableFromInlineAsPublic=*/true).isPackage();
4209+
getModuleContext()->inSamePackage(accessingModule) &&
4210+
!getModuleContext()->isBuiltFromInterface();
42134211
}
42144212

42154213
/// Given the formal access level for using \p VD, compute the scope where

test/SILGen/package_bypass_resilience.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,13 @@ func foo() {
3434
// CHECK: sil hidden [ossa] @$s6Client3fooyyF : $@convention(thin) () -> () {
3535
// CHECK-DEFAULT: [[F_REF:%.*]] = function_ref @$s5Utils9PkgStructV6pkgVarSivg : $@convention(method) (@in_guaranteed PkgStruct) -> Int
3636
// CHECK-DEFAULT: sil package_external @$s5Utils9PkgStructV6pkgVarSivg : $@convention(method) (@in_guaranteed PkgStruct) -> Int
37-
// CHECK-BYPASS: [[ADDR:%.*]] = struct_element_addr %7 : $*PkgStruct, #PkgStruct.pkgVar
37+
// CHECK-BYPASS: [[ADDR:%.*]] = struct_element_addr {{.*}} : $*PkgStruct, #PkgStruct.pkgVar
3838

3939
func bar() {
4040
print(PubStruct().pubVar)
4141
}
4242

4343
// CHECK: sil hidden [ossa] @$s6Client3baryyF : $@convention(thin) () -> () {
44-
// CHECK: [[F_REF:%.*]] = function_ref @$s5Utils9PubStructV6pubVarSivg : $@convention(method) (@in_guaranteed PubStruct) -> Int
45-
// CHECK: sil @$s5Utils9PubStructV6pubVarSivg : $@convention(method) (@in_guaranteed PubStruct) -> Int
44+
// CHECK-DEFAULT: [[F_REF:%.*]] = function_ref @$s5Utils9PubStructV6pubVarSivg : $@convention(method) (@in_guaranteed PubStruct) -> Int
45+
// CHECK-DEFAULT: sil @$s5Utils9PubStructV6pubVarSivg : $@convention(method) (@in_guaranteed PubStruct) -> Int
46+
// CHECK-BYPASS: [[ADDR:%.*]] = struct_element_addr {{.*}} : $*PubStruct, #PubStruct.pubVar

test/Sema/package_resilience_bypass_exhaustive_switch.swift

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,16 @@ public enum FrozenPublicEnum {
3535
case two(Int)
3636
}
3737

38+
@usableFromInline
39+
enum UfiInternalEnum {
40+
case one
41+
case two(Int)
42+
}
43+
3844
//--- ClientDefault.swift
3945
import Utils
4046

41-
func f(_ arg: PkgEnum) -> Int {
47+
package func f(_ arg: PkgEnum) -> Int {
4248
switch arg { // expected-warning {{switch covers known cases, but 'PkgEnum' may have additional unknown values}} {{none}} expected-note {{handle unknown values using "@unknown default"}}
4349
case .one:
4450
return 1
@@ -47,7 +53,7 @@ func f(_ arg: PkgEnum) -> Int {
4753
}
4854
}
4955

50-
func g(_ arg: UfiPkgEnum) -> Int {
56+
public func g(_ arg: UfiPkgEnum) -> Int {
5157
switch arg { // expected-warning {{switch covers known cases, but 'UfiPkgEnum' may have additional unknown values}} {{none}} expected-note {{handle unknown values using "@unknown default"}}
5258
case .one:
5359
return 1
@@ -74,33 +80,41 @@ public func k(_ arg: FrozenPublicEnum) -> Int {
7480
}
7581
}
7682

83+
public func m(_ arg: UfiInternalEnum) -> Int {
84+
switch arg { // no-warning
85+
case .one:
86+
return 1
87+
case .two(let val):
88+
return 2 + val
89+
}
90+
}
91+
7792
//--- ClientOptimized.swift
7893
import Utils
7994

80-
// No warning with optimization to bypass resilience checks for package enums.
81-
func f(_ arg: PkgEnum) -> Int {
82-
switch arg {
95+
// With optimization enabled to bypass resilience checks within
96+
// a package boundary, public (non-frozen) or package enums no
97+
// longer require `@unknown default` in source code switch stmts.
98+
package func f(_ arg: PkgEnum) -> Int {
99+
switch arg { // no-warning
83100
case .one:
84101
return 1
85102
case .two(let val):
86103
return 2 + val
87104
}
88105
}
89106

90-
// Warning still shows up for usableFromInline package enum as the optimization is targeted for
91-
// decls with package access, not the elevated public access. This might be allowed later.
92-
func g(_ arg: UfiPkgEnum) -> Int {
93-
switch arg { // expected-warning {{switch covers known cases, but 'UfiPkgEnum' may have additional unknown values}} {{none}} expected-note {{handle unknown values using "@unknown default"}}
107+
public func g(_ arg: UfiPkgEnum) -> Int {
108+
switch arg { // no-warning
94109
case .one:
95110
return 1
96111
case .two(let val):
97112
return 2 + val
98113
}
99114
}
100115

101-
// Warning still shows up for public enum as the optimization is targeted for package types.
102116
public func h(_ arg: PublicEnum) -> Int {
103-
switch arg { // expected-warning {{switch covers known cases, but 'PublicEnum' may have additional unknown values}} {{none}} expected-note {{handle unknown values using "@unknown default"}}
117+
switch arg { // no-warning
104118
case .one:
105119
return 1
106120
case .two(let val):
@@ -116,3 +130,12 @@ public func k(_ arg: FrozenPublicEnum) -> Int {
116130
return 2 + val
117131
}
118132
}
133+
134+
public func m(_ arg: UfiInternalEnum) -> Int {
135+
switch arg { // no-warning
136+
case .one:
137+
return 1
138+
case .two(let val):
139+
return 2 + val
140+
}
141+
}

0 commit comments

Comments
 (0)