Skip to content

Commit 517a539

Browse files
authored
Merge pull request #64033 from xymus/access-level-inlinable
[Sema] Report use of decls imported as non-public in inlinable code
2 parents 2abf14a + 0322ca0 commit 517a539

File tree

2 files changed

+188
-3
lines changed

2 files changed

+188
-3
lines changed

lib/Sema/ResilienceDiagnostics.cpp

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,28 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc,
3939
if (D->getDeclContext()->isLocalContext())
4040
return false;
4141

42+
// General check on access-level of the decl.
43+
auto declAccessScope = D->getFormalAccessScope(/*useDC=*/nullptr,
44+
fragileKind.allowUsableFromInline);
45+
46+
// If the decl is imported, check if the import lowers it's access level.
47+
auto importAccessLevel = AccessLevel::Public;
48+
ImportAccessLevel problematicImport = None;
49+
4250
auto *DC = where.getDeclContext();
51+
auto targetModule = D->getDeclContext()->getParentModule();
52+
auto file = where.getDeclContext()->getParentSourceFile();
53+
if (targetModule != DC->getParentModule() && file) {
54+
problematicImport = file->getImportAccessLevel(targetModule);
55+
if (problematicImport.has_value())
56+
importAccessLevel = problematicImport->accessLevel;
57+
}
4358

4459
// Public declarations are OK, even if they're SPI or came from an
4560
// implementation-only import. We'll diagnose exportability violations
4661
// from diagnoseDeclRefExportability().
47-
if (D->getFormalAccessScope(/*useDC=*/nullptr,
48-
fragileKind.allowUsableFromInline).isPublic())
62+
if (declAccessScope.isPublic() &&
63+
importAccessLevel == AccessLevel::Public)
4964
return false;
5065

5166
auto &Context = DC->getASTContext();
@@ -91,8 +106,11 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc,
91106
if (downgradeToWarning == DowngradeToWarning::Yes)
92107
diagID = diag::resilience_decl_unavailable_warn;
93108

109+
auto diagAccessLevel = std::min(declAccessScope.accessLevelForDiagnostics(),
110+
importAccessLevel);
111+
94112
Context.Diags.diagnose(loc, diagID, D->getDescriptiveKind(), diagName,
95-
D->getFormalAccessScope().accessLevelForDiagnostics(),
113+
diagAccessLevel,
96114
fragileKind.getSelector(), isAccessor);
97115

98116
if (fragileKind.allowUsableFromInline) {
@@ -103,6 +121,14 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc,
103121
D->getDescriptiveKind(), diagName, isAccessor);
104122
}
105123

124+
if (problematicImport.has_value() &&
125+
diagAccessLevel == importAccessLevel) {
126+
Context.Diags.diagnose(problematicImport->accessLevelLoc,
127+
diag::module_imported_here,
128+
problematicImport->module.importedModule->getName(),
129+
problematicImport->accessLevel);
130+
}
131+
106132
return (downgradeToWarning == DowngradeToWarning::No);
107133
}
108134

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
// Test use of decls restricted by an import access-level in inlinable code.
2+
3+
// RUN: %empty-directory(%t)
4+
// RUN: split-file %s %t
5+
6+
/// Build the libraries.
7+
// RUN: %target-swift-frontend -emit-module %t/PublicLib.swift -o %t \
8+
// RUN: -enable-library-evolution
9+
// RUN: %target-swift-frontend -emit-module %t/PackageLib.swift -o %t \
10+
// RUN: -enable-library-evolution
11+
// RUN: %target-swift-frontend -emit-module %t/InternalLib.swift -o %t \
12+
// RUN: -enable-library-evolution
13+
// RUN: %target-swift-frontend -emit-module %t/FileprivateLib.swift -o %t \
14+
// RUN: -enable-library-evolution
15+
// RUN: %target-swift-frontend -emit-module %t/PrivateLib.swift -o %t \
16+
// RUN: -enable-library-evolution
17+
18+
/// Check diagnostics.
19+
// RUN: %target-swift-frontend -typecheck %t/Client.swift -I %t \
20+
// RUN: -enable-library-evolution -swift-version 5 \
21+
// RUN: -enable-experimental-feature AccessLevelOnImport -verify
22+
23+
//--- PublicLib.swift
24+
public protocol PublicImportProto {
25+
associatedtype T
26+
}
27+
public struct PublicImportType {
28+
public init() {}
29+
}
30+
public func PublicFunc() {}
31+
32+
@propertyWrapper
33+
public struct PublicImportWrapper<T> {
34+
public var wrappedValue: T
35+
public init(wrappedValue: T) {
36+
self.wrappedValue = wrappedValue
37+
}
38+
}
39+
40+
//--- PackageLib.swift
41+
public struct PackageImportType {
42+
public init() {}
43+
}
44+
45+
//--- InternalLib.swift
46+
public protocol InternalImportProto {
47+
associatedtype T
48+
}
49+
public struct InternalImportType {
50+
public init() {}
51+
}
52+
public func InternalFunc() {}
53+
54+
//--- FileprivateLib.swift
55+
public protocol FileprivateImportProto {
56+
associatedtype T
57+
}
58+
59+
@propertyWrapper
60+
public struct FileprivateImportWrapper<T> {
61+
public var wrappedValue: T
62+
public init(wrappedValue: T) {
63+
self.wrappedValue = wrappedValue
64+
}
65+
}
66+
67+
//--- PrivateLib.swift
68+
public struct PrivateImportType {
69+
public init() {}
70+
}
71+
72+
//--- Client.swift
73+
public import PublicLib
74+
package import PackageLib // expected-note 2 {{module 'PackageLib' imported as 'package' here}}
75+
internal import InternalLib // expected-note 12 {{module 'InternalLib' imported as 'internal' here}}
76+
fileprivate import FileprivateLib // expected-note 6 {{module 'FileprivateLib' imported as 'fileprivate' here}}
77+
private import PrivateLib // expected-note 6 {{module 'PrivateLib' imported as 'private' here}}
78+
79+
public struct GenericType<T, U> {}
80+
81+
@inlinable public func inlinable() {
82+
83+
PublicFunc()
84+
InternalFunc() // expected-error {{global function 'InternalFunc()' is internal and cannot be referenced from an '@inlinable' function}}
85+
86+
let _: PublicImportType
87+
let _: InternalImportType // expected-error {{struct 'InternalImportType' is internal and cannot be referenced from an '@inlinable' function}}
88+
89+
let _ = PublicImportType()
90+
let _ = PrivateImportType() // expected-error {{struct 'PrivateImportType' is private and cannot be referenced from an '@inlinable' function}}
91+
// expected-error @-1 {{initializer 'init()' is private and cannot be referenced from an '@inlinable' function}}
92+
93+
let _: any PublicImportProto
94+
let _: any InternalImportProto // expected-error {{protocol 'InternalImportProto' is internal and cannot be referenced from an '@inlinable' function}}
95+
96+
let _: any FileprivateImportProto & InternalImportProto // expected-error {{protocol 'FileprivateImportProto' is fileprivate and cannot be referenced from an '@inlinable' function}}
97+
// expected-error @-1 {{protocol 'InternalImportProto' is internal and cannot be referenced from an '@inlinable' function}}
98+
99+
func PublicFuncUsesPublic(_: PublicImportType) {}
100+
func PublicFuncUsesPackage(_: PackageImportType) {} // expected-error {{struct 'PackageImportType' is package and cannot be referenced from an '@inlinable' function}}}
101+
102+
func PublicFuncUsesPublic() -> PublicImportType {
103+
fatalError()
104+
}
105+
func PublicFuncReturnUsesInternal() -> InternalImportType { // expected-error {{struct 'InternalImportType' is internal and cannot be referenced from an '@inlinable' function}}
106+
fatalError()
107+
}
108+
109+
@PublicImportWrapper
110+
var wrappedPublic: PublicImportType
111+
112+
@FileprivateImportWrapper // expected-error {{initializer 'init(wrappedValue:)' is fileprivate and cannot be referenced from an '@inlinable' function}}
113+
// expected-error @-1 {{generic struct 'FileprivateImportWrapper' is fileprivate and cannot be referenced from an '@inlinable' function}}
114+
var wrappedFileprivate: PublicImportType
115+
116+
let _: GenericType<PublicImportType, PublicImportType>
117+
let _: GenericType<InternalImportType, PrivateImportType> // expected-error {{struct 'InternalImportType' is internal and cannot be referenced from an '@inlinable' function}}
118+
// expected-error @-1 {{struct 'PrivateImportType' is private and cannot be referenced from an '@inlinable' function}}
119+
}
120+
121+
@_alwaysEmitIntoClient public func alwaysEmitIntoClient() {
122+
123+
PublicFunc()
124+
InternalFunc() // expected-error {{global function 'InternalFunc()' is internal and cannot be referenced from an '@_alwaysEmitIntoClient' function}}
125+
126+
let _: PublicImportType
127+
let _: InternalImportType // expected-error {{struct 'InternalImportType' is internal and cannot be referenced from an '@_alwaysEmitIntoClient' function}}
128+
129+
let _ = PublicImportType()
130+
let _ = PrivateImportType() // expected-error {{struct 'PrivateImportType' is private and cannot be referenced from an '@_alwaysEmitIntoClient' function}}
131+
// expected-error @-1 {{initializer 'init()' is private and cannot be referenced from an '@_alwaysEmitIntoClient' function}}
132+
133+
let _: any PublicImportProto
134+
let _: any InternalImportProto // expected-error {{protocol 'InternalImportProto' is internal and cannot be referenced from an '@_alwaysEmitIntoClient' function}}
135+
136+
let _: any FileprivateImportProto & InternalImportProto // expected-error {{protocol 'FileprivateImportProto' is fileprivate and cannot be referenced from an '@_alwaysEmitIntoClient' function}}
137+
// expected-error @-1 {{protocol 'InternalImportProto' is internal and cannot be referenced from an '@_alwaysEmitIntoClient' function}}
138+
139+
func PublicFuncUsesPublic(_: PublicImportType) {}
140+
func PublicFuncUsesPackage(_: PackageImportType) {} // expected-error {{struct 'PackageImportType' is package and cannot be referenced from an '@_alwaysEmitIntoClient' function}}}
141+
142+
func PublicFuncUsesPublic() -> PublicImportType {
143+
fatalError()
144+
}
145+
func PublicFuncReturnUsesInternal() -> InternalImportType { // expected-error {{struct 'InternalImportType' is internal and cannot be referenced from an '@_alwaysEmitIntoClient' function}}
146+
fatalError()
147+
}
148+
149+
@PublicImportWrapper
150+
var wrappedPublic: PublicImportType
151+
152+
@FileprivateImportWrapper // expected-error {{initializer 'init(wrappedValue:)' is fileprivate and cannot be referenced from an '@_alwaysEmitIntoClient' function}}
153+
// expected-error @-1 {{generic struct 'FileprivateImportWrapper' is fileprivate and cannot be referenced from an '@_alwaysEmitIntoClient' function}}
154+
var wrappedFileprivate: PublicImportType
155+
156+
let _: GenericType<PublicImportType, PublicImportType>
157+
let _: GenericType<InternalImportType, PrivateImportType> // expected-error {{struct 'InternalImportType' is internal and cannot be referenced from an '@_alwaysEmitIntoClient' function}}
158+
// expected-error @-1 {{struct 'PrivateImportType' is private and cannot be referenced from an '@_alwaysEmitIntoClient' function}}
159+
}

0 commit comments

Comments
 (0)