Skip to content

Commit 67c6682

Browse files
committed
Sema: Compute and store captures for default argument expressions
1 parent 4dac0d1 commit 67c6682

File tree

4 files changed

+55
-24
lines changed

4 files changed

+55
-24
lines changed

include/swift/AST/Decl.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5164,6 +5164,7 @@ class ParamDecl : public VarDecl {
51645164
PointerUnion<Expr *, VarDecl *> DefaultArg;
51655165
Initializer *InitContext = nullptr;
51665166
StringRef StringRepresentation;
5167+
CaptureInfo Captures;
51675168
};
51685169

51695170
enum class Flags : uint8_t {
@@ -5249,6 +5250,13 @@ class ParamDecl : public VarDecl {
52495250

52505251
void setDefaultArgumentInitContext(Initializer *initContext);
52515252

5253+
const CaptureInfo &getDefaultArgumentCaptureInfo() const {
5254+
assert(DefaultValueAndFlags.getPointer());
5255+
return DefaultValueAndFlags.getPointer()->Captures;
5256+
}
5257+
5258+
void setDefaultArgumentCaptureInfo(const CaptureInfo &captures);
5259+
52525260
/// Extracts the text of the default argument attached to the provided
52535261
/// ParamDecl, removing all inactive #if clauses and providing only the
52545262
/// text of active #if clauses.

lib/AST/Decl.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5866,6 +5866,11 @@ void ParamDecl::setDefaultArgumentInitContext(Initializer *initContext) {
58665866
DefaultValueAndFlags.getPointer()->InitContext = initContext;
58675867
}
58685868

5869+
void ParamDecl::setDefaultArgumentCaptureInfo(const CaptureInfo &captures) {
5870+
assert(DefaultValueAndFlags.getPointer());
5871+
DefaultValueAndFlags.getPointer()->Captures = captures;
5872+
}
5873+
58695874
/// Return nullptr if there is no property wrapper
58705875
Expr *swift::findOriginalPropertyWrapperInitialValue(VarDecl *var,
58715876
Expr *init) {

lib/Sema/TypeCheckCaptures.cpp

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -325,11 +325,8 @@ class FindCapturedVars : public ASTWalker {
325325
return { false, DRE };
326326
}
327327

328-
void propagateCaptures(AnyFunctionRef innerClosure, SourceLoc captureLoc) {
329-
TypeChecker::computeCaptures(innerClosure);
330-
331-
auto &captureInfo = innerClosure.getCaptureInfo();
332-
328+
void propagateCaptures(const CaptureInfo &captureInfo,
329+
SourceLoc loc) {
333330
for (auto capture : captureInfo.getCaptures()) {
334331
// If the decl was captured from us, it isn't captured *by* us.
335332
if (capture.getDecl()->getDeclContext() == CurDC)
@@ -347,18 +344,19 @@ class FindCapturedVars : public ASTWalker {
347344
if (!NoEscape)
348345
Flags &= ~CapturedValue::IsNoEscape;
349346

350-
addCapture(CapturedValue(capture.getDecl(), Flags, captureLoc));
347+
addCapture(CapturedValue(capture.getDecl(), Flags, capture.getLoc()));
351348
}
352349

353350
if (GenericParamCaptureLoc.isInvalid())
354351
if (captureInfo.hasGenericParamCaptures())
355-
GenericParamCaptureLoc = innerClosure.getLoc();
352+
GenericParamCaptureLoc = loc;
356353

357-
if (DynamicSelfCaptureLoc.isInvalid())
354+
if (DynamicSelfCaptureLoc.isInvalid()) {
358355
if (captureInfo.hasDynamicSelfCapture()) {
359-
DynamicSelfCaptureLoc = innerClosure.getLoc();
356+
DynamicSelfCaptureLoc = loc;
360357
DynamicSelf = captureInfo.getDynamicSelfType();
361358
}
359+
}
362360

363361
if (!OpaqueValue) {
364362
if (captureInfo.hasOpaqueValueCapture())
@@ -368,13 +366,13 @@ class FindCapturedVars : public ASTWalker {
368366

369367
bool walkToDeclPre(Decl *D) override {
370368
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(D)) {
371-
propagateCaptures(AFD, AFD->getLoc());
369+
TypeChecker::computeCaptures(AFD);
370+
propagateCaptures(AFD->getCaptureInfo(), AFD->getLoc());
372371

373-
// Can default parameter initializers capture state? That seems like
374-
// a really bad idea.
375-
for (auto *param : *AFD->getParameters())
376-
if (auto E = param->getDefaultValue())
377-
E->walk(*this);
372+
for (auto *P : *AFD->getParameters())
373+
if (P->getDefaultValue())
374+
propagateCaptures(P->getDefaultArgumentCaptureInfo(),
375+
P->getLoc());
378376

379377
return false;
380378
}
@@ -569,7 +567,8 @@ class FindCapturedVars : public ASTWalker {
569567
// list computed; we just propagate it, filtering out stuff that they
570568
// capture from us.
571569
if (auto *SubCE = dyn_cast<AbstractClosureExpr>(E)) {
572-
propagateCaptures(SubCE, SubCE->getStartLoc());
570+
TypeChecker::computeCaptures(SubCE);
571+
propagateCaptures(SubCE->getCaptureInfo(), SubCE->getLoc());
573572
return { false, E };
574573
}
575574

@@ -609,17 +608,36 @@ void TypeChecker::computeCaptures(AnyFunctionRef AFR) {
609608
finder.checkType(AFR.getType(), AFR.getLoc());
610609
}
611610

612-
auto captures = finder.getCaptureInfo();
613-
614611
// A generic function always captures outer generic parameters.
612+
bool isGeneric = false;
615613
auto *AFD = AFR.getAbstractFunctionDecl();
616-
if (AFD) {
617-
if (AFD->getGenericParams())
618-
captures.setGenericParamCaptures(true);
619-
}
614+
if (AFD)
615+
isGeneric = AFD->isGeneric();
620616

617+
auto captures = finder.getCaptureInfo();
618+
if (isGeneric)
619+
captures.setGenericParamCaptures(true);
621620
AFR.setCaptureInfo(captures);
622621

622+
// Compute captures for default argument expressions.
623+
if (auto *AFD = AFR.getAbstractFunctionDecl()) {
624+
for (auto *P : *AFD->getParameters()) {
625+
if (auto E = P->getDefaultValue()) {
626+
FindCapturedVars finder(Context,
627+
E->getLoc(),
628+
AFD,
629+
/*isNoEscape=*/false,
630+
/*isObjC=*/false);
631+
E->walk(finder);
632+
633+
auto captures = finder.getCaptureInfo();
634+
if (isGeneric)
635+
captures.setGenericParamCaptures(true);
636+
P->setDefaultArgumentCaptureInfo(captures);
637+
}
638+
}
639+
}
640+
623641
// Extensions of generic ObjC functions can't use generic parameters from
624642
// their context.
625643
if (AFD && finder.getGenericParamCaptureLoc().isValid()) {

test/SILGen/capture_order.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,10 +192,10 @@ class rdar40600800 {
192192
}
193193

194194
func innerFunction() {
195-
let closure = { // expected-note {{captured here}}
195+
let closure = {
196196
// FIXME: Bogus warning!
197197
// expected-warning@-2 {{initialization of immutable value 'closure' was never used; consider replacing with assignment to '_' or removing it}}
198-
callback()
198+
callback() // expected-note {{captured here}}
199199
}
200200
}
201201
}

0 commit comments

Comments
 (0)