Skip to content

Commit b3dadc8

Browse files
committed
AST: Use VarDecl::isInitExposedToClients() from DeclContext::getFragileFunctionKind()
getFragileFunctionKind() would report that all initializers in non-resilient public types were inlinable, including static properties. This was later patched by VarDecl::isInitExposedToClients(), which was checked in diagnoseInlinableDeclRefAccess(). However, the latter function only looked at the innermost DeclContexts, not all parent contexts, so it would incorrectly diagnose code with a nested DeclContext inside of a static property initializer. Fix this by changing getFragileFunctionKind() to call isInitExposedToClients() and simplifying diagnoseInlinableDeclRefAccess(). This commit also introduces a new isLayoutExposedToClients() method, which is similar to isInitExposedToClients(), except it also returns 'true' if the property does not have an initializer (and in fact the latter is implemented in terms of the former).
1 parent 0f27312 commit b3dadc8

File tree

5 files changed

+52
-27
lines changed

5 files changed

+52
-27
lines changed

include/swift/AST/Decl.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4763,11 +4763,19 @@ class VarDecl : public AbstractStorageDecl {
47634763

47644764
/// Determines if this var has an initializer expression that should be
47654765
/// exposed to clients.
4766+
///
47664767
/// There's a very narrow case when we would: if the decl is an instance
47674768
/// member with an initializer expression and the parent type is
47684769
/// @frozen and resides in a resilient module.
47694770
bool isInitExposedToClients() const;
4770-
4771+
4772+
/// Determines if this var is exposed as part of the layout of a
4773+
/// @frozen struct.
4774+
///
4775+
/// From the standpoint of access control and exportability checking, this
4776+
/// var will behave as if it was public, even if it is internal or private.
4777+
bool isLayoutExposedToClients() const;
4778+
47714779
/// Is this a special debugger variable?
47724780
bool isDebuggerVar() const { return Bits.VarDecl.IsDebuggerVar; }
47734781
void setDebuggerVar(bool IsDebuggerVar) {

lib/AST/Decl.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1582,12 +1582,27 @@ VarDecl *PatternBindingDecl::getAnchoringVarDecl(unsigned i) const {
15821582
}
15831583

15841584
bool VarDecl::isInitExposedToClients() const {
1585+
return hasInitialValue() && isLayoutExposedToClients();
1586+
}
1587+
1588+
bool VarDecl::isLayoutExposedToClients() const {
15851589
auto parent = dyn_cast<NominalTypeDecl>(getDeclContext());
15861590
if (!parent) return false;
1587-
if (!hasInitialValue()) return false;
15881591
if (isStatic()) return false;
1589-
return parent->getAttrs().hasAttribute<FrozenAttr>() ||
1590-
parent->getAttrs().hasAttribute<FixedLayoutAttr>();
1592+
1593+
if (!hasStorage() &&
1594+
!getAttrs().hasAttribute<LazyAttr>() &&
1595+
!hasAttachedPropertyWrapper()) {
1596+
return false;
1597+
}
1598+
1599+
auto nominalAccess =
1600+
parent->getFormalAccessScope(/*useDC=*/nullptr,
1601+
/*treatUsableFromInlineAsPublic=*/true);
1602+
if (!nominalAccess.isPublic()) return false;
1603+
1604+
return (parent->getAttrs().hasAttribute<FrozenAttr>() ||
1605+
parent->getAttrs().hasAttribute<FixedLayoutAttr>());
15911606
}
15921607

15931608
/// Check whether the given type representation will be

lib/AST/DeclContext.cpp

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -368,21 +368,17 @@ swift::FragileFunctionKindRequest::evaluate(Evaluator &evaluator,
368368

369369
// Stored property initializer contexts use minimal resilience expansion
370370
// if the type is formally fixed layout.
371-
if (isa<PatternBindingInitializer>(dc)) {
372-
if (auto *NTD = dyn_cast<NominalTypeDecl>(dc->getParent())) {
373-
auto nominalAccess =
374-
NTD->getFormalAccessScope(/*useDC=*/nullptr,
375-
/*treatUsableFromInlineAsPublic=*/true);
376-
if (!nominalAccess.isPublic())
377-
return {FragileFunctionKind::None,
378-
/*allowUsableFromInline=*/false};
379-
380-
if (NTD->isFormallyResilient())
381-
return {FragileFunctionKind::None,
382-
/*allowUsableFromInline=*/false};
383-
384-
return {FragileFunctionKind::PropertyInitializer, true};
371+
if (auto *init = dyn_cast <PatternBindingInitializer>(dc)) {
372+
auto bindingIndex = init->getBindingIndex();
373+
if (auto *varDecl = init->getBinding()->getAnchoringVarDecl(bindingIndex)) {
374+
if (varDecl->isInitExposedToClients()) {
375+
return {FragileFunctionKind::PropertyInitializer,
376+
/*allowUsableFromInline=*/true};
377+
}
385378
}
379+
380+
return {FragileFunctionKind::None,
381+
/*allowUsableFromInline=*/false};
386382
}
387383

388384
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(dc)) {
@@ -434,7 +430,8 @@ swift::FragileFunctionKindRequest::evaluate(Evaluator &evaluator,
434430
}
435431
}
436432

437-
return {FragileFunctionKind::None, false};
433+
return {FragileFunctionKind::None,
434+
/*allowUsableFromInline=*/false};
438435
}
439436

440437
/// Determine whether the innermost context is generic.

lib/Sema/ResilienceDiagnostics.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,6 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc,
5656
return false;
5757
}
5858

59-
// Property initializers that are not exposed to clients are OK.
60-
if (auto pattern = dyn_cast<PatternBindingInitializer>(DC)) {
61-
auto bindingIndex = pattern->getBindingIndex();
62-
auto *varDecl = pattern->getBinding()->getAnchoringVarDecl(bindingIndex);
63-
if (!varDecl->isInitExposedToClients())
64-
return false;
65-
}
66-
6759
DowngradeToWarning downgradeToWarning = DowngradeToWarning::No;
6860

6961
// Swift 4.2 did not perform any checks for type aliases.

test/attr/attr_inlinable.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,8 +275,21 @@ internal func internalIntReturningFunc() -> Int { return 0 }
275275
public struct PublicFixedStructWithInit {
276276
var x = internalGlobal // expected-error {{let 'internalGlobal' is internal and cannot be referenced from a property initializer in a '@frozen' type}}
277277
var y = publicGlobal // OK
278+
279+
// Static property initializers are not inlinable contexts.
278280
static var z = privateIntReturningFunc() // OK
279281
static var a = internalIntReturningFunc() // OK
282+
283+
// Test the same with a multi-statement closure, which introduces a
284+
// new DeclContext.
285+
static var zz: Int = {
286+
let x = privateIntReturningFunc()
287+
return x
288+
}()
289+
static var aa: Int = {
290+
let x = internalIntReturningFunc()
291+
return x
292+
}()
280293
}
281294

282295
public struct KeypathStruct {

0 commit comments

Comments
 (0)