Skip to content

Commit 9690397

Browse files
committed
[CoroutineAccessors] Unwind based on feature.
Now that coroutine kind (and consequently ABI) for the accessors is keyed off a SIL option, it's no longer possible to read whether a given SILFunction arose from a read/modify coroutine just by checking its coroutine kind. Regardless of ABI, read/modify coroutines may only unwind (i.e. are only permitted not to "run to completion") if the relevant experimental (soon to be deleted) feature is enabled.
1 parent 77055a5 commit 9690397

File tree

7 files changed

+132
-30
lines changed

7 files changed

+132
-30
lines changed

lib/SILGen/SILGenApply.cpp

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5000,14 +5000,16 @@ class CallEmission {
50005000
FormalEvaluationScope initialWritebackScope;
50015001
std::optional<ActorIsolation> implicitActorHopTarget;
50025002
bool implicitlyThrows;
5003+
bool canUnwind;
50035004

50045005
public:
50055006
/// Create an emission for a call of the given callee.
50065007
CallEmission(SILGenFunction &SGF, Callee &&callee,
50075008
FormalEvaluationScope &&writebackScope)
50085009
: SGF(SGF), callee(std::move(callee)),
50095010
initialWritebackScope(std::move(writebackScope)),
5010-
implicitActorHopTarget(std::nullopt), implicitlyThrows(false) {}
5011+
implicitActorHopTarget(std::nullopt), implicitlyThrows(false),
5012+
canUnwind(false) {}
50115013

50125014
/// A factory method for decomposing the apply expr \p e into a call
50135015
/// emission.
@@ -5058,6 +5060,8 @@ class CallEmission {
50585060
/// function can throw or not.
50595061
void setImplicitlyThrows(bool flag) { implicitlyThrows = flag; }
50605062

5063+
void setCanUnwind(bool flag) { canUnwind = flag; }
5064+
50615065
CleanupHandle applyCoroutine(SmallVectorImpl<ManagedValue> &yields);
50625066

50635067
RValue apply(SGFContext C = SGFContext()) {
@@ -5115,9 +5119,11 @@ namespace {
51155119
/// Cleanup to end a coroutine application.
51165120
class EndCoroutineApply : public Cleanup {
51175121
SILValue ApplyToken;
5122+
bool CanUnwind;
51185123
std::vector<BeginBorrowInst *> BorrowedMoveOnlyValues;
51195124
public:
5120-
EndCoroutineApply(SILValue applyToken) : ApplyToken(applyToken) {}
5125+
EndCoroutineApply(SILValue applyToken, bool CanUnwind)
5126+
: ApplyToken(applyToken), CanUnwind(CanUnwind) {}
51215127

51225128
void setBorrowedMoveOnlyValues(ArrayRef<BeginBorrowInst *> values) {
51235129
BorrowedMoveOnlyValues.insert(BorrowedMoveOnlyValues.end(),
@@ -5130,14 +5136,7 @@ class EndCoroutineApply : public Cleanup {
51305136
SGF.B.createEndBorrow(l, *i);
51315137
SGF.B.createDestroyValue(l, (*i)->getOperand());
51325138
}
5133-
auto *beginApply =
5134-
cast<BeginApplyInst>(ApplyToken->getDefiningInstruction());
5135-
auto isCalleeAllocated = beginApply->isCalleeAllocated();
5136-
auto unwindOnCallerError =
5137-
!isCalleeAllocated ||
5138-
SGF.SGM.getASTContext().LangOpts.hasFeature(
5139-
Feature::CoroutineAccessorsUnwindOnCallerError);
5140-
if (forUnwind && unwindOnCallerError) {
5139+
if (forUnwind && CanUnwind) {
51415140
SGF.B.createAbortApply(l, ApplyToken);
51425141
} else {
51435142
SGF.B.createEndApply(l, ApplyToken,
@@ -5180,18 +5179,15 @@ CallEmission::applyCoroutine(SmallVectorImpl<ManagedValue> &yields) {
51805179

51815180
auto fnValue = callee.getFnValue(SGF, borrowedSelf);
51825181

5183-
return SGF.emitBeginApply(uncurriedLoc.value(), fnValue,
5182+
return SGF.emitBeginApply(uncurriedLoc.value(), fnValue, canUnwind,
51845183
callee.getSubstitutions(), uncurriedArgs,
51855184
calleeTypeInfo.substFnType, options, yields);
51865185
}
51875186

5188-
CleanupHandle
5189-
SILGenFunction::emitBeginApply(SILLocation loc, ManagedValue fn,
5190-
SubstitutionMap subs,
5191-
ArrayRef<ManagedValue> args,
5192-
CanSILFunctionType substFnType,
5193-
ApplyOptions options,
5194-
SmallVectorImpl<ManagedValue> &yields) {
5187+
CleanupHandle SILGenFunction::emitBeginApply(
5188+
SILLocation loc, ManagedValue fn, bool canUnwind, SubstitutionMap subs,
5189+
ArrayRef<ManagedValue> args, CanSILFunctionType substFnType,
5190+
ApplyOptions options, SmallVectorImpl<ManagedValue> &yields) {
51955191
// Emit the call.
51965192
SmallVector<SILValue, 4> rawResults;
51975193
emitRawApply(*this, loc, fn, subs, args, substFnType, options,
@@ -5207,7 +5203,7 @@ SILGenFunction::emitBeginApply(SILLocation loc, ManagedValue fn,
52075203

52085204
// Push a cleanup to end the application.
52095205
// TODO: destroy all the arguments at exactly this point?
5210-
Cleanups.pushCleanup<EndCoroutineApply>(token);
5206+
Cleanups.pushCleanup<EndCoroutineApply>(token, canUnwind);
52115207
auto endApplyHandle = getTopCleanup();
52125208

52135209
// Manage all the yielded values.
@@ -6184,7 +6180,7 @@ SILValue SILGenFunction::emitApplyWithRethrow(SILLocation loc, SILValue fn,
61846180
std::tuple<MultipleValueInstructionResult *, CleanupHandle, SILValue,
61856181
CleanupHandle>
61866182
SILGenFunction::emitBeginApplyWithRethrow(SILLocation loc, SILValue fn,
6187-
SILType substFnType,
6183+
SILType substFnType, bool canUnwind,
61886184
SubstitutionMap subs,
61896185
ArrayRef<SILValue> args,
61906186
SmallVectorImpl<SILValue> &yields) {
@@ -6209,7 +6205,7 @@ SILGenFunction::emitBeginApplyWithRethrow(SILLocation loc, SILValue fn,
62096205
deallocCleanup = enterDeallocStackCleanup(allocation);
62106206
}
62116207

6212-
Cleanups.pushCleanup<EndCoroutineApply>(token);
6208+
Cleanups.pushCleanup<EndCoroutineApply>(token, canUnwind);
62136209
auto abortCleanup = Cleanups.getTopCleanup();
62146210

62156211
return {token, abortCleanup, allocation, deallocCleanup};
@@ -7562,6 +7558,21 @@ ManagedValue SILGenFunction::emitAddressorAccessor(
75627558
return ManagedValue::forLValue(address);
75637559
}
75647560

7561+
bool SILGenFunction::canUnwindAccessorDeclRef(SILDeclRef accessorRef) {
7562+
auto *accessor =
7563+
dyn_cast_or_null<AccessorDecl>(accessorRef.getAbstractFunctionDecl());
7564+
ASSERT(accessor && "only accessors can unwind");
7565+
auto kind = accessor->getAccessorKind();
7566+
ASSERT(isYieldingAccessor(kind) && "only yielding accessors can unwind");
7567+
if (!requiresFeatureCoroutineAccessors(kind)) {
7568+
// _read and _modify can unwind
7569+
return true;
7570+
}
7571+
// Coroutine accessors can only unwind with the experimental feature.
7572+
return getASTContext().LangOpts.hasFeature(
7573+
Feature::CoroutineAccessorsUnwindOnCallerError);
7574+
}
7575+
75657576
CleanupHandle
75667577
SILGenFunction::emitCoroutineAccessor(SILLocation loc, SILDeclRef accessor,
75677578
SubstitutionMap substitutions,
@@ -7597,6 +7608,8 @@ SILGenFunction::emitCoroutineAccessor(SILLocation loc, SILDeclRef accessor,
75977608

75987609
emission.addCallSite(loc, std::move(subscriptIndices));
75997610

7611+
emission.setCanUnwind(canUnwindAccessorDeclRef(accessor));
7612+
76007613
auto endApplyHandle = emission.applyCoroutine(yields);
76017614

76027615
return endApplyHandle;

lib/SILGen/SILGenFunction.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2034,6 +2034,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
20342034
PreparedArguments &&optionalSubscripts,
20352035
SILType addressType, bool isOnSelfParameter);
20362036

2037+
bool canUnwindAccessorDeclRef(SILDeclRef accessorRef);
20372038
CleanupHandle emitCoroutineAccessor(SILLocation loc, SILDeclRef accessor,
20382039
SubstitutionMap substitutions,
20392040
ArgumentSource &&optionalSelfValue,
@@ -2301,8 +2302,9 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
23012302
PreparedArguments &&args, Type overriddenSelfType,
23022303
SGFContext ctx);
23032304

2304-
CleanupHandle emitBeginApply(SILLocation loc, ManagedValue fn,
2305-
SubstitutionMap subs, ArrayRef<ManagedValue> args,
2305+
CleanupHandle emitBeginApply(SILLocation loc, ManagedValue fn, bool canUnwind,
2306+
SubstitutionMap subs,
2307+
ArrayRef<ManagedValue> args,
23062308
CanSILFunctionType substFnType,
23072309
ApplyOptions options,
23082310
SmallVectorImpl<ManagedValue> &yields);
@@ -2315,7 +2317,8 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
23152317
std::tuple<MultipleValueInstructionResult *, CleanupHandle, SILValue,
23162318
CleanupHandle>
23172319
emitBeginApplyWithRethrow(SILLocation loc, SILValue fn, SILType substFnType,
2318-
SubstitutionMap subs, ArrayRef<SILValue> args,
2320+
bool canUnwind, SubstitutionMap subs,
2321+
ArrayRef<SILValue> args,
23192322
SmallVectorImpl<SILValue> &yields);
23202323
void emitEndApplyWithRethrow(SILLocation loc,
23212324
MultipleValueInstructionResult *token,

lib/SILGen/SILGenLValue.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2535,9 +2535,9 @@ namespace {
25352535

25362536
// Perform the begin_apply.
25372537
SmallVector<ManagedValue, 1> yields;
2538-
auto cleanup =
2539-
SGF.emitBeginApply(loc, projectFnRef, subs, { base, keyPathValue },
2540-
substFnType, ApplyOptions(), yields);
2538+
auto cleanup = SGF.emitBeginApply(loc, projectFnRef, /*canUnwind=*/true,
2539+
subs, {base, keyPathValue}, substFnType,
2540+
ApplyOptions(), yields);
25412541

25422542
// Push an operation to do the end_apply.
25432543
pushEndApplyWriteback(SGF, loc, cleanup, getTypeData());

lib/SILGen/SILGenPoly.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7046,8 +7046,8 @@ SILGenFunction::emitVTableThunk(SILDeclRef base,
70467046
case SILCoroutineKind::YieldOnce2: {
70477047
SmallVector<SILValue, 4> derivedYields;
70487048
auto tokenAndCleanups = emitBeginApplyWithRethrow(
7049-
loc, derivedRef, SILType::getPrimitiveObjectType(derivedFTy), subs,
7050-
args, derivedYields);
7049+
loc, derivedRef, SILType::getPrimitiveObjectType(derivedFTy),
7050+
canUnwindAccessorDeclRef(base), subs, args, derivedYields);
70517051
auto token = std::get<0>(tokenAndCleanups);
70527052
auto abortCleanup = std::get<1>(tokenAndCleanups);
70537053
auto allocation = std::get<2>(tokenAndCleanups);
@@ -7441,7 +7441,8 @@ void SILGenFunction::emitProtocolWitness(
74417441
case SILCoroutineKind::YieldOnce2: {
74427442
SmallVector<SILValue, 4> witnessYields;
74437443
auto tokenAndCleanups = emitBeginApplyWithRethrow(
7444-
loc, witnessFnRef, witnessSILTy, witnessSubs, args, witnessYields);
7444+
loc, witnessFnRef, witnessSILTy, canUnwindAccessorDeclRef(requirement),
7445+
witnessSubs, args, witnessYields);
74457446
auto token = std::get<0>(tokenAndCleanups);
74467447
auto abortCleanup = std::get<1>(tokenAndCleanups);
74477448
auto allocation = std::get<2>(tokenAndCleanups);
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// RUN: %target-run-simple-swift(-Xfrontend -disable-callee-allocated-coro-abi -enable-experimental-feature CoroutineAccessors) | %FileCheck %s
2+
3+
// REQUIRES: swift_feature_CoroutineAccessors
4+
// REQUIRES: executable_test
5+
6+
struct AirOr : Error {
7+
}
8+
9+
struct Thrower {
10+
mutating func doit() throws {
11+
throw AirOr()
12+
}
13+
}
14+
15+
struct S {
16+
var _thrower = Thrower()
17+
var thrower: Thrower {
18+
read {
19+
yield _thrower
20+
}
21+
modify {
22+
// CHECK: first
23+
print("first")
24+
yield &_thrower
25+
// CHECK: also ran
26+
print("also ran")
27+
}
28+
}
29+
}
30+
31+
func doit() {
32+
do {
33+
var s = S()
34+
try s.thrower.doit()
35+
} catch let error {
36+
// CHECK: AirOr
37+
print(error)
38+
}
39+
}
40+
41+
doit()
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %target-swift-emit-silgen -Xllvm -sil-print-types \
2+
// RUN: %s \
3+
// RUN: -enable-callee-allocated-coro-abi \
4+
// RUN: -enable-library-evolution \
5+
// RUN: -enable-experimental-feature CoroutineAccessors \
6+
// RUN: | %FileCheck %s --check-prefixes=CHECK,CHECK-NORMAL
7+
8+
// REQUIRES: swift_feature_CoroutineAccessors
9+
10+
// CHECK: yield_once_2
11+
12+
struct S {
13+
14+
var one: Int = 1
15+
var i: Int {
16+
read {
17+
yield one
18+
}
19+
}
20+
21+
}
22+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %target-swift-emit-silgen -Xllvm -sil-print-types \
2+
// RUN: %s \
3+
// RUN: -disable-callee-allocated-coro-abi \
4+
// RUN: -enable-library-evolution \
5+
// RUN: -enable-experimental-feature CoroutineAccessors \
6+
// RUN: | %FileCheck %s --check-prefixes=CHECK,CHECK-NORMAL
7+
8+
// REQUIRES: swift_feature_CoroutineAccessors
9+
10+
// CHECK: yield_once
11+
// CHECK-NOT: yield_once_2
12+
13+
struct S {
14+
15+
var zero: Int = 0
16+
var i: Int {
17+
read {
18+
yield zero
19+
}
20+
}
21+
22+
}

0 commit comments

Comments
 (0)