Skip to content

Commit 82ef5b3

Browse files
committed
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 52b3ba1 commit 82ef5b3

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

0 commit comments

Comments
 (0)