mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[silgen] Balance out the +1 from the self argument in deallocating deinits using end_lifetime.
The issue here is that: 1. Self is passed into deallocating deinits at +1. 2. Destroying deinits take in self as a +0 value that is then returned at +1. This means that the lifetime of self can not be modeled statically in a deallocating deinit without analyzing the body of the destroying deinit (something that violates semantic sil). Thus we add an artifical destroy of self before the actual destroy of self so that the verifier can understand that self is being properly balanced. rdar://29791263
This commit is contained in:
@@ -85,29 +85,45 @@ void SILGenFunction::emitDeallocatingDestructor(DestructorDecl *dd) {
|
||||
loc.markAutoGenerated();
|
||||
|
||||
// Emit the prolog.
|
||||
SILValue selfValue = emitSelfDecl(dd->getImplicitSelfDecl());
|
||||
SILValue initialSelfValue = emitSelfDecl(dd->getImplicitSelfDecl());
|
||||
|
||||
// Form a reference to the destroying destructor.
|
||||
SILDeclRef dtorConstant(dd, SILDeclRef::Kind::Destroyer);
|
||||
auto classTy = selfValue->getType();
|
||||
auto classTy = initialSelfValue->getType();
|
||||
ManagedValue dtorValue;
|
||||
SILType dtorTy;
|
||||
SubstitutionList subs = classTy.gatherAllSubstitutions(SGM.M);
|
||||
std::tie(dtorValue, dtorTy, subs)
|
||||
= emitSiblingMethodRef(loc, selfValue, dtorConstant, subs);
|
||||
= emitSiblingMethodRef(loc, initialSelfValue, dtorConstant, subs);
|
||||
|
||||
// Call the destroying destructor.
|
||||
SILValue selfForDealloc;
|
||||
{
|
||||
FullExpr CleanupScope(Cleanups, CleanupLocation::get(loc));
|
||||
ManagedValue borrowedSelf = emitManagedBeginBorrow(loc, selfValue);
|
||||
ManagedValue borrowedSelf = emitManagedBeginBorrow(loc, initialSelfValue);
|
||||
SILType objectPtrTy = SILType::getNativeObjectType(F.getASTContext());
|
||||
selfValue = B.createApply(loc, dtorValue.forward(*this),
|
||||
dtorTy, objectPtrTy, subs, borrowedSelf.getUnmanagedValue());
|
||||
selfForDealloc = B.createApply(loc, dtorValue.forward(*this),
|
||||
dtorTy, objectPtrTy, subs, borrowedSelf.getUnmanagedValue());
|
||||
}
|
||||
|
||||
// Balance out the +1 from the self argument using end_lifetime.
|
||||
//
|
||||
// The issue here is that:
|
||||
//
|
||||
// 1. Self is passed into deallocating deinits at +1.
|
||||
// 2. Destroying deinits take in self as a +0 value that is then returned at
|
||||
// +1.
|
||||
//
|
||||
// This means that the lifetime of self can not be modeled statically in a
|
||||
// deallocating deinit without analyzing the body of the destroying deinit
|
||||
// (something that violates semantic sil). Thus we add an artifical destroy of
|
||||
// self before the actual destroy of self so that the verifier can understand
|
||||
// that self is being properly balanced.
|
||||
B.createEndLifetime(loc, initialSelfValue);
|
||||
|
||||
// Deallocate the object.
|
||||
selfValue = B.createUncheckedRefCast(loc, selfValue, classTy);
|
||||
B.createDeallocRef(loc, selfValue, false);
|
||||
selfForDealloc = B.createUncheckedRefCast(loc, selfForDealloc, classTy);
|
||||
B.createDeallocRef(loc, selfForDealloc, false);
|
||||
|
||||
// Return.
|
||||
B.createReturn(loc, emitEmptyTuple(loc));
|
||||
|
||||
Reference in New Issue
Block a user