Skip to content

Commit 24869a4

Browse files
authored
Merge pull request #69099 from apple/es-pkg-interface
[5.10] Lift restrictions of access check for inlinalbe package symbols referenced in interfaces
2 parents 20940c2 + 74f7f31 commit 24869a4

File tree

4 files changed

+145
-15
lines changed

4 files changed

+145
-15
lines changed

include/swift/AST/Decl.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2684,8 +2684,29 @@ class ValueDecl : public Decl {
26842684

26852685
SourceLoc getNameLoc() const { return NameLoc; }
26862686

2687+
/// Returns \c true if this value decl is inlinable with attributes
2688+
/// \c \@usableFromInline, \c \@inlinalbe, and \c \@_alwaysEmitIntoClient
26872689
bool isUsableFromInline() const;
26882690

2691+
/// Returns \c true if this value decl needs a special case handling for an
2692+
/// interface file.
2693+
///
2694+
/// One such case is a reference of an inlinable decl with a `package` access level
2695+
/// in an interface file as follows: Package decls are only printed in interface files if
2696+
/// they are inlinable (as defined in \c isUsableFromInline). They could be
2697+
/// referenced by a module outside of its defining module that belong to the same
2698+
/// package determined by the `package-name` flag. However, the flag is only in
2699+
/// .swiftmodule and .private.swiftinterface, thus type checking references of inlinable
2700+
/// package symbols in public interfaces fails due to the missing flag.
2701+
/// Instead of adding the package-name flag to the public interfaces, which
2702+
/// could raise a security concern, we grant access to such cases.
2703+
///
2704+
/// \sa useDC The use site where this value decl is referenced.
2705+
/// \sa useAcl The access level of its use site.
2706+
/// \sa declScope The access scope of this decl site.
2707+
bool skipAccessCheckIfInterface(const DeclContext *useDC, AccessLevel useAcl,
2708+
AccessScope declScope) const;
2709+
26892710
/// Returns \c true if this declaration is *not* intended to be used directly
26902711
/// by application developers despite the visibility.
26912712
bool shouldHideFromEditor() const;

lib/AST/Decl.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3818,6 +3818,17 @@ bool ValueDecl::isUsableFromInline() const {
38183818
return false;
38193819
}
38203820

3821+
bool ValueDecl::skipAccessCheckIfInterface(const DeclContext *useDC,
3822+
AccessLevel useAcl,
3823+
AccessScope declScope) const {
3824+
if (!useDC || useAcl != AccessLevel::Package || !declScope.isPackage() ||
3825+
!isUsableFromInline() ||
3826+
getDeclContext()->getParentModule() == useDC->getParentModule())
3827+
return false;
3828+
auto useSF = useDC->getParentSourceFile();
3829+
return useSF && useSF->Kind == SourceFileKind::Interface;
3830+
}
3831+
38213832
bool ValueDecl::shouldHideFromEditor() const {
38223833
// Hide private stdlib declarations.
38233834
if (isPrivateStdlibDecl(/*treatNonBuiltinProtocolsAsPublic*/ false) ||
@@ -4154,8 +4165,13 @@ static bool checkAccessUsingAccessScopes(const DeclContext *useDC,
41544165
VD, access, useDC,
41554166
/*treatUsableFromInlineAsPublic*/ includeInlineable);
41564167
if (accessScope.getDeclContext() == useDC) return true;
4157-
if (!AccessScope(useDC).isChildOf(accessScope)) return false;
4158-
4168+
if (!AccessScope(useDC).isChildOf(accessScope)) {
4169+
// Grant access if this VD is an inlinable package decl referenced by
4170+
// another module in an interface file.
4171+
if (VD->skipAccessCheckIfInterface(useDC, access, accessScope))
4172+
return true;
4173+
return false;
4174+
}
41594175
// useDC is null only when caller wants to skip non-public type checks.
41604176
if (!useDC) return true;
41614177

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4372,6 +4372,10 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
43724372
requiredAccessScope.requiredAccessForDiagnostics();
43734373
auto proto = conformance->getProtocol();
43744374
auto protoAccessScope = proto->getFormalAccessScope(DC);
4375+
// Skip diagnostics of a witness of a package protocol that is inlinalbe
4376+
// referenced in an interface file.
4377+
if (proto->skipAccessCheckIfInterface(DC, requiredAccess, protoAccessScope))
4378+
return;
43754379
bool protoForcesAccess =
43764380
requiredAccessScope.hasEqualDeclContextWith(protoAccessScope);
43774381
auto diagKind = protoForcesAccess

test/Sema/accessibility_package_interface.swift

Lines changed: 102 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,118 @@
1010
// RUN: -emit-private-module-interface-path %t/Utils.private.swiftinterface
1111

1212
// RUN: %target-swift-typecheck-module-from-interface(%t/Utils.swiftinterface) -I %t
13-
// RUN: %FileCheck %s --check-prefix=CHECK-PUBLIC < %t/Utils.swiftinterface
14-
// CHECK-PUBLIC-NOT: -package-name swift-utils.log
15-
// CHECK-PUBLIC-NOT: package func packageFunc()
16-
// CHECK-PUBLIC: -module-name Utils
17-
// CHECK-PUBLIC: public func publicFunc()
13+
// RUN: %FileCheck %s --check-prefix=CHECK-PUBLIC-UTILS < %t/Utils.swiftinterface
14+
15+
// CHECK-PUBLIC-UTILS-NOT: -package-name swift-utils.log
16+
// CHECK-PUBLIC-UTILS-NOT: package func packageFunc()
17+
// CHECK-PUBLIC-UTILS-NOT: package protocol PackageProto
18+
// CHECK-PUBLIC-UTILS-NOT: var pkgVar
19+
// CHECK-PUBLIC-UTILS-NOT: package class PackageKlass
20+
// CHECK-PUBLIC-UTILS-NOT: package var pkgVar
21+
// CHECK-PUBLIC-UTILS: -module-name Utils
22+
// CHECK-PUBLIC-UTILS: public func publicFunc()
23+
// CHECK-PUBLIC-UTILS: @usableFromInline
24+
// CHECK-PUBLIC-UTILS: package func ufiPackageFunc()
25+
// CHECK-PUBLIC-UTILS: @usableFromInline
26+
// CHECK-PUBLIC-UTILS: package protocol UfiPackageProto
27+
// CHECK-PUBLIC-UTILS: var ufiPkgVar
28+
// CHECK-PUBLIC-UTILS: @usableFromInline
29+
// CHECK-PUBLIC-UTILS: package class UfiPackageKlass
30+
// CHECK-PUBLIC-UTILS: @usableFromInline
31+
// CHECK-PUBLIC-UTILS: package var ufiPkgVar
1832

1933
// RUN: %target-swift-typecheck-module-from-interface(%t/Utils.private.swiftinterface) -module-name Utils -I %t
20-
// RUN: %FileCheck %s --check-prefix=CHECK-PRIVATE < %t/Utils.private.swiftinterface
34+
// RUN: %FileCheck %s --check-prefix=CHECK-PRIVATE-UTILS < %t/Utils.private.swiftinterface
35+
36+
// CHECK-PRIVATE-UTILS-NOT: package func packageFunc()
37+
// CHECK-PRIVATE-UTILS-NOT: package protocol PackageProto
38+
// CHECK-PRIVATE-UTILS-NOT: var pkgVar
39+
// CHECK-PRIVATE-UTILS-NOT: package class PackageKlass
40+
// CHECK-PRIVATE-UTILS-NOT: package var pkgVar
41+
// CHECK-PRIVATE-UTILS: -module-name Utils
42+
// CHECK-PRIVATE-UTILS: swift-module-flags-ignorable-private: -package-name swift-utils.log
43+
// CHECK-PRIVATE-UTILS: public func publicFunc()
44+
// CHECK-PRIVATE-UTILS: @usableFromInline
45+
// CHECK-PRIVATE-UTILS: package func ufiPackageFunc()
46+
// CHECK-PRIVATE-UTILS: @usableFromInline
47+
// CHECK-PRIVATE-UTILS: package protocol UfiPackageProto
48+
// CHECK-PRIVATE-UTILS: var ufiPkgVar
49+
// CHECK-PRIVATE-UTILS: @usableFromInline
50+
// CHECK-PRIVATE-UTILS: package class UfiPackageKlass
51+
// CHECK-PRIVATE-UTILS: @usableFromInline
52+
// CHECK-PRIVATE-UTILS: package var ufiPkgVar
53+
54+
// RUN: %target-swift-frontend -emit-module %t/Client.swift \
55+
// RUN: -module-name Client -swift-version 5 -I %t \
56+
// RUN: -package-name swift-utils.log \
57+
// RUN: -enable-library-evolution \
58+
// RUN: -emit-module-path %t/Client.swiftmodule \
59+
// RUN: -emit-module-interface-path %t/Client.swiftinterface \
60+
// RUN: -emit-private-module-interface-path %t/Client.private.swiftinterface
61+
62+
// RUN: rm -rf %t/Utils.swiftmodule
63+
// RUN: rm -rf %t/Client.swiftmodule
2164

22-
// CHECK-PRIVATE-NOT: package func packageFunc()
23-
// CHECK-PRIVATE: swift-module-flags-ignorable-private: -package-name swift-utils.log
24-
// CHECK-PRIVATE: public func publicFunc()
65+
// RUN: %target-swift-typecheck-module-from-interface(%t/Client.swiftinterface) -I %t -verify
66+
// RUN: %FileCheck %s --check-prefix=CHECK-PUBLIC-CLIENT < %t/Client.swiftinterface
67+
// CHECK-PUBLIC-CLIENT-NOT: -package-name swift-utils.log
68+
// CHECK-PUBLIC-CLIENT: @inlinable public func clientFunc()
69+
// CHECK-PUBLIC-CLIENT: publicFunc()
70+
// CHECK-PUBLIC-CLIENT: ufiPackageFunc()
71+
// CHECK-PUBLIC-CLIENT: let u = UfiPackageKlass()
72+
// CHECK-PUBLIC-CLIENT: return u.ufiPkgVar
73+
// CHECK-PUBLIC-CLIENT: public class ClientKlass1 : Utils.UfiPackageProto
74+
// CHECK-PUBLIC-CLIENT: @usableFromInline
75+
// CHECK-PUBLIC-CLIENT: package var ufiPkgVar: Swift.String
76+
// CHECK-PUBLIC-CLIENT: public class ClientKlass2 : Utils.UfiPackageProto
77+
// CHECK-PUBLIC-CLIENT: public var ufiPkgVar: Swift.String
78+
79+
// RUN: %target-swift-typecheck-module-from-interface(%t/Client.private.swiftinterface) -module-name Client -I %t -verify
2580

26-
// RUN: %target-swift-frontend -typecheck %t/Client.swift -package-name swift-utils.log -I %t -verify
2781

2882
//--- Utils.swift
29-
package func packageFunc() {}
3083
public func publicFunc() {}
3184

85+
package func packageFunc() {}
86+
@usableFromInline
87+
package func ufiPackageFunc() {}
88+
89+
package protocol PackageProto {
90+
var pkgVar: String { get set }
91+
}
92+
package class PackageKlass: PackageProto {
93+
package var pkgVar = ""
94+
}
95+
96+
@usableFromInline
97+
package protocol UfiPackageProto {
98+
var ufiPkgVar: String { get set }
99+
}
100+
101+
@usableFromInline
102+
package class UfiPackageKlass: UfiPackageProto {
103+
@usableFromInline
104+
package init() {}
105+
@usableFromInline
106+
package var ufiPkgVar = ""
107+
}
108+
109+
32110
//--- Client.swift
33111
import Utils
34112

35-
func clientFunc() {
36-
packageFunc()
113+
@inlinable public func clientFunc() -> String {
37114
publicFunc()
115+
ufiPackageFunc()
116+
let u = UfiPackageKlass()
117+
return u.ufiPkgVar
118+
}
119+
120+
public class ClientKlass1: UfiPackageProto {
121+
@usableFromInline
122+
package var ufiPkgVar = "B"
123+
}
124+
125+
public class ClientKlass2: UfiPackageProto {
126+
public var ufiPkgVar = "C"
38127
}

0 commit comments

Comments
 (0)