Skip to content

Commit 77719a5

Browse files
committed
SILGen: Evaluate loaded lvalues in a writeback scope.
emitLValue always has to occur in a writeback scope, even if the lvalue isn't formally accessed until later, because some lvalue productions immediately access their parent lvalue expression (namely optional chaining expressions). Fixes rdar://problem/26642478.
1 parent 4505d6e commit 77719a5

File tree

3 files changed

+15
-0
lines changed

3 files changed

+15
-0
lines changed

lib/SILGen/SILGenExpr.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,8 @@ RValue RValueEmitter::visitStringLiteralExpr(StringLiteralExpr *E,
803803
}
804804

805805
RValue RValueEmitter::visitLoadExpr(LoadExpr *E, SGFContext C) {
806+
// Any writebacks here are tightly scoped.
807+
WritebackScope writeback(SGF);
806808
LValue lv = SGF.emitLValue(E->getSubExpr(), AccessKind::Read);
807809
return SGF.emitLoadOfLValue(E, std::move(lv), C);
808810
}
@@ -3436,13 +3438,15 @@ void SILGenFunction::emitIgnoredExpr(Expr *E) {
34363438
FullExpr scope(Cleanups, CleanupLocation(E));
34373439
if (!E->getType()->isMaterializable()) {
34383440
// Emit the l-value, but don't perform an access.
3441+
WritebackScope scope(*this);
34393442
emitLValue(E, AccessKind::Read);
34403443
return;
34413444
}
34423445

34433446
// If this is a load expression, we try hard not to actually do the load
34443447
// (which could materialize a potentially expensive value with cleanups).
34453448
if (auto *LE = dyn_cast<LoadExpr>(E)) {
3449+
WritebackScope scope(*this);
34463450
LValue lv = emitLValue(LE->getSubExpr(), AccessKind::Read);
34473451
// If the lvalue is purely physical, then it won't have any side effects,
34483452
// and we don't need to drill into it.

lib/SILGen/SILGenLValue.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,6 +1514,11 @@ void LValue::print(raw_ostream &OS) const {
15141514
}
15151515

15161516
LValue SILGenFunction::emitLValue(Expr *e, AccessKind accessKind) {
1517+
// Some lvalue nodes (namely BindOptionalExprs) require immediate evaluation
1518+
// of their subexpression, so we must have a writeback scope open while
1519+
// building an lvalue.
1520+
assert(InWritebackScope && "must be in a writeback scope");
1521+
15171522
LValue r = SILGenLValue(*this).visit(e, accessKind);
15181523
// If the final component has an abstraction change, introduce a
15191524
// reabstraction component.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// RUN: %target-swift-frontend -emit-silgen -verify -parse-as-library %s
2+
3+
func foo(x: UnsafeMutablePointer<UnsafeMutablePointer<()>?>) {
4+
_ = x.pointee?.pointee
5+
_ = x.pointee?.dynamicType
6+
}

0 commit comments

Comments
 (0)