Skip to content

Commit db59dc1

Browse files
committed
Sema: Split off checkPatternBindingCaptures() from computeCaptures()
Store the captures for each stored property initializer separately, instead of incorporating them into the capture list of each designated initializer. Fixes <rdar://problem/41490541>
1 parent aa6a55d commit db59dc1

File tree

6 files changed

+71
-36
lines changed

6 files changed

+71
-36
lines changed

include/swift/AST/Decl.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1931,6 +1931,9 @@ class PatternBindingEntry {
19311931
/// The initializer context used for this pattern binding entry.
19321932
llvm::PointerIntPair<DeclContext *, 1, bool> InitContextAndIsText;
19331933

1934+
/// Values captured by this initializer.
1935+
CaptureInfo Captures;
1936+
19341937
friend class PatternBindingInitializer;
19351938

19361939
public:
@@ -2024,6 +2027,9 @@ class PatternBindingEntry {
20242027
/// \param omitAccessors Whether the computation should omit the accessors
20252028
/// from the source range.
20262029
SourceRange getSourceRange(bool omitAccessors = false) const;
2030+
2031+
const CaptureInfo &getCaptureInfo() const { return Captures; }
2032+
void setCaptureInfo(const CaptureInfo &captures) { Captures = captures; }
20272033
};
20282034

20292035
/// This decl contains a pattern and optional initializer for a set
@@ -2121,6 +2127,18 @@ class PatternBindingDecl final : public Decl,
21212127

21222128
void setPattern(unsigned i, Pattern *Pat, DeclContext *InitContext);
21232129

2130+
DeclContext *getInitContext(unsigned i) const {
2131+
return getPatternList()[i].getInitContext();
2132+
}
2133+
2134+
const CaptureInfo &getCaptureInfo(unsigned i) const {
2135+
return getPatternList()[i].getCaptureInfo();
2136+
}
2137+
2138+
void setCaptureInfo(unsigned i, const CaptureInfo &captures) {
2139+
getMutablePatternList()[i].setCaptureInfo(captures);
2140+
}
2141+
21242142
/// Given that this PBD is the parent pattern for the specified VarDecl,
21252143
/// return the entry of the VarDecl in our PatternList. For example, in:
21262144
///

lib/SILGen/SILGen.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,7 @@ emitStoredPropertyInitialization(PatternBindingDecl *pbd, unsigned i) {
11321132
auto *var = pbdEntry.getAnchoringVarDecl();
11331133
auto *init = pbdEntry.getInit();
11341134
auto *initDC = pbdEntry.getInitContext();
1135+
auto &captureInfo = pbdEntry.getCaptureInfo();
11351136
assert(!pbdEntry.isInitializerSubsumed());
11361137

11371138
// If this is the backing storage for a property with an attached wrapper
@@ -1148,12 +1149,23 @@ emitStoredPropertyInitialization(PatternBindingDecl *pbd, unsigned i) {
11481149

11491150
SILDeclRef constant(var, SILDeclRef::Kind::StoredPropertyInitializer);
11501151
emitOrDelayFunction(*this, constant,
1151-
[this,constant,init,initDC](SILFunction *f) {
1152+
[this,var,captureInfo,constant,init,initDC](SILFunction *f) {
11521153
preEmitFunction(constant, init, f, init);
11531154
PrettyStackTraceSILFunction X("silgen emitStoredPropertyInitialization", f);
11541155
f->createProfiler(init, constant, ForDefinition);
1155-
SILGenFunction(*this, *f, initDC)
1156-
.emitGeneratorFunction(constant, init, /*EmitProfilerIncrement=*/true);
1156+
SILGenFunction SGF(*this, *f, initDC);
1157+
1158+
// If this is a stored property initializer inside a type at global scope,
1159+
// it may close over a global variable. If we're emitting top-level code,
1160+
// then emit a "mark_function_escape" that lists the captured global
1161+
// variables so that definite initialization can reason about this
1162+
// escape point.
1163+
if (!var->getDeclContext()->isLocalContext() &&
1164+
TopLevelSGF && TopLevelSGF->B.hasValidInsertionPoint()) {
1165+
emitMarkFunctionEscapeForTopLevelCodeGlobals(var, captureInfo);
1166+
}
1167+
1168+
SGF.emitGeneratorFunction(constant, init, /*EmitProfilerIncrement=*/true);
11571169
postEmitFunction(constant, f);
11581170
});
11591171
}

lib/Sema/TypeCheckCaptures.cpp

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -627,37 +627,12 @@ void TypeChecker::computeCaptures(AnyFunctionRef AFR) {
627627
AFR.getAsDeclContext(),
628628
AFR.isKnownNoEscape(),
629629
AFR.isObjC());
630-
if (AFR.getBody())
631-
AFR.getBody()->walk(finder);
630+
AFR.getBody()->walk(finder);
632631

633632
if (AFR.hasType() && !AFR.isObjC()) {
634633
finder.checkType(AFR.getType(), AFR.getLoc());
635634
}
636635

637-
// If this is an init(), explicitly walk the initializer values for members of
638-
// the type. They will be implicitly emitted by SILGen into the generated
639-
// initializer.
640-
if (auto CD =
641-
dyn_cast_or_null<ConstructorDecl>(AFR.getAbstractFunctionDecl())) {
642-
auto *typeDecl = dyn_cast<NominalTypeDecl>(CD->getDeclContext());
643-
if (typeDecl && CD->isDesignatedInit()) {
644-
for (auto member : typeDecl->getMembers()) {
645-
// Ignore everything other than PBDs.
646-
auto *PBD = dyn_cast<PatternBindingDecl>(member);
647-
if (!PBD) continue;
648-
// Walk the initializers for all properties declared in the type with
649-
// an initializer.
650-
for (auto &elt : PBD->getPatternList()) {
651-
if (elt.isInitializerSubsumed())
652-
continue;
653-
654-
if (auto *init = elt.getInit())
655-
init->walk(finder);
656-
}
657-
}
658-
}
659-
}
660-
661636
auto captures = finder.getCaptureInfo();
662637

663638
// A generic function always captures outer generic parameters.
@@ -700,3 +675,31 @@ void TypeChecker::computeCaptures(AnyFunctionRef AFR) {
700675
for (auto *expr : cFunctionPointers->second)
701676
maybeDiagnoseCaptures(expr, AFR);
702677
}
678+
679+
void TypeChecker::checkPatternBindingCaptures(NominalTypeDecl *typeDecl) {
680+
for (auto member : typeDecl->getMembers()) {
681+
// Ignore everything other than PBDs.
682+
auto *PBD = dyn_cast<PatternBindingDecl>(member);
683+
if (!PBD) continue;
684+
// Walk the initializers for all properties declared in the type with
685+
// an initializer.
686+
for (unsigned i = 0, e = PBD->getNumPatternEntries(); i < e; ++i) {
687+
if (PBD->isInitializerSubsumed(i))
688+
continue;
689+
690+
auto *init = PBD->getInit(i);
691+
if (init == nullptr)
692+
continue;
693+
694+
FindCapturedVars finder(*this,
695+
init->getLoc(),
696+
PBD->getInitContext(i),
697+
/*NoEscape=*/false,
698+
/*ObjC=*/false);
699+
init->walk(finder);
700+
701+
auto captures = finder.getCaptureInfo();
702+
PBD->setCaptureInfo(i, captures);
703+
}
704+
}
705+
}

lib/Sema/TypeCheckDecl.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2829,6 +2829,8 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
28292829
for (Decl *Member : SD->getMembers())
28302830
visit(Member);
28312831

2832+
TC.checkPatternBindingCaptures(SD);
2833+
28322834
TC.checkDeclAttributes(SD);
28332835

28342836
checkInheritanceClause(SD);
@@ -2955,6 +2957,8 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
29552957
visit(Member);
29562958
}
29572959

2960+
TC.checkPatternBindingCaptures(CD);
2961+
29582962
// If this class requires all of its stored properties to have
29592963
// in-class initializers, diagnose this now.
29602964
if (CD->requiresStoredPropertyInits())
@@ -5644,10 +5648,6 @@ void TypeChecker::defineDefaultConstructor(NominalTypeDecl *decl) {
56445648
stmts.push_back(new (Context) ReturnStmt(decl->getLoc(), nullptr));
56455649
ctor->setBody(BraceStmt::create(Context, SourceLoc(), stmts, SourceLoc()));
56465650
ctor->setBodyTypeCheckedIfPresent();
5647-
5648-
// FIXME: This is still needed so that DI can check captures for
5649-
// initializer expressions. Rethink that completely.
5650-
Context.addSynthesizedDecl(ctor);
56515651
}
56525652

56535653
static void validateAttributes(TypeChecker &TC, Decl *D) {

lib/Sema/TypeChecker.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1441,6 +1441,9 @@ class TypeChecker final : public LazyResolver {
14411441
/// Compute the set of captures for the given function or closure.
14421442
void computeCaptures(AnyFunctionRef AFR);
14431443

1444+
/// Check for invalid captures from stored property initializers.
1445+
void checkPatternBindingCaptures(NominalTypeDecl *typeDecl);
1446+
14441447
/// Change the context of closures in the given initializer
14451448
/// expression to the given context.
14461449
///

test/SILOptimizer/definite_init_diagnostics_globals.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,8 @@ var w: String // expected-note {{variable defined here}}
6060
// expected-note@-1 {{variable defined here}}
6161
// expected-note@-2 {{variable defined here}}
6262

63-
// FIXME: the error should blame the class definition: <rdar://41490541>.
64-
class TestClass1 { // expected-error {{variable 'w' used by function definition before being initialized}}
65-
let fld = w
63+
class TestClass1 {
64+
let fld = w // expected-error {{variable 'w' used by function definition before being initialized}}
6665
}
6766

6867
class TestClass2 {

0 commit comments

Comments
 (0)