Skip to content

Commit 107b220

Browse files
slavapestovrjmccall
authored andcommitted
SILGen: Fix LogicalPathComponent::getMaterialized() for opened existentials
This is pretty awkward. If an lvalue has an open existential as its RValue type, we would emit an alloc_stack instruction holding the materialized temporary before we emitted the value itself. This introduced a def-after-use violation because the open existential type in the stack allocation was not dominated by its definition. To get around this, don't use an SGFContext to emit the 'get' in-place. There's no performance degradation, because the only time we will attempt materializing an lvalue with an open existential type is when performing an lvalue access of a class existential payload, and here we in-place initialization makes no difference since the value is a single reference.
1 parent 5c3ad65 commit 107b220

File tree

1 file changed

+57
-0
lines changed

1 file changed

+57
-0
lines changed

lib/SILGen/SILGenLValue.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,63 @@ ManagedValue LogicalPathComponent::getMaterialized(SILGenFunction &SGF,
227227
SILLocation loc,
228228
ManagedValue base,
229229
AccessKind kind) && {
230+
if (getTypeOfRValue().getSwiftRValueType()->hasOpenedExistential()) {
231+
if (kind == AccessKind::Read) {
232+
// Emit a 'get' into the temporary.
233+
RValue value =
234+
std::move(*this).get(SGF, loc, base, SGFContext());
235+
236+
// Create a temporary.
237+
std::unique_ptr<TemporaryInitialization> temporaryInit =
238+
SGF.emitFormalAccessTemporary(loc,
239+
SGF.getTypeLowering(getTypeOfRValue()));
240+
241+
std::move(value).forwardInto(SGF, loc, temporaryInit.get());
242+
243+
return temporaryInit->getManagedAddress();
244+
}
245+
246+
assert(SGF.InWritebackScope &&
247+
"materializing l-value for modification without writeback scope");
248+
249+
// Clone anything else about the component that we might need in the
250+
// writeback.
251+
auto clonedComponent = clone(SGF, loc);
252+
253+
SILValue mv;
254+
{
255+
FormalEvaluationScope Scope(SGF);
256+
257+
// Otherwise, we need to emit a get and set. Borrow the base for
258+
// the getter.
259+
ManagedValue getterBase =
260+
base ? base.formalAccessBorrow(SGF, loc) : ManagedValue();
261+
262+
// Emit a 'get' into a temporary and then pop the borrow of base.
263+
RValue value =
264+
std::move(*this).get(SGF, loc, getterBase, SGFContext());
265+
266+
mv = std::move(value).forwardAsSingleValue(SGF, loc);
267+
}
268+
269+
auto &TL = SGF.getTypeLowering(getTypeOfRValue());
270+
271+
// Create a temporary.
272+
std::unique_ptr<TemporaryInitialization> temporaryInit =
273+
SGF.emitFormalAccessTemporary(loc, TL);
274+
275+
SGF.emitSemanticStore(loc, mv, temporaryInit->getAddress(),
276+
TL, IsInitialization);
277+
temporaryInit->finishInitialization(SGF);
278+
279+
auto temporary = temporaryInit->getManagedAddress();
280+
281+
// Push a writeback for the temporary.
282+
pushWriteback(SGF, loc, std::move(clonedComponent), base,
283+
MaterializedLValue(temporary));
284+
return temporary.unmanagedBorrow();
285+
}
286+
230287
// If this is just for a read, emit a load into a temporary memory
231288
// location.
232289
if (kind == AccessKind::Read) {

0 commit comments

Comments
 (0)