Skip to content

Commit 4964a66

Browse files
committed
silgen: inherit eval scope for OpenExistentialExpr
We were not able to use an existential as the base of an access that strictly borrows the existential, because SILGen's RValue emission would establish a fresh evaluation scope just for the existential's opening, and then copy the opened value out. This is problematic for noncopyable existentials. So this patch moves & adds FormalEvaluationScope's around so they're broad enough to enable a borrow of an existential. The idea behind this refactoring is to establish top-level FormalEvaluationScopes when initially creating RValue's for Expr's in SILGen. Any more-tightly scoped operations will already establish their own nested scope, so this is mostly adding safe-guards. I've limited the existentials fix to noncopyables for now. part of rdar://159079818
1 parent 906a4cb commit 4964a66

File tree

3 files changed

+21
-6
lines changed

3 files changed

+21
-6
lines changed

lib/SILGen/SILGenDecl.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1770,6 +1770,7 @@ void SILGenFunction::emitStmtCondition(StmtCondition Cond, JumpDest FalseDest,
17701770
auto *expr = elt.getBoolean();
17711771
// Evaluate the condition as an i1 value (guaranteed by Sema).
17721772
FullExpr Scope(Cleanups, CleanupLocation(expr));
1773+
FormalEvaluationScope EvalScope(*this);
17731774
booleanTestValue = emitRValue(expr).forwardAsSingleValue(*this, expr);
17741775
booleanTestValue = emitUnwrapIntegerResult(expr, booleanTestValue);
17751776
booleanTestLoc = expr;

lib/SILGen/SILGenExpr.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,7 @@ void SILGenFunction::emitExprInto(Expr *E, Initialization *I,
412412
return;
413413
}
414414

415+
FormalEvaluationScope writeback(*this);
415416
RValue result = emitRValue(E, SGFContext(I));
416417
if (result.isInContext())
417418
return;
@@ -6161,6 +6162,8 @@ RValue RValueEmitter::visitOptionalEvaluationExpr(OptionalEvaluationExpr *E,
61616162
SmallVector<ManagedValue, 1> results;
61626163
SGF.emitOptionalEvaluation(E, E->getType(), results, C,
61636164
[&](SmallVectorImpl<ManagedValue> &results, SGFContext primaryC) {
6165+
// Generate each result in its own evaluation scope.
6166+
FormalEvaluationScope evalScope(SGF);
61646167
ManagedValue result;
61656168
if (!emitOptimizedOptionalEvaluation(SGF, E, result, primaryC)) {
61666169
result = SGF.emitRValueAsSingleValue(E->getSubExpr(), primaryC);
@@ -6494,7 +6497,7 @@ RValue RValueEmitter::emitForceValue(ForceValueExpr *loc, Expr *E,
64946497
void SILGenFunction::emitOpenExistentialExprImpl(
64956498
OpenExistentialExpr *E,
64966499
llvm::function_ref<void(Expr *)> emitSubExpr) {
6497-
assert(isInFormalEvaluationScope());
6500+
ASSERT(isInFormalEvaluationScope());
64986501

64996502
// Emit the existential value.
65006503
if (E->getExistentialValue()->getType()->is<LValueType>()) {
@@ -6529,7 +6532,14 @@ RValue RValueEmitter::visitOpenExistentialExpr(OpenExistentialExpr *E,
65296532
return RValue(SGF, E, *result);
65306533
}
65316534

6532-
FormalEvaluationScope writebackScope(SGF);
6535+
// Introduce a fresh, nested evaluation scope for Copyable types.
6536+
// This is a bit of a hack, as it should always be up to our caller
6537+
// to establish the right level of formal access scope, in case we
6538+
// formally borrow the opened existential instead of copying it.
6539+
std::optional<FormalEvaluationScope> scope;
6540+
if (!E->getType()->isNoncopyable())
6541+
scope.emplace(SGF);
6542+
65336543
return SGF.emitOpenExistentialExpr<RValue>(E,
65346544
[&](Expr *subExpr) -> RValue {
65356545
return visit(subExpr, C);
@@ -7514,17 +7524,17 @@ void SILGenFunction::emitIgnoredExpr(Expr *E) {
75147524
// arguments.
75157525

75167526
FullExpr scope(Cleanups, CleanupLocation(E));
7527+
FormalEvaluationScope evalScope(*this);
7528+
75177529
if (E->getType()->hasLValueType()) {
75187530
// Emit the l-value, but don't perform an access.
7519-
FormalEvaluationScope scope(*this);
75207531
emitLValue(E, SGFAccessKind::IgnoredRead);
75217532
return;
75227533
}
75237534

75247535
// If this is a load expression, we try hard not to actually do the load
75257536
// (which could materialize a potentially expensive value with cleanups).
75267537
if (auto *LE = dyn_cast<LoadExpr>(E)) {
7527-
FormalEvaluationScope scope(*this);
75287538
LValue lv = emitLValue(LE->getSubExpr(), SGFAccessKind::IgnoredRead);
75297539

75307540
// If loading from the lvalue is guaranteed to have no side effects, we
@@ -7559,7 +7569,6 @@ void SILGenFunction::emitIgnoredExpr(Expr *E) {
75597569
// emit the precondition(s) without having to load the value.
75607570
SmallVector<ForceValueExpr *, 4> forceValueExprs;
75617571
if (auto *LE = findLoadThroughForceValueExprs(E, forceValueExprs)) {
7562-
FormalEvaluationScope scope(*this);
75637572
LValue lv = emitLValue(LE->getSubExpr(), SGFAccessKind::IgnoredRead);
75647573

75657574
ManagedValue value;

lib/SILGen/SILGenStmt.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,7 @@ void SILGenFunction::emitReturnExpr(SILLocation branchLoc,
729729
} else {
730730
// SILValue return.
731731
FullExpr scope(Cleanups, CleanupLocation(ret));
732+
FormalEvaluationScope writeback(*this);
732733

733734
// Does the return context require reabstraction?
734735
RValue RV;
@@ -774,7 +775,11 @@ void StmtEmitter::visitThrowStmt(ThrowStmt *S) {
774775
return;
775776
}
776777

777-
ManagedValue exn = SGF.emitRValueAsSingleValue(S->getSubExpr());
778+
ManagedValue exn;
779+
{
780+
FormalEvaluationScope scope(SGF);
781+
exn = SGF.emitRValueAsSingleValue(S->getSubExpr());
782+
}
778783
SGF.emitThrow(S, exn, /* emit a call to willThrow */ true);
779784
}
780785

0 commit comments

Comments
 (0)