Skip to content

Commit 48f3704

Browse files
authored
Merge pull request #68811 from apple/es-add-pkg
Lift restrictions of access check for inlinalbe package symbols referenced in interfaces.
2 parents 102c3d0 + e41f314 commit 48f3704

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
@@ -2707,8 +2707,29 @@ class ValueDecl : public Decl {
27072707

27082708
SourceLoc getNameLoc() const { return NameLoc; }
27092709

2710+
/// Returns \c true if this value decl is inlinable with attributes
2711+
/// \c \@usableFromInline, \c \@inlinalbe, and \c \@_alwaysEmitIntoClient
27102712
bool isUsableFromInline() const;
27112713

2714+
/// Returns \c true if this value decl needs a special case handling for an
2715+
/// interface file.
2716+
///
2717+
/// One such case is a reference of an inlinable decl with a `package` access level
2718+
/// in an interface file as follows: Package decls are only printed in interface files if
2719+
/// they are inlinable (as defined in \c isUsableFromInline). They could be
2720+
/// referenced by a module outside of its defining module that belong to the same
2721+
/// package determined by the `package-name` flag. However, the flag is only in
2722+
/// .swiftmodule and .private.swiftinterface, thus type checking references of inlinable
2723+
/// package symbols in public interfaces fails due to the missing flag.
2724+
/// Instead of adding the package-name flag to the public interfaces, which
2725+
/// could raise a security concern, we grant access to such cases.
2726+
///
2727+
/// \sa useDC The use site where this value decl is referenced.
2728+
/// \sa useAcl The access level of its use site.
2729+
/// \sa declScope The access scope of this decl site.
2730+
bool skipAccessCheckIfInterface(const DeclContext *useDC, AccessLevel useAcl,
2731+
AccessScope declScope) const;
2732+
27122733
/// Returns \c true if this declaration is *not* intended to be used directly
27132734
/// by application developers despite the visibility.
27142735
bool shouldHideFromEditor() const;

lib/AST/Decl.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3850,6 +3850,17 @@ bool ValueDecl::isUsableFromInline() const {
38503850
return false;
38513851
}
38523852

3853+
bool ValueDecl::skipAccessCheckIfInterface(const DeclContext *useDC,
3854+
AccessLevel useAcl,
3855+
AccessScope declScope) const {
3856+
if (!useDC || useAcl != AccessLevel::Package || !declScope.isPackage() ||
3857+
!isUsableFromInline() ||
3858+
getDeclContext()->getParentModule() == useDC->getParentModule())
3859+
return false;
3860+
auto useSF = useDC->getParentSourceFile();
3861+
return useSF && useSF->Kind == SourceFileKind::Interface;
3862+
}
3863+
38533864
bool ValueDecl::shouldHideFromEditor() const {
38543865
// Hide private stdlib declarations.
38553866
if (isPrivateStdlibDecl(/*treatNonBuiltinProtocolsAsPublic*/ false) ||
@@ -4181,8 +4192,13 @@ static bool checkAccessUsingAccessScopes(const DeclContext *useDC,
41814192
VD, access, useDC,
41824193
/*treatUsableFromInlineAsPublic*/ includeInlineable);
41834194
if (accessScope.getDeclContext() == useDC) return true;
4184-
if (!AccessScope(useDC).isChildOf(accessScope)) return false;
4185-
4195+
if (!AccessScope(useDC).isChildOf(accessScope)) {
4196+
// Grant access if this VD is an inlinable package decl referenced by
4197+
// another module in an interface file.
4198+
if (VD->skipAccessCheckIfInterface(useDC, access, accessScope))
4199+
return true;
4200+
return false;
4201+
}
41864202
// useDC is null only when caller wants to skip non-public type checks.
41874203
if (!useDC) return true;
41884204

lib/Sema/TypeCheckProtocol.cpp

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