Skip to content

Commit aa208bb

Browse files
committed
Add SILType::containsNoEscapeFunction()
Add PartialApplyInst.hasNoescapeCapture Add PartialApplyInst.mayEscape Refactor DiagnoseInvalidEscapingCaptures. This may change functionality because tuples containing a noescape closure are now correctly recognized. Although I'm not sure such tupes can ever be captured directly.
1 parent 6b3d62c commit aa208bb

File tree

11 files changed

+44
-24
lines changed

11 files changed

+44
-24
lines changed

SwiftCompilerSources/Sources/Optimizer/Utilities/AddressUtils.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,10 @@ extension AddressUseVisitor {
107107
// A potentially escaping value depends on this address.
108108
return escapingAddressUse(of: operand)
109109

110-
case let pai as PartialApplyInst where pai.isOnStack:
110+
case let pai as PartialApplyInst where !pai.mayEscape:
111111
return dependentAddressUse(of: operand, into: pai)
112112

113-
case let pai as PartialApplyInst where !pai.isOnStack:
113+
case let pai as PartialApplyInst where pai.mayEscape:
114114
return escapingAddressUse(of: operand)
115115

116116
case is ReturnInst, is ThrowInst, is YieldInst, is AddressToPointerInst:

SwiftCompilerSources/Sources/Optimizer/Utilities/BorrowUtils.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ enum BorrowingInstruction : CustomStringConvertible, Hashable {
169169
self = .storeBorrow(sbi)
170170
case let bai as BeginApplyInst:
171171
self = .beginApply(bai)
172-
case let pai as PartialApplyInst where pai.isOnStack:
172+
case let pai as PartialApplyInst where !pai.mayEscape:
173173
self = .partialApply(pai)
174174
case let mdi as MarkDependenceInst:
175175
self = .markDependence(mdi)

SwiftCompilerSources/Sources/Optimizer/Utilities/ForwardingUtils.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ struct NonEscapingClosureDefUseWalker {
355355
}
356356

357357
mutating func walkDown(closure: PartialApplyInst) -> WalkResult {
358-
assert(closure.isOnStack)
358+
assert(!closure.mayEscape)
359359
return walkDownUses(of: closure, using: nil)
360360
}
361361

SwiftCompilerSources/Sources/Optimizer/Utilities/LocalVariableUtils.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ extension LocalVariableAccessWalker: AddressUseVisitor {
416416

417417
mutating func dependentAddressUse(of operand: Operand, into value: Value) -> WalkResult {
418418
// Find all uses of partial_apply [on_stack].
419-
if let pai = value as? PartialApplyInst, pai.isOnStack {
419+
if let pai = value as? PartialApplyInst, !pai.mayEscape {
420420
var walker = NonEscapingClosureDefUseWalker(context)
421421
defer { walker.deinitialize() }
422422
if walker.walkDown(closure: pai) == .abortWalk {

SwiftCompilerSources/Sources/Optimizer/Utilities/OwnershipLiveness.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ extension OwnershipUseVisitor {
388388
-> WalkResult {
389389
switch operand.instruction {
390390
case let pai as PartialApplyInst:
391-
assert(pai.isOnStack)
391+
assert(!pai.mayEscape)
392392
return dependentUse(of: operand, into: pai)
393393
case let mdi as MarkDependenceInst:
394394
assert(operand == mdi.baseOperand && mdi.isNonEscaping)

SwiftCompilerSources/Sources/SIL/Instruction.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,7 +1011,21 @@ class ClassifyBridgeObjectInst : SingleValueInstruction, UnaryInstruction {}
10111011

10121012
final public class PartialApplyInst : SingleValueInstruction, ApplySite {
10131013
public var numArguments: Int { bridged.PartialApplyInst_numArguments() }
1014+
1015+
/// WARNING: isOnStack incorrectly returns false for all closures prior to ClosureLifetimeFixup, even if they need to
1016+
/// be diagnosed as on-stack closures. Use has mayEscape instead.
10141017
public var isOnStack: Bool { bridged.PartialApplyInst_isOnStack() }
1018+
1019+
public var mayEscape: Bool { !isOnStack && !hasNoescapeCapture }
1020+
1021+
/// True if this closure captures anything nonescaping.
1022+
public var hasNoescapeCapture: Bool {
1023+
if operandConventions.contains(.indirectInoutAliasable) {
1024+
return true
1025+
}
1026+
return arguments.contains { $0.type.containsNoEscapeFunction }
1027+
}
1028+
10151029
public var unappliedArgumentCount: Int { bridged.PartialApply_getCalleeArgIndexOfFirstAppliedArg() }
10161030
}
10171031

SwiftCompilerSources/Sources/SIL/Type.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ public struct Type : CustomStringConvertible, NoReflectionChildren {
5757
public var isFunction: Bool { bridged.isFunction() }
5858
public var isMetatype: Bool { bridged.isMetatype() }
5959
public var isNoEscapeFunction: Bool { bridged.isNoEscapeFunction() }
60+
public var containsNoEscapeFunction: Bool { bridged.containsNoEscapeFunction() }
6061
public var isAsyncFunction: Bool { bridged.isAsyncFunction() }
6162

6263
public var canBeClass: BridgedType.TraitResult { bridged.canBeClass() }

include/swift/SIL/SILBridging.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,7 @@ struct BridgedType {
346346
BRIDGED_INLINE bool isFunction() const;
347347
BRIDGED_INLINE bool isMetatype() const;
348348
BRIDGED_INLINE bool isNoEscapeFunction() const;
349+
BRIDGED_INLINE bool containsNoEscapeFunction() const;
349350
BRIDGED_INLINE bool isAsyncFunction() const;
350351
BRIDGED_INLINE bool isEmpty(BridgedFunction f) const;
351352
BRIDGED_INLINE TraitResult canBeClass() const;

include/swift/SIL/SILBridgingImpl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,10 @@ bool BridgedType::isNoEscapeFunction() const {
258258
return unbridged().isNoEscapeFunction();
259259
}
260260

261+
bool BridgedType::containsNoEscapeFunction() const {
262+
return unbridged().containsNoEscapeFunction();
263+
}
264+
261265
bool BridgedType::isAsyncFunction() const {
262266
return unbridged().isAsyncFunction();
263267
}

include/swift/SIL/SILType.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,22 @@ class SILType {
534534
return false;
535535
}
536536

537+
bool containsNoEscapeFunction() const {
538+
auto ty = getASTType();
539+
if (auto *fTy = ty->getAs<SILFunctionType>()) {
540+
return fTy->isNoEscape();
541+
}
542+
// Look through box types to handle mutable 'var' bindings.
543+
if (auto boxType = dyn_cast<SILBoxType>(ty)) {
544+
for (auto field : boxType->getLayout()->getFields()) {
545+
if (field.getLoweredType()->isNoEscape())
546+
return true;
547+
}
548+
}
549+
// Handle whatever AST types are known to hold functions. Namely tuples.
550+
return ty->isNoEscape();
551+
}
552+
537553
bool isAsyncFunction() const {
538554
if (auto *fTy = getASTType()->getAs<SILFunctionType>()) {
539555
return fTy->isAsync();

lib/SILOptimizer/Mandatory/DiagnoseInvalidEscapingCaptures.cpp

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -336,22 +336,6 @@ static void diagnoseCaptureLoc(ASTContext &Context, DeclContext *DC,
336336
}
337337
}
338338

339-
static bool isNonEscapingFunctionValue(SILValue value) {
340-
auto type = value->getType().getASTType();
341-
342-
// Look through box types to handle mutable 'var' bindings.
343-
if (auto boxType = dyn_cast<SILBoxType>(type)) {
344-
for (auto field : boxType->getLayout()->getFields()) {
345-
if (field.getLoweredType()->isNoEscape())
346-
return true;
347-
}
348-
349-
return false;
350-
}
351-
352-
return type->isNoEscape();
353-
}
354-
355339
// Diagnose this partial_apply if it captures a non-escaping value and has
356340
// an escaping use.
357341
static void checkPartialApply(ASTContext &Context, DeclContext *DC,
@@ -379,7 +363,7 @@ static void checkPartialApply(ASTContext &Context, DeclContext *DC,
379363

380364
// Captures of noescape function types or tuples containing noescape
381365
// function types cannot escape.
382-
if (isNonEscapingFunctionValue(value))
366+
if (value->getType().containsNoEscapeFunction())
383367
noEscapeCaptures.push_back(&oper);
384368
}
385369

@@ -501,7 +485,7 @@ static void checkPartialApply(ASTContext &Context, DeclContext *DC,
501485
static void checkApply(ASTContext &Context, FullApplySite site) {
502486
auto isNoEscapeParam = [&](SILValue value) -> const ParamDecl * {
503487
// If the value is an escaping, do not enforce any restrictions.
504-
if (!isNonEscapingFunctionValue(value))
488+
if (!value->getType().containsNoEscapeFunction())
505489
return nullptr;
506490

507491
// If the value is not a function parameter, do not enforce any restrictions.

0 commit comments

Comments
 (0)