Skip to content

Commit b76a76b

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 056fbc4 commit b76a76b

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
@@ -4999,14 +4999,16 @@ class CallEmission {
49994999
FormalEvaluationScope initialWritebackScope;
50005000
std::optional<ActorIsolation> implicitActorHopTarget;
50015001
bool implicitlyThrows;
5002+
bool canUnwind;
50025003

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

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

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

50625066
RValue apply(SGFContext C = SGFContext()) {
@@ -5114,9 +5118,11 @@ namespace {
51145118
/// Cleanup to end a coroutine application.
51155119
class EndCoroutineApply : public Cleanup {
51165120
SILValue ApplyToken;
5121+
bool CanUnwind;
51175122
std::vector<BeginBorrowInst *> BorrowedMoveOnlyValues;
51185123
public:
5119-
EndCoroutineApply(SILValue applyToken) : ApplyToken(applyToken) {}
5124+
EndCoroutineApply(SILValue applyToken, bool CanUnwind)
5125+
: ApplyToken(applyToken), CanUnwind(CanUnwind) {}
51205126

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

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

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

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

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

52125208
// Manage all the yielded values.
@@ -6183,7 +6179,7 @@ SILValue SILGenFunction::emitApplyWithRethrow(SILLocation loc, SILValue fn,
61836179
std::tuple<MultipleValueInstructionResult *, CleanupHandle, SILValue,
61846180
CleanupHandle>
61856181
SILGenFunction::emitBeginApplyWithRethrow(SILLocation loc, SILValue fn,
6186-
SILType substFnType,
6182+
SILType substFnType, bool canUnwind,
61876183
SubstitutionMap subs,
61886184
ArrayRef<SILValue> args,
61896185
SmallVectorImpl<SILValue> &yields) {
@@ -6208,7 +6204,7 @@ SILGenFunction::emitBeginApplyWithRethrow(SILLocation loc, SILValue fn,
62086204
deallocCleanup = enterDeallocStackCleanup(allocation);
62096205
}
62106206

6211-
Cleanups.pushCleanup<EndCoroutineApply>(token);
6207+
Cleanups.pushCleanup<EndCoroutineApply>(token, canUnwind);
62126208
auto abortCleanup = Cleanups.getTopCleanup();
62136209

62146210
return {token, abortCleanup, allocation, deallocCleanup};
@@ -7561,6 +7557,21 @@ ManagedValue SILGenFunction::emitAddressorAccessor(
75617557
return ManagedValue::forLValue(address);
75627558
}
75637559

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

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

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

76017614
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
@@ -2518,9 +2518,9 @@ namespace {
25182518

25192519
// Perform the begin_apply.
25202520
SmallVector<ManagedValue, 1> yields;
2521-
auto cleanup =
2522-
SGF.emitBeginApply(loc, projectFnRef, subs, { base, keyPathValue },
2523-
substFnType, ApplyOptions(), yields);
2521+
auto cleanup = SGF.emitBeginApply(loc, projectFnRef, /*canUnwind=*/true,
2522+
subs, {base, keyPathValue}, substFnType,
2523+
ApplyOptions(), yields);
25242524

25252525
// Push an operation to do the end_apply.
25262526
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)