mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[silgen] When exploding tuple values into RValues, use a load_borrow instead of a load [take].
This can only come up if you have a tuple that is part address only and part non-trivial, but loadable. Previously, the non-trivial value would be taken but no cleanup would be created. This would trip the ownership verifier. Now we properly model this via a load_borrow. *NOTE* Due to us modeling a take as not-copying a value, after ownership is stripped we have the same underlying singular load, so this is not a bug, but a semantic violation of the model (i.e. taking a +0 self value). rdar://33358110
This commit is contained in:
@@ -108,36 +108,44 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void visitAddressTupleType(CanTupleType tupleFormalType,
|
||||
ManagedValue tupleMV) {
|
||||
bool isPlusZero = tupleMV.isPlusZeroRValueOrTrivial();
|
||||
SILValue tuple = tupleMV.forward(SGF);
|
||||
void visitAddressTupleType(CanTupleType tupleFormalType, ManagedValue tuple) {
|
||||
bool isPlusZero = tuple.isPlusZeroRValueOrTrivial();
|
||||
|
||||
for (auto i : indices(tupleFormalType->getElements())) {
|
||||
for (unsigned i : indices(tupleFormalType->getElements())) {
|
||||
CanType eltFormalType = tupleFormalType.getElementType(i);
|
||||
assert(eltFormalType->isMaterializable());
|
||||
|
||||
auto eltTy = tuple->getType().getTupleElementType(i);
|
||||
assert(eltTy.isAddress() == tuple->getType().isAddress());
|
||||
auto eltTy = tuple.getType().getTupleElementType(i);
|
||||
assert(eltTy.isAddress() == tuple.getType().isAddress());
|
||||
auto &eltTI = SGF.getTypeLowering(eltTy);
|
||||
|
||||
// Project the element.
|
||||
SILValue elt = SGF.B.createTupleElementAddr(loc, tuple, i, eltTy);
|
||||
// Project the element. This always returns a +0 handle with independent
|
||||
// lifetime from tuple. We forward tuple when we are done so we can use
|
||||
// ownership APIs.
|
||||
ManagedValue elt = SGF.B.createTupleElementAddr(loc, tuple, i, eltTy);
|
||||
|
||||
// RValue has an invariant that loadable values have been
|
||||
// loaded. Except it's not really an invariant, because
|
||||
// argument emission likes to lie sometimes.
|
||||
// RValue has an invariant that loadable values have been loaded. Except
|
||||
// it's not really an invariant, because argument emission likes to lie
|
||||
// sometimes.
|
||||
if (eltTI.isLoadable()) {
|
||||
elt = eltTI.emitLoad(SGF.B, loc, elt, LoadOwnershipQualifier::Take);
|
||||
if (isPlusZero) {
|
||||
elt = SGF.B.createLoadBorrow(loc, elt);
|
||||
} else {
|
||||
elt = SGF.B.createLoadTake(loc, elt);
|
||||
}
|
||||
} else {
|
||||
// In contrast if we have an address only type, we can not rely on
|
||||
// ownership APIs to help us. So, manually create a cleanup to make up
|
||||
// for the cleanup that we will forward on tuple.
|
||||
if (!isPlusZero)
|
||||
elt = SGF.emitManagedRValueWithCleanup(elt.getValue(), eltTI);
|
||||
}
|
||||
|
||||
// If we're returning a +1 value, emit a cleanup for the member
|
||||
// to cover for the cleanup we disabled for the tuple aggregate.
|
||||
auto eltMV = isPlusZero ? ManagedValue::forUnmanaged(elt)
|
||||
: SGF.emitManagedRValueWithCleanup(elt, eltTI);
|
||||
|
||||
visit(eltFormalType, eltMV);
|
||||
visit(eltFormalType, elt);
|
||||
}
|
||||
|
||||
// Forward the cleanup for tuple now that we have finished emitting values.
|
||||
tuple.forward(SGF);
|
||||
}
|
||||
|
||||
void visitTupleType(CanTupleType tupleFormalType, ManagedValue tuple) {
|
||||
|
||||
Reference in New Issue
Block a user