Skip to content

Commit 8503f72

Browse files
authored
Merge pull request swiftlang#76111 from tshortli/lazy-typecheck-lazy-var-in-inlinable-func
SILGen: Only skip decls nested in functions when the function is skipped
2 parents dfa60a1 + 185022c commit 8503f72

File tree

7 files changed

+51
-14
lines changed

7 files changed

+51
-14
lines changed

include/swift/AST/DeclContext.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,16 @@ class alignas(1 << DeclContextAlignInBits) DeclContext
496496
return const_cast<DeclContext *>(this)->getTopmostDeclarationDeclContext();
497497
}
498498

499+
/// This routine looks through closure, initializer, and local function
500+
/// contexts to find the outermost function declaration.
501+
///
502+
/// \returns the outermost function, or null if there is no such context.
503+
LLVM_READONLY
504+
DeclContext *getOutermostFunctionContext();
505+
const DeclContext *getOutermostFunctionContext() const {
506+
return const_cast<DeclContext *>(this)->getOutermostFunctionContext();
507+
}
508+
499509
/// Returns the innermost context that is an AbstractFunctionDecl whose
500510
/// body has been skipped.
501511
LLVM_READONLY

include/swift/AST/DeclExportabilityVisitor.h

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ class DeclExportabilityVisitor
3333
DeclExportabilityVisitor(){};
3434

3535
bool visit(const Decl *D) {
36+
// Declarations nested in fragile functions are exported.
37+
if (D->getDeclContext()->getFragileFunctionKind().kind !=
38+
FragileFunctionKind::None)
39+
return true;
40+
3641
if (auto value = dyn_cast<ValueDecl>(D)) {
3742
// A decl is exportable if it has a public access level.
3843
auto accessScope =
@@ -50,20 +55,6 @@ class DeclExportabilityVisitor
5055
bool visitDecl(const Decl *D) = delete;
5156
bool visitValueDecl(const ValueDecl *valueDecl) = delete;
5257

53-
bool visitAbstractFunctionDecl(const AbstractFunctionDecl *afd) {
54-
// If this function is nested within another function that is exportable to
55-
// clients then it is also exportable.
56-
auto dc = afd->getDeclContext();
57-
do {
58-
if (auto parent = dyn_cast<AbstractFunctionDecl>(dc)) {
59-
if (DeclExportabilityVisitor().visit(parent))
60-
return true;
61-
}
62-
} while ((dc = dc->getParent()));
63-
64-
return false;
65-
}
66-
6758
bool visitExtensionDecl(const ExtensionDecl *ext) {
6859
// Extensions must extend exportable types to be exportable.
6960
auto nominalType = ext->getExtendedNominal();
@@ -149,6 +140,7 @@ class DeclExportabilityVisitor
149140
DEFAULT_TO_ACCESS_LEVEL(TypeAlias);
150141
DEFAULT_TO_ACCESS_LEVEL(AssociatedType);
151142
DEFAULT_TO_ACCESS_LEVEL(AbstractStorage);
143+
DEFAULT_TO_ACCESS_LEVEL(AbstractFunction);
152144
DEFAULT_TO_ACCESS_LEVEL(Macro);
153145
DEFAULT_TO_ACCESS_LEVEL(EnumElement);
154146

lib/AST/DeclContext.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,22 @@ Decl *DeclContext::getTopmostDeclarationDeclContext() {
253253
return topmost;
254254
}
255255

256+
DeclContext *DeclContext::getOutermostFunctionContext() {
257+
AbstractFunctionDecl *result = nullptr;
258+
auto dc = this;
259+
do {
260+
if (auto afd = dyn_cast<AbstractFunctionDecl>(dc))
261+
result = afd;
262+
263+
// If we've found a non-local context, we don't have to keep walking up
264+
// the hierarchy.
265+
if (!dc->isLocalContext())
266+
break;
267+
} while ((dc = dc->getParent()));
268+
269+
return result;
270+
}
271+
256272
DeclContext *DeclContext::getInnermostSkippedFunctionContext() {
257273
auto dc = this;
258274
do {

lib/SILGen/SILGen.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,11 @@ bool SILGenModule::shouldSkipDecl(Decl *D) {
807807
if (!getASTContext().SILOpts.SkipNonExportableDecls)
808808
return false;
809809

810+
// Declarations nested in functions should be emitted whenever the function
811+
// containing them should also be emitted.
812+
if (auto funcContext = D->getDeclContext()->getOutermostFunctionContext())
813+
return shouldSkipDecl(funcContext->getAsDecl());
814+
810815
if (D->isExposedToClients())
811816
return false;
812817

test/Inputs/lazy_typecheck.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ public func publicFuncWithDefaultArg(_ x: Int = 1) -> Int {
2424
return NoTypecheck.int
2525
}
2626

27+
@inlinable public func publicInlinableFunc() -> Int {
28+
lazy var x = inlinableFunc()
29+
func nestedFunc() {}
30+
defer { nestedFunc() }
31+
return x
32+
}
33+
2734
package func packageFunc() -> Int {
2835
return NoTypecheck.int
2936
}

test/Inputs/lazy_typecheck_client.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ func testGlobalFunctions() {
1515
let _: Int = publicFunc()
1616
let _: Int = publicFuncReturnsTypealias()
1717
let _: Int = publicFuncWithDefaultArg()
18+
let _: Int = publicInlinableFunc()
1819
#if TEST_PACKAGE
1920
let _: Int = packageFunc()
2021
#endif

test/SILGen/skip_non_exportable_decls.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ internal func internalFunc() {}
2828
// CHECK-NO-SKIP: sil hidden{{.*}} @$s4Test022internalFuncWithNestedC0yyF : $@convention(thin) () -> () {
2929
// CHECK-SKIP-NOT: s4Test022internalFuncWithNestedC0yyF
3030
internal func internalFuncWithNestedFunc() {
31+
lazy var x = 1
3132
defer { internalFunc() }
3233
func nested() {}
3334
nested()
@@ -36,6 +37,9 @@ internal func internalFuncWithNestedFunc() {
3637
internalFunc()
3738
}()
3839
}
40+
// CHECK-NO-SKIP: sil private{{.*}} @$s4Test022internalFuncWithNestedC0yyF1xL_Sivg : $@convention(thin) (@guaranteed { var Optional<Int> }) -> Int
41+
// CHECK-SKIP-NOT: s4Test022internalFuncWithNestedC0yyF1xL_Sivg
42+
3943
// CHECK-NO-SKIP: sil private{{.*}} @$s4Test022internalFuncWithNestedC0yyF6$deferL_yyF : $@convention(thin) () -> () {
4044
// CHECK-SKIP-NOT: s4Test022internalFuncWithNestedC0yyF6$deferL_yyF
4145

@@ -53,10 +57,12 @@ public func publicFunc() {}
5357

5458
// CHECK: sil{{.*}} @$s4Test25publicFuncWithNestedFuncsyyF : $@convention(thin) () -> () {
5559
public func publicFuncWithNestedFuncs() {
60+
lazy var x = 1
5661
defer { publicFunc() }
5762
func nested() {}
5863
nested()
5964
}
65+
// CHECK: sil private{{.*}} @$s4Test25publicFuncWithNestedFuncsyyF1xL_Sivg : $@convention(thin) (@guaranteed { var Optional<Int> }) -> Int
6066
// CHECK: sil private{{.*}} @$s4Test25publicFuncWithNestedFuncsyyF6$deferL_yyF : $@convention(thin) () -> () {
6167
// CHECK: sil private{{.*}} @$s4Test25publicFuncWithNestedFuncsyyF6nestedL_yyF : $@convention(thin) () -> () {
6268

0 commit comments

Comments
 (0)