Skip to content

Commit 0dffe5c

Browse files
committed
Sema: Use VarDecl::isLayoutExposedToClients() when checking access in @Frozen structs
We require that all stored properties in a @Frozen struct have public or @usableFromInline types, even if the property itself is not public. This is so that clients can correctly generate code to manipulate the @Frozen struct. This check was only looking for bona-fide stored properties, and missing out looking at properties that have backing storage, namely 'lazy' properties and property wrappers.
1 parent 5f5372a commit 0dffe5c

File tree

2 files changed

+37
-28
lines changed

2 files changed

+37
-28
lines changed

lib/Sema/TypeCheckAccess.cpp

Lines changed: 15 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,29 +1051,25 @@ class UsableFromInlineChecker : public AccessControlCheckerBase,
10511051
UNINTERESTING(Accessor) // Handled by the Var or Subscript.
10521052
UNINTERESTING(OpaqueType) // Handled by the Var or Subscript.
10531053

1054-
/// If \p PBD declared stored instance properties in a fixed-contents struct,
1055-
/// return said struct.
1056-
static const StructDecl *
1057-
getFixedLayoutStructContext(const PatternBindingDecl *PBD) {
1058-
auto *parentStruct = dyn_cast<StructDecl>(PBD->getDeclContext());
1059-
if (!parentStruct)
1060-
return nullptr;
1061-
if (!(parentStruct->getAttrs().hasAttribute<FrozenAttr>() ||
1062-
parentStruct->getAttrs().hasAttribute<FixedLayoutAttr>()) ||
1063-
PBD->isStatic() || !PBD->hasStorage()) {
1064-
return nullptr;
1065-
}
1066-
// We don't check for "in resilient modules" because there's no reason to
1067-
// write '@_fixedLayout' on a struct in a non-resilient module.
1068-
return parentStruct;
1054+
/// If \p VD's layout is exposed by a @frozen struct, return said struct.
1055+
///
1056+
/// Stored instance properties in @frozen structs must always use
1057+
/// public/@usableFromInline types. In these cases, check the access against
1058+
/// the struct instead of the VarDecl, and customize the diagnostics.
1059+
static const ValueDecl *
1060+
getFixedLayoutStructContext(const VarDecl *VD) {
1061+
if (VD->isLayoutExposedToClients())
1062+
return dyn_cast<StructDecl>(VD->getDeclContext());
1063+
1064+
return nullptr;
10691065
}
10701066

10711067
/// \see visitPatternBindingDecl
10721068
void checkNamedPattern(const NamedPattern *NP,
1073-
const ValueDecl *fixedLayoutStructContext,
10741069
bool isTypeContext,
10751070
const llvm::DenseSet<const VarDecl *> &seenVars) {
10761071
const VarDecl *theVar = NP->getDecl();
1072+
auto *fixedLayoutStructContext = getFixedLayoutStructContext(theVar);
10771073
if (!fixedLayoutStructContext && shouldSkipChecking(theVar))
10781074
return;
10791075
// Only check individual variables if we didn't check an enclosing
@@ -1101,7 +1097,6 @@ class UsableFromInlineChecker : public AccessControlCheckerBase,
11011097

11021098
/// \see visitPatternBindingDecl
11031099
void checkTypedPattern(const TypedPattern *TP,
1104-
const ValueDecl *fixedLayoutStructContext,
11051100
bool isTypeContext,
11061101
llvm::DenseSet<const VarDecl *> &seenVars) {
11071102
// FIXME: We need an access level to check against, so we pull one out
@@ -1114,6 +1109,7 @@ class UsableFromInlineChecker : public AccessControlCheckerBase,
11141109
});
11151110
if (!anyVar)
11161111
return;
1112+
auto *fixedLayoutStructContext = getFixedLayoutStructContext(anyVar);
11171113
if (!fixedLayoutStructContext && shouldSkipChecking(anyVar))
11181114
return;
11191115

@@ -1154,27 +1150,18 @@ class UsableFromInlineChecker : public AccessControlCheckerBase,
11541150
void visitPatternBindingDecl(PatternBindingDecl *PBD) {
11551151
bool isTypeContext = PBD->getDeclContext()->isTypeContext();
11561152

1157-
// Stored instance properties in public/@usableFromInline fixed-contents
1158-
// structs in resilient modules must always use public/@usableFromInline
1159-
// types. In these cases, check the access against the struct instead of the
1160-
// VarDecl, and customize the diagnostics.
1161-
const ValueDecl *fixedLayoutStructContext =
1162-
getFixedLayoutStructContext(PBD);
1163-
11641153
llvm::DenseSet<const VarDecl *> seenVars;
11651154
for (auto idx : range(PBD->getNumPatternEntries())) {
11661155
PBD->getPattern(idx)->forEachNode([&](const Pattern *P) {
11671156
if (auto *NP = dyn_cast<NamedPattern>(P)) {
1168-
checkNamedPattern(NP, fixedLayoutStructContext, isTypeContext,
1169-
seenVars);
1157+
checkNamedPattern(NP, isTypeContext, seenVars);
11701158
return;
11711159
}
11721160

11731161
auto *TP = dyn_cast<TypedPattern>(P);
11741162
if (!TP)
11751163
return;
1176-
checkTypedPattern(TP, fixedLayoutStructContext, isTypeContext,
1177-
seenVars);
1164+
checkTypedPattern(TP, isTypeContext, seenVars);
11781165
});
11791166
seenVars.clear();
11801167
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %target-typecheck-verify-swift -swift-version 5
2+
3+
private class PrivateType {} // expected-note {{class 'PrivateType' is not '@usableFromInline' or public}}
4+
// expected-note@-1 {{initializer 'init()' is not '@usableFromInline' or public}}
5+
// expected-note@-2 {{type declared here}}
6+
7+
@propertyWrapper
8+
public struct Wrapper<T> {
9+
public init(wrappedValue: T) {}
10+
11+
public var wrappedValue: T { fatalError() }
12+
}
13+
14+
@frozen public struct UsesPrivateType {
15+
@Wrapper private var y1: PrivateType
16+
// expected-error@-1 {{type referenced from a stored property in a '@frozen' struct must be '@usableFromInline' or public}}
17+
18+
@Wrapper private var y2 = PrivateType()
19+
// expected-error@-1 {{class 'PrivateType' is private and cannot be referenced from a property initializer in a '@frozen' type}}
20+
// expected-error@-2 {{initializer 'init()' is private and cannot be referenced from a property initializer in a '@frozen' type}}
21+
// expected-error@-3 {{type referenced from a stored property with inferred type 'PrivateType' in a '@frozen' struct must be '@usableFromInline' or public}}
22+
}

0 commit comments

Comments
 (0)