Skip to content

Commit 1fd44e6

Browse files
committed
Sema: Allow refs to hidden dependencies in prorperties of non-open classes
We now report properties referencing types imported from implementation-only dependencies in non-library-evolution mode as the memory layouts of structs and enums may be exposed to clients. Here we exempt non-open classes from this check as clients hold pointers to classes which hides the class internal memory layouts. Keep forbidding it for open classes in order to error early, a client trying to subclass an open class with such a reference from their property would already see an error about members not deserializable.
1 parent e3571eb commit 1fd44e6

File tree

2 files changed

+86
-24
lines changed

2 files changed

+86
-24
lines changed

lib/AST/Decl.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2803,6 +2803,11 @@ ExportedLevel VarDecl::isLayoutExposedToClients() const {
28032803
if (parent->getAttrs().hasAttribute<ImplementationOnlyAttr>())
28042804
return ExportedLevel::None;
28052805

2806+
// Class layouts are not exposed to clients, except for subclassing.
2807+
if (isa<ClassDecl>(parent) &&
2808+
!parent->hasOpenAccess(getDeclContext()))
2809+
return ExportedLevel::None;
2810+
28062811
auto M = getDeclContext()->getParentModule();
28072812
if (getASTContext().LangOpts.hasFeature(Feature::CheckImplementationOnly) &&
28082813
M->getResilienceStrategy() != ResilienceStrategy::Resilient) {

test/Sema/hidden-memory-layout.swift

Lines changed: 81 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,12 @@ public struct ExposedLayoutPublic {
7272
}
7373

7474
internal struct ExposedLayoutInternal {
75-
// expected-note @-1 2 {{type declared here}}
75+
// expected-note @-1 3 {{type declared here}}
7676
}
7777

7878
private struct ExposedLayoutPrivate {
7979
// expected-note @-1 2 {{struct 'ExposedLayoutPrivate' is not '@usableFromInline' or public}}
80-
// expected-note @-2 3 {{type declared here}}
80+
// expected-note @-2 4 {{type declared here}}
8181
init() { fatalError() } // expected-note {{initializer 'init()' is not '@usableFromInline' or public}}
8282
}
8383

@@ -116,14 +116,14 @@ private class HiddenClass {
116116
private struct HiddenLayout {
117117
// expected-opt-in-note @-1 2 {{struct 'HiddenLayout' is not '@usableFromInline' or public}}
118118
// expected-opt-in-note @-2 1 {{initializer 'init()' is not '@usableFromInline' or public}}
119-
// expected-opt-in-note @-3 10 {{struct declared here}}
120-
// expected-opt-in-note @-4 3 {{type declared here}}
119+
// expected-opt-in-note @-3 9 {{struct declared here}}
120+
// expected-opt-in-note @-4 4 {{type declared here}}
121121
}
122122
#else
123123
private struct HiddenLayout {
124124
// expected-not-opt-in-note @-1 2 {{struct 'HiddenLayout' is not '@usableFromInline' or public}}
125125
// expected-not-opt-in-note @-2 1 {{initializer 'init()' is not '@usableFromInline' or public}}
126-
// expected-not-opt-in-note @-3 3 {{type declared here}}
126+
// expected-not-opt-in-note @-3 4 {{type declared here}}
127127
}
128128
#endif
129129

@@ -134,7 +134,7 @@ public enum ExposedEnumPublic {
134134

135135
private enum ExposedEnumPrivate {
136136
// expected-note @-1 2 {{enum 'ExposedEnumPrivate' is not '@usableFromInline' or public}}
137-
// expected-note @-2 {{type declared here}}
137+
// expected-note @-2 2 {{type declared here}}
138138
case A
139139
// expected-note @-1 1 {{enum case 'A' is not '@usableFromInline' or public}}
140140
case B
@@ -143,17 +143,17 @@ private enum ExposedEnumPrivate {
143143
#if UseImplementationOnly
144144
@_implementationOnly
145145
private enum HiddenEnum {
146-
// expected-opt-in-note @-1 7 {{enum declared here}}
146+
// expected-opt-in-note @-1 6 {{enum declared here}}
147147
// expected-opt-in-note @-2 2 {{enum 'HiddenEnum' is not '@usableFromInline' or public}}
148-
// expected-opt-in-note @-3 {{type declared here}}
148+
// expected-opt-in-note @-3 2 {{type declared here}}
149149
case A
150150
// expected-opt-in-note @-1 {{enum case 'A' is not '@usableFromInline' or public}}
151151
case B
152152
}
153153
#else
154154
private enum HiddenEnum {
155155
// expected-not-opt-in-note @-1 2 {{enum 'HiddenEnum' is not '@usableFromInline' or public}}
156-
// expected-not-opt-in-note @-2 {{type declared here}}
156+
// expected-not-opt-in-note @-2 2 {{type declared here}}
157157
case A
158158
// expected-not-opt-in-note @-1 {{enum case 'A' is not '@usableFromInline' or public}}
159159
case B
@@ -165,25 +165,25 @@ public protocol ExposedProtocolPublic {
165165

166166
internal protocol ExposedProtocolInternal {
167167
// expected-note @-1 {{protocol 'ExposedProtocolInternal' is not '@usableFromInline' or public}}
168-
// expected-note @-2 2 {{type declared here}}
168+
// expected-note @-2 3 {{type declared here}}
169169
}
170170

171171
private protocol ExposedProtocolPrivate {
172172
// expected-note @-1 {{protocol 'ExposedProtocolPrivate' is not '@usableFromInline' or public}}
173-
// expected-note @-2 3 {{type declared here}}
173+
// expected-note @-2 4 {{type declared here}}
174174
}
175175

176176
#if UseImplementationOnly
177177
@_implementationOnly
178178
private protocol HiddenProtocol {
179179
// expected-opt-in-note @-1 {{protocol 'HiddenProtocol' is not '@usableFromInline' or public}}
180-
// expected-opt-in-note @-2 10 {{protocol declared here}}
181-
// expected-opt-in-note @-3 3 {{type declared here}}
180+
// expected-opt-in-note @-2 9 {{protocol declared here}}
181+
// expected-opt-in-note @-3 4 {{type declared here}}
182182
}
183183
#else
184184
private protocol HiddenProtocol {
185185
// expected-not-opt-in-note @-1 1 {{protocol 'HiddenProtocol' is not '@usableFromInline' or public}}
186-
// expected-not-opt-in-note @-2 3 {{type declared here}}
186+
// expected-not-opt-in-note @-2 4 {{type declared here}}
187187
}
188188
#endif
189189

@@ -642,6 +642,33 @@ public class PublicClassUser: ProtocolFromDirect {
642642
public var publicField: StructFromDirect
643643
// expected-error @-1 {{cannot use struct 'StructFromDirect' in a property declaration marked public or in a '@frozen' or '@usableFromInline' context; 'directs' has been imported as implementation-only}}
644644

645+
private var privateField: StructFromDirect
646+
private var a: ExposedLayoutPublic
647+
private var aa: ExposedLayoutInternal
648+
private var b: ExposedLayoutPrivate
649+
private var c: HiddenLayout
650+
651+
private var d: ExposedEnumPublic
652+
private var e: ExposedEnumPrivate
653+
private var f: HiddenEnum
654+
655+
private var g: ExposedProtocolPublic
656+
private var h: ExposedProtocolInternal
657+
private var i: ExposedProtocolPrivate
658+
private var j: HiddenProtocol
659+
660+
@export(interface)
661+
private func privateFunc(h: HiddenLayout) {}
662+
}
663+
664+
open class OpenClassUser: ProtocolFromDirect {
665+
// expected-error @-1 {{cannot use protocol 'ProtocolFromDirect' in a public or '@usableFromInline' conformance; 'directs' has been imported as implementation-only}}
666+
667+
public init() { fatalError() }
668+
669+
public var publicField: StructFromDirect
670+
// expected-error @-1 {{cannot use struct 'StructFromDirect' in a property declaration marked public or in a '@frozen' or '@usableFromInline' context; 'directs' has been imported as implementation-only}}
671+
645672
private var privateField: StructFromDirect
646673
// expected-opt-in-error @-1 {{cannot use struct 'StructFromDirect' in a property declaration member of a type not marked '@_implementationOnly'; 'directs' has been imported as implementation-only}}
647674
private var a: ExposedLayoutPublic
@@ -665,32 +692,67 @@ public class PublicClassUser: ProtocolFromDirect {
665692
private func privateFunc(h: HiddenLayout) {}
666693
}
667694

695+
@_fixed_layout
696+
public class FixedClassUser: ProtocolFromDirect {
697+
// expected-error @-1 {{cannot use protocol 'ProtocolFromDirect' in a public or '@usableFromInline' conformance; 'directs' has been imported as implementation-only}}
698+
699+
public init() { fatalError() }
700+
701+
public var publicField: StructFromDirect
702+
// expected-error @-1 {{cannot use struct 'StructFromDirect' in a property declaration marked public or in a '@frozen' or '@usableFromInline' context; 'directs' has been imported as implementation-only}}
703+
704+
private var privateField: StructFromDirect
705+
// expected-error @-1 {{cannot use struct 'StructFromDirect' in a property declaration marked public or in a '@frozen' or '@usableFromInline' context; 'directs' has been imported as implementation-only}}
706+
private var a: ExposedLayoutPublic
707+
private var aa: ExposedLayoutInternal
708+
// expected-error @-1 {{type referenced from a stored property in a '@frozen' struct must be '@usableFromInline' or public}}
709+
private var b: ExposedLayoutPrivate
710+
// expected-error @-1 {{type referenced from a stored property in a '@frozen' struct must be '@usableFromInline' or public}}
711+
private var c: HiddenLayout
712+
// expected-opt-in-error @-1 {{cannot use struct 'HiddenLayout' in a property declaration marked public or in a '@frozen' or '@usableFromInline' context; 'HiddenLayout' is marked '@_implementationOnly'}}
713+
// expected-error @-2 {{type referenced from a stored property in a '@frozen' struct must be '@usableFromInline' or public}}
714+
715+
private var d: ExposedEnumPublic
716+
private var e: ExposedEnumPrivate
717+
// expected-error @-1 {{type referenced from a stored property in a '@frozen' struct must be '@usableFromInline' or public}}
718+
private var f: HiddenEnum
719+
// expected-opt-in-error @-1 {{cannot use enum 'HiddenEnum' in a property declaration marked public or in a '@frozen' or '@usableFromInline' context; 'HiddenEnum' is marked '@_implementationOnly'}}
720+
// expected-error @-2 {{type referenced from a stored property in a '@frozen' struct must be '@usableFromInline' or public}}
721+
722+
private var g: ExposedProtocolPublic
723+
private var h: ExposedProtocolInternal
724+
// expected-error @-1 {{type referenced from a stored property in a '@frozen' struct must be '@usableFromInline' or public}}
725+
private var i: ExposedProtocolPrivate
726+
// expected-error @-1 {{type referenced from a stored property in a '@frozen' struct must be '@usableFromInline' or public}}
727+
private var j: HiddenProtocol
728+
// expected-opt-in-error @-1 {{cannot use protocol 'HiddenProtocol' in a property declaration marked public or in a '@frozen' or '@usableFromInline' context; 'HiddenProtocol' is marked '@_implementationOnly'}}
729+
// expected-error @-2 {{type referenced from a stored property in a '@frozen' struct must be '@usableFromInline' or public}}
730+
731+
@export(interface)
732+
private func privateFunc(h: HiddenLayout) {}
733+
}
734+
668735
internal class InternalClassUser: ProtocolFromDirect {
669736
// expected-opt-in-error @-1 {{cannot use protocol 'ProtocolFromDirect' in a public or '@usableFromInline' conformance; 'directs' has been imported as implementation-only}}
670737

671738
public init() { fatalError() }
672739

673740
public var publicField: StructFromDirect
674-
// expected-opt-in-error @-1 {{cannot use struct 'StructFromDirect' in a property declaration member of a type not marked '@_implementationOnly'; 'directs' has been imported as implementation-only}}
675741
private var privateField: StructFromDirect
676-
// expected-opt-in-error @-1 {{cannot use struct 'StructFromDirect' in a property declaration member of a type not marked '@_implementationOnly'; 'directs' has been imported as implementation-only}}
677742

678743
private var a: ExposedLayoutPublic
679744
private var aa: ExposedLayoutInternal
680745
private var b: ExposedLayoutPrivate
681746
private var c: HiddenLayout
682-
// expected-opt-in-error @-1 {{cannot use struct 'HiddenLayout' in a property declaration member of a type not marked '@_implementationOnly'; 'HiddenLayout' is marked '@_implementationOnly'}}
683747

684748
private var d: ExposedEnumPublic
685749
private var e: ExposedEnumPrivate
686750
private var f: HiddenEnum
687-
// expected-opt-in-error @-1 {{cannot use enum 'HiddenEnum' in a property declaration member of a type not marked '@_implementationOnly'; 'HiddenEnum' is marked '@_implementationOnly'}}
688751

689752
private var g: ExposedProtocolPublic
690753
private var h: ExposedProtocolInternal
691754
private var i: ExposedProtocolPrivate
692755
private var j: HiddenProtocol
693-
// expected-opt-in-error @-1 {{cannot use protocol 'HiddenProtocol' in a property declaration member of a type not marked '@_implementationOnly'; 'HiddenProtocol' is marked '@_implementationOnly'}}
694756

695757
private func privateFunc(h: HiddenLayout) {} // expected-embedded-opt-in-error {{struct 'HiddenLayout' cannot be used in an embedded function not marked '@export(interface)' because 'HiddenLayout' is marked '@_implementationOnly'}}
696758
}
@@ -701,26 +763,21 @@ private class PrivateClassUser: ProtocolFromDirect {
701763
public init() { fatalError() }
702764

703765
public var publicField: StructFromDirect
704-
// expected-opt-in-error @-1 {{cannot use struct 'StructFromDirect' in a property declaration member of a type not marked '@_implementationOnly'; 'directs' has been imported as implementation-only}}
705766
private var privateField: StructFromDirect
706-
// expected-opt-in-error @-1 {{cannot use struct 'StructFromDirect' in a property declaration member of a type not marked '@_implementationOnly'; 'directs' has been imported as implementation-only}}
707767

708768
private var a: ExposedLayoutPublic
709769
private var aa: ExposedLayoutInternal
710770
private var b: ExposedLayoutPrivate
711771
private var c: HiddenLayout
712-
// expected-opt-in-error @-1 {{cannot use struct 'HiddenLayout' in a property declaration member of a type not marked '@_implementationOnly'; 'HiddenLayout' is marked '@_implementationOnly'}}
713772

714773
private var d: ExposedEnumPublic
715774
private var e: ExposedEnumPrivate
716775
private var f: HiddenEnum
717-
// expected-opt-in-error @-1 {{cannot use enum 'HiddenEnum' in a property declaration member of a type not marked '@_implementationOnly'; 'HiddenEnum' is marked '@_implementationOnly'}}
718776

719777
private var g: ExposedProtocolPublic
720778
private var h: ExposedProtocolInternal
721779
private var i: ExposedProtocolPrivate
722780
private var j: HiddenProtocol
723-
// expected-opt-in-error @-1 {{cannot use protocol 'HiddenProtocol' in a property declaration member of a type not marked '@_implementationOnly'; 'HiddenProtocol' is marked '@_implementationOnly'}}
724781

725782
private func privateFunc(h: HiddenLayout) {} // expected-embedded-opt-in-error {{struct 'HiddenLayout' cannot be used in an embedded function not marked '@export(interface)' because 'HiddenLayout' is marked '@_implementationOnly'}}
726783
}

0 commit comments

Comments
 (0)